karnel-termux 4.7.6 → 4.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +230 -225
- package/install.sh +30 -9
- package/karnel/bin/karnel +2 -2
- package/karnel/cli/commands/backup.sh +10 -2
- package/karnel/cli/commands/brain.sh +28 -23
- package/karnel/cli/commands/cleanup.sh +10 -4
- package/karnel/cli/commands/deploy.sh +53 -0
- package/karnel/cli/commands/doctor/code.sh +225 -0
- package/karnel/cli/commands/doctor/code_detect.sh +184 -0
- package/karnel/cli/commands/doctor/code_exec.sh +278 -0
- package/karnel/cli/commands/doctor/code_langs.sh +229 -0
- package/karnel/cli/commands/doctor/fixes.sh +63 -46
- package/karnel/cli/commands/doctor.sh +222 -80
- package/karnel/cli/commands/env.sh +2 -0
- package/karnel/cli/commands/ia.sh +12 -2
- package/karnel/cli/commands/init.sh +17 -9
- package/karnel/cli/commands/install.sh +90 -54
- package/karnel/cli/commands/list.sh +36 -0
- package/karnel/cli/commands/pg.sh +21 -6
- package/karnel/cli/commands/reinstall.sh +99 -0
- package/karnel/cli/commands/restore.sh +43 -3
- package/karnel/cli/commands/search.sh +2 -2
- package/karnel/cli/commands/update.sh +6 -1
- package/karnel/cli/commands/upgrade.sh +8 -1
- package/karnel/cli/commands/voice.sh +2 -1
- package/karnel/cli/karnel.sh +11 -5
- package/karnel/modules/games.sh +11 -0
- package/karnel/tools/ai/all.sh +1 -0
- package/karnel/tools/ai/copilot-termux/README.md +40 -0
- package/karnel/tools/ai/copilot-termux/install.sh +80 -0
- package/karnel/tools/ai/copilot-termux/package.json +20 -0
- package/karnel/tools/db/all.sh +2 -0
- package/karnel/tools/deploy/railway/install.sh +2 -2
- package/karnel/tools/dev/all.sh +8 -0
- package/karnel/tools/dev/applaunch/__pycache__/applaunch.cpython-314.pyc +0 -0
- package/karnel/tools/dev/applaunch/applaunch.py +434 -0
- package/karnel/tools/dev/applaunch/install.sh +51 -0
- package/karnel/tools/dev/fconv/__pycache__/fconv.cpython-314.pyc +0 -0
- package/karnel/tools/dev/fconv/fconv.py +749 -0
- package/karnel/tools/dev/fconv/install.sh +51 -0
- package/karnel/tools/dev/filecheck/__pycache__/filecheck.cpython-314.pyc +0 -0
- package/karnel/tools/dev/filecheck/filecheck.py +429 -0
- package/karnel/tools/dev/filecheck/install.sh +51 -0
- package/karnel/tools/dev/notes/__pycache__/notes.cpython-314.pyc +0 -0
- package/karnel/tools/dev/notes/install.sh +51 -0
- package/karnel/tools/dev/notes/notes.py +849 -0
- package/karnel/tools/dev/passman/__pycache__/passman.cpython-314.pyc +0 -0
- package/karnel/tools/dev/passman/install.sh +51 -0
- package/karnel/tools/dev/passman/passman.py +536 -0
- package/karnel/tools/dev/splash/__pycache__/splash.cpython-314.pyc +0 -0
- package/karnel/tools/dev/splash/install.sh +51 -0
- package/karnel/tools/dev/splash/splash.py +188 -0
- package/karnel/tools/dev/treex/install.sh +51 -0
- package/karnel/tools/dev/treex/treex.py +2036 -0
- package/karnel/tools/dev/websites/__pycache__/websites.cpython-314.pyc +0 -0
- package/karnel/tools/dev/websites/install.sh +51 -0
- package/karnel/tools/dev/websites/websites.py +844 -0
- package/karnel/tools/games/all.sh +62 -0
- package/karnel/tools/games/arcade/__pycache__/arcade.cpython-314.pyc +0 -0
- package/karnel/tools/games/arcade/arcade.py +193 -0
- package/karnel/tools/games/arcade/install.sh +51 -0
- package/karnel/tools/games/buzz/__pycache__/buzz.cpython-314.pyc +0 -0
- package/karnel/tools/games/buzz/buzz.py +1264 -0
- package/karnel/tools/games/buzz/install.sh +51 -0
- package/karnel/tools/games/ctfgod/__pycache__/ctfgod.cpython-314.pyc +0 -0
- package/karnel/tools/games/ctfgod/ctfgod.py +1576 -0
- package/karnel/tools/games/ctfgod/install.sh +51 -0
- package/karnel/tools/games/detective/__pycache__/detective.cpython-314.pyc +0 -0
- package/karnel/tools/games/detective/detective.py +2091 -0
- package/karnel/tools/games/detective/install.sh +51 -0
- package/karnel/tools/games/pet-friends/__pycache__/pet-friends.cpython-314.pyc +0 -0
- package/karnel/tools/games/pet-friends/install.sh +51 -0
- package/karnel/tools/games/pet-friends/pet-friends.py +15802 -0
- package/karnel/tools/games/tamagotchi/__pycache__/tamagotchi.cpython-314.pyc +0 -0
- package/karnel/tools/games/tamagotchi/install.sh +51 -0
- package/karnel/tools/games/tamagotchi/tamagotchi.py +1224 -0
- package/karnel/tools/games/terminal-arcade/__pycache__/terminal-arcade.cpython-314.pyc +0 -0
- package/karnel/tools/games/terminal-arcade/terminal-arcade.py +193 -0
- package/karnel/tools/npm/all.sh +1 -0
- package/karnel/utils/log.sh +34 -12
- package/package.json +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
import "@/utils/log"
|
|
4
|
+
import "@/utils/version"
|
|
5
|
+
|
|
6
|
+
LOG_FILE="$KARNEL_CACHE/install_dev.log"
|
|
7
|
+
|
|
8
|
+
install_fconv() {
|
|
9
|
+
local TOOL_DIR="$KARNEL_PATH/tools/dev/fconv"
|
|
10
|
+
local BIN_NAME="fconv"
|
|
11
|
+
local DOWNLOAD_URL="https://raw.githubusercontent.com/dedsec1121fk/DedSec/main/Scripts/Developer%20Base/File%20Converter.py"
|
|
12
|
+
if command -v fconv &>/dev/null; then
|
|
13
|
+
log_info "File Converter is already installed"
|
|
14
|
+
return 2
|
|
15
|
+
fi
|
|
16
|
+
log_info "Installing File Converter..."
|
|
17
|
+
mkdir -p "$(dirname "$LOG_FILE")" "$TOOL_DIR"
|
|
18
|
+
if ! command -v python3 &>/dev/null; then pkg install python -y &>>"$LOG_FILE" || return 1; fi
|
|
19
|
+
|
|
20
|
+
curl -sL "$DOWNLOAD_URL" -o "$TOOL_DIR/$BIN_NAME.py" || return 1
|
|
21
|
+
chmod +x "$TOOL_DIR/$BIN_NAME.py"
|
|
22
|
+
sed -i "1s|.*|#\!$PREFIX/bin/python3|" "$TOOL_DIR/$BIN_NAME.py"
|
|
23
|
+
ln -sf "$TOOL_DIR/$BIN_NAME.py" "$PREFIX/bin/$BIN_NAME"
|
|
24
|
+
log_success "File Converter installed"
|
|
25
|
+
return 0
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
uninstall_fconv() {
|
|
29
|
+
local BIN_NAME="fconv"
|
|
30
|
+
local TOOL_DIR="$KARNEL_PATH/tools/dev/fconv"
|
|
31
|
+
if ! command -v fconv &>/dev/null; then log_info "File Converter is not installed"; return 2; fi
|
|
32
|
+
log_info "Uninstalling File Converter..."
|
|
33
|
+
rm -f "$PREFIX/bin/$BIN_NAME" "$TOOL_DIR/$BIN_NAME.py"
|
|
34
|
+
log_success "File Converter uninstalled"
|
|
35
|
+
return 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
update_fconv() {
|
|
39
|
+
local TOOL_DIR="$KARNEL_PATH/tools/dev/fconv"
|
|
40
|
+
local BIN_NAME="fconv"
|
|
41
|
+
local DOWNLOAD_URL="https://raw.githubusercontent.com/dedsec1121fk/DedSec/main/Scripts/Developer%20Base/File%20Converter.py"
|
|
42
|
+
log_info "Updating File Converter..."
|
|
43
|
+
curl -sL "$DOWNLOAD_URL" -o "$TOOL_DIR/$BIN_NAME.py" || return 1
|
|
44
|
+
log_success "File Converter updated"
|
|
45
|
+
return 0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
reinstall_fconv() {
|
|
49
|
+
uninstall_fconv
|
|
50
|
+
install_fconv
|
|
51
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
#!/data/data/com.termux/files/usr/bin/python3
|
|
2
|
+
import sys
|
|
3
|
+
import subprocess
|
|
4
|
+
import hashlib
|
|
5
|
+
import math
|
|
6
|
+
import re
|
|
7
|
+
import zipfile
|
|
8
|
+
import binascii
|
|
9
|
+
import struct
|
|
10
|
+
import platform
|
|
11
|
+
import shutil
|
|
12
|
+
import json
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
|
|
15
|
+
# --- Configuration ---
|
|
16
|
+
FOLDER_NAME = "File Type Checker"
|
|
17
|
+
MAX_FILE_SIZE_LIMIT = 50 * 1024 * 1024 * 1024 # 50 GB Limit
|
|
18
|
+
ANALYSIS_RAM_LIMIT = 200 * 1024 * 1024 # Only load 200MB into RAM for pattern scanning
|
|
19
|
+
QUARANTINE_THRESHOLD = 7
|
|
20
|
+
VIRUSTOTAL_API_KEY = ""
|
|
21
|
+
|
|
22
|
+
# --- Cross-Platform Setup ---
|
|
23
|
+
def get_target_dir():
|
|
24
|
+
if os.path.exists('/data/data/com.termux/files/home'):
|
|
25
|
+
return "/sdcard/Download/" + FOLDER_NAME
|
|
26
|
+
return os.path.join(os.path.expanduser("~"), "Downloads", FOLDER_NAME)
|
|
27
|
+
|
|
28
|
+
TARGET_DIR = get_target_dir()
|
|
29
|
+
|
|
30
|
+
def install_dependencies():
|
|
31
|
+
print(f"\033[96m[*] Checking dependencies...\033[0m")
|
|
32
|
+
required = ['rich', 'requests', 'exifread']
|
|
33
|
+
for lib in required:
|
|
34
|
+
try:
|
|
35
|
+
__import__(lib)
|
|
36
|
+
except ImportError:
|
|
37
|
+
print(f"\033[93m[!] Installing '{lib}'...\033[0m")
|
|
38
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", lib])
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
install_dependencies()
|
|
42
|
+
import requests
|
|
43
|
+
import exifread
|
|
44
|
+
from rich.console import Console
|
|
45
|
+
from rich.table import Table
|
|
46
|
+
from rich.panel import Panel
|
|
47
|
+
from rich.layout import Layout
|
|
48
|
+
from rich.markup import escape
|
|
49
|
+
except Exception as e:
|
|
50
|
+
print(f"Critical Error: {e}")
|
|
51
|
+
sys.exit(1)
|
|
52
|
+
|
|
53
|
+
console = Console()
|
|
54
|
+
|
|
55
|
+
# --- Magic Byte Detection ---
|
|
56
|
+
def get_file_mime(filepath, data_head):
|
|
57
|
+
hex_head = binascii.hexlify(data_head[:16]).decode().upper()
|
|
58
|
+
|
|
59
|
+
signatures = {
|
|
60
|
+
"FFD8FF": ("image/jpeg", "JPEG Image"),
|
|
61
|
+
"89504E47": ("image/png", "PNG Image"),
|
|
62
|
+
"25504446": ("application/pdf", "PDF Document"),
|
|
63
|
+
"504B0304": ("application/zip", "ZIP Archive"),
|
|
64
|
+
"4D5A": ("application/x-dosexec", "Windows Executable"),
|
|
65
|
+
"7F454C46": ("application/x-elf", "Linux/Android Executable"),
|
|
66
|
+
"52617221": ("application/x-rar", "RAR Archive"),
|
|
67
|
+
"D0CF11E0": ("application/msword", "Legacy Office Doc"),
|
|
68
|
+
"CAFEBABE": ("application/java", "Java Class/Mach-O"),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for sig, (mime, desc) in signatures.items():
|
|
72
|
+
if hex_head.startswith(sig):
|
|
73
|
+
return mime, desc
|
|
74
|
+
|
|
75
|
+
if shutil.which("file"):
|
|
76
|
+
try:
|
|
77
|
+
mime = subprocess.check_output(["file", "-b", "--mime-type", filepath], stderr=subprocess.DEVNULL).decode().strip()
|
|
78
|
+
return mime, "System Identified"
|
|
79
|
+
except: pass
|
|
80
|
+
|
|
81
|
+
return "unknown/data", "Unknown Binary"
|
|
82
|
+
|
|
83
|
+
# --- Analysis Core ---
|
|
84
|
+
class GlobalStats:
|
|
85
|
+
total = 0
|
|
86
|
+
risky = 0
|
|
87
|
+
clean = 0
|
|
88
|
+
|
|
89
|
+
class AdvancedAnalyzer:
|
|
90
|
+
def __init__(self, filepath):
|
|
91
|
+
self.filepath = filepath
|
|
92
|
+
self.filename = os.path.basename(filepath)
|
|
93
|
+
self.size = os.path.getsize(filepath)
|
|
94
|
+
self.risk_score = 0
|
|
95
|
+
self.warnings = []
|
|
96
|
+
self.hidden_data = []
|
|
97
|
+
self.indicators = []
|
|
98
|
+
self.data = b"" # Analysis Buffer (Partial)
|
|
99
|
+
self.vt_result = "N/A"
|
|
100
|
+
self.is_quarantined = False
|
|
101
|
+
self.is_partial_read = False
|
|
102
|
+
|
|
103
|
+
# --- SMART LOADING (Optimized for 50GB files) ---
|
|
104
|
+
try:
|
|
105
|
+
with open(filepath, 'rb') as f:
|
|
106
|
+
if self.size <= ANALYSIS_RAM_LIMIT:
|
|
107
|
+
# Small file: Read all
|
|
108
|
+
self.data = f.read()
|
|
109
|
+
else:
|
|
110
|
+
# Large file: Read Head + Tail only
|
|
111
|
+
self.is_partial_read = True
|
|
112
|
+
head_size = ANALYSIS_RAM_LIMIT - (10 * 1024 * 1024) # Reserve 10MB for tail
|
|
113
|
+
self.data = f.read(head_size)
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
f.seek(- (10 * 1024 * 1024), 2) # Go to end minus 10MB
|
|
117
|
+
self.data += f.read()
|
|
118
|
+
except: pass # File might be smaller than we thought if seek fails
|
|
119
|
+
|
|
120
|
+
self.warnings.append(f"Large File ({self.size/1024/1024/1024:.2f} GB). Analyzed Head/Tail only to save RAM.")
|
|
121
|
+
except Exception as e:
|
|
122
|
+
self.warnings.append(f"Read Error: {str(e)}")
|
|
123
|
+
|
|
124
|
+
def get_hashes(self):
|
|
125
|
+
# STREAMING HASH (Does not load file into RAM)
|
|
126
|
+
s = hashlib.sha256()
|
|
127
|
+
try:
|
|
128
|
+
with open(self.filepath, 'rb') as f:
|
|
129
|
+
while chunk := f.read(8192 * 1024): # Read in 8MB chunks
|
|
130
|
+
s.update(chunk)
|
|
131
|
+
return s.hexdigest()
|
|
132
|
+
except:
|
|
133
|
+
return "HASH_ERROR"
|
|
134
|
+
|
|
135
|
+
def check_virustotal(self, sha256):
|
|
136
|
+
if not VIRUSTOTAL_API_KEY: return
|
|
137
|
+
try:
|
|
138
|
+
url = f"https://www.virustotal.com/api/v3/files/{sha256}"
|
|
139
|
+
headers = {"x-apikey": VIRUSTOTAL_API_KEY}
|
|
140
|
+
resp = requests.get(url, headers=headers, timeout=5)
|
|
141
|
+
if resp.status_code == 200:
|
|
142
|
+
stats = resp.json()['data']['attributes']['last_analysis_stats']
|
|
143
|
+
mal = stats['malicious']
|
|
144
|
+
if mal > 0:
|
|
145
|
+
self.risk_score += 15
|
|
146
|
+
self.vt_result = f"[bold red]MALICIOUS ({mal} engines)[/]"
|
|
147
|
+
self.warnings.append(f"Cloud antivirus detected {mal} threats.")
|
|
148
|
+
else:
|
|
149
|
+
self.vt_result = "[green]Clean (Cloud)[/]"
|
|
150
|
+
except: pass
|
|
151
|
+
|
|
152
|
+
def calculate_entropy(self):
|
|
153
|
+
# Calculate entropy on the buffered data (Head/Tail)
|
|
154
|
+
if not self.data: return 0
|
|
155
|
+
entropy = 0
|
|
156
|
+
# Use a sample for speed on large buffers
|
|
157
|
+
sample = self.data[:100000] if len(self.data) > 100000 else self.data
|
|
158
|
+
for x in range(256):
|
|
159
|
+
p_x = float(sample.count(x)) / len(sample)
|
|
160
|
+
if p_x > 0: entropy += - p_x * math.log(p_x, 2)
|
|
161
|
+
return entropy
|
|
162
|
+
|
|
163
|
+
def analyze_pdf_structure(self):
|
|
164
|
+
try:
|
|
165
|
+
text_data = self.data.decode('latin-1', errors='ignore')
|
|
166
|
+
triggers = {'/JavaScript': 5, '/JS': 5, '/OpenAction': 4, '/Launch': 6, '/URI': 2, '/SubmitForm': 3}
|
|
167
|
+
for keyword, score in triggers.items():
|
|
168
|
+
if keyword in text_data:
|
|
169
|
+
self.risk_score += score
|
|
170
|
+
self.warnings.append(f"PDF Active Content detected: {keyword}")
|
|
171
|
+
except: pass
|
|
172
|
+
|
|
173
|
+
def analyze_office_macros(self):
|
|
174
|
+
if self.data[:4] == b'PK\x03\x04':
|
|
175
|
+
try:
|
|
176
|
+
if zipfile.is_zipfile(self.filepath):
|
|
177
|
+
with zipfile.ZipFile(self.filepath, 'r') as z:
|
|
178
|
+
for f in z.namelist():
|
|
179
|
+
if 'vbaProject.bin' in f or '.bas' in f:
|
|
180
|
+
self.risk_score += 8
|
|
181
|
+
self.warnings.append("Office Macro (VBA) Detected in Zip Structure")
|
|
182
|
+
return
|
|
183
|
+
except: pass
|
|
184
|
+
|
|
185
|
+
if b'Attribute VB_Name' in self.data:
|
|
186
|
+
self.risk_score += 8
|
|
187
|
+
self.warnings.append("Legacy Office Macro (VBA) Detected")
|
|
188
|
+
|
|
189
|
+
def analyze_pe_header(self):
|
|
190
|
+
if self.data[:2] != b'4D5A': return
|
|
191
|
+
try:
|
|
192
|
+
pe_offset = struct.unpack('<I', self.data[0x3C:0x40])[0]
|
|
193
|
+
if pe_offset + 1000 > len(self.data): return # Header outside of buffer
|
|
194
|
+
|
|
195
|
+
if self.data[pe_offset:pe_offset+4] != b'PE\x00\x00': return
|
|
196
|
+
ts_offset = pe_offset + 8
|
|
197
|
+
timestamp = struct.unpack('<I', self.data[ts_offset:ts_offset+4])[0]
|
|
198
|
+
|
|
199
|
+
year = datetime.fromtimestamp(timestamp).year
|
|
200
|
+
if year < 1990 or year > 2030:
|
|
201
|
+
self.warnings.append(f"Suspicious Compilation Year: {year} (TimeStomping?)")
|
|
202
|
+
self.risk_score += 3
|
|
203
|
+
else:
|
|
204
|
+
self.indicators.append(f"Compiled: {year}")
|
|
205
|
+
|
|
206
|
+
header_chunk = self.data[pe_offset:pe_offset+1000]
|
|
207
|
+
suspicious_sections = [b'.upx', b'.themida', b'.vmprotect', b'.aspack']
|
|
208
|
+
for sec in suspicious_sections:
|
|
209
|
+
if sec in header_chunk.lower():
|
|
210
|
+
self.warnings.append(f"Packed Binary Detected: {sec.decode()}")
|
|
211
|
+
self.risk_score += 4
|
|
212
|
+
except: pass
|
|
213
|
+
|
|
214
|
+
def analyze_metadata(self):
|
|
215
|
+
if self.filename.lower().endswith(('.jpg', '.jpeg', '.tif', '.wav')):
|
|
216
|
+
try:
|
|
217
|
+
# ExifRead reads the file path directly, so it handles large files automatically
|
|
218
|
+
with open(self.filepath, 'rb') as f:
|
|
219
|
+
tags = exifread.process_file(f, details=False)
|
|
220
|
+
for tag in tags.keys():
|
|
221
|
+
if tag in ('Image ImageDescription', 'Image Software', 'Image Artist', 'Image Copyright'):
|
|
222
|
+
self.hidden_data.append(f"Metadata {tag}: {tags[tag]}")
|
|
223
|
+
if 'GPS' in tag:
|
|
224
|
+
self.indicators.append("GPS Location Data Found")
|
|
225
|
+
except: pass
|
|
226
|
+
|
|
227
|
+
def analyze_steganography_overlay(self, mime):
|
|
228
|
+
eof_signatures = {
|
|
229
|
+
"image/jpeg": b"\xFF\xD9",
|
|
230
|
+
"image/png": b"\x49\x45\x4E\x44\xAE\x42\x60\x82",
|
|
231
|
+
"application/zip": None
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
# Scan the end of our BUFFER (which corresponds to end of file due to Tail read)
|
|
235
|
+
if mime in eof_signatures and eof_signatures[mime]:
|
|
236
|
+
sig = eof_signatures[mime]
|
|
237
|
+
# Search in the last 1MB of data for performance
|
|
238
|
+
search_area = self.data[-1048576:] if len(self.data) > 1048576 else self.data
|
|
239
|
+
end_offset = search_area.rfind(sig)
|
|
240
|
+
|
|
241
|
+
if end_offset != -1:
|
|
242
|
+
# Calculate actual bytes remaining after sig in the search area
|
|
243
|
+
actual_end = end_offset + len(sig)
|
|
244
|
+
if actual_end < len(search_area):
|
|
245
|
+
excess = len(search_area) - actual_end
|
|
246
|
+
if excess > 100:
|
|
247
|
+
self.warnings.append(f"[bold red]STEGANOGRAPHY ALERT:[/bold red] {excess} bytes of hidden data found after EOF.")
|
|
248
|
+
self.risk_score += 5
|
|
249
|
+
|
|
250
|
+
def analyze_archives(self):
|
|
251
|
+
# ZipFile module handles large files via streaming automatically
|
|
252
|
+
if zipfile.is_zipfile(self.filepath):
|
|
253
|
+
try:
|
|
254
|
+
with zipfile.ZipFile(self.filepath, 'r') as z:
|
|
255
|
+
file_list = z.namelist()
|
|
256
|
+
suspicious_ext = ['.exe', '.vbs', '.bat', '.sh', '.dex', '.so', '.dll', '.ps1']
|
|
257
|
+
|
|
258
|
+
for f in file_list:
|
|
259
|
+
info = z.getinfo(f)
|
|
260
|
+
if info.file_size > 0 and info.compress_size > 0:
|
|
261
|
+
ratio = info.file_size / info.compress_size
|
|
262
|
+
if ratio > 100:
|
|
263
|
+
self.warnings.append(f"Possible Zip Bomb: {f} (Ratio {ratio:.0f}:1)")
|
|
264
|
+
self.risk_score += 5
|
|
265
|
+
|
|
266
|
+
for ext in suspicious_ext:
|
|
267
|
+
if f.lower().endswith(ext):
|
|
268
|
+
self.warnings.append(f"Archive contains executable: {f}")
|
|
269
|
+
self.risk_score += 3
|
|
270
|
+
except:
|
|
271
|
+
self.warnings.append("Corrupt Archive or Protected Zip")
|
|
272
|
+
|
|
273
|
+
def analyze_strings(self):
|
|
274
|
+
try:
|
|
275
|
+
# Decode only the buffer
|
|
276
|
+
text_data = self.data.decode('utf-8', errors='ignore')
|
|
277
|
+
|
|
278
|
+
patterns = {
|
|
279
|
+
"IPv4": r'\b(?:\d{1,3}\.){3}\d{1,3}\b',
|
|
280
|
+
"Email": r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
|
|
281
|
+
"URL": r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+',
|
|
282
|
+
"Bitcoin Wallet": r'\b(bc1|[13])[a-zA-Z0-9]{25,39}\b',
|
|
283
|
+
"Private Key": r'-----BEGIN (RSA|DSA|EC|OPENSSH|PGP) PRIVATE KEY-----',
|
|
284
|
+
"PowerShell Obfuscation": r'(FromBase64String|::Decode|GNwZW|SUVY|IgB8AC|cwB3AGkAdABjAGgA)',
|
|
285
|
+
"WebShell": r'(passthru|exec|shell_exec|eval\(base64_decode)',
|
|
286
|
+
"WinAPI (Malware)": r'(VirtualAlloc|CreateRemoteThread|WriteProcessMemory|ShellExecute|URLDownloadToFile)'
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
found_ips = set()
|
|
290
|
+
|
|
291
|
+
for p_name, p_val in patterns.items():
|
|
292
|
+
matches = re.findall(p_val, text_data, re.IGNORECASE)
|
|
293
|
+
if matches:
|
|
294
|
+
unique_matches = list(set(matches))[:3]
|
|
295
|
+
|
|
296
|
+
if p_name == "IPv4":
|
|
297
|
+
for ip in unique_matches:
|
|
298
|
+
if not ip.startswith(('192.168', '127.0', '10.')): found_ips.add(ip)
|
|
299
|
+
elif p_name in ["WebShell", "WinAPI (Malware)", "PowerShell Obfuscation"]:
|
|
300
|
+
self.warnings.append(f"Suspicious {p_name} detected: {unique_matches}")
|
|
301
|
+
self.risk_score += 4
|
|
302
|
+
elif p_name == "Private Key":
|
|
303
|
+
self.warnings.append("CRITICAL: Private Cryptographic Key Found!")
|
|
304
|
+
self.risk_score += 10
|
|
305
|
+
else:
|
|
306
|
+
self.indicators.append(f"{p_name}: {len(matches)} found")
|
|
307
|
+
|
|
308
|
+
if found_ips:
|
|
309
|
+
self.indicators.append(f"Public IPs: {', '.join(list(found_ips)[:3])}")
|
|
310
|
+
|
|
311
|
+
except Exception: pass
|
|
312
|
+
|
|
313
|
+
def quarantine_file(self):
|
|
314
|
+
if self.risk_score >= QUARANTINE_THRESHOLD:
|
|
315
|
+
try:
|
|
316
|
+
new_name = self.filepath + ".dangerous"
|
|
317
|
+
os.rename(self.filepath, new_name)
|
|
318
|
+
self.filename = os.path.basename(new_name)
|
|
319
|
+
self.filepath = new_name
|
|
320
|
+
self.is_quarantined = True
|
|
321
|
+
self.warnings.append(f"[bold red]File Auto-Quarantined to: .dangerous[/]")
|
|
322
|
+
except Exception as e:
|
|
323
|
+
self.warnings.append(f"Quarantine Failed: {e}")
|
|
324
|
+
|
|
325
|
+
def run(self):
|
|
326
|
+
# Size Check: Only if strictly greater than limit, but we set limit to 50GB
|
|
327
|
+
if self.size > MAX_FILE_SIZE_LIMIT:
|
|
328
|
+
console.print(f"[red]Skipping {self.filename}: Too massive (>50GB)[/]")
|
|
329
|
+
return
|
|
330
|
+
|
|
331
|
+
sha256 = self.get_hashes()
|
|
332
|
+
console.print(f"[cyan]>> Analyzing {escape(self.filename)}...[/cyan]")
|
|
333
|
+
|
|
334
|
+
self.check_virustotal(sha256)
|
|
335
|
+
mime, desc = get_file_mime(self.filepath, self.data)
|
|
336
|
+
entropy = self.calculate_entropy()
|
|
337
|
+
|
|
338
|
+
if entropy > 7.4 and "zip" not in mime and "image" not in mime:
|
|
339
|
+
self.warnings.append(f"High Entropy ({entropy:.2f}): Likely Packed/Encrypted payload.")
|
|
340
|
+
self.risk_score += 3
|
|
341
|
+
|
|
342
|
+
# Run Modules
|
|
343
|
+
self.analyze_metadata()
|
|
344
|
+
self.analyze_steganography_overlay(mime)
|
|
345
|
+
self.analyze_archives()
|
|
346
|
+
self.analyze_strings()
|
|
347
|
+
self.analyze_pdf_structure()
|
|
348
|
+
self.analyze_office_macros()
|
|
349
|
+
self.analyze_pe_header()
|
|
350
|
+
|
|
351
|
+
if any(x in mime for x in ["dosexec", "executable", "x-elf"]):
|
|
352
|
+
self.risk_score += 5
|
|
353
|
+
self.warnings.append(f"File is an Executable Binary ({mime})")
|
|
354
|
+
|
|
355
|
+
if re.search(r'\.(exe|bat|sh|vbs|apk)\.[a-z]{3}$', self.filename.lower()):
|
|
356
|
+
self.risk_score += 8
|
|
357
|
+
self.warnings.append("Double Extension Spoofing Detected")
|
|
358
|
+
|
|
359
|
+
if self.risk_score >= QUARANTINE_THRESHOLD:
|
|
360
|
+
self.quarantine_file()
|
|
361
|
+
|
|
362
|
+
self.print_report(sha256, mime, desc, entropy)
|
|
363
|
+
|
|
364
|
+
def print_report(self, sha256, mime, desc, entropy):
|
|
365
|
+
if self.risk_score >= 7:
|
|
366
|
+
color = "red"
|
|
367
|
+
verdict = "DANGEROUS"
|
|
368
|
+
GlobalStats.risky += 1
|
|
369
|
+
elif self.risk_score >= 4:
|
|
370
|
+
color = "yellow"
|
|
371
|
+
verdict = "SUSPICIOUS"
|
|
372
|
+
GlobalStats.risky += 1
|
|
373
|
+
else:
|
|
374
|
+
color = "green"
|
|
375
|
+
verdict = "CLEAN"
|
|
376
|
+
GlobalStats.clean += 1
|
|
377
|
+
|
|
378
|
+
info_table = Table(show_header=False, box=None)
|
|
379
|
+
info_table.add_row("Type", f"{mime} ({desc})")
|
|
380
|
+
info_table.add_row("Entropy", f"{entropy:.3f}")
|
|
381
|
+
info_table.add_row("Cloud", self.vt_result)
|
|
382
|
+
|
|
383
|
+
details = f"[bold {color} size=16]{verdict}[/] (Score: {self.risk_score})"
|
|
384
|
+
|
|
385
|
+
if self.is_quarantined:
|
|
386
|
+
details += "\n\n[bold white on red] FILE QUARANTINED [/]"
|
|
387
|
+
|
|
388
|
+
if self.warnings:
|
|
389
|
+
details += "\n\n[bold red]--- THREATS ---[/]"
|
|
390
|
+
for w in self.warnings: details += f"\n[red]![/] {escape(str(w))}"
|
|
391
|
+
|
|
392
|
+
if self.hidden_data:
|
|
393
|
+
details += "\n\n[bold magenta]--- HIDDEN DATA/STEGO ---[/]"
|
|
394
|
+
for h in self.hidden_data: details += f"\n[magenta]*[/] {escape(str(h))}"
|
|
395
|
+
|
|
396
|
+
if self.indicators:
|
|
397
|
+
details += "\n\n[bold blue]--- INTEL ---[/]"
|
|
398
|
+
for i in self.indicators: details += f"\n[blue]i[/] {escape(str(i))}"
|
|
399
|
+
|
|
400
|
+
layout = Layout()
|
|
401
|
+
layout.split_row(
|
|
402
|
+
Layout(Panel(info_table, title="File Info")),
|
|
403
|
+
Layout(Panel(details, title="Analysis Verdict", border_style=color))
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
console.print(Panel(f"[bold]{escape(self.filename)}[/bold]", style=f"on {color} black" if color=="red" else "bold white"))
|
|
407
|
+
console.print(layout)
|
|
408
|
+
console.print(f"[dim]SHA256: {sha256}[/dim]\n")
|
|
409
|
+
|
|
410
|
+
# --- Main Loop ---
|
|
411
|
+
def main():
|
|
412
|
+
if not os.path.exists(TARGET_DIR):
|
|
413
|
+
os.makedirs(TARGET_DIR, exist_ok=True)
|
|
414
|
+
console.print(f"[green]Created folder:[/green] {TARGET_DIR}")
|
|
415
|
+
console.print("[yellow]Put files there to scan![/yellow]")
|
|
416
|
+
return
|
|
417
|
+
|
|
418
|
+
files = [f for f in os.listdir(TARGET_DIR) if os.path.isfile(os.path.join(TARGET_DIR, f))]
|
|
419
|
+
|
|
420
|
+
if not files:
|
|
421
|
+
console.print(f"[yellow]Folder empty: {TARGET_DIR}[/yellow]")
|
|
422
|
+
return
|
|
423
|
+
|
|
424
|
+
console.print(f"[bold]Scanning {len(files)} files...[/bold]\n")
|
|
425
|
+
for f in files:
|
|
426
|
+
AdvancedAnalyzer(os.path.join(TARGET_DIR, f)).run()
|
|
427
|
+
|
|
428
|
+
if __name__ == "__main__":
|
|
429
|
+
main()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
import "@/utils/log"
|
|
4
|
+
import "@/utils/version"
|
|
5
|
+
|
|
6
|
+
LOG_FILE="$KARNEL_CACHE/install_dev.log"
|
|
7
|
+
|
|
8
|
+
install_filecheck() {
|
|
9
|
+
local TOOL_DIR="$KARNEL_PATH/tools/dev/filecheck"
|
|
10
|
+
local BIN_NAME="filecheck"
|
|
11
|
+
local DOWNLOAD_URL="https://raw.githubusercontent.com/dedsec1121fk/DedSec/main/Scripts/Developer%20Base/File%20Type%20Checker.py"
|
|
12
|
+
if command -v filecheck &>/dev/null; then
|
|
13
|
+
log_info "File Checker is already installed"
|
|
14
|
+
return 2
|
|
15
|
+
fi
|
|
16
|
+
log_info "Installing File Checker..."
|
|
17
|
+
mkdir -p "$(dirname "$LOG_FILE")" "$TOOL_DIR"
|
|
18
|
+
if ! command -v python3 &>/dev/null; then pkg install python -y &>>"$LOG_FILE" || return 1; fi
|
|
19
|
+
|
|
20
|
+
curl -sL "$DOWNLOAD_URL" -o "$TOOL_DIR/$BIN_NAME.py" || return 1
|
|
21
|
+
chmod +x "$TOOL_DIR/$BIN_NAME.py"
|
|
22
|
+
sed -i "1s|.*|#\!$PREFIX/bin/python3|" "$TOOL_DIR/$BIN_NAME.py"
|
|
23
|
+
ln -sf "$TOOL_DIR/$BIN_NAME.py" "$PREFIX/bin/$BIN_NAME"
|
|
24
|
+
log_success "File Checker installed"
|
|
25
|
+
return 0
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
uninstall_filecheck() {
|
|
29
|
+
local BIN_NAME="filecheck"
|
|
30
|
+
local TOOL_DIR="$KARNEL_PATH/tools/dev/filecheck"
|
|
31
|
+
if ! command -v filecheck &>/dev/null; then log_info "File Checker is not installed"; return 2; fi
|
|
32
|
+
log_info "Uninstalling File Checker..."
|
|
33
|
+
rm -f "$PREFIX/bin/$BIN_NAME" "$TOOL_DIR/$BIN_NAME.py"
|
|
34
|
+
log_success "File Checker uninstalled"
|
|
35
|
+
return 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
update_filecheck() {
|
|
39
|
+
local TOOL_DIR="$KARNEL_PATH/tools/dev/filecheck"
|
|
40
|
+
local BIN_NAME="filecheck"
|
|
41
|
+
local DOWNLOAD_URL="https://raw.githubusercontent.com/dedsec1121fk/DedSec/main/Scripts/Developer%20Base/File%20Type%20Checker.py"
|
|
42
|
+
log_info "Updating File Checker..."
|
|
43
|
+
curl -sL "$DOWNLOAD_URL" -o "$TOOL_DIR/$BIN_NAME.py" || return 1
|
|
44
|
+
log_success "File Checker updated"
|
|
45
|
+
return 0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
reinstall_filecheck() {
|
|
49
|
+
uninstall_filecheck
|
|
50
|
+
install_filecheck
|
|
51
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
import "@/utils/log"
|
|
4
|
+
import "@/utils/version"
|
|
5
|
+
|
|
6
|
+
LOG_FILE="$KARNEL_CACHE/install_dev.log"
|
|
7
|
+
|
|
8
|
+
install_notes() {
|
|
9
|
+
local TOOL_DIR="$KARNEL_PATH/tools/dev/notes"
|
|
10
|
+
local BIN_NAME="notes"
|
|
11
|
+
local DOWNLOAD_URL="https://raw.githubusercontent.com/dedsec1121fk/DedSec/main/Scripts/Developer%20Base/Smart%20Notes.py"
|
|
12
|
+
if command -v notes &>/dev/null; then
|
|
13
|
+
log_info "Smart Notes is already installed"
|
|
14
|
+
return 2
|
|
15
|
+
fi
|
|
16
|
+
log_info "Installing Smart Notes..."
|
|
17
|
+
mkdir -p "$(dirname "$LOG_FILE")" "$TOOL_DIR"
|
|
18
|
+
if ! command -v python3 &>/dev/null; then pkg install python -y &>>"$LOG_FILE" || return 1; fi
|
|
19
|
+
|
|
20
|
+
curl -sL "$DOWNLOAD_URL" -o "$TOOL_DIR/$BIN_NAME.py" || return 1
|
|
21
|
+
chmod +x "$TOOL_DIR/$BIN_NAME.py"
|
|
22
|
+
sed -i "1s|.*|#\!$PREFIX/bin/python3|" "$TOOL_DIR/$BIN_NAME.py"
|
|
23
|
+
ln -sf "$TOOL_DIR/$BIN_NAME.py" "$PREFIX/bin/$BIN_NAME"
|
|
24
|
+
log_success "Smart Notes installed"
|
|
25
|
+
return 0
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
uninstall_notes() {
|
|
29
|
+
local BIN_NAME="notes"
|
|
30
|
+
local TOOL_DIR="$KARNEL_PATH/tools/dev/notes"
|
|
31
|
+
if ! command -v notes &>/dev/null; then log_info "Smart Notes is not installed"; return 2; fi
|
|
32
|
+
log_info "Uninstalling Smart Notes..."
|
|
33
|
+
rm -f "$PREFIX/bin/$BIN_NAME" "$TOOL_DIR/$BIN_NAME.py"
|
|
34
|
+
log_success "Smart Notes uninstalled"
|
|
35
|
+
return 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
update_notes() {
|
|
39
|
+
local TOOL_DIR="$KARNEL_PATH/tools/dev/notes"
|
|
40
|
+
local BIN_NAME="notes"
|
|
41
|
+
local DOWNLOAD_URL="https://raw.githubusercontent.com/dedsec1121fk/DedSec/main/Scripts/Developer%20Base/Smart%20Notes.py"
|
|
42
|
+
log_info "Updating Smart Notes..."
|
|
43
|
+
curl -sL "$DOWNLOAD_URL" -o "$TOOL_DIR/$BIN_NAME.py" || return 1
|
|
44
|
+
log_success "Smart Notes updated"
|
|
45
|
+
return 0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
reinstall_notes() {
|
|
49
|
+
uninstall_notes
|
|
50
|
+
install_notes
|
|
51
|
+
}
|