├── DumpDex.js ├── LICENSE ├── README.md ├── dumpdex.jpg └── pkg_id.jpg /DumpDex.js: -------------------------------------------------------------------------------- 1 | /* 2 | Hook fork to prevent child processes from interrupting Frida 3 | Returns -1 with errno EPERM 4 | */ 5 | (() => { 6 | const forkSymbol = Module.findExportByName(null, "fork"); 7 | if (!forkSymbol) { 8 | console.warn("[-] fork() not found"); 9 | return; 10 | } 11 | const errnoPtr = (() => { 12 | const errnoLocation = Module.findExportByName(null, "__errno_location"); 13 | return errnoLocation ? new NativeFunction(errnoLocation, "pointer", [])() : null; 14 | })(); 15 | 16 | const safeForkHandler = new NativeCallback(() => { 17 | console.warn("[!] Fork intercepted - returning -1 (EPERM)"); 18 | if (errnoPtr) errnoPtr.writeS32(1); 19 | return -1; 20 | }, 'int', []); 21 | 22 | Interceptor.replace(forkSymbol, safeForkHandler); 23 | console.warn("[+] Fork hook: ACTIVE"); 24 | })(); 25 | 26 | /* Enter your target package name here */ 27 | const TARGET_PKG = "com.dexprotector.detector.envchecks"; 28 | const SAFE_DIR = `/data/data/${TARGET_PKG}/`; 29 | 30 | const DETECTION_LIBRARIES = [ 31 | { pattern: "libdexprotector", message: "DexProtector: https://licelus.com" }, 32 | { pattern: "libjiagu", message: "Jiagu360: https://jiagu.360.cn" }, 33 | { pattern: "libAppGuard", message: "AppGuard: http://appguard.nprotect.com" }, 34 | { pattern: "libDexHelper", message: "Secneo: http://www.secneo.com" }, 35 | { pattern: "libsecexe|libsecmain|libSecShell", message: "Bangcle: https://github.com/woxihuannisja/Bangcle" }, 36 | { pattern: "libprotectt|libapp-protectt", message: "Protectt: https://www.protectt.ai" }, 37 | { pattern: "libkonyjsvm", message: "Kony: http://www.kony.com/" }, 38 | { pattern: "libnesec", message: "Yidun: https://dun.163.com/product/app-protect" }, 39 | { pattern: "libcovault", message: "AppSealing: https://www.appsealing.com/" }, 40 | { pattern: "libpairipcore", message: "Pairip: https://github.com/rednaga/APKiD/issues/329" } 41 | ]; 42 | 43 | function hookDlopen() { 44 | return new Promise((resolve, reject) => { 45 | try { 46 | const isArm = Process.arch === "arm" ? "linker" : "linker64"; 47 | const reg = Process.arch === "arm" ? "r0" : "x0"; 48 | const linker = Process.findModuleByName(isArm); 49 | 50 | if (!linker) { 51 | reject(new Error("Linker module not found")); 52 | return; 53 | } 54 | 55 | let resolved = false; 56 | const resolveOnce = () => { 57 | if (!resolved) { 58 | resolved = true; 59 | resolve(); 60 | } 61 | }; 62 | 63 | const sym = linker.enumerateExports().find(e => e.name.includes('android_dlopen_ext')); 64 | Interceptor.attach(sym.address, { 65 | onEnter(args) { 66 | const libPath = this.context[reg].readUtf8String(); 67 | if (!libPath) return; 68 | 69 | for (const { pattern, message } of DETECTION_LIBRARIES) { 70 | if (new RegExp(pattern).test(libPath)) { 71 | console.warn(`\n[*] Packer Detected: ${message}`); 72 | resolveOnce(); 73 | return; 74 | } 75 | } 76 | } 77 | }); 78 | setTimeout(resolveOnce, 3000); 79 | } catch (e) { 80 | reject(new Error("Unsupported architecture/emulator")); 81 | } 82 | }); 83 | } 84 | 85 | function processDex(Buf, C, Path) { 86 | // Ensure the buffer is valid 87 | if (!Buf || Buf.byteLength < 8) { 88 | console.error(`[!] Invalid buffer for classes${C - 1}.dex`); 89 | return; 90 | } 91 | const DumpDex = Buf instanceof Uint8Array ? Buf : new Uint8Array(Buf); 92 | const Count = C - 1; 93 | // Signatures for detecting CDEX, Empty Header, and Wiped Header 94 | const CDEX_SIGNATURE = [0x63, 0x64, 0x65, 0x78, 0x30, 0x30, 0x31]; 95 | const EMPTY_HEADER = [0x00, 0x00, 0x00, 0x00]; 96 | const WIPED_HEADER = [0x64]; 97 | // Detect CDEX 98 | if (CDEX_SIGNATURE.every((val, i) => DumpDex[i] == val)) { 99 | console.warn(`[*] classes${Count}.dex is a Compact Dex (CDEX). Ignoring.`); 100 | return; 101 | } 102 | // Detect Empty Header (DexProtector) 103 | if (EMPTY_HEADER.every((val, i) => DumpDex[i] == val) && DumpDex[7] == 0x00) { 104 | console.warn(`[*] 00000 Header detected in classes${Count}.dex, possible DexProtector.`); 105 | writeDexFile(Count, Buf, Path, 0); 106 | return; 107 | } 108 | // Detect Wiped Header (Obfuscation/Tampered) 109 | if (DumpDex[0] == 0x00 || WIPED_HEADER.every((val, i) => DumpDex[i] != val)) { 110 | console.warn(`[*] Wiped Header detected, classes${Count}.dex might be interesting.`); 111 | writeDexFile(Count, Buf, Path, 0); 112 | return; 113 | } 114 | // Default: Consider it as a normal Dex file 115 | writeDexFile(Count, Buf, Path, 1); 116 | } 117 | 118 | function writeDexFile(count, buffer, path, isValid) { 119 | try { 120 | const file = new File(path, "wb"); 121 | file.write(buffer); 122 | file.close(); 123 | console.log(`[Dex${count}] Saved to: ${path} ${isValid ? '(valid)' : '(modified)'}`); 124 | } catch (error) { 125 | console.error(`[!] Failed to save Dex${count} to ${path}: ${error.message}`); 126 | } 127 | } 128 | 129 | function findDefineClass(libart) { 130 | const matcher = /ClassLinker.*DefineClass.*Thread.*DexFile/; 131 | const search = (items, type) => items.find(item => matcher.test(item.name))?.address; 132 | 133 | return search(libart.enumerateSymbols(), 'symbols') || 134 | search(libart.enumerateImports(), 'imports') || 135 | search(libart.enumerateExports(), 'exports'); 136 | } 137 | 138 | function dumpDex() { 139 | const libart = Process.findModuleByName("libart.so"); 140 | if (!libart) return console.error("[!] libart.so not found"); 141 | const defineClassAddr = findDefineClass(libart); 142 | console.warn("[*] DefineClass found at : ", defineClassAddr); 143 | if (!defineClassAddr) return console.error("[!] DefineClass not found"); 144 | const seenDex = new Set(); 145 | let dexCount = 1; 146 | 147 | Interceptor.attach(defineClassAddr, { 148 | onEnter(args) { 149 | const dexFilePtr = args[5]; 150 | const base = dexFilePtr.add(Process.pointerSize).readPointer(); 151 | const size = dexFilePtr.add(Process.pointerSize * 2).readUInt(); 152 | if (seenDex.has(base.toString())) return; 153 | seenDex.add(base.toString()); 154 | const dexBuffer = base.readByteArray(size); 155 | if (!dexBuffer || dexBuffer.byteLength !== size) return; 156 | const path = `${SAFE_DIR}classes${dexCount}.dex`; 157 | processDex(dexBuffer, dexCount++, path); 158 | } 159 | }); 160 | } 161 | 162 | async function main() { 163 | try { 164 | await hookDlopen(); 165 | console.warn("[*] Hooking Finished. Starting dex dump..."); 166 | dumpDex(); 167 | } catch (e) { 168 | console.error(`[!] Error: ${e.message}`); 169 | } 170 | } 171 | 172 | setImmediate(main); 173 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 The Author 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Frida Android Hook Script 2 | > [!NOTE] 3 | > Only For Android device support arm, arm64 4 | ## Features 5 | - ✅ Detects popular application protectors: 6 | - DexProtector 7 | - Jiagu360 8 | - AppGuard 9 | - Secneo 10 | - Bangcle 11 | - Protectt.ai 12 | - Kony 13 | - Yidun 14 | - AppSealing 15 | - Pairip 16 | - ✅ Dumps loaded Dex files for analysis. 17 | - ✅ Compatible with arm and arm64 architectures. 18 | - ✅ Fixed DefineClass not found for Android 13+ and Newer. 19 | 20 | ## Requirements 21 | - ✅ Frida installed on the target device. 22 | - ✅ Root access (recommended). 23 | 24 | ## Usage 25 | Before running the script, make sure to set the target package name correctly: 26 | 27 | + Open the script file. 28 | + Locate the following line of code: 29 | ```javascript 30 | // Enter your package name here 31 | let Pro = "com.dexprotector.detector.envchecks"; 32 | ``` 33 | ![screenshot](pkg_id.jpg) 34 | 35 | + Run the script using Frida: 36 | ```bash 37 | frida -R -f -l DumpDex.js 38 | ``` 39 | if spawn from USB 40 | ```bash 41 | frida -U -f -l DumpDex.js 42 | ``` 43 | 44 | 45 | ## Output Example 46 | ```text 47 | [*] DexProtector Found : https://dexprotector.com/ 48 | [*] Dumped classes1.dex to /storage/emulated/0/Android/data/com.app.name/classes1.dex 49 | ``` 50 | ![screnshoot](dumpdex.jpg) 51 | 52 | # Disclaimer 53 | 54 | This script is provided for **educational and research purposes only**. 55 | Use this code **at your own risk**. The author takes **no responsibility** for any consequences resulting from the use of this script. 56 | 57 | **By using this script, you agree that:** 58 | - You will not use this script for any illegal activity. 59 | - The author is not responsible for any damage, data loss, or legal issues arising from the use of this script. 60 | - This script is intended for testing and security research within the boundaries of applicable laws and regulations. 61 | 62 | --- 63 | 64 | # MIT License 65 | 66 | Copyright (c) 2025 The Author 67 | 68 | Permission is hereby granted, free of charge, to any person obtaining a copy 69 | of this software and associated documentation files (the "Software"), to deal 70 | in the Software without restriction, including without limitation the rights 71 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 72 | copies of the Software, and to permit persons to whom the Software is 73 | furnished to do so, subject to the following conditions: 74 | 75 | The above copyright notice and this permission notice shall be included in all 76 | copies or substantial portions of the Software. 77 | 78 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 79 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 80 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 81 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 82 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 83 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 84 | SOFTWARE. 85 | -------------------------------------------------------------------------------- /dumpdex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexjr2/Android_Dump_Dex/ca8da894bd6071de1e4b4a8f094f91e5a5f01430/dumpdex.jpg -------------------------------------------------------------------------------- /pkg_id.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexjr2/Android_Dump_Dex/ca8da894bd6071de1e4b4a8f094f91e5a5f01430/pkg_id.jpg --------------------------------------------------------------------------------