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/scripts/setup.sh
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
###############################################
|
|
4
|
+
# Quick Setup Script
|
|
5
|
+
# Sets up the analysis framework and validates
|
|
6
|
+
###############################################
|
|
7
|
+
|
|
8
|
+
set -e
|
|
9
|
+
|
|
10
|
+
GREEN='\033[0;32m'
|
|
11
|
+
YELLOW='\033[1;33m'
|
|
12
|
+
RED='\033[0;31m'
|
|
13
|
+
BLUE='\033[0;34m'
|
|
14
|
+
NC='\033[0m'
|
|
15
|
+
|
|
16
|
+
echo -e "${BLUE}"
|
|
17
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
18
|
+
echo "ā Anais Static Core Setup ā"
|
|
19
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
20
|
+
echo -e "${NC}"
|
|
21
|
+
|
|
22
|
+
# Check if on macOS or Linux
|
|
23
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
24
|
+
OS="macos"
|
|
25
|
+
echo -e "${GREEN}[+] Detected macOS${NC}"
|
|
26
|
+
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
|
27
|
+
OS="linux"
|
|
28
|
+
echo -e "${GREEN}[+] Detected Linux${NC}"
|
|
29
|
+
else
|
|
30
|
+
echo -e "${RED}[!] Unsupported OS${NC}"
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Function to check if command exists
|
|
35
|
+
command_exists() {
|
|
36
|
+
command -v "$1" >/dev/null 2>&1
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Check Python3
|
|
40
|
+
echo -e "\n${YELLOW}[*] Checking Python3...${NC}"
|
|
41
|
+
if command_exists python3; then
|
|
42
|
+
PYTHON_VERSION=$(python3 --version | awk '{print $2}')
|
|
43
|
+
echo -e "${GREEN}[+] Python3 found: $PYTHON_VERSION${NC}"
|
|
44
|
+
else
|
|
45
|
+
echo -e "${RED}[!] Python3 not found${NC}"
|
|
46
|
+
echo "Install with:"
|
|
47
|
+
if [ "$OS" = "macos" ]; then
|
|
48
|
+
echo " brew install python3"
|
|
49
|
+
else
|
|
50
|
+
echo " sudo apt-get install python3 python3-pip"
|
|
51
|
+
fi
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Check Java
|
|
56
|
+
echo -e "\n${YELLOW}[*] Checking Java...${NC}"
|
|
57
|
+
if command_exists java; then
|
|
58
|
+
JAVA_VERSION=$(java -version 2>&1 | head -n 1)
|
|
59
|
+
echo -e "${GREEN}[+] Java found: $JAVA_VERSION${NC}"
|
|
60
|
+
else
|
|
61
|
+
echo -e "${RED}[!] Java not found${NC}"
|
|
62
|
+
echo "Install with:"
|
|
63
|
+
if [ "$OS" = "macos" ]; then
|
|
64
|
+
echo " brew install openjdk"
|
|
65
|
+
else
|
|
66
|
+
echo " sudo apt-get install default-jdk"
|
|
67
|
+
fi
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# Check APKTool
|
|
72
|
+
echo -e "\n${YELLOW}[*] Checking APKTool...${NC}"
|
|
73
|
+
if command_exists apktool; then
|
|
74
|
+
APKTOOL_VERSION=$(apktool --version 2>&1 | head -n 1)
|
|
75
|
+
echo -e "${GREEN}[+] APKTool found: $APKTOOL_VERSION${NC}"
|
|
76
|
+
else
|
|
77
|
+
echo -e "${YELLOW}[!] APKTool not found${NC}"
|
|
78
|
+
echo "Install with:"
|
|
79
|
+
if [ "$OS" = "macos" ]; then
|
|
80
|
+
echo " brew install apktool"
|
|
81
|
+
else
|
|
82
|
+
echo " sudo apt-get install apktool"
|
|
83
|
+
fi
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Check JADX
|
|
87
|
+
echo -e "\n${YELLOW}[*] Checking JADX...${NC}"
|
|
88
|
+
if command_exists jadx; then
|
|
89
|
+
JADX_VERSION=$(jadx --version 2>&1 | head -n 1)
|
|
90
|
+
echo -e "${GREEN}[+] JADX found: $JADX_VERSION${NC}"
|
|
91
|
+
else
|
|
92
|
+
echo -e "${YELLOW}[!] JADX not found${NC}"
|
|
93
|
+
echo "Install with:"
|
|
94
|
+
if [ "$OS" = "macos" ]; then
|
|
95
|
+
echo " brew install jadx"
|
|
96
|
+
else
|
|
97
|
+
echo " Download from: https://github.com/skylot/jadx/releases"
|
|
98
|
+
fi
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Check YARA
|
|
102
|
+
echo -e "\n${YELLOW}[*] Checking YARA...${NC}"
|
|
103
|
+
if command_exists yara; then
|
|
104
|
+
YARA_VERSION=$(yara --version 2>&1)
|
|
105
|
+
echo -e "${GREEN}[+] YARA found: $YARA_VERSION${NC}"
|
|
106
|
+
else
|
|
107
|
+
echo -e "${YELLOW}[!] YARA not found${NC}"
|
|
108
|
+
echo "Install with:"
|
|
109
|
+
if [ "$OS" = "macos" ]; then
|
|
110
|
+
echo " brew install yara"
|
|
111
|
+
else
|
|
112
|
+
echo " sudo apt-get install yara"
|
|
113
|
+
fi
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Install Python packages
|
|
117
|
+
echo -e "\n${YELLOW}[*] Checking Python packages...${NC}"
|
|
118
|
+
|
|
119
|
+
REQUIRED_PACKAGES=("androguard" "yara-python" "requests" "cryptography")
|
|
120
|
+
MISSING_PACKAGES=()
|
|
121
|
+
|
|
122
|
+
for package in "${REQUIRED_PACKAGES[@]}"; do
|
|
123
|
+
if python3 -c "import ${package//-/_}" 2>/dev/null; then
|
|
124
|
+
echo -e "${GREEN}[+] $package installed${NC}"
|
|
125
|
+
else
|
|
126
|
+
echo -e "${YELLOW}[!] $package not installed${NC}"
|
|
127
|
+
MISSING_PACKAGES+=("$package")
|
|
128
|
+
fi
|
|
129
|
+
done
|
|
130
|
+
|
|
131
|
+
if [ ${#MISSING_PACKAGES[@]} -ne 0 ]; then
|
|
132
|
+
echo -e "\n${YELLOW}[*] Installing missing Python packages...${NC}"
|
|
133
|
+
pip3 install "${MISSING_PACKAGES[@]}"
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# Make scripts executable
|
|
137
|
+
echo -e "\n${YELLOW}[*] Setting execute permissions...${NC}"
|
|
138
|
+
chmod +x malware_analyzer.sh
|
|
139
|
+
chmod +x scripts/dynamic_analysis_helper.sh
|
|
140
|
+
|
|
141
|
+
if [ -d "analysis_tools" ]; then
|
|
142
|
+
chmod +x analysis_tools/*.py
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
echo -e "${GREEN}[+] Scripts are now executable${NC}"
|
|
146
|
+
|
|
147
|
+
# Create necessary directories
|
|
148
|
+
echo -e "\n${YELLOW}[*] Creating directories...${NC}"
|
|
149
|
+
mkdir -p "${HOME}/Documents/Anais-Reports"
|
|
150
|
+
mkdir -p "${HOME}/Documents/Anais-Reports/reports"
|
|
151
|
+
echo -e "${GREEN}[+] Directories created in ${HOME}/Documents/Anais-Reports${NC}"
|
|
152
|
+
|
|
153
|
+
# Validate YARA rules
|
|
154
|
+
echo -e "\n${YELLOW}[*] Validating YARA rules...${NC}"
|
|
155
|
+
if [ -f "rules/yara_general_rules.yar" ]; then
|
|
156
|
+
if yara -w rules/yara_general_rules.yar rules/yara_general_rules.yar >/dev/null 2>&1; then
|
|
157
|
+
echo -e "${GREEN}[+] yara_general_rules.yar is valid${NC}"
|
|
158
|
+
else
|
|
159
|
+
echo -e "${YELLOW}[!] yara_general_rules.yar has warnings${NC}"
|
|
160
|
+
fi
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# Summary
|
|
164
|
+
echo -e "\n${BLUE}āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā${NC}"
|
|
165
|
+
echo -e "${BLUE} Setup Summary${NC}"
|
|
166
|
+
echo -e "${BLUE}āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā${NC}"
|
|
167
|
+
|
|
168
|
+
echo -e "\n${GREEN}ā Setup Complete!${NC}\n"
|
|
169
|
+
|
|
170
|
+
echo "Quick Start:"
|
|
171
|
+
echo " 1. Analyze an APK:"
|
|
172
|
+
echo " ./malware_analyzer.sh /path/to/app.apk"
|
|
173
|
+
echo ""
|
|
174
|
+
echo " 2. Dynamic analysis (with device connected):"
|
|
175
|
+
echo " ./scripts/dynamic_analysis_helper.sh dex-dump com.package.name"
|
|
176
|
+
echo ""
|
|
177
|
+
echo " 3. View documentation:"
|
|
178
|
+
echo " cat ANALYZER_README.md"
|
|
179
|
+
echo ""
|
|
180
|
+
|
|
181
|
+
# Check if ADB is available for dynamic analysis
|
|
182
|
+
if command_exists adb; then
|
|
183
|
+
echo -e "${GREEN}[+] ADB found - Dynamic analysis available${NC}"
|
|
184
|
+
echo ""
|
|
185
|
+
else
|
|
186
|
+
echo -e "${YELLOW}[!] ADB not found - Dynamic analysis will not be available${NC}"
|
|
187
|
+
echo "Install with:"
|
|
188
|
+
if [ "$OS" = "macos" ]; then
|
|
189
|
+
echo " brew install android-platform-tools"
|
|
190
|
+
else
|
|
191
|
+
echo " sudo apt-get install android-tools-adb"
|
|
192
|
+
fi
|
|
193
|
+
echo ""
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
# Check for Frida
|
|
197
|
+
if command_exists frida; then
|
|
198
|
+
echo -e "${GREEN}[+] Frida found - Advanced hooking available${NC}"
|
|
199
|
+
else
|
|
200
|
+
echo -e "${YELLOW}[!] Frida not found - Install for advanced dynamic analysis${NC}"
|
|
201
|
+
echo "Install with: pip3 install frida-tools"
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
echo ""
|
|
205
|
+
echo -e "${BLUE}āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā${NC}"
|
|
206
|
+
echo ""
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Test script untuk validasi framework
|
|
3
|
+
# Run this untuk test framework dengan dummy APK
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
8
|
+
echo " Anais Static Core - Validation Test"
|
|
9
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
10
|
+
echo ""
|
|
11
|
+
|
|
12
|
+
# Test 1: Check all scripts exist
|
|
13
|
+
echo "[TEST 1] Checking script files..."
|
|
14
|
+
files=(
|
|
15
|
+
"anais.sh"
|
|
16
|
+
"scripts/dynamic_analysis_helper.sh"
|
|
17
|
+
"scripts/setup.sh"
|
|
18
|
+
"analysis_tools/check_zip_encryption.py"
|
|
19
|
+
"analysis_tools/fix_apk_headers.py"
|
|
20
|
+
"analysis_tools/detect_obfuscation.py"
|
|
21
|
+
"analysis_tools/sast_scanner.py"
|
|
22
|
+
"analysis_tools/apk_basic_info.py"
|
|
23
|
+
"analysis_tools/manifest_analyzer.py"
|
|
24
|
+
"analysis_tools/network_analyzer.py"
|
|
25
|
+
"analysis_tools/report_generator.py"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
missing=0
|
|
29
|
+
for file in "${files[@]}"; do
|
|
30
|
+
if [ -f "$file" ]; then
|
|
31
|
+
echo " ā $file"
|
|
32
|
+
else
|
|
33
|
+
echo " ā $file (MISSING)"
|
|
34
|
+
missing=$((missing + 1))
|
|
35
|
+
fi
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
if [ $missing -eq 0 ]; then
|
|
39
|
+
echo "ā All script files present"
|
|
40
|
+
else
|
|
41
|
+
echo "ā $missing files missing"
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
echo ""
|
|
45
|
+
|
|
46
|
+
# Test 2: Check permissions
|
|
47
|
+
echo "[TEST 2] Checking execute permissions..."
|
|
48
|
+
if [ -x "anais.sh" ] && [ -x "scripts/dynamic_analysis_helper.sh" ] && [ -x "scripts/setup.sh" ]; then
|
|
49
|
+
echo "ā Main scripts are executable"
|
|
50
|
+
else
|
|
51
|
+
echo "ā Scripts not executable. Run: chmod +x *.sh"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
echo ""
|
|
55
|
+
|
|
56
|
+
# Test 3: Check Python scripts
|
|
57
|
+
echo "[TEST 3] Checking Python scripts syntax..."
|
|
58
|
+
python_errors=0
|
|
59
|
+
for script in analysis_tools/*.py; do
|
|
60
|
+
if python3 -m py_compile "$script" 2>/dev/null; then
|
|
61
|
+
echo " ā $(basename $script)"
|
|
62
|
+
else
|
|
63
|
+
echo " ā $(basename $script) (SYNTAX ERROR)"
|
|
64
|
+
python_errors=$((python_errors + 1))
|
|
65
|
+
fi
|
|
66
|
+
done
|
|
67
|
+
|
|
68
|
+
if [ $python_errors -eq 0 ]; then
|
|
69
|
+
echo "ā All Python scripts valid"
|
|
70
|
+
else
|
|
71
|
+
echo "ā $python_errors Python scripts have syntax errors"
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
echo ""
|
|
75
|
+
|
|
76
|
+
# Test 4: Check YARA rules
|
|
77
|
+
echo "[TEST 4] Validating YARA rules..."
|
|
78
|
+
if command -v yara >/dev/null 2>&1; then
|
|
79
|
+
if [ -f "rules/yara_general_rules.yar" ]; then
|
|
80
|
+
if yara -w rules/yara_general_rules.yar rules/yara_general_rules.yar >/dev/null 2>&1; then
|
|
81
|
+
echo " ā rules/yara_general_rules.yar"
|
|
82
|
+
else
|
|
83
|
+
echo " ā rules/yara_general_rules.yar (has warnings)"
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
echo "ā YARA rules validated"
|
|
87
|
+
else
|
|
88
|
+
echo "ā YARA not installed, skipping rule validation"
|
|
89
|
+
fi
|
|
90
|
+
echo ""
|
|
91
|
+
|
|
92
|
+
# Test 5: Check documentation
|
|
93
|
+
echo "[TEST 5] Checking documentation files..."
|
|
94
|
+
docs=(
|
|
95
|
+
"README.md"
|
|
96
|
+
"docs/ARCHITECTURE.txt"
|
|
97
|
+
"docs/Workflow and Reference.md"
|
|
98
|
+
"analyzer_config.json"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
for doc in "${docs[@]}"; do
|
|
102
|
+
if [ -f "$doc" ]; then
|
|
103
|
+
echo " ā $doc"
|
|
104
|
+
else
|
|
105
|
+
echo " ā $doc (MISSING)"
|
|
106
|
+
fi
|
|
107
|
+
done
|
|
108
|
+
echo ""
|
|
109
|
+
|
|
110
|
+
# Test 6: Check directories
|
|
111
|
+
echo "[TEST 6] Checking directory structure..."
|
|
112
|
+
if [ -d "analysis_tools" ]; then
|
|
113
|
+
echo " ā analysis_tools/"
|
|
114
|
+
else
|
|
115
|
+
echo " ā analysis_tools/ (MISSING)"
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
if [ -d "scripts" ]; then
|
|
119
|
+
echo " ā scripts/"
|
|
120
|
+
else
|
|
121
|
+
echo " ā scripts/ (MISSING)"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
if [ -d "rules" ]; then
|
|
125
|
+
echo " ā rules/"
|
|
126
|
+
else
|
|
127
|
+
echo " ā rules/ (MISSING)"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if [ -d "docs" ]; then
|
|
131
|
+
echo " ā docs/"
|
|
132
|
+
else
|
|
133
|
+
echo " ā docs/ (MISSING)"
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
if [ -d "${HOME}/Documents/Anais-Reports" ]; then
|
|
137
|
+
echo " ā ~/Documents/Anais-Reports/"
|
|
138
|
+
else
|
|
139
|
+
echo " ā ~/Documents/Anais-Reports/ (will be created on first run)"
|
|
140
|
+
fi
|
|
141
|
+
echo ""
|
|
142
|
+
|
|
143
|
+
# Test 7: Check dependencies
|
|
144
|
+
echo "[TEST 7] Checking dependencies..."
|
|
145
|
+
|
|
146
|
+
check_cmd() {
|
|
147
|
+
if command -v "$1" >/dev/null 2>&1; then
|
|
148
|
+
echo " ā $1"
|
|
149
|
+
return 0
|
|
150
|
+
else
|
|
151
|
+
echo " ā $1 (NOT INSTALLED)"
|
|
152
|
+
return 1
|
|
153
|
+
fi
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
deps_missing=0
|
|
157
|
+
check_cmd python3 || deps_missing=$((deps_missing + 1))
|
|
158
|
+
check_cmd java || deps_missing=$((deps_missing + 1))
|
|
159
|
+
check_cmd apktool || deps_missing=$((deps_missing + 1))
|
|
160
|
+
check_cmd jadx || deps_missing=$((deps_missing + 1))
|
|
161
|
+
check_cmd yara || deps_missing=$((deps_missing + 1))
|
|
162
|
+
|
|
163
|
+
if [ $deps_missing -eq 0 ]; then
|
|
164
|
+
echo "ā All dependencies installed"
|
|
165
|
+
else
|
|
166
|
+
echo "ā $deps_missing dependencies missing (run setup.sh for details)"
|
|
167
|
+
fi
|
|
168
|
+
echo ""
|
|
169
|
+
|
|
170
|
+
# Test 8: Check Python packages
|
|
171
|
+
echo "[TEST 8] Checking Python packages..."
|
|
172
|
+
|
|
173
|
+
check_pkg() {
|
|
174
|
+
if python3 -c "import ${1//-/_}" 2>/dev/null; then
|
|
175
|
+
echo " ā $1"
|
|
176
|
+
return 0
|
|
177
|
+
else
|
|
178
|
+
echo " ā $1 (NOT INSTALLED)"
|
|
179
|
+
return 1
|
|
180
|
+
fi
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
pkgs_missing=0
|
|
184
|
+
check_pkg androguard || pkgs_missing=$((pkgs_missing + 1))
|
|
185
|
+
check_pkg yara-python || pkgs_missing=$((pkgs_missing + 1))
|
|
186
|
+
check_pkg requests || pkgs_missing=$((pkgs_missing + 1))
|
|
187
|
+
check_pkg cryptography || pkgs_missing=$((pkgs_missing + 1))
|
|
188
|
+
|
|
189
|
+
if [ $pkgs_missing -eq 0 ]; then
|
|
190
|
+
echo "ā All Python packages installed"
|
|
191
|
+
else
|
|
192
|
+
echo "ā $pkgs_missing Python packages missing"
|
|
193
|
+
echo " Install with: pip3 install androguard yara-python requests cryptography"
|
|
194
|
+
fi
|
|
195
|
+
echo ""
|
|
196
|
+
|
|
197
|
+
# Summary
|
|
198
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
199
|
+
echo " TEST SUMMARY"
|
|
200
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
201
|
+
echo ""
|
|
202
|
+
|
|
203
|
+
if [ $missing -eq 0 ] && [ $python_errors -eq 0 ]; then
|
|
204
|
+
echo "ā
FRAMEWORK VALIDATION PASSED"
|
|
205
|
+
echo ""
|
|
206
|
+
echo "Framework is ready to use!"
|
|
207
|
+
echo ""
|
|
208
|
+
echo "Quick Start:"
|
|
209
|
+
echo " 1. Run setup (if not done): ./scripts/setup.sh"
|
|
210
|
+
echo " 2. Analyze an APK: ./anais.sh app.apk"
|
|
211
|
+
echo ""
|
|
212
|
+
|
|
213
|
+
if [ $deps_missing -gt 0 ] || [ $pkgs_missing -gt 0 ]; then
|
|
214
|
+
echo "ā ļø Some dependencies are missing. The framework will work with"
|
|
215
|
+
echo " limited functionality. Run ./scripts/setup.sh for details."
|
|
216
|
+
fi
|
|
217
|
+
else
|
|
218
|
+
echo "ā FRAMEWORK VALIDATION FAILED"
|
|
219
|
+
echo ""
|
|
220
|
+
echo "Please fix the errors above before using the framework."
|
|
221
|
+
exit 1
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { executeForensicAnalysis } from "./index";
|
|
4
|
+
import {
|
|
5
|
+
formatError,
|
|
6
|
+
formatSuccess,
|
|
7
|
+
printBanner,
|
|
8
|
+
printSeparator,
|
|
9
|
+
} from "./utils";
|
|
10
|
+
|
|
11
|
+
const main = async () => {
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
|
|
14
|
+
if (args.length === 0) {
|
|
15
|
+
printBanner();
|
|
16
|
+
console.log("Usage:");
|
|
17
|
+
console.log(" anais <apk-file-path> Analyze an APK file");
|
|
18
|
+
console.log(" anais --version Show version");
|
|
19
|
+
console.log(" anais --help Show this help message");
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (args[0] === "--version" || args[0] === "-v") {
|
|
24
|
+
console.log("Anais APK Forensic CLI v1.0.0");
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (args[0] === "--help" || args[0] === "-h") {
|
|
29
|
+
printBanner();
|
|
30
|
+
console.log("Usage:");
|
|
31
|
+
console.log(" anais <apk-file-path> Analyze an APK file");
|
|
32
|
+
console.log(" anais --version Show version");
|
|
33
|
+
console.log(" anais --help Show this help message");
|
|
34
|
+
console.log("\nDescription:");
|
|
35
|
+
console.log(" Comprehensive APK security analysis and SAST scanner");
|
|
36
|
+
console.log(" - Decompilation with APKTool and JADX");
|
|
37
|
+
console.log(" - YARA malware detection");
|
|
38
|
+
console.log(" - Obfuscation detection");
|
|
39
|
+
console.log(" - Network traffic analysis");
|
|
40
|
+
console.log(" - AndroidManifest analysis");
|
|
41
|
+
console.log(" - Entropy analysis for encrypted payloads");
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const apkPath = args[0];
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
console.log(`š Anais APK Forensic Analysis\n`);
|
|
49
|
+
printSeparator();
|
|
50
|
+
console.log();
|
|
51
|
+
|
|
52
|
+
const result = await executeForensicAnalysis(apkPath);
|
|
53
|
+
|
|
54
|
+
console.log();
|
|
55
|
+
printSeparator();
|
|
56
|
+
|
|
57
|
+
if (result.success) {
|
|
58
|
+
console.log(`\n${formatSuccess("Analysis completed successfully!")}\n`);
|
|
59
|
+
|
|
60
|
+
if (result.workspaceDir) {
|
|
61
|
+
console.log(`š Workspace: ${result.workspaceDir}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (result.reportPath) {
|
|
65
|
+
console.log(`š Report: ${result.reportPath}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (result.jsonReportPath) {
|
|
69
|
+
console.log(`š JSON Report: ${result.jsonReportPath}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log(
|
|
73
|
+
"\nš” Tip: Open the report with your preferred markdown viewer",
|
|
74
|
+
);
|
|
75
|
+
console.log(` e.g., cat "${result.reportPath}"\n`);
|
|
76
|
+
} else {
|
|
77
|
+
console.log(`\n${formatError("Analysis failed!")}\n`);
|
|
78
|
+
console.log(`Error: ${result.message}`);
|
|
79
|
+
if (result.error) {
|
|
80
|
+
console.log(`Details: ${result.error}`);
|
|
81
|
+
}
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error(`\n${formatError("Unexpected error during analysis:")}`);
|
|
86
|
+
console.error(error);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
main();
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { AnalysisResult } from "./types";
|
|
3
|
+
import {
|
|
4
|
+
fileExists,
|
|
5
|
+
getAnaisScriptPath,
|
|
6
|
+
getBasename,
|
|
7
|
+
getProjectRoot,
|
|
8
|
+
resolveAbsolutePath,
|
|
9
|
+
} from "./utils";
|
|
10
|
+
|
|
11
|
+
export * from "./types";
|
|
12
|
+
|
|
13
|
+
export const executeForensicAnalysis = async (
|
|
14
|
+
apkPath: string,
|
|
15
|
+
): Promise<AnalysisResult> => {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
// Resolve absolute path
|
|
18
|
+
const absoluteApkPath = resolveAbsolutePath(apkPath);
|
|
19
|
+
|
|
20
|
+
// Check if APK file exists
|
|
21
|
+
if (!fileExists(absoluteApkPath)) {
|
|
22
|
+
return resolve({
|
|
23
|
+
success: false,
|
|
24
|
+
apkPath,
|
|
25
|
+
message: `APK file not found: ${apkPath}`,
|
|
26
|
+
error: "File not found",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log(`\nš± APK: ${getBasename(absoluteApkPath)}`);
|
|
31
|
+
console.log(`š Path: ${absoluteApkPath}\n`);
|
|
32
|
+
|
|
33
|
+
// Get paths
|
|
34
|
+
const scriptDir = getProjectRoot();
|
|
35
|
+
const anaisScript = getAnaisScriptPath();
|
|
36
|
+
|
|
37
|
+
if (!fileExists(anaisScript)) {
|
|
38
|
+
return resolve({
|
|
39
|
+
success: false,
|
|
40
|
+
apkPath,
|
|
41
|
+
message: `Analysis script not found: ${anaisScript}`,
|
|
42
|
+
error: "Script not found",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(`š Executing analysis...\n`);
|
|
47
|
+
|
|
48
|
+
// Spawn the bash script
|
|
49
|
+
const analysis = spawn("bash", [anaisScript, absoluteApkPath], {
|
|
50
|
+
cwd: scriptDir,
|
|
51
|
+
env: {
|
|
52
|
+
...process.env,
|
|
53
|
+
PYTHONWARNINGS: "ignore",
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
let stdout = "";
|
|
58
|
+
let stderr = "";
|
|
59
|
+
let workspaceDir = "";
|
|
60
|
+
let reportPath = "";
|
|
61
|
+
|
|
62
|
+
// Capture stdout
|
|
63
|
+
analysis.stdout.on("data", (data) => {
|
|
64
|
+
const output = data.toString();
|
|
65
|
+
process.stdout.write(output);
|
|
66
|
+
stdout += output;
|
|
67
|
+
|
|
68
|
+
// Extract workspace directory from output
|
|
69
|
+
const workspaceMatch = output.match(/Workspace initialized: (.+)/);
|
|
70
|
+
if (workspaceMatch) {
|
|
71
|
+
workspaceDir = workspaceMatch[1].trim();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Extract report path
|
|
75
|
+
const reportMatch = output.match(/Main report: (.+\.md)/);
|
|
76
|
+
if (reportMatch) {
|
|
77
|
+
reportPath = reportMatch[1].trim();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Capture stderr (though we're logging warnings there)
|
|
82
|
+
analysis.stderr.on("data", (data) => {
|
|
83
|
+
stderr += data.toString();
|
|
84
|
+
// Don't print stderr to console as it's handled by the script
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Handle process completion
|
|
88
|
+
analysis.on("close", (code) => {
|
|
89
|
+
if (code === 0) {
|
|
90
|
+
const jsonReportPath = reportPath.replace(/\.md$/, ".json");
|
|
91
|
+
|
|
92
|
+
resolve({
|
|
93
|
+
success: true,
|
|
94
|
+
apkPath: absoluteApkPath,
|
|
95
|
+
workspaceDir,
|
|
96
|
+
reportPath,
|
|
97
|
+
jsonReportPath: fileExists(jsonReportPath)
|
|
98
|
+
? jsonReportPath
|
|
99
|
+
: undefined,
|
|
100
|
+
message: "Analysis completed successfully",
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
resolve({
|
|
104
|
+
success: false,
|
|
105
|
+
apkPath: absoluteApkPath,
|
|
106
|
+
workspaceDir,
|
|
107
|
+
message: `Analysis failed with exit code ${code}`,
|
|
108
|
+
error: stderr || "Unknown error",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Handle errors
|
|
114
|
+
analysis.on("error", (error) => {
|
|
115
|
+
reject({
|
|
116
|
+
success: false,
|
|
117
|
+
apkPath: absoluteApkPath,
|
|
118
|
+
message: "Failed to execute analysis script",
|
|
119
|
+
error: error.message,
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analysis result from the forensic analysis
|
|
3
|
+
*/
|
|
4
|
+
export interface AnalysisResult {
|
|
5
|
+
success: boolean;
|
|
6
|
+
apkPath: string;
|
|
7
|
+
workspaceDir?: string;
|
|
8
|
+
reportPath?: string;
|
|
9
|
+
jsonReportPath?: string;
|
|
10
|
+
message: string;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* CLI command options
|
|
16
|
+
*/
|
|
17
|
+
export interface CLIOptions {
|
|
18
|
+
help?: boolean;
|
|
19
|
+
version?: boolean;
|
|
20
|
+
verbose?: boolean;
|
|
21
|
+
output?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Original types (kept for compatibility)
|
|
26
|
+
*/
|
|
27
|
+
export interface CommandLineOptions {
|
|
28
|
+
inputFile: string;
|
|
29
|
+
outputFile?: string;
|
|
30
|
+
verbose?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ApkAnalysisResult {
|
|
34
|
+
packageName: string;
|
|
35
|
+
versionCode: number;
|
|
36
|
+
versionName: string;
|
|
37
|
+
permissions: string[];
|
|
38
|
+
activities: string[];
|
|
39
|
+
services: string[];
|
|
40
|
+
receivers: string[];
|
|
41
|
+
providers: string[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type AnalysisStatus = "pending" | "in-progress" | "completed" | "failed";
|