anais-apk-forensic 1.0.0
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/LICENSE +21 -0
- package/README.md +249 -0
- package/anais.sh +669 -0
- package/analysis_tools/__pycache__/apk_basic_info.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/apk_basic_info.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/check_zip_encryption.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/check_zip_encryption.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/detect_obfuscation.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/detect_obfuscation.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/dex_payload_hunter.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/entropy_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/error_logger.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/error_logger.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/find_encrypted_payload.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/fix_apk_headers.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/fix_apk_headers.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/manifest_analyzer.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/manifest_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/network_analyzer.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/network_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/report_generator.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/report_generator.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/report_generator_modular.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/sast_scanner.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/sast_scanner.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/so_string_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/yara_enhanced_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/yara_results_processor.cpython-314.pyc +0 -0
- package/analysis_tools/apk_basic_info.py +85 -0
- package/analysis_tools/check_zip_encryption.py +142 -0
- package/analysis_tools/detect_obfuscation.py +650 -0
- package/analysis_tools/dex_payload_hunter.py +734 -0
- package/analysis_tools/entropy_analyzer.py +335 -0
- package/analysis_tools/error_logger.py +75 -0
- package/analysis_tools/find_encrypted_payload.py +485 -0
- package/analysis_tools/fix_apk_headers.py +154 -0
- package/analysis_tools/manifest_analyzer.py +214 -0
- package/analysis_tools/network_analyzer.py +287 -0
- package/analysis_tools/report_generator.py +506 -0
- package/analysis_tools/report_generator_modular.py +885 -0
- package/analysis_tools/sast_scanner.py +412 -0
- package/analysis_tools/so_string_analyzer.py +406 -0
- package/analysis_tools/yara_enhanced_analyzer.py +330 -0
- package/analysis_tools/yara_results_processor.py +368 -0
- package/analyzer_config.json +113 -0
- package/apkid/__init__.py +32 -0
- package/apkid/__pycache__/__init__.cpython-313.pyc +0 -0
- package/apkid/__pycache__/__init__.cpython-314.pyc +0 -0
- package/apkid/__pycache__/apkid.cpython-313.pyc +0 -0
- package/apkid/__pycache__/apkid.cpython-314.pyc +0 -0
- package/apkid/__pycache__/main.cpython-313.pyc +0 -0
- package/apkid/__pycache__/main.cpython-314.pyc +0 -0
- package/apkid/__pycache__/output.cpython-313.pyc +0 -0
- package/apkid/__pycache__/rules.cpython-313.pyc +0 -0
- package/apkid/apkid.py +266 -0
- package/apkid/main.py +98 -0
- package/apkid/output.py +177 -0
- package/apkid/rules/apk/common.yara +68 -0
- package/apkid/rules/apk/obfuscators.yara +118 -0
- package/apkid/rules/apk/packers.yara +1197 -0
- package/apkid/rules/apk/protectors.yara +301 -0
- package/apkid/rules/dex/abnormal.yara +104 -0
- package/apkid/rules/dex/anti-vm.yara +568 -0
- package/apkid/rules/dex/common.yara +60 -0
- package/apkid/rules/dex/compilers.yara +434 -0
- package/apkid/rules/dex/obfuscators.yara +602 -0
- package/apkid/rules/dex/packers.yara +761 -0
- package/apkid/rules/dex/protectors.yara +520 -0
- package/apkid/rules/dll/common.yara +38 -0
- package/apkid/rules/dll/obfuscators.yara +43 -0
- package/apkid/rules/elf/anti-vm.yara +43 -0
- package/apkid/rules/elf/common.yara +54 -0
- package/apkid/rules/elf/obfuscators.yara +991 -0
- package/apkid/rules/elf/packers.yara +1128 -0
- package/apkid/rules/elf/protectors.yara +794 -0
- package/apkid/rules/res/common.yara +43 -0
- package/apkid/rules/res/obfuscators.yara +46 -0
- package/apkid/rules/res/protectors.yara +46 -0
- package/apkid/rules.py +77 -0
- package/bin/anais +3 -0
- package/dist/cli.js +82 -0
- package/dist/index.js +123 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/index.js +21 -0
- package/dist/utils/output.js +44 -0
- package/dist/utils/paths.js +107 -0
- package/docs/ARCHITECTURE.txt +353 -0
- package/docs/Workflow and Reference.md +445 -0
- package/package.json +70 -0
- package/rules/yara_general_rules.yar +323 -0
- package/scripts/dynamic_analysis_helper.sh +334 -0
- package/scripts/frida/dpt_dex_dumper.js +145 -0
- package/scripts/frida/frida_dex_dump.js +145 -0
- package/scripts/frida/frida_hooks.js +437 -0
- package/scripts/frida/frida_websocket_extractor.js +154 -0
- package/scripts/setup.sh +206 -0
- package/scripts/validate_framework.sh +224 -0
- package/src/cli.ts +91 -0
- package/src/index.ts +123 -0
- package/src/types/index.ts +44 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/output.ts +50 -0
- package/src/utils/paths.ts +72 -0
- package/tsconfig.json +14 -0
package/anais.sh
ADDED
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
#################################################
|
|
4
|
+
# Anais Static Core
|
|
5
|
+
# Author: Reezcode24
|
|
6
|
+
# Date: 2026-01-23
|
|
7
|
+
# Description: Comprehensive APK analysis with multiple protection bypass techniques
|
|
8
|
+
#################################################
|
|
9
|
+
|
|
10
|
+
set -e
|
|
11
|
+
|
|
12
|
+
# Suppress Python warnings globally
|
|
13
|
+
export PYTHONWARNINGS="ignore"
|
|
14
|
+
|
|
15
|
+
# Colors for output
|
|
16
|
+
RED='\033[0;31m'
|
|
17
|
+
GREEN='\033[0;32m'
|
|
18
|
+
YELLOW='\033[1;33m'
|
|
19
|
+
BLUE='\033[0;34m'
|
|
20
|
+
MAGENTA='\033[0;35m'
|
|
21
|
+
CYAN='\033[0;36m'
|
|
22
|
+
NC='\033[0m' # No Color
|
|
23
|
+
|
|
24
|
+
# Configuration
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
WORK_DIR="${HOME}/Documents/Anais-Reports"
|
|
27
|
+
TOOLS_DIR="${SCRIPT_DIR}/analysis_tools"
|
|
28
|
+
CONFIG_FILE="${SCRIPT_DIR}/analyzer_config.json"
|
|
29
|
+
ERROR_LOG="${SCRIPT_DIR}/analysis_errors.log"
|
|
30
|
+
|
|
31
|
+
# Ensure workspace directory exists
|
|
32
|
+
if [ ! -d "$WORK_DIR" ]; then
|
|
33
|
+
mkdir -p "$WORK_DIR/reports"
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Banner
|
|
37
|
+
print_banner() {
|
|
38
|
+
echo -e "${CYAN}"
|
|
39
|
+
echo "╔═══════════════════════════════════════════════════════════╗"
|
|
40
|
+
echo "║ Anais Static Core v1.0 ║"
|
|
41
|
+
echo "║ Comprehensive APK Security Analysis & SAST ║"
|
|
42
|
+
echo "╚═══════════════════════════════════════════════════════════╝"
|
|
43
|
+
echo -e "${NC}"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Logging functions
|
|
47
|
+
log_info() {
|
|
48
|
+
echo -e "${BLUE}[INFO]${NC} $1"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
log_success() {
|
|
52
|
+
echo -e "${GREEN}[✓]${NC} $1"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
log_warning() {
|
|
56
|
+
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
57
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARNING] $1" >> "$ERROR_LOG" 2>/dev/null || true
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
log_error() {
|
|
61
|
+
echo -e "${RED}[ERROR]${NC} $1"
|
|
62
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $1" >> "$ERROR_LOG" 2>/dev/null || true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
log_error_detail() {
|
|
66
|
+
# Log detailed error to file only
|
|
67
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR DETAIL] $1" >> "$ERROR_LOG" 2>/dev/null || true
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
log_critical() {
|
|
71
|
+
echo -e "${RED}[CRITICAL]${NC} $1"
|
|
72
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [CRITICAL] $1" >> "$ERROR_LOG" 2>/dev/null || true
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
log_section() {
|
|
76
|
+
echo -e "\n${MAGENTA}═══ $1 ═══${NC}\n"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Check dependencies
|
|
80
|
+
check_dependencies() {
|
|
81
|
+
log_section "Checking Dependencies"
|
|
82
|
+
|
|
83
|
+
local missing_deps=()
|
|
84
|
+
|
|
85
|
+
# Core tools
|
|
86
|
+
command -v python3 >/dev/null 2>&1 || missing_deps+=("python3")
|
|
87
|
+
command -v java >/dev/null 2>&1 || missing_deps+=("java")
|
|
88
|
+
command -v apktool >/dev/null 2>&1 || missing_deps+=("apktool")
|
|
89
|
+
command -v jadx >/dev/null 2>&1 || missing_deps+=("jadx")
|
|
90
|
+
command -v yara >/dev/null 2>&1 || missing_deps+=("yara")
|
|
91
|
+
command -v unzip >/dev/null 2>&1 || missing_deps+=("unzip")
|
|
92
|
+
command -v zipinfo >/dev/null 2>&1 || missing_deps+=("zipinfo")
|
|
93
|
+
command -v xxd >/dev/null 2>&1 || missing_deps+=("xxd")
|
|
94
|
+
|
|
95
|
+
# Python modules check
|
|
96
|
+
python3 -c "import androguard" 2>/dev/null || log_warning "androguard not installed (pip3 install androguard)"
|
|
97
|
+
python3 -c "import yara" 2>/dev/null || log_warning "yara-python not installed (pip3 install yara-python)"
|
|
98
|
+
python3 -c "import requests" 2>/dev/null || log_warning "requests not installed (pip3 install requests)"
|
|
99
|
+
|
|
100
|
+
if [ ${#missing_deps[@]} -ne 0 ]; then
|
|
101
|
+
log_error "Missing dependencies: ${missing_deps[*]}"
|
|
102
|
+
log_info "Install using: brew install ${missing_deps[*]} (macOS) or apt-get install ${missing_deps[*]} (Linux)"
|
|
103
|
+
exit 1
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
log_success "All core dependencies satisfied"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
# Initialize workspace
|
|
110
|
+
init_workspace() {
|
|
111
|
+
local apk_path="$1"
|
|
112
|
+
local apk_name=$(basename "$apk_path" .apk)
|
|
113
|
+
|
|
114
|
+
APK_WORK_DIR="${WORK_DIR}/${apk_name}_$(date +%Y%m%d_%H%M%S)"
|
|
115
|
+
DECOMPILED_DIR="${APK_WORK_DIR}/decompiled"
|
|
116
|
+
JADX_OUTPUT="${APK_WORK_DIR}/jadx_output"
|
|
117
|
+
TEMP_DIR="${APK_WORK_DIR}/temp"
|
|
118
|
+
REPORTS_DIR="${APK_WORK_DIR}/reports"
|
|
119
|
+
REPORT_FILE="${REPORTS_DIR}/report.md"
|
|
120
|
+
JSON_REPORT="${REPORTS_DIR}/report.json"
|
|
121
|
+
|
|
122
|
+
mkdir -p "$APK_WORK_DIR" "$DECOMPILED_DIR" "$JADX_OUTPUT" "$TEMP_DIR" "$REPORTS_DIR"
|
|
123
|
+
|
|
124
|
+
log_success "Workspace initialized: $APK_WORK_DIR"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# APK Basic Info Extraction
|
|
128
|
+
extract_basic_info() {
|
|
129
|
+
log_section "Extracting Basic APK Information"
|
|
130
|
+
|
|
131
|
+
local apk_path="$1"
|
|
132
|
+
|
|
133
|
+
# File hash
|
|
134
|
+
SHA256=$(shasum -a 256 "$apk_path" | awk '{print $1}')
|
|
135
|
+
MD5=$(md5 -q "$apk_path")
|
|
136
|
+
FILE_SIZE=$(stat -f%z "$apk_path" 2>/dev/null || stat -c%s "$apk_path")
|
|
137
|
+
|
|
138
|
+
log_info "SHA256: $SHA256"
|
|
139
|
+
log_info "MD5: $MD5"
|
|
140
|
+
log_info "Size: $FILE_SIZE bytes"
|
|
141
|
+
|
|
142
|
+
# Try to get basic APK info using aapt
|
|
143
|
+
if command -v aapt >/dev/null 2>&1; then
|
|
144
|
+
aapt dump badging "$apk_path" > "${TEMP_DIR}/aapt_info.txt" 2>/dev/null || true
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
# Use Python androguard for detailed analysis
|
|
148
|
+
python3 "${TOOLS_DIR}/apk_basic_info.py" "$apk_path" "${TEMP_DIR}/basic_info.json" || true
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# Check if APK is encrypted/password protected
|
|
152
|
+
check_apk_protection() {
|
|
153
|
+
log_section "Checking APK Protection Mechanisms"
|
|
154
|
+
|
|
155
|
+
local apk_path="$1"
|
|
156
|
+
|
|
157
|
+
# Test unzip
|
|
158
|
+
if ! unzip -t "$apk_path" >/dev/null 2>&1; then
|
|
159
|
+
log_warning "APK appears to be corrupted or encrypted"
|
|
160
|
+
|
|
161
|
+
# Check ZIP encryption flags
|
|
162
|
+
python3 "${TOOLS_DIR}/check_zip_encryption.py" "$apk_path" "${TEMP_DIR}/encryption_check.json"
|
|
163
|
+
|
|
164
|
+
# Attempt header manipulation
|
|
165
|
+
if [ -f "${TEMP_DIR}/encryption_check.json" ]; then
|
|
166
|
+
local is_encrypted=$(python3 -c "import json; print(json.load(open('${TEMP_DIR}/encryption_check.json'))['encrypted'])")
|
|
167
|
+
|
|
168
|
+
if [ "$is_encrypted" = "True" ]; then
|
|
169
|
+
log_warning "Attempting to fix ZIP headers..."
|
|
170
|
+
python3 "${TOOLS_DIR}/fix_apk_headers.py" "$apk_path" "${TEMP_DIR}/fixed_apk.apk"
|
|
171
|
+
|
|
172
|
+
if [ -f "${TEMP_DIR}/fixed_apk.apk" ]; then
|
|
173
|
+
log_success "Headers fixed, using modified APK"
|
|
174
|
+
APK_TO_ANALYZE="${TEMP_DIR}/fixed_apk.apk"
|
|
175
|
+
return 0
|
|
176
|
+
else
|
|
177
|
+
log_error "Failed to fix APK headers"
|
|
178
|
+
return 1
|
|
179
|
+
fi
|
|
180
|
+
fi
|
|
181
|
+
fi
|
|
182
|
+
else
|
|
183
|
+
log_success "APK is not encrypted"
|
|
184
|
+
APK_TO_ANALYZE="$apk_path"
|
|
185
|
+
return 0
|
|
186
|
+
fi
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
# Decompile with apktool
|
|
190
|
+
decompile_apktool() {
|
|
191
|
+
log_section "Decompiling with APKTool"
|
|
192
|
+
|
|
193
|
+
local apk_path="$1"
|
|
194
|
+
|
|
195
|
+
if apktool d -f -o "$DECOMPILED_DIR" "$apk_path" 2>&1 | tee "${TEMP_DIR}/apktool.log"; then
|
|
196
|
+
log_success "APKTool decompilation successful"
|
|
197
|
+
return 0
|
|
198
|
+
else
|
|
199
|
+
log_error "APKTool decompilation failed"
|
|
200
|
+
return 1
|
|
201
|
+
fi
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
# Decompile with JADX
|
|
205
|
+
decompile_jadx() {
|
|
206
|
+
log_section "Decompiling with JADX"
|
|
207
|
+
|
|
208
|
+
local apk_path="$1"
|
|
209
|
+
|
|
210
|
+
if jadx -d "$JADX_OUTPUT" "$apk_path" 2>&1 | tee "${TEMP_DIR}/jadx.log"; then
|
|
211
|
+
log_success "JADX decompilation successful"
|
|
212
|
+
return 0
|
|
213
|
+
else
|
|
214
|
+
log_error "JADX decompilation failed"
|
|
215
|
+
return 1
|
|
216
|
+
fi
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
# Analyze protection libraries
|
|
220
|
+
analyze_protection_libraries() {
|
|
221
|
+
log_section "Analyzing Protection Libraries"
|
|
222
|
+
|
|
223
|
+
local protection_type="$1"
|
|
224
|
+
local target_libs=()
|
|
225
|
+
|
|
226
|
+
# Map protection type to library names
|
|
227
|
+
case "$protection_type" in
|
|
228
|
+
"dpt-shell")
|
|
229
|
+
target_libs=("libdpt")
|
|
230
|
+
log_info "Targeting DPT-Shell libraries: libdpt.so"
|
|
231
|
+
;;
|
|
232
|
+
"bangcle")
|
|
233
|
+
target_libs=("libbangcle" "libsecexe" "libDexHelper")
|
|
234
|
+
log_info "Targeting Bangcle libraries: libbangcle*.so, libsecexe.so"
|
|
235
|
+
;;
|
|
236
|
+
"qihoo-360"|"jiagu")
|
|
237
|
+
target_libs=("libjiagu" "libjiagu_art" "libjiagu_dvm")
|
|
238
|
+
log_info "Targeting Qihoo 360 libraries: libjiagu*.so"
|
|
239
|
+
;;
|
|
240
|
+
"dexprotector")
|
|
241
|
+
target_libs=("libprotect" "libdexprotector")
|
|
242
|
+
log_info "Targeting DexProtector libraries: libprotect*.so"
|
|
243
|
+
;;
|
|
244
|
+
"secneo")
|
|
245
|
+
target_libs=("libshell" "libsecexe")
|
|
246
|
+
log_info "Targeting SecNeo libraries: libshell*.so"
|
|
247
|
+
;;
|
|
248
|
+
*)
|
|
249
|
+
log_info "Unknown protection type: $protection_type"
|
|
250
|
+
log_info "Analyzing all suspicious .so files"
|
|
251
|
+
# Will analyze all .so files if found
|
|
252
|
+
;;
|
|
253
|
+
esac
|
|
254
|
+
|
|
255
|
+
# Build target arguments
|
|
256
|
+
local target_args=""
|
|
257
|
+
for lib in "${target_libs[@]}"; do
|
|
258
|
+
target_args="$target_args --target $lib"
|
|
259
|
+
done
|
|
260
|
+
|
|
261
|
+
# Run SO String Analyzer
|
|
262
|
+
log_info "Extracting strings from protection libraries..."
|
|
263
|
+
|
|
264
|
+
if [ -n "$target_args" ]; then
|
|
265
|
+
# Analyze specific targets
|
|
266
|
+
if python3 "${TOOLS_DIR}/so_string_analyzer.py" \
|
|
267
|
+
"$APK_PATH" \
|
|
268
|
+
$target_args \
|
|
269
|
+
--json "${TEMP_DIR}/so_strings.json" \
|
|
270
|
+
--limit 20 2>> "$ERROR_LOG"; then
|
|
271
|
+
log_success "Protection library analysis completed"
|
|
272
|
+
|
|
273
|
+
# Show brief summary
|
|
274
|
+
if [ -f "${TEMP_DIR}/so_strings.json" ]; then
|
|
275
|
+
log_info "String extraction summary:"
|
|
276
|
+
python3 -c "
|
|
277
|
+
import json
|
|
278
|
+
try:
|
|
279
|
+
data = json.load(open('${TEMP_DIR}/so_strings.json'))
|
|
280
|
+
for result in data:
|
|
281
|
+
cats = result.get('categories', {})
|
|
282
|
+
critical = ['dex_files', 'zip_files', 'code_cache_paths']
|
|
283
|
+
for cat in critical:
|
|
284
|
+
if cat in cats:
|
|
285
|
+
items = cats[cat]
|
|
286
|
+
print(f' 🎯 {cat}: {len(items)} found')
|
|
287
|
+
for item in items[:2]:
|
|
288
|
+
print(f' • {item}')
|
|
289
|
+
except Exception as e:
|
|
290
|
+
pass
|
|
291
|
+
" 2>/dev/null || true
|
|
292
|
+
fi
|
|
293
|
+
else
|
|
294
|
+
log_warning "SO string analysis completed but no output file generated"
|
|
295
|
+
fi
|
|
296
|
+
else
|
|
297
|
+
# Analyze all .so files (no specific targets)
|
|
298
|
+
log_info "No specific targets - scanning all native libraries..."
|
|
299
|
+
|
|
300
|
+
# Just extract and log the presence of .so files
|
|
301
|
+
python3 -c "
|
|
302
|
+
import zipfile
|
|
303
|
+
import sys
|
|
304
|
+
try:
|
|
305
|
+
with zipfile.ZipFile('$APK_PATH', 'r') as zf:
|
|
306
|
+
so_files = [f.filename for f in zf.filelist if f.filename.endswith('.so')]
|
|
307
|
+
if so_files:
|
|
308
|
+
print(f'Found {len(so_files)} .so file(s)')
|
|
309
|
+
for so in so_files[:5]:
|
|
310
|
+
print(f' • {so}')
|
|
311
|
+
if len(so_files) > 5:
|
|
312
|
+
print(f' ... and {len(so_files) - 5} more')
|
|
313
|
+
except Exception as e:
|
|
314
|
+
print(f'Error: {e}', file=sys.stderr)
|
|
315
|
+
" 2>/dev/null || log_info "No native libraries found or error reading APK"
|
|
316
|
+
fi
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# Detect obfuscation
|
|
320
|
+
detect_obfuscation() {
|
|
321
|
+
log_section "Detecting Obfuscation Techniques"
|
|
322
|
+
|
|
323
|
+
# Generate basic APK info first if not exists
|
|
324
|
+
if [ ! -f "${TEMP_DIR}/basic_info.json" ]; then
|
|
325
|
+
python3 "${TOOLS_DIR}/apk_basic_info.py" "$APK_PATH" "${TEMP_DIR}/basic_info.json" 2>> "$ERROR_LOG" || true
|
|
326
|
+
fi
|
|
327
|
+
|
|
328
|
+
# First run DEX payload hunter to find encrypted payloads
|
|
329
|
+
log_info "Hunting for encrypted DEX payloads..."
|
|
330
|
+
local package_name=$(python3 -c "import json; f=open('${TEMP_DIR}/basic_info.json'); print(json.load(f).get('package_name', ''))" 2>> "$ERROR_LOG" || echo "")
|
|
331
|
+
|
|
332
|
+
if python3 "${TOOLS_DIR}/dex_payload_hunter.py" \
|
|
333
|
+
"$APK_PATH" \
|
|
334
|
+
"${TEMP_DIR}/dex_payload_report.json" \
|
|
335
|
+
"$package_name" --brief 2>> "$ERROR_LOG"; then
|
|
336
|
+
log_success "DEX payload analysis completed"
|
|
337
|
+
else
|
|
338
|
+
log_warning "DEX payload hunter encountered issues (check $ERROR_LOG)"
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
# Then run standard obfuscation detection
|
|
342
|
+
if python3 "${TOOLS_DIR}/detect_obfuscation.py" \
|
|
343
|
+
"$APK_PATH" \
|
|
344
|
+
"$DECOMPILED_DIR" \
|
|
345
|
+
"$JADX_OUTPUT" \
|
|
346
|
+
"${TEMP_DIR}/obfuscation_report.json" 2>> "$ERROR_LOG"; then
|
|
347
|
+
log_success "Obfuscation detection completed"
|
|
348
|
+
else
|
|
349
|
+
log_error "Obfuscation detection failed (check $ERROR_LOG for details)"
|
|
350
|
+
return 1
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
if [ -f "${TEMP_DIR}/obfuscation_report.json" ]; then
|
|
354
|
+
local obf_type=$(python3 -c "import json; print(json.load(open('${TEMP_DIR}/obfuscation_report.json'))['type'])" 2>/dev/null || echo "unknown")
|
|
355
|
+
log_info "Obfuscation type detected: $obf_type"
|
|
356
|
+
|
|
357
|
+
# Check if DEX payload hunter found encrypted payloads
|
|
358
|
+
local stub_detected=$(python3 -c "import json; print(json.load(open('${TEMP_DIR}/dex_payload_report.json')).get('stub_dex_detected', False))" 2>/dev/null || echo "False")
|
|
359
|
+
local payload_count=$(python3 -c "import json; print(len(json.load(open('${TEMP_DIR}/dex_payload_report.json')).get('encrypted_payloads', [])))" 2>/dev/null || echo "0")
|
|
360
|
+
|
|
361
|
+
if [ "$stub_detected" = "True" ] || [ "$payload_count" -gt 0 ]; then
|
|
362
|
+
log_warning "🔒 ENCRYPTED DEX DETECTED!"
|
|
363
|
+
log_info "Stub DEX: $stub_detected | Encrypted Payloads: $payload_count"
|
|
364
|
+
log_info ""
|
|
365
|
+
log_warning "Real DEX is NOT in the APK - it will be unpacked at runtime"
|
|
366
|
+
log_info ""
|
|
367
|
+
fi
|
|
368
|
+
|
|
369
|
+
case "$obf_type" in
|
|
370
|
+
"dpt-shell"|"dexprotector"|"bangcle"|"qihoo-360"|"jiagu"|"secneo")
|
|
371
|
+
log_warning "Advanced protection detected: $obf_type"
|
|
372
|
+
|
|
373
|
+
# Run SO String Analyzer for protection libraries
|
|
374
|
+
log_info ""
|
|
375
|
+
log_info "🔍 Analyzing protection library strings..."
|
|
376
|
+
analyze_protection_libraries "$obf_type"
|
|
377
|
+
|
|
378
|
+
log_info ""
|
|
379
|
+
log_info "📍 DYNAMIC ANALYSIS REQUIRED:"
|
|
380
|
+
log_info " 1. Install APK on rooted device/emulator"
|
|
381
|
+
log_info " 2. Run app to trigger DEX unpacking"
|
|
382
|
+
log_info " 3. Monitor these locations for unpacked DEX:"
|
|
383
|
+
|
|
384
|
+
# Show top 3 likely unpack locations
|
|
385
|
+
python3 -c "
|
|
386
|
+
import json
|
|
387
|
+
data = json.load(open('${TEMP_DIR}/dex_payload_report.json'))
|
|
388
|
+
for loc in data.get('likely_unpack_locations', [])[:3]:
|
|
389
|
+
if loc['priority'] == 'HIGH':
|
|
390
|
+
print(f\" • {loc['path']}\")
|
|
391
|
+
" 2>/dev/null
|
|
392
|
+
|
|
393
|
+
log_info " 4. Use Frida to dump DEX from memory:"
|
|
394
|
+
log_info " frida -U -l scripts/frida/frida_dex_dump.js -f <package>"
|
|
395
|
+
log_info " 5. Pull dumped DEX files for re-analysis"
|
|
396
|
+
log_info ""
|
|
397
|
+
echo "$obf_type" > "${TEMP_DIR}/protection_type.txt"
|
|
398
|
+
;;
|
|
399
|
+
"proguard"|"r8")
|
|
400
|
+
log_info "Standard obfuscation detected: $obf_type"
|
|
401
|
+
log_info "Proceeding with static analysis..."
|
|
402
|
+
;;
|
|
403
|
+
*)
|
|
404
|
+
log_info "No significant obfuscation detected or unknown type"
|
|
405
|
+
;;
|
|
406
|
+
esac
|
|
407
|
+
fi
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
# Run entropy analysis
|
|
411
|
+
run_entropy_analysis() {
|
|
412
|
+
log_section "Running Entropy Analysis"
|
|
413
|
+
|
|
414
|
+
local apk_path="$1"
|
|
415
|
+
|
|
416
|
+
log_info "Analyzing file entropy to detect encrypted/obfuscated regions..."
|
|
417
|
+
|
|
418
|
+
if python3 "${TOOLS_DIR}/entropy_analyzer.py" \
|
|
419
|
+
"$apk_path" \
|
|
420
|
+
"${TEMP_DIR}/entropy_analysis.json" \
|
|
421
|
+
--chunk-size 2048 2>> "$ERROR_LOG"; then
|
|
422
|
+
|
|
423
|
+
log_success "Entropy analysis completed"
|
|
424
|
+
|
|
425
|
+
# Check for highly suspicious files
|
|
426
|
+
if [ -f "${TEMP_DIR}/entropy_analysis.json" ]; then
|
|
427
|
+
local critical_count=$(python3 -c "import json; d=json.load(open('${TEMP_DIR}/entropy_analysis.json')); print(len(d.get('summary', {}).get('highly_suspicious', [])))" 2>/dev/null || echo "0")
|
|
428
|
+
local suspicious_count=$(python3 -c "import json; d=json.load(open('${TEMP_DIR}/entropy_analysis.json')); print(len(d.get('summary', {}).get('suspicious', [])))" 2>/dev/null || echo "0")
|
|
429
|
+
|
|
430
|
+
if [ "$critical_count" -gt 0 ]; then
|
|
431
|
+
log_warning "🔴 ${critical_count} highly encrypted file(s) detected!"
|
|
432
|
+
log_info "High entropy indicates encrypted payloads - check entropy charts in report"
|
|
433
|
+
fi
|
|
434
|
+
|
|
435
|
+
if [ "$suspicious_count" -gt 0 ]; then
|
|
436
|
+
log_info "🟡 ${suspicious_count} suspicious file(s) with elevated entropy"
|
|
437
|
+
fi
|
|
438
|
+
fi
|
|
439
|
+
else
|
|
440
|
+
log_warning "Entropy analysis encountered issues (check error log)"
|
|
441
|
+
fi
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
# Run YARA rules
|
|
445
|
+
run_yara_scan() {
|
|
446
|
+
log_section "Running YARA Rules"
|
|
447
|
+
|
|
448
|
+
local apk_path="$1"
|
|
449
|
+
|
|
450
|
+
# Scan original APK
|
|
451
|
+
if [ -f "${SCRIPT_DIR}/rules/yara_general_rules.yar" ]; then
|
|
452
|
+
log_info "Scanning with yara_general_rules.yar..."
|
|
453
|
+
yara -s "${SCRIPT_DIR}/rules/yara_general_rules.yar" "$apk_path" > "${TEMP_DIR}/yara_apk_results.txt" 2>&1 || true
|
|
454
|
+
fi
|
|
455
|
+
|
|
456
|
+
# Scan decompiled directory
|
|
457
|
+
if [ -d "$DECOMPILED_DIR" ]; then
|
|
458
|
+
log_info "Scanning decompiled files..."
|
|
459
|
+
find "$DECOMPILED_DIR" -type f -name "*.smali" -o -name "*.xml" | while read file; do
|
|
460
|
+
yara -s "${SCRIPT_DIR}/rules/yara_general_rules.yar" "$file" 2>/dev/null || true
|
|
461
|
+
done > "${TEMP_DIR}/yara_decompiled_results.txt"
|
|
462
|
+
fi
|
|
463
|
+
|
|
464
|
+
# Scan JADX output
|
|
465
|
+
if [ -d "$JADX_OUTPUT" ]; then
|
|
466
|
+
log_info "Scanning JADX sources..."
|
|
467
|
+
find "$JADX_OUTPUT" -type f -name "*.java" | while read file; do
|
|
468
|
+
yara -s "${SCRIPT_DIR}/rules/yara_general_rules.yar" "$file" 2>/dev/null || true
|
|
469
|
+
done > "${TEMP_DIR}/yara_jadx_results.txt"
|
|
470
|
+
fi
|
|
471
|
+
|
|
472
|
+
log_success "YARA scan completed"
|
|
473
|
+
|
|
474
|
+
# Process YARA results with enhanced analyzer
|
|
475
|
+
log_info "Processing YARA results..."
|
|
476
|
+
if python3 "${TOOLS_DIR}/yara_enhanced_analyzer.py" \
|
|
477
|
+
"$TEMP_DIR" \
|
|
478
|
+
"${TEMP_DIR}/yara_enhanced.json" 2>> "$ERROR_LOG"; then
|
|
479
|
+
|
|
480
|
+
# Show summary
|
|
481
|
+
if [ -f "${TEMP_DIR}/yara_enhanced.json" ]; then
|
|
482
|
+
local total_rules=$(python3 -c "import json; print(json.load(open('${TEMP_DIR}/yara_enhanced.json'))['summary']['total_rules_checked'])" 2>/dev/null || echo "0")
|
|
483
|
+
local matched_rules=$(python3 -c "import json; print(json.load(open('${TEMP_DIR}/yara_enhanced.json'))['summary']['rules_matched'])" 2>/dev/null || echo "0")
|
|
484
|
+
local critical=$(python3 -c "import json; print(json.load(open('${TEMP_DIR}/yara_enhanced.json'))['summary']['critical_findings'])" 2>/dev/null || echo "0")
|
|
485
|
+
local high=$(python3 -c "import json; print(json.load(open('${TEMP_DIR}/yara_enhanced.json'))['summary']['high_severity'])" 2>/dev/null || echo "0")
|
|
486
|
+
|
|
487
|
+
log_success "YARA analysis complete"
|
|
488
|
+
log_info "Rules: ${matched_rules}/${total_rules} matched | 🔴 ${critical} Critical | 🟠 ${high} High"
|
|
489
|
+
fi
|
|
490
|
+
else
|
|
491
|
+
log_warning "YARA result processing had issues"
|
|
492
|
+
fi
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
# Static Application Security Testing (SAST)
|
|
496
|
+
run_sast_analysis() {
|
|
497
|
+
log_section "Running SAST Analysis"
|
|
498
|
+
|
|
499
|
+
# Run comprehensive SAST
|
|
500
|
+
if python3 "${TOOLS_DIR}/sast_scanner.py" \
|
|
501
|
+
--apk "$APK_TO_ANALYZE" \
|
|
502
|
+
--decompiled "$DECOMPILED_DIR" \
|
|
503
|
+
--jadx "$JADX_OUTPUT" \
|
|
504
|
+
--output "${TEMP_DIR}/sast_findings.json" 2>> "$ERROR_LOG"; then
|
|
505
|
+
|
|
506
|
+
# Show summary with accurate counts
|
|
507
|
+
if [ -f "${TEMP_DIR}/sast_findings.json" ]; then
|
|
508
|
+
local critical=$(python3 -c "import json; d=json.load(open('${TEMP_DIR}/sast_findings.json')); print(len(d.get('critical', [])))" 2>/dev/null || echo "0")
|
|
509
|
+
local high=$(python3 -c "import json; d=json.load(open('${TEMP_DIR}/sast_findings.json')); print(len(d.get('high', [])))" 2>/dev/null || echo "0")
|
|
510
|
+
local medium=$(python3 -c "import json; d=json.load(open('${TEMP_DIR}/sast_findings.json')); print(len(d.get('medium', [])))" 2>/dev/null || echo "0")
|
|
511
|
+
local total=$((critical + high + medium))
|
|
512
|
+
|
|
513
|
+
log_success "SAST analysis completed"
|
|
514
|
+
log_info "Findings: 🔴 ${critical} Critical | 🟠 ${high} High | 🟡 ${medium} Medium | Total: ${total}"
|
|
515
|
+
else
|
|
516
|
+
log_success "SAST analysis completed"
|
|
517
|
+
fi
|
|
518
|
+
else
|
|
519
|
+
log_warning "SAST analysis had issues (check error log)"
|
|
520
|
+
fi
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
# Analyze AndroidManifest
|
|
524
|
+
analyze_manifest() {
|
|
525
|
+
log_section "Analyzing AndroidManifest.xml"
|
|
526
|
+
|
|
527
|
+
if [ -f "${DECOMPILED_DIR}/AndroidManifest.xml" ]; then
|
|
528
|
+
if python3 "${TOOLS_DIR}/manifest_analyzer.py" \
|
|
529
|
+
"${DECOMPILED_DIR}/AndroidManifest.xml" \
|
|
530
|
+
"${TEMP_DIR}/manifest_findings.json" 2>> "$ERROR_LOG"; then
|
|
531
|
+
|
|
532
|
+
# Show summary with accurate counts
|
|
533
|
+
if [ -f "${TEMP_DIR}/manifest_findings.json" ]; then
|
|
534
|
+
local findings=$(python3 -c "import json; d=json.load(open('${TEMP_DIR}/manifest_findings.json')); print(len(d.get('findings', [])))" 2>/dev/null || echo "0")
|
|
535
|
+
log_success "Manifest analysis completed"
|
|
536
|
+
log_info "Findings: ${findings} issue(s) detected"
|
|
537
|
+
else
|
|
538
|
+
log_success "Manifest analysis completed"
|
|
539
|
+
fi
|
|
540
|
+
else
|
|
541
|
+
log_warning "Manifest analysis had issues (check error log)"
|
|
542
|
+
fi
|
|
543
|
+
else
|
|
544
|
+
log_warning "AndroidManifest.xml not found"
|
|
545
|
+
fi
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
# Network artifacts analysis
|
|
549
|
+
analyze_network_artifacts() {
|
|
550
|
+
log_section "Analyzing Network Artifacts"
|
|
551
|
+
|
|
552
|
+
if python3 "${TOOLS_DIR}/network_analyzer.py" \
|
|
553
|
+
--decompiled "$DECOMPILED_DIR" \
|
|
554
|
+
--jadx "$JADX_OUTPUT" \
|
|
555
|
+
--output "${TEMP_DIR}/network_findings.json" 2>> "$ERROR_LOG"; then
|
|
556
|
+
|
|
557
|
+
# Show summary with accurate counts
|
|
558
|
+
if [ -f "${TEMP_DIR}/network_findings.json" ]; then
|
|
559
|
+
local urls=$(python3 -c "import json; d=json.load(open('${TEMP_DIR}/network_findings.json')); print(len(d.get('urls', [])))" 2>/dev/null || echo "0")
|
|
560
|
+
local suspicious=$(python3 -c "import json; d=json.load(open('${TEMP_DIR}/network_findings.json')); print(len(d.get('suspicious_urls', [])))" 2>/dev/null || echo "0")
|
|
561
|
+
log_success "Network analysis completed"
|
|
562
|
+
log_info "Found: ${urls} URL(s) | 🚨 ${suspicious} Suspicious"
|
|
563
|
+
else
|
|
564
|
+
log_success "Network analysis completed"
|
|
565
|
+
fi
|
|
566
|
+
else
|
|
567
|
+
log_warning "Network analysis had issues (check error log)"
|
|
568
|
+
fi
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
# Generate comprehensive report
|
|
572
|
+
generate_report() {
|
|
573
|
+
log_section "Generating Analysis Report"
|
|
574
|
+
|
|
575
|
+
# Use modular report generator for separate pages
|
|
576
|
+
if python3 "${TOOLS_DIR}/report_generator_modular.py" \
|
|
577
|
+
"$APK_WORK_DIR" \
|
|
578
|
+
"$TEMP_DIR" \
|
|
579
|
+
"$(basename "$APK_PATH")" \
|
|
580
|
+
"$SHA256" \
|
|
581
|
+
--output-md "report.md" \
|
|
582
|
+
--output-json "report.json" 2>> "$ERROR_LOG"; then
|
|
583
|
+
|
|
584
|
+
# Update report file paths
|
|
585
|
+
REPORT_FILE="$REPORTS_DIR/report.md"
|
|
586
|
+
JSON_REPORT="$REPORTS_DIR/report.json"
|
|
587
|
+
|
|
588
|
+
# Copy cumulative error log to reports folder
|
|
589
|
+
if [ -f "$ERROR_LOG" ] && [ -s "$ERROR_LOG" ]; then
|
|
590
|
+
cp "$ERROR_LOG" "$REPORTS_DIR/analysis_errors.log"
|
|
591
|
+
log_info "Error log copied to reports folder"
|
|
592
|
+
fi
|
|
593
|
+
|
|
594
|
+
log_success "Main report: $REPORT_FILE"
|
|
595
|
+
log_success "Detailed reports in: $REPORTS_DIR/"
|
|
596
|
+
log_success " - entropy_analysis.md (🆕 Encrypted Payload Detection)"
|
|
597
|
+
log_success " - sast_findings.md"
|
|
598
|
+
log_success " - manifest_analysis.md"
|
|
599
|
+
log_success " - network_analysis.md"
|
|
600
|
+
log_success " - yara_results.md (🆕 Enhanced with Categorization)"
|
|
601
|
+
log_success " - recommendations.md"
|
|
602
|
+
else
|
|
603
|
+
log_error "Report generation failed (check $ERROR_LOG for details)"
|
|
604
|
+
fi
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
# Main analysis workflow
|
|
608
|
+
main() {
|
|
609
|
+
print_banner
|
|
610
|
+
|
|
611
|
+
if [ $# -lt 1 ]; then
|
|
612
|
+
echo "Usage: $0 <path_to_apk>"
|
|
613
|
+
echo ""
|
|
614
|
+
echo "Options:"
|
|
615
|
+
echo " -h, --help Show this help message"
|
|
616
|
+
echo ""
|
|
617
|
+
exit 1
|
|
618
|
+
fi
|
|
619
|
+
|
|
620
|
+
APK_PATH="$1"
|
|
621
|
+
|
|
622
|
+
if [ ! -f "$APK_PATH" ]; then
|
|
623
|
+
log_error "APK file not found: $APK_PATH"
|
|
624
|
+
exit 1
|
|
625
|
+
fi
|
|
626
|
+
|
|
627
|
+
# Check dependencies
|
|
628
|
+
check_dependencies
|
|
629
|
+
|
|
630
|
+
# Initialize workspace
|
|
631
|
+
init_workspace "$APK_PATH"
|
|
632
|
+
|
|
633
|
+
# Extract basic info
|
|
634
|
+
extract_basic_info "$APK_PATH"
|
|
635
|
+
|
|
636
|
+
# Check and bypass protections
|
|
637
|
+
if check_apk_protection "$APK_PATH"; then
|
|
638
|
+
# Decompile
|
|
639
|
+
decompile_apktool "$APK_TO_ANALYZE" || log_warning "APKTool failed, continuing..."
|
|
640
|
+
decompile_jadx "$APK_TO_ANALYZE" || log_warning "JADX failed, continuing..."
|
|
641
|
+
|
|
642
|
+
# Detect obfuscation
|
|
643
|
+
detect_obfuscation
|
|
644
|
+
|
|
645
|
+
# Run entropy analysis (especially useful for protected APKs)
|
|
646
|
+
run_entropy_analysis "$APK_TO_ANALYZE"
|
|
647
|
+
|
|
648
|
+
# Security analysis
|
|
649
|
+
run_yara_scan "$APK_TO_ANALYZE"
|
|
650
|
+
analyze_manifest
|
|
651
|
+
analyze_network_artifacts
|
|
652
|
+
run_sast_analysis
|
|
653
|
+
|
|
654
|
+
# Generate report
|
|
655
|
+
generate_report
|
|
656
|
+
|
|
657
|
+
log_section "Analysis Complete"
|
|
658
|
+
log_success "All results saved to: $APK_WORK_DIR"
|
|
659
|
+
log_info "Open report: cat $REPORT_FILE"
|
|
660
|
+
|
|
661
|
+
else
|
|
662
|
+
log_critical "Unable to analyze APK due to protection mechanisms"
|
|
663
|
+
log_info "Manual intervention required"
|
|
664
|
+
exit 1
|
|
665
|
+
fi
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
# Run main
|
|
669
|
+
main "$@"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|