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
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
rule Android_General_Malware {
|
|
2
|
+
meta:
|
|
3
|
+
description = "General Android malware indicators"
|
|
4
|
+
author = "Mobile Security Researcher"
|
|
5
|
+
date = "2026-01-23"
|
|
6
|
+
threat_level = "high"
|
|
7
|
+
|
|
8
|
+
strings:
|
|
9
|
+
// Generic malware behaviors
|
|
10
|
+
$runtime_exec = "Runtime.exec" ascii
|
|
11
|
+
$process_builder = "ProcessBuilder" ascii
|
|
12
|
+
$root_su = "/system/bin/su" ascii
|
|
13
|
+
$root_xbin = "/system/xbin/su" ascii
|
|
14
|
+
|
|
15
|
+
// Dynamic code loading
|
|
16
|
+
$dex_loader = "DexClassLoader" ascii
|
|
17
|
+
$path_loader = "PathClassLoader" ascii
|
|
18
|
+
$load_class = ".loadClass(" ascii
|
|
19
|
+
|
|
20
|
+
// Native library loading
|
|
21
|
+
$load_library = "System.loadLibrary" ascii
|
|
22
|
+
$load_native = "System.load" ascii
|
|
23
|
+
|
|
24
|
+
// Reflection abuse
|
|
25
|
+
$get_method = "getMethod" ascii
|
|
26
|
+
$invoke = ".invoke(" ascii
|
|
27
|
+
$get_declared = "getDeclaredMethod" ascii
|
|
28
|
+
|
|
29
|
+
// Obfuscation indicators
|
|
30
|
+
$base64_decode = "Base64.decode" ascii
|
|
31
|
+
$cipher_instance = "Cipher.getInstance" ascii
|
|
32
|
+
$decrypt = /decrypt[A-Za-z]{0,20}\(/ ascii
|
|
33
|
+
|
|
34
|
+
condition:
|
|
35
|
+
(3 of them) or
|
|
36
|
+
($dex_loader and $load_class) or
|
|
37
|
+
($runtime_exec and $process_builder)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
rule Android_Accessibility_Abuse {
|
|
41
|
+
meta:
|
|
42
|
+
description = "Detects accessibility service abuse for overlay/keylogging"
|
|
43
|
+
threat_level = "critical"
|
|
44
|
+
|
|
45
|
+
strings:
|
|
46
|
+
$accessibility_1 = "AccessibilityService" ascii
|
|
47
|
+
$accessibility_2 = "AccessibilityEvent" ascii
|
|
48
|
+
$accessibility_3 = "BIND_ACCESSIBILITY_SERVICE" ascii
|
|
49
|
+
$perform_action = "performGlobalAction" ascii
|
|
50
|
+
$find_node = "findAccessibilityNodeInfo" ascii
|
|
51
|
+
$get_text = "getText" ascii
|
|
52
|
+
$click_action = "ACTION_CLICK" ascii
|
|
53
|
+
|
|
54
|
+
condition:
|
|
55
|
+
3 of them
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
rule Android_SMS_Trojan {
|
|
59
|
+
meta:
|
|
60
|
+
description = "Detects SMS trojans and SMS interception"
|
|
61
|
+
threat_level = "critical"
|
|
62
|
+
|
|
63
|
+
strings:
|
|
64
|
+
$sms_1 = "android.provider.Telephony.SMS_RECEIVED" ascii
|
|
65
|
+
$sms_2 = "SmsManager" ascii
|
|
66
|
+
$sms_3 = "sendTextMessage" ascii
|
|
67
|
+
$sms_4 = "getMessagesFromIntent" ascii
|
|
68
|
+
$intercept = "abortBroadcast" ascii
|
|
69
|
+
|
|
70
|
+
condition:
|
|
71
|
+
3 of them
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
rule Android_Banking_Trojan_Indicators {
|
|
75
|
+
meta:
|
|
76
|
+
description = "Generic banking trojan indicators"
|
|
77
|
+
threat_level = "critical"
|
|
78
|
+
|
|
79
|
+
strings:
|
|
80
|
+
// Banking app targeting
|
|
81
|
+
$bank_pkg_1 = "com.bank" ascii
|
|
82
|
+
$bank_pkg_2 = "banking" ascii
|
|
83
|
+
$bank_pkg_3 = "mobile.bank" ascii
|
|
84
|
+
|
|
85
|
+
// Overlay techniques
|
|
86
|
+
$overlay_1 = "SYSTEM_ALERT_WINDOW" ascii
|
|
87
|
+
$overlay_2 = "TYPE_SYSTEM_OVERLAY" ascii
|
|
88
|
+
$overlay_3 = "TYPE_PHONE" ascii
|
|
89
|
+
$window_manager = "WindowManager" ascii
|
|
90
|
+
$add_view = "addView" ascii
|
|
91
|
+
|
|
92
|
+
// SMS/2FA interception
|
|
93
|
+
$sms_read = "READ_SMS" ascii
|
|
94
|
+
$sms_receive = "RECEIVE_SMS" ascii
|
|
95
|
+
|
|
96
|
+
// Screen capture
|
|
97
|
+
$media_projection = "MediaProjection" ascii
|
|
98
|
+
$screen_capture = "createVirtualDisplay" ascii
|
|
99
|
+
|
|
100
|
+
condition:
|
|
101
|
+
(2 of ($bank_*) and 3 of ($overlay_*, $add_view, $window_manager)) or
|
|
102
|
+
(2 of ($bank_*) and 2 of ($sms_*)) or
|
|
103
|
+
($media_projection and $screen_capture and 1 of ($bank_*)) or
|
|
104
|
+
($window_manager and 2 of ($overlay_*, $add_view) and 1 of ($bank_*))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
rule Android_Spyware_Indicators {
|
|
108
|
+
meta:
|
|
109
|
+
description = "Detects spyware and surveillance apps"
|
|
110
|
+
threat_level = "high"
|
|
111
|
+
|
|
112
|
+
strings:
|
|
113
|
+
// Location tracking
|
|
114
|
+
$location_1 = "LocationManager" ascii
|
|
115
|
+
$location_2 = "getLastKnownLocation" ascii
|
|
116
|
+
$location_3 = "requestLocationUpdates" ascii
|
|
117
|
+
|
|
118
|
+
// Contact exfiltration
|
|
119
|
+
$contacts_1 = "ContactsContract" ascii
|
|
120
|
+
$contacts_2 = "content://com.android.contacts" ascii
|
|
121
|
+
|
|
122
|
+
// Call log access
|
|
123
|
+
$calls_1 = "CallLog" ascii
|
|
124
|
+
$calls_2 = "content://call_log" ascii
|
|
125
|
+
|
|
126
|
+
// Camera/Microphone
|
|
127
|
+
$camera = "Camera.open" ascii
|
|
128
|
+
$record_audio = "MediaRecorder" ascii
|
|
129
|
+
$audio_record = "AudioRecord" ascii
|
|
130
|
+
|
|
131
|
+
// File system access
|
|
132
|
+
$external_storage = "Environment.getExternalStorageDirectory" ascii
|
|
133
|
+
$file_list = "listFiles" ascii
|
|
134
|
+
|
|
135
|
+
condition:
|
|
136
|
+
(2 of ($location_*) and 2 of ($contacts_*)) or
|
|
137
|
+
(2 of ($location_*) and 2 of ($calls_*)) or
|
|
138
|
+
(3 of ($location_*) and ($camera or $record_audio)) or
|
|
139
|
+
(2 of ($location_*) and $audio_record) or
|
|
140
|
+
(2 of ($location_*) and $external_storage and $file_list)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
rule Android_Crypto_Wallet_Stealer {
|
|
144
|
+
meta:
|
|
145
|
+
description = "Detects cryptocurrency wallet targeting"
|
|
146
|
+
threat_level = "critical"
|
|
147
|
+
|
|
148
|
+
strings:
|
|
149
|
+
// Popular wallet apps
|
|
150
|
+
$wallet_1 = "im.token.app" ascii
|
|
151
|
+
$wallet_2 = "vip.mytokenpocket" ascii
|
|
152
|
+
$wallet_3 = "io.metamask" ascii
|
|
153
|
+
$wallet_4 = "com.wallet.crypto.trustapp" ascii
|
|
154
|
+
$wallet_5 = "com.tronlinkpro.wallet" ascii
|
|
155
|
+
$wallet_6 = "com.coinbase.android" ascii
|
|
156
|
+
$wallet_7 = "piuk.blockchain.android" ascii
|
|
157
|
+
|
|
158
|
+
// Wallet-related strings
|
|
159
|
+
$mnemonic = "mnemonic" ascii nocase
|
|
160
|
+
$seed_phrase = "seed phrase" ascii nocase
|
|
161
|
+
$private_key = "private key" ascii nocase
|
|
162
|
+
$keystore = "keystore" ascii nocase
|
|
163
|
+
$bip39 = "BIP39" ascii
|
|
164
|
+
|
|
165
|
+
// Clipboard monitoring
|
|
166
|
+
$clipboard = "ClipboardManager" ascii
|
|
167
|
+
$get_clip = "getPrimaryClip" ascii
|
|
168
|
+
|
|
169
|
+
condition:
|
|
170
|
+
(2 of ($wallet_*)) or
|
|
171
|
+
(1 of ($wallet_*) and 2 of ($mnemonic, $seed_phrase, $private_key, $keystore)) or
|
|
172
|
+
(3 of ($mnemonic, $seed_phrase, $private_key, $keystore, $bip39) and $clipboard) or
|
|
173
|
+
($get_clip and 2 of ($mnemonic, $seed_phrase, $private_key, $keystore, $bip39))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
rule Android_Data_Exfiltration {
|
|
177
|
+
meta:
|
|
178
|
+
description = "Detects data exfiltration patterns"
|
|
179
|
+
threat_level = "high"
|
|
180
|
+
|
|
181
|
+
strings:
|
|
182
|
+
// Network upload
|
|
183
|
+
$http_post = "HttpPost" ascii
|
|
184
|
+
$http_put = "HttpPut" ascii
|
|
185
|
+
$multipart = "MultipartEntity" ascii
|
|
186
|
+
$upload = /upload[A-Za-z]{0,20}\(/ ascii
|
|
187
|
+
|
|
188
|
+
// File operations
|
|
189
|
+
$file_input = "FileInputStream" ascii
|
|
190
|
+
$read_file = "readFile" ascii
|
|
191
|
+
$get_bytes = "getBytes" ascii
|
|
192
|
+
|
|
193
|
+
// Compression
|
|
194
|
+
$zip_output = "ZipOutputStream" ascii
|
|
195
|
+
$gzip = "GZIPOutputStream" ascii
|
|
196
|
+
|
|
197
|
+
// Base64 encoding (for exfiltration)
|
|
198
|
+
$base64_encode = "Base64.encode" ascii
|
|
199
|
+
|
|
200
|
+
// External URLs
|
|
201
|
+
$http_url = /https?:\/\/[\w\-\.]+\/[^\s'"]+/ ascii
|
|
202
|
+
|
|
203
|
+
condition:
|
|
204
|
+
(($http_post or $http_put or $upload) and 2 of ($file_input, $read_file, $get_bytes)) or
|
|
205
|
+
(($http_post or $http_put or $upload) and ($zip_output or $gzip) and $base64_encode) or
|
|
206
|
+
($multipart and $file_input) or
|
|
207
|
+
(($http_post or $http_put) and $http_url)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
rule Android_C2_Communication {
|
|
211
|
+
meta:
|
|
212
|
+
description = "Detects C2 communication patterns"
|
|
213
|
+
threat_level = "critical"
|
|
214
|
+
|
|
215
|
+
strings:
|
|
216
|
+
// WebSocket (common for C2)
|
|
217
|
+
$websocket_1 = "WebSocket" ascii
|
|
218
|
+
$websocket_2 = "wss://" ascii
|
|
219
|
+
$websocket_3 = "ws://" ascii
|
|
220
|
+
|
|
221
|
+
// Common C2 endpoints
|
|
222
|
+
$endpoint_1 = "/api/command" ascii
|
|
223
|
+
$endpoint_2 = "/api/upload" ascii
|
|
224
|
+
$endpoint_3 = "/api/download" ascii
|
|
225
|
+
$endpoint_4 = "/bot/" ascii
|
|
226
|
+
$endpoint_5 = "/c2/" ascii
|
|
227
|
+
$endpoint_6 = "/panel/" ascii
|
|
228
|
+
|
|
229
|
+
// Suspicious domains
|
|
230
|
+
$domain_top = ".top" ascii
|
|
231
|
+
$domain_xyz = ".xyz" ascii
|
|
232
|
+
|
|
233
|
+
// Device ID (for C2 registration)
|
|
234
|
+
$device_id = "getDeviceId" ascii
|
|
235
|
+
$android_id = "ANDROID_ID" ascii
|
|
236
|
+
|
|
237
|
+
// Periodic checks
|
|
238
|
+
$alarm_manager = "AlarmManager" ascii
|
|
239
|
+
$set_repeating = "setRepeating" ascii
|
|
240
|
+
|
|
241
|
+
condition:
|
|
242
|
+
(2 of ($websocket_*)) or
|
|
243
|
+
(3 of ($endpoint_*)) or
|
|
244
|
+
(1 of ($websocket_*) and 2 of ($endpoint_*)) or
|
|
245
|
+
(2 of ($domain_*) and $device_id and $alarm_manager) or
|
|
246
|
+
($android_id and 2 of ($domain_*)) or
|
|
247
|
+
($alarm_manager and $set_repeating and 2 of ($endpoint_*))
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
rule Android_Native_Protection_Shell {
|
|
251
|
+
meta:
|
|
252
|
+
description = "Detects native protection shells (DPT, Bangcle, etc)"
|
|
253
|
+
threat_level = "info"
|
|
254
|
+
|
|
255
|
+
strings:
|
|
256
|
+
// Common protection library names
|
|
257
|
+
$lib_dpt = "libdpt" ascii
|
|
258
|
+
$lib_protect = "libprotect" ascii
|
|
259
|
+
$lib_shell = "libshell" ascii
|
|
260
|
+
$lib_jiagu = "libjiagu" ascii
|
|
261
|
+
$lib_bangcle = "libbangcle" ascii
|
|
262
|
+
$lib_secexe = "libsecexe" ascii
|
|
263
|
+
|
|
264
|
+
// Protection signatures in DEX
|
|
265
|
+
$dex_protected = { 64 65 78 0A ?? ?? ?? 00 } // Modified DEX header
|
|
266
|
+
|
|
267
|
+
condition:
|
|
268
|
+
any of ($lib_*) or $dex_protected
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
rule Android_Screen_Recording {
|
|
272
|
+
meta:
|
|
273
|
+
description = "Detects screen recording capabilities"
|
|
274
|
+
threat_level = "high"
|
|
275
|
+
|
|
276
|
+
strings:
|
|
277
|
+
$media_projection = "MediaProjectionManager" ascii
|
|
278
|
+
$virtual_display = "createVirtualDisplay" ascii
|
|
279
|
+
$image_reader = "ImageReader" ascii
|
|
280
|
+
$media_recorder = "MediaRecorder" ascii
|
|
281
|
+
$video_encoder = "MediaCodec" ascii
|
|
282
|
+
|
|
283
|
+
condition:
|
|
284
|
+
($media_projection and $virtual_display) or
|
|
285
|
+
($media_projection and $image_reader) or
|
|
286
|
+
($virtual_display and $media_recorder) or
|
|
287
|
+
($video_encoder and ($media_projection or $virtual_display))
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
rule Android_Anti_Analysis {
|
|
291
|
+
meta:
|
|
292
|
+
description = "Detects anti-analysis and anti-debugging techniques"
|
|
293
|
+
threat_level = "medium"
|
|
294
|
+
|
|
295
|
+
strings:
|
|
296
|
+
// Debugger detection
|
|
297
|
+
$debug_1 = "isDebuggerConnected" ascii
|
|
298
|
+
$debug_2 = "ApplicationInfo.FLAG_DEBUGGABLE" ascii
|
|
299
|
+
$debug_3 = "/proc/self/status" ascii
|
|
300
|
+
$traced_pid = "TracerPid" ascii
|
|
301
|
+
|
|
302
|
+
// Emulator detection
|
|
303
|
+
$emulator_1 = "goldfish" ascii
|
|
304
|
+
$emulator_2 = "generic" ascii
|
|
305
|
+
$emulator_3 = "Andy" ascii
|
|
306
|
+
$build_tags = "Build.TAGS" ascii
|
|
307
|
+
|
|
308
|
+
// Root detection
|
|
309
|
+
$root_1 = "Superuser.apk" ascii
|
|
310
|
+
$root_2 = "su" ascii
|
|
311
|
+
$root_3 = "/system/app/Superuser.apk" ascii
|
|
312
|
+
|
|
313
|
+
// Frida detection
|
|
314
|
+
$frida_1 = "frida" ascii nocase
|
|
315
|
+
$frida_2 = "LIBFRIDA" ascii
|
|
316
|
+
|
|
317
|
+
condition:
|
|
318
|
+
(2 of ($debug_*)) or
|
|
319
|
+
($traced_pid and 1 of ($debug_*)) or
|
|
320
|
+
(2 of ($emulator_*) and $build_tags) or
|
|
321
|
+
(2 of ($root_*)) or
|
|
322
|
+
(1 of ($frida_*))
|
|
323
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
#############################################
|
|
4
|
+
# Helper script untuk dynamic analysis
|
|
5
|
+
# Automate common tasks untuk frida & analysis
|
|
6
|
+
#############################################
|
|
7
|
+
|
|
8
|
+
set -e
|
|
9
|
+
|
|
10
|
+
# Get the parent directory (Anais root)
|
|
11
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
12
|
+
|
|
13
|
+
GREEN='\033[0;32m'
|
|
14
|
+
YELLOW='\033[1;33m'
|
|
15
|
+
RED='\033[0;31m'
|
|
16
|
+
NC='\033[0m'
|
|
17
|
+
|
|
18
|
+
print_usage() {
|
|
19
|
+
echo "Usage: $0 <command> [options]"
|
|
20
|
+
echo ""
|
|
21
|
+
echo "Commands:"
|
|
22
|
+
echo " dex-dump <package> - Dump DEX files from running app"
|
|
23
|
+
echo " hook-crypto <package> - Hook cryptographic operations"
|
|
24
|
+
echo " hook-network <package> - Hook network operations"
|
|
25
|
+
echo " monitor-all <package> - Monitor all activities"
|
|
26
|
+
echo " pull-dumps - Pull all dumped files from device"
|
|
27
|
+
echo " install-frida - Install Frida server on device"
|
|
28
|
+
echo ""
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
check_device() {
|
|
32
|
+
if ! adb devices | grep -q "device$"; then
|
|
33
|
+
echo -e "${RED}[!] No Android device connected${NC}"
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
echo -e "${GREEN}[+] Device connected${NC}"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
check_frida() {
|
|
40
|
+
if ! command -v frida >/dev/null 2>&1; then
|
|
41
|
+
echo -e "${RED}[!] Frida not installed. Install with: pip3 install frida-tools${NC}"
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
echo -e "${GREEN}[+] Frida tools found${NC}"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
install_frida_server() {
|
|
48
|
+
echo -e "${YELLOW}[*] Installing Frida server...${NC}"
|
|
49
|
+
|
|
50
|
+
# Get device architecture
|
|
51
|
+
ABI=$(adb shell getprop ro.product.cpu.abi | tr -d '\r')
|
|
52
|
+
echo "[+] Device ABI: $ABI"
|
|
53
|
+
|
|
54
|
+
# Get Frida version
|
|
55
|
+
FRIDA_VERSION=$(frida --version)
|
|
56
|
+
echo "[+] Frida version: $FRIDA_VERSION"
|
|
57
|
+
|
|
58
|
+
# Download URL
|
|
59
|
+
case $ABI in
|
|
60
|
+
arm64-v8a)
|
|
61
|
+
FRIDA_ARCH="arm64"
|
|
62
|
+
;;
|
|
63
|
+
armeabi-v7a)
|
|
64
|
+
FRIDA_ARCH="arm"
|
|
65
|
+
;;
|
|
66
|
+
x86)
|
|
67
|
+
FRIDA_ARCH="x86"
|
|
68
|
+
;;
|
|
69
|
+
x86_64)
|
|
70
|
+
FRIDA_ARCH="x86_64"
|
|
71
|
+
;;
|
|
72
|
+
*)
|
|
73
|
+
echo -e "${RED}[!] Unsupported architecture: $ABI${NC}"
|
|
74
|
+
exit 1
|
|
75
|
+
;;
|
|
76
|
+
esac
|
|
77
|
+
|
|
78
|
+
echo "[*] Downloading frida-server for $FRIDA_ARCH..."
|
|
79
|
+
DOWNLOAD_URL="https://github.com/frida/frida/releases/download/${FRIDA_VERSION}/frida-server-${FRIDA_VERSION}-android-${FRIDA_ARCH}.xz"
|
|
80
|
+
|
|
81
|
+
curl -L -o frida-server.xz "$DOWNLOAD_URL"
|
|
82
|
+
unxz frida-server.xz
|
|
83
|
+
|
|
84
|
+
echo "[*] Pushing to device..."
|
|
85
|
+
adb push frida-server /data/local/tmp/
|
|
86
|
+
adb shell "chmod 755 /data/local/tmp/frida-server"
|
|
87
|
+
|
|
88
|
+
echo "[*] Starting frida-server..."
|
|
89
|
+
adb shell "/data/local/tmp/frida-server &"
|
|
90
|
+
|
|
91
|
+
sleep 2
|
|
92
|
+
|
|
93
|
+
if adb shell "ps | grep frida-server" >/dev/null; then
|
|
94
|
+
echo -e "${GREEN}[+] Frida server installed and running${NC}"
|
|
95
|
+
else
|
|
96
|
+
echo -e "${RED}[!] Frida server failed to start${NC}"
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
rm -f frida-server
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
dex_dump() {
|
|
104
|
+
local package=$1
|
|
105
|
+
|
|
106
|
+
echo -e "${YELLOW}[*] Dumping DEX from $package...${NC}"
|
|
107
|
+
|
|
108
|
+
# Check if app is running
|
|
109
|
+
if ! adb shell "ps | grep $package" >/dev/null; then
|
|
110
|
+
echo "[*] App not running, starting it..."
|
|
111
|
+
adb shell "monkey -p $package -c android.intent.category.LAUNCHER 1" >/dev/null 2>&1
|
|
112
|
+
sleep 3
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# Run Frida script
|
|
116
|
+
frida -U -f "$package" -l "${SCRIPT_DIR}/frida/frida_dex_dump.js" --no-pause
|
|
117
|
+
|
|
118
|
+
echo -e "${GREEN}[+] DEX dump complete${NC}"
|
|
119
|
+
echo "[*] Check device /sdcard/ for dumped_dex_*.dex files"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
hook_crypto() {
|
|
123
|
+
local package=$1
|
|
124
|
+
|
|
125
|
+
echo -e "${YELLOW}[*] Hooking crypto operations for $package...${NC}"
|
|
126
|
+
|
|
127
|
+
# Create temporary Frida script
|
|
128
|
+
cat > /tmp/frida_crypto_hook.js <<'EOF'
|
|
129
|
+
Java.perform(function() {
|
|
130
|
+
console.log("[*] Hooking crypto operations...");
|
|
131
|
+
|
|
132
|
+
// Hook MessageDigest
|
|
133
|
+
var MessageDigest = Java.use("java.security.MessageDigest");
|
|
134
|
+
MessageDigest.digest.overload('[B').implementation = function(input) {
|
|
135
|
+
console.log("[+] MessageDigest.digest called");
|
|
136
|
+
console.log(" Algorithm: " + this.getAlgorithm());
|
|
137
|
+
console.log(" Input: " + bytesToHex(input));
|
|
138
|
+
|
|
139
|
+
var result = this.digest(input);
|
|
140
|
+
console.log(" Output: " + bytesToHex(result));
|
|
141
|
+
|
|
142
|
+
return result;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Hook Cipher
|
|
146
|
+
var Cipher = Java.use("javax.crypto.Cipher");
|
|
147
|
+
Cipher.doFinal.overload('[B').implementation = function(input) {
|
|
148
|
+
console.log("[+] Cipher.doFinal called");
|
|
149
|
+
console.log(" Algorithm: " + this.getAlgorithm());
|
|
150
|
+
console.log(" Mode: " + this.getOpmode());
|
|
151
|
+
console.log(" Input length: " + input.length);
|
|
152
|
+
|
|
153
|
+
var result = this.doFinal(input);
|
|
154
|
+
console.log(" Output length: " + result.length);
|
|
155
|
+
|
|
156
|
+
return result;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Hook SecretKeySpec
|
|
160
|
+
var SecretKeySpec = Java.use("javax.crypto.spec.SecretKeySpec");
|
|
161
|
+
SecretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function(key, algorithm) {
|
|
162
|
+
console.log("[+] SecretKeySpec created");
|
|
163
|
+
console.log(" Algorithm: " + algorithm);
|
|
164
|
+
console.log(" Key: " + bytesToHex(key));
|
|
165
|
+
|
|
166
|
+
return this.$init(key, algorithm);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
function bytesToHex(bytes) {
|
|
170
|
+
var hex = "";
|
|
171
|
+
for (var i = 0; i < Math.min(bytes.length, 32); i++) {
|
|
172
|
+
hex += ("0" + (bytes[i] & 0xFF).toString(16)).slice(-2);
|
|
173
|
+
}
|
|
174
|
+
if (bytes.length > 32) hex += "...";
|
|
175
|
+
return hex;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
console.log("[*] Crypto hooks installed");
|
|
179
|
+
});
|
|
180
|
+
EOF
|
|
181
|
+
|
|
182
|
+
frida -U -f "$package" -l /tmp/frida_crypto_hook.js --no-pause
|
|
183
|
+
|
|
184
|
+
rm -f /tmp/frida_crypto_hook.js
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
hook_network() {
|
|
188
|
+
local package=$1
|
|
189
|
+
|
|
190
|
+
echo -e "${YELLOW}[*] Hooking network operations for $package...${NC}"
|
|
191
|
+
|
|
192
|
+
# Create temporary Frida script
|
|
193
|
+
cat > /tmp/frida_network_hook.js <<'EOF'
|
|
194
|
+
Java.perform(function() {
|
|
195
|
+
console.log("[*] Hooking network operations...");
|
|
196
|
+
|
|
197
|
+
// Hook URL connection
|
|
198
|
+
var URL = Java.use("java.net.URL");
|
|
199
|
+
URL.openConnection.overload().implementation = function() {
|
|
200
|
+
console.log("[+] URL.openConnection: " + this.toString());
|
|
201
|
+
return this.openConnection();
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// Hook OkHttp
|
|
205
|
+
try {
|
|
206
|
+
var OkHttpClient = Java.use("okhttp3.OkHttpClient");
|
|
207
|
+
var Request = Java.use("okhttp3.Request");
|
|
208
|
+
|
|
209
|
+
var Builder = OkHttpClient.Builder;
|
|
210
|
+
Builder.build.implementation = function() {
|
|
211
|
+
console.log("[+] OkHttpClient built");
|
|
212
|
+
return this.build();
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
Request.url.implementation = function() {
|
|
216
|
+
var url = this.url();
|
|
217
|
+
console.log("[+] HTTP Request to: " + url.toString());
|
|
218
|
+
return url;
|
|
219
|
+
};
|
|
220
|
+
} catch(e) {
|
|
221
|
+
console.log("[-] OkHttp not found");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Hook WebSocket
|
|
225
|
+
try {
|
|
226
|
+
var WebSocket = Java.use("okhttp3.WebSocket");
|
|
227
|
+
// Note: Interface, hook implementations
|
|
228
|
+
} catch(e) {
|
|
229
|
+
console.log("[-] WebSocket not found");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Hook Socket
|
|
233
|
+
var Socket = Java.use("java.net.Socket");
|
|
234
|
+
Socket.$init.overload('java.lang.String', 'int').implementation = function(host, port) {
|
|
235
|
+
console.log("[+] Socket connection: " + host + ":" + port);
|
|
236
|
+
return this.$init(host, port);
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
console.log("[*] Network hooks installed");
|
|
240
|
+
});
|
|
241
|
+
EOF
|
|
242
|
+
|
|
243
|
+
frida -U -f "$package" -l /tmp/frida_network_hook.js --no-pause
|
|
244
|
+
|
|
245
|
+
rm -f /tmp/frida_network_hook.js
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
monitor_all() {
|
|
249
|
+
local package=$1
|
|
250
|
+
|
|
251
|
+
echo -e "${YELLOW}[*] Monitoring all activities for $package...${NC}"
|
|
252
|
+
|
|
253
|
+
frida -U -f "$package" -l frida_hooks.js --no-pause
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
pull_dumps() {
|
|
257
|
+
echo -e "${YELLOW}[*] Pulling dumped files from device...${NC}"
|
|
258
|
+
|
|
259
|
+
mkdir -p ./dumps
|
|
260
|
+
|
|
261
|
+
# Pull DEX files
|
|
262
|
+
adb shell "ls /sdcard/dumped_*.dex" 2>/dev/null | while read file; do
|
|
263
|
+
if [ ! -z "$file" ]; then
|
|
264
|
+
adb pull "$file" ./dumps/
|
|
265
|
+
fi
|
|
266
|
+
done
|
|
267
|
+
|
|
268
|
+
# Pull memory dumps
|
|
269
|
+
adb shell "ls /sdcard/memory_*.bin" 2>/dev/null | while read file; do
|
|
270
|
+
if [ ! -z "$file" ]; then
|
|
271
|
+
adb pull "$file" ./dumps/
|
|
272
|
+
fi
|
|
273
|
+
done
|
|
274
|
+
|
|
275
|
+
echo -e "${GREEN}[+] Files pulled to ./dumps/${NC}"
|
|
276
|
+
ls -lh ./dumps/
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
# Main
|
|
280
|
+
if [ $# -lt 1 ]; then
|
|
281
|
+
print_usage
|
|
282
|
+
exit 1
|
|
283
|
+
fi
|
|
284
|
+
|
|
285
|
+
COMMAND=$1
|
|
286
|
+
shift
|
|
287
|
+
|
|
288
|
+
check_device
|
|
289
|
+
|
|
290
|
+
case $COMMAND in
|
|
291
|
+
dex-dump)
|
|
292
|
+
check_frida
|
|
293
|
+
if [ $# -lt 1 ]; then
|
|
294
|
+
echo "Usage: $0 dex-dump <package>"
|
|
295
|
+
exit 1
|
|
296
|
+
fi
|
|
297
|
+
dex_dump "$1"
|
|
298
|
+
;;
|
|
299
|
+
hook-crypto)
|
|
300
|
+
check_frida
|
|
301
|
+
if [ $# -lt 1 ]; then
|
|
302
|
+
echo "Usage: $0 hook-crypto <package>"
|
|
303
|
+
exit 1
|
|
304
|
+
fi
|
|
305
|
+
hook_crypto "$1"
|
|
306
|
+
;;
|
|
307
|
+
hook-network)
|
|
308
|
+
check_frida
|
|
309
|
+
if [ $# -lt 1 ]; then
|
|
310
|
+
echo "Usage: $0 hook-network <package>"
|
|
311
|
+
exit 1
|
|
312
|
+
fi
|
|
313
|
+
hook_network "$1"
|
|
314
|
+
;;
|
|
315
|
+
monitor-all)
|
|
316
|
+
check_frida
|
|
317
|
+
if [ $# -lt 1 ]; then
|
|
318
|
+
echo "Usage: $0 monitor-all <package>"
|
|
319
|
+
exit 1
|
|
320
|
+
fi
|
|
321
|
+
monitor_all "$1"
|
|
322
|
+
;;
|
|
323
|
+
pull-dumps)
|
|
324
|
+
pull_dumps
|
|
325
|
+
;;
|
|
326
|
+
install-frida)
|
|
327
|
+
install_frida_server
|
|
328
|
+
;;
|
|
329
|
+
*)
|
|
330
|
+
echo -e "${RED}Unknown command: $COMMAND${NC}"
|
|
331
|
+
print_usage
|
|
332
|
+
exit 1
|
|
333
|
+
;;
|
|
334
|
+
esac
|