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,145 @@
|
|
|
1
|
+
|
|
2
|
+
console.log("[*] DPT-Shell DEX Dumper Started");
|
|
3
|
+
|
|
4
|
+
// Hook file write operations to catch when decrypted DEX is written
|
|
5
|
+
var open = Module.findExportByName("libc.so", "open");
|
|
6
|
+
var write = Module.findExportByName("libc.so", "write");
|
|
7
|
+
var close = Module.findExportByName("libc.so", "close");
|
|
8
|
+
|
|
9
|
+
var targetFiles = {};
|
|
10
|
+
|
|
11
|
+
// Monitor file opens
|
|
12
|
+
Interceptor.attach(open, {
|
|
13
|
+
onEnter: function(args) {
|
|
14
|
+
var path = Memory.readUtf8String(args[0]);
|
|
15
|
+
this.path = path;
|
|
16
|
+
|
|
17
|
+
// Check if it's writing to code_cache with our target filename
|
|
18
|
+
if (path.indexOf("code_cache") !== -1 && path.indexOf("i11111i111.zip") !== -1) {
|
|
19
|
+
console.log("[+] Target file being opened: " + path);
|
|
20
|
+
this.isTarget = true;
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
onLeave: function(retval) {
|
|
24
|
+
if (this.isTarget) {
|
|
25
|
+
var fd = retval.toInt32();
|
|
26
|
+
targetFiles[fd] = {
|
|
27
|
+
path: this.path,
|
|
28
|
+
data: []
|
|
29
|
+
};
|
|
30
|
+
console.log("[+] Tracking FD: " + fd);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Capture writes to tracked files
|
|
36
|
+
Interceptor.attach(write, {
|
|
37
|
+
onEnter: function(args) {
|
|
38
|
+
var fd = args[0].toInt32();
|
|
39
|
+
|
|
40
|
+
if (targetFiles[fd]) {
|
|
41
|
+
var buf = args[1];
|
|
42
|
+
var count = args[2].toInt32();
|
|
43
|
+
|
|
44
|
+
// Read the data being written
|
|
45
|
+
var data = Memory.readByteArray(buf, count);
|
|
46
|
+
targetFiles[fd].data.push(data);
|
|
47
|
+
|
|
48
|
+
console.log("[+] Captured " + count + " bytes written to " + targetFiles[fd].path);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// When file is closed, save the complete data
|
|
54
|
+
Interceptor.attach(close, {
|
|
55
|
+
onEnter: function(args) {
|
|
56
|
+
var fd = args[0].toInt32();
|
|
57
|
+
|
|
58
|
+
if (targetFiles[fd]) {
|
|
59
|
+
console.log("[+] File closed, dumping data...");
|
|
60
|
+
|
|
61
|
+
// Combine all chunks
|
|
62
|
+
var totalSize = 0;
|
|
63
|
+
targetFiles[fd].data.forEach(function(chunk) {
|
|
64
|
+
totalSize += chunk.byteLength;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
console.log("[+] Total size: " + totalSize + " bytes");
|
|
68
|
+
|
|
69
|
+
// Save to file
|
|
70
|
+
var file = new File("/data/local/tmp/decrypted_dex.zip", "wb");
|
|
71
|
+
targetFiles[fd].data.forEach(function(chunk) {
|
|
72
|
+
file.write(chunk);
|
|
73
|
+
});
|
|
74
|
+
file.close();
|
|
75
|
+
|
|
76
|
+
console.log("[+] ✅ Decrypted DEX dumped to: /data/local/tmp/decrypted_dex.zip");
|
|
77
|
+
console.log("[+] Pull it with: adb pull /data/local/tmp/decrypted_dex.zip");
|
|
78
|
+
|
|
79
|
+
delete targetFiles[fd];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Also hook DexFile.loadDex to catch DEX loading
|
|
85
|
+
Java.perform(function() {
|
|
86
|
+
console.log("[*] Hooking DexFile.loadDex...");
|
|
87
|
+
|
|
88
|
+
var DexFile = Java.use("dalvik.system.DexFile");
|
|
89
|
+
|
|
90
|
+
DexFile.loadDex.overload('java.lang.String', 'java.lang.String', 'int').implementation = function(sourcePathName, outputPathName, flags) {
|
|
91
|
+
console.log("[+] DexFile.loadDex called:");
|
|
92
|
+
console.log(" Source: " + sourcePathName);
|
|
93
|
+
console.log(" Output: " + outputPathName);
|
|
94
|
+
console.log(" Flags: " + flags);
|
|
95
|
+
|
|
96
|
+
var result = this.loadDex(sourcePathName, outputPathName, flags);
|
|
97
|
+
|
|
98
|
+
// If this is our target, copy the file
|
|
99
|
+
if (sourcePathName.indexOf("i11111i111.zip") !== -1) {
|
|
100
|
+
console.log("[+] ✅ Found target DEX load! Copying file...");
|
|
101
|
+
|
|
102
|
+
// Copy the decrypted file
|
|
103
|
+
var File = Java.use("java.io.File");
|
|
104
|
+
var source = File.$new(sourcePathName);
|
|
105
|
+
|
|
106
|
+
if (source.exists()) {
|
|
107
|
+
console.log("[+] Source exists, size: " + source.length() + " bytes");
|
|
108
|
+
|
|
109
|
+
// Use shell to copy
|
|
110
|
+
var Runtime = Java.use("java.lang.Runtime");
|
|
111
|
+
var runtime = Runtime.getRuntime();
|
|
112
|
+
runtime.exec("cp " + sourcePathName + " /data/local/tmp/decrypted_from_load.zip");
|
|
113
|
+
|
|
114
|
+
console.log("[+] Copied to: /data/local/tmp/decrypted_from_load.zip");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return result;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
console.log("[*] DexFile.loadDex hooked!");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Hook BaseDexClassLoader to catch DEX loading
|
|
125
|
+
Java.perform(function() {
|
|
126
|
+
console.log("[*] Hooking BaseDexClassLoader...");
|
|
127
|
+
|
|
128
|
+
var BaseDexClassLoader = Java.use("dalvik.system.BaseDexClassLoader");
|
|
129
|
+
|
|
130
|
+
BaseDexClassLoader.$init.overload('java.lang.String', 'java.io.File', 'java.lang.String', 'java.lang.ClassLoader').implementation = function(dexPath, optimizedDirectory, librarySearchPath, parent) {
|
|
131
|
+
console.log("[+] BaseDexClassLoader constructor called:");
|
|
132
|
+
console.log(" DEX path: " + dexPath);
|
|
133
|
+
console.log(" Optimized dir: " + optimizedDirectory);
|
|
134
|
+
|
|
135
|
+
if (dexPath.indexOf("i11111i111.zip") !== -1) {
|
|
136
|
+
console.log("[+] ✅ Target DEX being loaded!");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return this.$init(dexPath, optimizedDirectory, librarySearchPath, parent);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
console.log("[*] BaseDexClassLoader hooked!");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
console.log("[*] All hooks installed, waiting for DEX decryption...");
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
|
|
2
|
+
// Frida script untuk dump DEX dari memory saat runtime
|
|
3
|
+
// Berguna untuk bypass DPT - Shell, DexProtector, dan proteksi lainnya
|
|
4
|
+
|
|
5
|
+
Java.perform(function () {
|
|
6
|
+
console.log("[*] Starting DEX Dump Script...");
|
|
7
|
+
|
|
8
|
+
// Hook DexFile class untuk intercept loaded DEX
|
|
9
|
+
var DexFile = Java.use("dalvik.system.DexFile");
|
|
10
|
+
|
|
11
|
+
// Hook openDexFile untuk capture DEX files
|
|
12
|
+
DexFile.openDexFile.overload('java.lang.String', 'java.lang.String', 'int').implementation = function (source, output, flags) {
|
|
13
|
+
console.log("[+] DexFile.openDexFile called");
|
|
14
|
+
console.log(" Source: " + source);
|
|
15
|
+
console.log(" Output: " + output);
|
|
16
|
+
|
|
17
|
+
var result = this.openDexFile(source, output, flags);
|
|
18
|
+
|
|
19
|
+
// Try to dump the DEX
|
|
20
|
+
try {
|
|
21
|
+
var file = Java.use("java.io.File").$new(source);
|
|
22
|
+
if (file.exists()) {
|
|
23
|
+
console.log("[+] DEX file exists, attempting to dump...");
|
|
24
|
+
dumpDexFile(source);
|
|
25
|
+
}
|
|
26
|
+
} catch (e) {
|
|
27
|
+
console.log("[-] Error dumping DEX: " + e);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Hook DexClassLoader untuk capture dynamically loaded DEX
|
|
34
|
+
var DexClassLoader = Java.use("dalvik.system.DexClassLoader");
|
|
35
|
+
DexClassLoader.$init.overload('java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.ClassLoader').implementation = function (dexPath, optimizedDir, libraryPath, parent) {
|
|
36
|
+
console.log("[+] DexClassLoader initialized");
|
|
37
|
+
console.log(" DEX Path: " + dexPath);
|
|
38
|
+
console.log(" Optimized: " + optimizedDir);
|
|
39
|
+
|
|
40
|
+
// Dump the DEX before loading
|
|
41
|
+
dumpDexFile(dexPath);
|
|
42
|
+
|
|
43
|
+
return this.$init(dexPath, optimizedDir, libraryPath, parent);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Hook PathClassLoader
|
|
47
|
+
var PathClassLoader = Java.use("dalvik.system.PathClassLoader");
|
|
48
|
+
PathClassLoader.$init.overload('java.lang.String', 'java.lang.ClassLoader').implementation = function (dexPath, parent) {
|
|
49
|
+
console.log("[+] PathClassLoader initialized");
|
|
50
|
+
console.log(" DEX Path: " + dexPath);
|
|
51
|
+
|
|
52
|
+
dumpDexFile(dexPath);
|
|
53
|
+
|
|
54
|
+
return this.$init(dexPath, parent);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Function to dump DEX file
|
|
58
|
+
function dumpDexFile(dexPath) {
|
|
59
|
+
try {
|
|
60
|
+
var File = Java.use("java.io.File");
|
|
61
|
+
var FileInputStream = Java.use("java.io.FileInputStream");
|
|
62
|
+
var FileOutputStream = Java.use("java.io.FileOutputStream");
|
|
63
|
+
|
|
64
|
+
var srcFile = File.$new(dexPath);
|
|
65
|
+
if (!srcFile.exists()) {
|
|
66
|
+
console.log("[-] Source file doesn't exist: " + dexPath);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
var timestamp = Date.now();
|
|
71
|
+
var outputPath = "/sdcard/dumped_dex_" + timestamp + ".dex";
|
|
72
|
+
var dstFile = File.$new(outputPath);
|
|
73
|
+
|
|
74
|
+
var fis = FileInputStream.$new(srcFile);
|
|
75
|
+
var fos = FileOutputStream.$new(dstFile);
|
|
76
|
+
|
|
77
|
+
var buffer = Java.array('byte', []);
|
|
78
|
+
buffer = Java.use("java.lang.reflect.Array").newInstance(Java.use("java.lang.Byte").TYPE, 8192);
|
|
79
|
+
|
|
80
|
+
var bytesRead = 0;
|
|
81
|
+
while ((bytesRead = fis.read(buffer)) !== -1) {
|
|
82
|
+
fos.write(buffer, 0, bytesRead);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
fis.close();
|
|
86
|
+
fos.close();
|
|
87
|
+
|
|
88
|
+
console.log("[+] DEX dumped to: " + outputPath);
|
|
89
|
+
|
|
90
|
+
} catch (e) {
|
|
91
|
+
console.log("[-] Error in dumpDexFile: " + e);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Hook native methods that might decrypt DEX
|
|
96
|
+
// Common patterns in DPT-Shell and similar protectors
|
|
97
|
+
|
|
98
|
+
var System = Java.use("java.lang.System");
|
|
99
|
+
System.loadLibrary.implementation = function (libname) {
|
|
100
|
+
console.log("[+] Loading native library: " + libname);
|
|
101
|
+
|
|
102
|
+
// Common protection library names
|
|
103
|
+
var protectionLibs = ["dpt", "protect", "shell", "jiagu", "bangcle"];
|
|
104
|
+
var isProtectionLib = protectionLibs.some(function (name) {
|
|
105
|
+
return libname.toLowerCase().indexOf(name) !== -1;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (isProtectionLib) {
|
|
109
|
+
console.log("[!] PROTECTION LIBRARY DETECTED: " + libname);
|
|
110
|
+
console.log("[!] DEX decryption may occur after this");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return this.loadLibrary(libname);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Hook Runtime.load for additional native library monitoring
|
|
117
|
+
var Runtime = Java.use("java.lang.Runtime");
|
|
118
|
+
Runtime.load.implementation = function (libpath) {
|
|
119
|
+
console.log("[+] Runtime.load called: " + libpath);
|
|
120
|
+
return this.load(libpath);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Dump all loaded classes periodically
|
|
124
|
+
setTimeout(function () {
|
|
125
|
+
console.log("[*] Enumerating loaded classes...");
|
|
126
|
+
|
|
127
|
+
Java.enumerateLoadedClasses({
|
|
128
|
+
onMatch: function (className) {
|
|
129
|
+
// Filter for potentially interesting classes
|
|
130
|
+
if (className.indexOf("com.") === 0 &&
|
|
131
|
+
!className.startsWith("com.android") &&
|
|
132
|
+
!className.startsWith("com.google")) {
|
|
133
|
+
console.log(" " + className);
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
onComplete: function () {
|
|
137
|
+
console.log("[*] Class enumeration complete");
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}, 5000);
|
|
141
|
+
|
|
142
|
+
console.log("[*] DEX Dump Script ready. Hooks installed.");
|
|
143
|
+
console.log("[*] Dumped files will be in /sdcard/dumped_dex_*.dex");
|
|
144
|
+
console.log("[*] Use 'adb pull /sdcard/dumped_dex_*.dex' to retrieve them");
|
|
145
|
+
});
|