├── src ├── capture │ ├── __init__.py │ └── ins.js ├── copy │ ├── hook_method.js │ ├── .DS_Store │ ├── Using Frida on Android without root.png │ ├── connect_frida.py │ ├── call-method-of-class.js │ ├── hook-method-of-class.js │ ├── README.md │ ├── popen.js │ ├── so │ │ ├── hook_native.js │ │ └── find_func_from_symbols.js │ ├── show-all-classes-methods.js │ ├── test.js │ ├── StringBuffer.js │ ├── HashMap.js │ ├── anti_frida.js │ ├── so.js │ └── JSONObject.js ├── ios │ ├── class_members.js │ ├── refelaction.py │ ├── os_log.js │ ├── class _hierarchy.js │ ├── trace.js │ └── 万能http-ssl-tls抓包frida脚本(ios).js ├── so │ ├── sktrace │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ └── sktracemgr.cpython-311.pyc │ │ └── sktrace.py │ ├── android │ │ ├── SoFixer32 │ │ └── SoFixer64 │ ├── so_info.ts │ ├── dump_so.js │ ├── all_so.ts │ ├── so_method.ts │ ├── scan.ts │ ├── libc_method.js │ ├── hook_str.ts │ ├── init_array.ts │ ├── dump_so.py │ ├── BufferUtils.ts │ ├── inlinehook.ts │ ├── socket.ts │ └── call_constructor.js ├── frida-dexdump │ ├── frida_dexdump │ │ ├── __init__.py │ │ ├── agent │ │ │ └── __init__.py │ │ ├── banner.py │ │ └── __main__.py │ ├── agent │ │ ├── .gitignore │ │ ├── tsconfig.json │ │ ├── package.json │ │ └── src │ │ │ └── index.ts │ ├── build │ │ └── lib │ │ │ └── frida_dexdump │ │ │ ├── __init__.py │ │ │ ├── agent │ │ │ └── __init__.py │ │ │ ├── banner.py │ │ │ └── __main__.py │ ├── frida_dexdump.egg-info │ │ ├── dependency_links.txt │ │ ├── top_level.txt │ │ ├── requires.txt │ │ ├── entry_points.txt │ │ ├── SOURCES.txt │ │ └── PKG-INFO │ ├── requirements.txt │ ├── dist │ │ ├── frida-dexdump-2.0.1.tar.gz │ │ └── frida_dexdump-2.0.1-py3-none-any.whl │ ├── makefile │ ├── .github │ │ └── workflows │ │ │ └── python-publish.yml │ ├── setup.py │ └── README.md ├── jni │ ├── frida_hook_libart │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── hook_RegisterNatives.js │ │ └── hook_artmethod.js │ ├── JNI-Frida-Hook │ │ ├── .DS_Store │ │ ├── README.md │ │ └── agent.js │ └── all_jni.js ├── .DS_Store ├── r0gson.dex ├── test │ ├── log.ts │ ├── agent.ts │ ├── test.py │ └── _agent.js ├── java │ ├── .DS_Store │ ├── r0tracer │ │ ├── pic │ │ │ ├── 01.png │ │ │ ├── 02.png │ │ │ ├── 03.png │ │ │ ├── 04.png │ │ │ └── 05.png │ │ └── README.md │ ├── inspectClass.ts │ ├── inspectClass.js │ ├── one_instance.ts │ ├── file.js │ ├── file.ts │ ├── abstract.ts │ ├── stringBuilder.js │ ├── stringBuilder.ts │ ├── JsonObject.js │ ├── JsonObject.ts │ ├── myscript.js │ ├── AeBanBi.js │ ├── findClass.ts │ ├── encryption.ts │ ├── encryption.js │ └── one_method_hook.js ├── Frida-Seccomp │ ├── .DS_Store │ ├── img │ │ ├── 1.png │ │ ├── 2.JPG │ │ └── 3.JPG │ ├── README.md │ └── multi_frida_seccomp.py ├── r0capture │ ├── pic │ │ ├── Sample.PNG │ │ ├── bypass.png │ │ ├── clientcer.png │ │ ├── difport.png │ │ ├── locator.png │ │ ├── summary1.jpg │ │ ├── summary2.jpg │ │ └── sslunpinningcer.png │ ├── __pycache__ │ │ ├── myhexdump.cpython-310.pyc │ │ ├── myhexdump.cpython-311.pyc │ │ └── myhexdump.cpython-39.pyc │ └── README.md ├── utils │ ├── system_property_get.ts │ ├── test_color.ts │ ├── ioctl.ts │ ├── test_chalk.ts │ └── log.ts ├── socket │ ├── connect.ts │ ├── connect.js │ └── frida-trace_close.js ├── cert │ ├── sslpinning5.js │ ├── ssl_bypass.js │ └── trust_cert.js ├── cli.ts └── child_gating.py ├── .gitignore ├── .jshintrc ├── tsconfig.json ├── test.sh ├── package.json ├── frida17 api.txt ├── README.md └── test.js /src/capture/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/copy/hook_method.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ios/class_members.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/so/sktrace/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .history 2 | .idea/ 3 | node_modules/ -------------------------------------------------------------------------------- /src/jni/frida_hook_libart/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | -------------------------------------------------------------------------------- /src/frida-dexdump/agent/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /src/frida-dexdump/build/lib/frida_dexdump/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true 4 | } 5 | -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | frida_dexdump 2 | -------------------------------------------------------------------------------- /src/frida-dexdump/requirements.txt: -------------------------------------------------------------------------------- 1 | click 2 | frida-tools 3 | wallbreaker -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /src/r0gson.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0gson.dex -------------------------------------------------------------------------------- /src/test/log.ts: -------------------------------------------------------------------------------- 1 | export function log(...args: any[]) { 2 | console.log(...args); 3 | } -------------------------------------------------------------------------------- /src/copy/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/copy/.DS_Store -------------------------------------------------------------------------------- /src/java/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/java/.DS_Store -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump.egg-info/requires.txt: -------------------------------------------------------------------------------- 1 | click 2 | frida-tools 3 | wallbreaker 4 | -------------------------------------------------------------------------------- /src/test/agent.ts: -------------------------------------------------------------------------------- 1 | import { log } from "./log.js"; 2 | 3 | log("Hello from Frida:", Frida.version); -------------------------------------------------------------------------------- /src/so/android/SoFixer32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/so/android/SoFixer32 -------------------------------------------------------------------------------- /src/so/android/SoFixer64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/so/android/SoFixer64 -------------------------------------------------------------------------------- /src/Frida-Seccomp/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/Frida-Seccomp/.DS_Store -------------------------------------------------------------------------------- /src/Frida-Seccomp/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/Frida-Seccomp/img/1.png -------------------------------------------------------------------------------- /src/Frida-Seccomp/img/2.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/Frida-Seccomp/img/2.JPG -------------------------------------------------------------------------------- /src/Frida-Seccomp/img/3.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/Frida-Seccomp/img/3.JPG -------------------------------------------------------------------------------- /src/java/r0tracer/pic/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/java/r0tracer/pic/01.png -------------------------------------------------------------------------------- /src/java/r0tracer/pic/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/java/r0tracer/pic/02.png -------------------------------------------------------------------------------- /src/java/r0tracer/pic/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/java/r0tracer/pic/03.png -------------------------------------------------------------------------------- /src/java/r0tracer/pic/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/java/r0tracer/pic/04.png -------------------------------------------------------------------------------- /src/java/r0tracer/pic/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/java/r0tracer/pic/05.png -------------------------------------------------------------------------------- /src/r0capture/pic/Sample.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/pic/Sample.PNG -------------------------------------------------------------------------------- /src/r0capture/pic/bypass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/pic/bypass.png -------------------------------------------------------------------------------- /src/r0capture/pic/clientcer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/pic/clientcer.png -------------------------------------------------------------------------------- /src/r0capture/pic/difport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/pic/difport.png -------------------------------------------------------------------------------- /src/r0capture/pic/locator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/pic/locator.png -------------------------------------------------------------------------------- /src/r0capture/pic/summary1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/pic/summary1.jpg -------------------------------------------------------------------------------- /src/r0capture/pic/summary2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/pic/summary2.jpg -------------------------------------------------------------------------------- /src/jni/JNI-Frida-Hook/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/jni/JNI-Frida-Hook/.DS_Store -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump.egg-info/entry_points.txt: -------------------------------------------------------------------------------- 1 | [console_scripts] 2 | frida-dexdump = frida_dexdump.__main__:main 3 | -------------------------------------------------------------------------------- /src/r0capture/pic/sslunpinningcer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/pic/sslunpinningcer.png -------------------------------------------------------------------------------- /src/copy/Using Frida on Android without root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/copy/Using Frida on Android without root.png -------------------------------------------------------------------------------- /src/frida-dexdump/dist/frida-dexdump-2.0.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/frida-dexdump/dist/frida-dexdump-2.0.1.tar.gz -------------------------------------------------------------------------------- /src/r0capture/__pycache__/myhexdump.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/__pycache__/myhexdump.cpython-310.pyc -------------------------------------------------------------------------------- /src/r0capture/__pycache__/myhexdump.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/__pycache__/myhexdump.cpython-311.pyc -------------------------------------------------------------------------------- /src/r0capture/__pycache__/myhexdump.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/r0capture/__pycache__/myhexdump.cpython-39.pyc -------------------------------------------------------------------------------- /src/copy/connect_frida.py: -------------------------------------------------------------------------------- 1 | import frida 2 | manager = frida.get_device_manager() 3 | device = manager.add_remote_device("192.168.101.15:9999") 4 | print(device) 5 | -------------------------------------------------------------------------------- /src/so/sktrace/__pycache__/sktracemgr.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/so/sktrace/__pycache__/sktracemgr.cpython-311.pyc -------------------------------------------------------------------------------- /src/frida-dexdump/dist/frida_dexdump-2.0.1-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thouger/frida_script/HEAD/src/frida-dexdump/dist/frida_dexdump-2.0.1-py3-none-any.whl -------------------------------------------------------------------------------- /src/frida-dexdump/makefile: -------------------------------------------------------------------------------- 1 | all: package 2 | 3 | frida_dexdump/agent/agent.js: agent/src/index.ts agent/src/search.ts 4 | 5 | cd agent; npm install; npm run build 6 | 7 | package: frida_dexdump/agent/agent.js 8 | python3 setup.py sdist bdist_wheel -------------------------------------------------------------------------------- /src/frida-dexdump/agent/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "lib": [ 5 | "esnext" 6 | ], 7 | "allowJs": true, 8 | "noEmit": true, 9 | "strict": true, 10 | "esModuleInterop": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/test.py: -------------------------------------------------------------------------------- 1 | import frida 2 | 3 | def on_diagnostics(diag): 4 | print("on_diagnostics:", diag) 5 | 6 | compiler = frida.Compiler() 7 | compiler.on("diagnostics", on_diagnostics) 8 | bundle = compiler.build("agent.ts") 9 | with open("_agent.js", "w", newline="\n") as f: 10 | f.write(bundle) -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "lib": ["es2020"], 5 | "module": "ES2020", 6 | "moduleResolution": "node", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "rootDir": "src", 10 | "outDir": "dist", 11 | "declaration": true 12 | }, 13 | "include": [ 14 | "src/**/*.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/Frida-Seccomp/README.md: -------------------------------------------------------------------------------- 1 | # 一个Android通用svc跟踪以及hook方案——Frida-Seccomp 2 | 3 | ## 效果 4 | ### openat 5 | ![图片描述](img/2.JPG) 6 | ### recvfrom 7 | ![图片描述](img/3.JPG) 8 | # 原理及其介绍 9 | https://bbs.pediy.com/thread-271815.htm 10 | # 如何使用 11 | ``` 12 | pip3 install frida 13 | python3 multi_frida_seccomp.py 14 | ``` 15 | log信息可以在logcat过滤“seccomp”查看 16 | 同时也自动保存到了「包名\_pid\_时间戳」文件夹内(支持多进程) 17 | ![图片描述](img/1.png) -------------------------------------------------------------------------------- /src/utils/system_property_get.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | Interceptor.attach(Module.findExportByName(null, '__system_property_get'), { 3 | onEnter: function (args) { 4 | this._name = args[0].readCString(); 5 | this._value = args[1]; 6 | }, 7 | onLeave: function (retval) { 8 | console.log(JSON.stringify({ 9 | result_length: retval, 10 | name: this._name, 11 | val: this._value.readCString() 12 | })); 13 | } 14 | }); -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | LICENSE 2 | README.md 3 | setup.py 4 | frida_dexdump/__init__.py 5 | frida_dexdump/__main__.py 6 | frida_dexdump/banner.py 7 | frida_dexdump.egg-info/PKG-INFO 8 | frida_dexdump.egg-info/SOURCES.txt 9 | frida_dexdump.egg-info/dependency_links.txt 10 | frida_dexdump.egg-info/entry_points.txt 11 | frida_dexdump.egg-info/requires.txt 12 | frida_dexdump.egg-info/top_level.txt 13 | frida_dexdump/agent/__init__.py 14 | frida_dexdump/agent/agent.js -------------------------------------------------------------------------------- /src/utils/test_color.ts: -------------------------------------------------------------------------------- 1 | console.log('\x1b[31m%s\x1b[0m', '红色'); 2 | console.log('\x1b[32m%s\x1b[0m', '绿色'); 3 | console.log('\x1b[33m%s\x1b[0m', '黄色'); 4 | console.log('\x1b[34m%s\x1b[0m', '蓝色'); 5 | console.log('\x1b[35m%s\x1b[0m', '洋红色'); 6 | console.log('\x1b[36m%s\x1b[0m', '青色'); 7 | console.log('\x1b[45m%s\x1b[0m', '洋红色背景'); 8 | console.log('\x1b[1m%s\x1b[0m', '粗体'); 9 | console.log('\x1b[2m%s\x1b[0m', '淡色'); 10 | console.log('\x1b[4m%s\x1b[0m', '下划线'); 11 | console.log('\x1b[7m%s\x1b[0m', '反转前景色和背景色'); 12 | -------------------------------------------------------------------------------- /src/so/so_info.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | 3 | export function so_info(so_name) { 4 | // 导入 5 | var imports = Module.enumerateImportsSync(so_name); 6 | for (var i = 0; i < imports.length; i++) { 7 | console.log('import:'+imports[i].name + ": " + imports[i].address+'\n') 8 | } 9 | 10 | // 导出 11 | var exports = Module.enumerateExportsSync(so_name); 12 | for (var i = 0; i < exports.length; i++) { 13 | console.log('export'+exports[i].name + ": " + exports[i].address+'\n'); 14 | } 15 | } -------------------------------------------------------------------------------- /src/copy/call-method-of-class.js: -------------------------------------------------------------------------------- 1 | //Source: https://11x256.github.io/Frida-hooking-android-part-2/ 2 | 3 | //Update fully qualified activity class name here 4 | Java.choose("com.example.app.activity_class_name" , { 5 | onMatch : function(instance){ //This function will be called for every instance found by frida 6 | console.log("Found instance: "+instance); 7 | console.log("Result of method call: " + instance.method_name_to_call()); //Update method name here to call 8 | }, 9 | onComplete:function(){} 10 | }); 11 | -------------------------------------------------------------------------------- /src/frida-dexdump/agent/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frida-dexdump-agent", 3 | "version": "1.0.0", 4 | "description": "frida-dexdump Agent", 5 | "private": true, 6 | "main": "src/index.ts", 7 | "scripts": { 8 | "prepare": "npm run build", 9 | "build": "frida-compile src/index.ts -o ../frida_dexdump/agent/agent.js" 10 | }, 11 | "devDependencies": { 12 | "@types/frida-gum": "^14.5.0", 13 | "@types/node": "^12.12.34", 14 | "frida-compile": "^9.3.0" 15 | }, 16 | "dependencies": { 17 | "@babel/compat-data": "^7.12.7" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/java/inspectClass.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | const Class = Java.use("com.Awesome.App.MainActivity"); 3 | function inspectClass(obj) { 4 | const obj_class = Java.cast(obj.getClass(), Class); 5 | const fields = obj_class.getDeclaredFields(); 6 | const methods = obj_class.getMethods(); 7 | console.log("Inspect " + obj.getClass().toString()); 8 | console.log("\tFields:"); 9 | for (var i in fields) 10 | console.log("\t" + fields[i].toString()); 11 | console.log("\tMethods:"); 12 | for (var i in methods) 13 | console.log("\t" + methods[i].toString()); 14 | } -------------------------------------------------------------------------------- /src/copy/hook-method-of-class.js: -------------------------------------------------------------------------------- 1 | Java.perform(function() { 2 | //enter class name here: example android.security.keystore.KeyGenParameterSpec$Builder 3 | //class inside a class is defined using CLASS_NAME$SUB_CLASS_NAME 4 | var class_name = Java.use("android.security.keystore.KeyGenParameterSpec$Builder"); 5 | //replace FUNC_NAME_HERE with method name you want to hook and remove arg1 or add more if the function has arguments 6 | class_name.FUNC_NAME_HERE.implementation = function (arg1) { 7 | console.log("[*] CLASS_NAME:FUNC_NAME was called"); 8 | return this.FUNC_NAME_HERE(arg1) 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /src/java/inspectClass.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //@ts-nocheck 3 | const Class = Java.use("com.Awesome.App.MainActivity"); 4 | function inspectClass(obj) { 5 | const obj_class = Java.cast(obj.getClass(), Class); 6 | const fields = obj_class.getDeclaredFields(); 7 | const methods = obj_class.getMethods(); 8 | console.log("Inspect " + obj.getClass().toString()); 9 | console.log("\tFields:"); 10 | for (var i in fields) 11 | console.log("\t" + fields[i].toString()); 12 | console.log("\tMethods:"); 13 | for (var i in methods) 14 | console.log("\t" + methods[i].toString()); 15 | } 16 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | adb shell am force-stop com.mobilechess.gp 4 | # 启动应用 5 | adb shell am start -n com.mobilechess.gp/com.moba.unityplugin.MobaGameUnityActivity 6 | 7 | # 死循环等待第二个端口进程 8 | while true; do 9 | # 获取应用进程的第二个端口PID 10 | pid=$(adb shell ps -ef | grep mobilechess | awk 'NR==2 {print $2}') 11 | 12 | # 如果找到PID,则退出循环 13 | if [ -n "$pid" ]; then 14 | echo "找到进程PID: $pid" 15 | break 16 | fi 17 | 18 | # 如果没有找到PID,输出等待信息并继续等待 19 | echo "未找到第二个端口进程,继续等待..." 20 | done 21 | 22 | # 使用frida命令附加到该进程 23 | /home/thouger/Desktop/softdown/miniconda3/envs/py3.9/bin/frida -U -F $pid -l _agent.js -------------------------------------------------------------------------------- /src/copy/README.md: -------------------------------------------------------------------------------- 1 | # frida_script 2 | 3 | ## 介绍几个常用的脚本 4 | 5 | 1. anti_frida.js,最基础的模块,建议复制这个模块再去写新的脚本,一个对frida的检测,一个对ida调试的检测,还有console.颜色输出功能 6 | 2. HashMap.js,hook map类,追踪常用 7 | 3. StringBuffer.js,也是追踪常用,构造加密参数时前的参数常常会用StringBuffer.append 8 | 4. encrypts.js,也是追踪用(没上面两个好用),追踪常见的aes/base/md5加密方法 9 | 5. Okhttp3.js,hook没有混淆的okhttp3框架抓包 10 | 6. popen.js,hook so层的libc.so的popen函数 11 | 7. so.js,忘记了,比较重要 12 | 8. vpn.js,绕过vpn检测 13 | 9. show-all-classes-methods.js,输出所有类名(包含壳里面的),非常多,建议一次性输出并保存 14 | 10. all_method_hook.js,由r0tracer.js改进,删了黑白名单和一些不需要的输出,第一行填hook的类,以及增加了antifrida和一个功能:printHashMap(r0tracer.js输出函数参数是map时有问题). 15 | 11. one_method_hook.js,模糊匹配类下指定的一个方法 -------------------------------------------------------------------------------- /src/so/dump_so.js: -------------------------------------------------------------------------------- 1 | rpc.exports = { 2 | findmodule: function(so_name) { 3 | var libso = Process.findModuleByName(so_name); 4 | return libso; 5 | }, 6 | dumpmodule: function(so_name) { 7 | var libso = Process.findModuleByName(so_name); 8 | if (libso == null) { 9 | return -1; 10 | } 11 | Memory.protect(ptr(libso.base), libso.size, 'rwx'); 12 | var libso_buffer = ptr(libso.base).readByteArray(libso.size); 13 | libso.buffer = libso_buffer; 14 | return libso_buffer; 15 | }, 16 | allmodule: function() { 17 | return Process.enumerateModules() 18 | }, 19 | arch: function() { 20 | return Process.arch; 21 | } 22 | } -------------------------------------------------------------------------------- /src/test/_agent.js: -------------------------------------------------------------------------------- 1 | 📦 2 | 239 /agent.js.map 3 | 72 /agent.js 4 | 234 /log.js.map 5 | 58 /log.js 6 | ✄ 7 | {"version":3,"file":"agent.js","sourceRoot":"/Users/thouger/Documents/code/frida_script/src/test/","sources":["agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,GAAG,CAAC,mBAAmB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC"} 8 | ✄ 9 | import { log } from "./log.js"; 10 | log("Hello from Frida:", Frida.version); 11 | ✄ 12 | {"version":3,"file":"log.js","sourceRoot":"/Users/thouger/Documents/code/frida_script/src/test/","sources":["log.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAAG,CAAC,GAAG,IAAW;IAC9B,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;AACzB,CAAC"} 13 | ✄ 14 | export function log(...args) { 15 | console.log(...args); 16 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frida-compile", 3 | "version": "16.4.1", 4 | "description": "Compile a Frida script comprised of one or more Node.js modules", 5 | "keywords": [ 6 | "frida" 7 | ], 8 | "homepage": "https://frida.re", 9 | "main": "dist/compiler.js", 10 | "types": "dist/compiler.d.ts", 11 | "type": "module", 12 | "bin": "dist/cli.js", 13 | "files": [ 14 | "/dist/**/*.d.ts", 15 | "/dist/**/*.js", 16 | "/ext/*.d.ts", 17 | "/ext/*.js" 18 | ], 19 | "scripts": { 20 | "prepare": "npm run build", 21 | "build": "frida-compile src/index.ts -o _agent.js -c", 22 | "watch": "frida-compile src/index.ts -o _agent.js -w" 23 | }, 24 | "dependencies": { 25 | "frida-compile": "^16.4.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/socket/connect.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | Process 3 | .getModuleByName({ linux: 'libc.so', darwin: 'libSystem.B.dylib', windows: 'ws2_32.dll' }[Process.platform]) 4 | .enumerateExports().filter(ex => ex.type === 'function' && ['connect', 'recv', 'send', 'read', 'write'].some(prefix => ex.name.indexOf(prefix) === 0)) 5 | .forEach(ex => { 6 | Interceptor.attach(ex.address, { 7 | onEnter: function (args) { 8 | var fd = args[0].toInt32(); 9 | var socktype = Socket.type(fd); 10 | if (socktype !== 'tcp' && socktype !== 'tcp6') 11 | return; 12 | var address = Socket.peerAddress(fd); 13 | if (address === null) 14 | return; 15 | console.log(fd, ex.name, address.ip + ':' + address.port); 16 | } 17 | }) 18 | }) -------------------------------------------------------------------------------- /src/so/all_so.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | // import {log} from "../utils/log.js"; 3 | 4 | export function all_so(system: boolean = false) { 5 | { 6 | Process.enumerateModules({ 7 | onMatch: function (module) { 8 | 9 | if (system) { 10 | if (!module.path.includes('/data/app')) 11 | console.log('Module name: ' + module.name + " - " + "Base Address: " + module.base.toString() + " - " + "path: " + module.path); 12 | } else { 13 | console.log('Module name: ' + module.name + " - " + "Base Address: " + module.base.toString() + " - " + "path: " + module.path); 14 | } 15 | }, 16 | onComplete: function () { 17 | } 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ios/refelaction.py: -------------------------------------------------------------------------------- 1 | import frida, sys 2 | 3 | f = open('/tmp/log', 'w') 4 | 5 | def on_message(msg, _data): 6 | f.write(msg['payload']+'\n') 7 | 8 | frida_script = """ 9 | Interceptor.attach(Module.findExportByName('/usr/lib/libobjc.A.dylib', 'objc_msgSend'), { 10 | onEnter: function(args) { 11 | var m = Memory.readCString(args[1]); 12 | if (m != 'length' && !m.startsWith('_fastC')) 13 | send(m); 14 | } 15 | }); 16 | """ 17 | 18 | name = 'Music' 19 | device = frida.get_usb_device() 20 | # pid = device.spawn(["com.apple.Music"]) # or .get_frontmost_application() 21 | # session = device.attach(pid) 22 | session = device.attach(name) 23 | script = session.create_script(frida_script) 24 | script.on('message', on_message) 25 | script.load() 26 | # device.resume(pid) 27 | sys.stdin.read() -------------------------------------------------------------------------------- /src/socket/connect.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //@ts-nocheck 3 | Process 4 | .getModuleByName({ linux: 'libc.so', darwin: 'libSystem.B.dylib', windows: 'ws2_32.dll' }[Process.platform]) 5 | .enumerateExports().filter(ex => ex.type === 'function' && ['connect', 'recv', 'send', 'read', 'write'].some(prefix => ex.name.indexOf(prefix) === 0)) 6 | .forEach(ex => { 7 | Interceptor.attach(ex.address, { 8 | onEnter: function (args) { 9 | var fd = args[0].toInt32(); 10 | var socktype = Socket.type(fd); 11 | if (socktype !== 'tcp' && socktype !== 'tcp6') 12 | return; 13 | var address = Socket.peerAddress(fd); 14 | if (address === null) 15 | return; 16 | console.log(fd, ex.name, address.ip + ':' + address.port); 17 | } 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/so/so_method.ts: -------------------------------------------------------------------------------- 1 | 2 | //@ts-nocheck 3 | import { log } from "../utils/log.js"; 4 | import {hook_dlopen} from "./utils.js"; 5 | 6 | 7 | export function so_method(so_name:string){ 8 | hook_dlopen(so_name,function(){ 9 | var output = '' 10 | const export_method = Module.enumerateExports(so_name) 11 | export_method.forEach((element: { name: string }) => { 12 | output += `export method:${element.name}\n`; 13 | }); 14 | 15 | const symbols_method = Module.enumerateSymbols(so_name) 16 | symbols_method.forEach((element: { name: string }) => { 17 | output += `export method:${element.name}\n`; 18 | }); 19 | 20 | const improt_method = Module.enumerateImports('libencryptlib.so') 21 | improt_method.forEach((element: { name: string }) => { 22 | output += `export method:${element.name}\n`; 23 | }); 24 | log(output) 25 | }) 26 | } -------------------------------------------------------------------------------- /src/java/one_instance.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | import { stacktrace,log } from "../utils/log.js"; 3 | 4 | export function one_instance(target){ 5 | Java.enumerateClassLoaders({ 6 | onMatch: function (loader) { 7 | try { 8 | if (loader.findClass(target)) { 9 | log("Successfully found loader") 10 | Java.classFactory.loader = loader; 11 | log("Switch Classloader Successfully ! ") 12 | } 13 | } catch (error) { 14 | } 15 | }, 16 | onComplete: function () { 17 | log("EnumerateClassloader END") 18 | } 19 | }) 20 | 21 | Java.choose(target, { 22 | onMatch: function (instance) { 23 | console.log("enter "+instance); 24 | }, onComplete: function () { 25 | console.log("end"); 26 | console.log(arg[-1].toString()) 27 | } 28 | }); 29 | } -------------------------------------------------------------------------------- /src/copy/popen.js: -------------------------------------------------------------------------------- 1 | function hook_libc(){ 2 | let fgets_ptr = Module.findExportByName("libc.so", "fgets"); 3 | let fgets = new NativeFunction(fgets_ptr, "pointer", ["pointer", "int", "pointer"]); 4 | let popen_addr = Module.findExportByName("libc.so", "popen"); 5 | console.log(`popen_addr => ${popen_addr}`); 6 | Interceptor.attach(popen_addr, { 7 | onEnter: function(args){ 8 | let command = args[0].readUtf8String(); 9 | let mode = args[1].readUtf8String(); 10 | console.log(`[popen] [onEnter] command=${command} mode=${mode}`) 11 | }, 12 | onLeave: function(fp){ 13 | let output = ""; 14 | let buffer = Memory.alloc(1024); 15 | while (fgets(buffer, 1024, fp) > 0) { 16 | output += buffer.readUtf8String(); 17 | } 18 | console.log(`[popen] [onLeave] fp=${fp} output =>${output}<=`); 19 | } 20 | }) 21 | } 22 | // hook_libc(); 23 | -------------------------------------------------------------------------------- /frida17 api.txt: -------------------------------------------------------------------------------- 1 | Frida command before 17 Frida command for 17+ 2 | Module.getGlobalExportByName(null, 'open'); Module.getGlobalExportByName('open'); 3 | Module.findExportByName(null, "open"); Module.findGlobalExportByName('open'); 4 | Module.getSymbolByName(null, 'open') Module.getGlobalExportByName('open') 5 | Module.findExportByName(null, 'open'); Module.findGlobalExportByName("open"); 6 | Module.findExportByName('libc.so', 'open') Process.getModuleByName('libc.so').findExportByName('open') 7 | Module.getExportByName('libc.so', 'open') Process.getModuleByName('libc.so').getExportByName('open') 8 | Module.getBaseAddress('libc.so') Process.getModuleByName('libc.so').base 9 | Memory.readCString(somePtr) somePtr.readCString() 10 | Memory.readUtf8String(somePtr) somePtr.readUtf8String() 11 | Memory.readUtf16String(somePtr) somePtr.readUtf16String() 12 | Memory.readAnsiString(somePtr) somePtr.readAnsiString() 13 | Memory.readInt(somePtr) somePtr.readInt() 14 | Memory.writeUInt(somePtr) somePtr.writeUInt() -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump/agent/__init__.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreateTime: 2021/6/3 4 | import os 5 | 6 | from wallbreaker.agent import Agent 7 | 8 | 9 | class DexDumpAgent(Agent): 10 | 11 | def __init__(self, connection=None): 12 | super().__init__(connection=connection, script_file=os.path.join(os.path.dirname(__file__), "agent.js")) 13 | 14 | def on_message(self, message, data): 15 | if message['type'] == 'send': 16 | print("[*] {0}".format(message)) 17 | else: 18 | print(message) 19 | 20 | def search_dex(self, enable_deep_search=True): 21 | return self._rpc.searchdex(enable_deep_search) 22 | 23 | def memory_dump(self, base, size): 24 | return self._rpc.memorydump(base, size) 25 | 26 | def read_code(self, buffer_size, class_name, method_name, *overload): 27 | return self._rpc.readcode(buffer_size, class_name, method_name, *overload) 28 | -------------------------------------------------------------------------------- /src/frida-dexdump/build/lib/frida_dexdump/agent/__init__.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreateTime: 2021/6/3 4 | import os 5 | 6 | from wallbreaker.agent import Agent 7 | 8 | 9 | class DexDumpAgent(Agent): 10 | 11 | def __init__(self, connection=None): 12 | super().__init__(connection=connection, script_file=os.path.join(os.path.dirname(__file__), "agent.js")) 13 | 14 | def on_message(self, message, data): 15 | if message['type'] == 'send': 16 | print("[*] {0}".format(message)) 17 | else: 18 | print(message) 19 | 20 | def search_dex(self, enable_deep_search=True): 21 | return self._rpc.searchdex(enable_deep_search) 22 | 23 | def memory_dump(self, base, size): 24 | return self._rpc.memorydump(base, size) 25 | 26 | def read_code(self, buffer_size, class_name, method_name, *overload): 27 | return self._rpc.readcode(buffer_size, class_name, method_name, *overload) 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # frida_script 2 | 3 | ## 编译 4 | 每次用时先运行npm run watch然后改代码改index.ts文件,运行时运行命令frida -U -f 包名 --no-pause -l _agent.js 5 | 6 | ## 运行 7 | 新版的frida可以直接运行ts文件 8 | 包名可以用adb shell dumpsys window | grep mCurrentFocus查看最前端的app 9 | 10 | ### 如果是多进程的app 11 | ```shell 12 | pid=$(frida-ps -U | rg -i Mobile | awk 'NR==1 {print $1}') && [ -n "$pid" ] && frida -U $pid -l _agent.js 13 | ``` 14 | NR==1是第一个进程,NR==2是第二个进程,frida-ps -U | rg -i Mobile,是查看包含Mobile关键字的进程,可以根据自己的需求修改 15 | 16 | 1. dump.so.py 运行:python .\dump_so.py libsgmainso-6.5.75.so 17 | 2. java/findClass.ts 有一些dex会延迟加载,这样无论在什么时候进行hook 18 | 3. encryption.ts java层自吐加密算法 19 | 4. one_instance.ts hook一个类的实例化时候 20 | 5. stringBuilder.ts 和JsonObject.ts 两个类,对有时候没有思路hook一下有奇效 21 | 6. so_method.ts 输出所有 so 的方法 22 | 7. all_java.ts 输出所有 java 的方法,包括隐藏的,真正解决一代壳加载的问题 23 | 8. stalker.ts stalker函数输出所有调用与被调用的函数地址,native_trace函数输出一段内存所有寄存器变化的值 24 | 9. 增加sktrace native层的trace 25 | 10. child_gating.py 适用于子进程的hook 26 | 11. findAllJavaClasses方法,对于读取内存的jar文件的精准定位 27 | 12. abstract.ts 增加hook抽象类下所有子类的功能 -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: frida-dexdump 3 | Version: 2.0.1 4 | Summary: Useful and fast android unpacker 5 | Home-page: https://github.com/hluwa/frida-dexdump 6 | Author: hluwa 7 | Author-email: hluwa888@gmail.com 8 | Keywords: frida android dexdump unpacker wallbreaker 9 | Classifier: Development Status :: 5 - Production/Stable 10 | Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) 11 | Classifier: Operating System :: MacOS :: MacOS X 12 | Classifier: Operating System :: Microsoft :: Windows 13 | Classifier: Operating System :: POSIX :: Linux 14 | Classifier: Programming Language :: Python :: 3 15 | Classifier: Programming Language :: Python :: 3.4 16 | Classifier: Programming Language :: Python :: 3.5 17 | Classifier: Programming Language :: Python :: 3.6 18 | Classifier: Programming Language :: Python :: 3.7 19 | Classifier: Programming Language :: Python :: 3.8 20 | Classifier: Programming Language :: Python :: 3.9 21 | License-File: LICENSE 22 | -------------------------------------------------------------------------------- /src/so/scan.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | // var _m = Process.enumerateModules();// enumerate loaded modules and take the first on_m 3 | // for (var module of _m) { 4 | 5 | // var pattern = 'C7 C7 65 47 65 74 44 65 78 44 61 74 61 00 35 30' 6 | 7 | // Memory.scan(/*NativePointer*/ module.base, /*number*/ module.size, /*string*/ pattern, { 8 | // onMatch: function (address, size) {// called when pattern matches 9 | // console.log("Memory.scan() found at " + address +'Module name: ' + module.name + " - " + "Base Address: " + module.base.toString() + " - " + "path: " + module.path); 10 | // }, 11 | // onError: function(reason){ 12 | // //搜索失败 13 | // // console.log('搜索失败'); 14 | // }, 15 | // onComplete: function () { 16 | // // console.log("搜索完毕") 17 | // } 18 | // }); 19 | // } 20 | 21 | // // var results = Memory.scanSync(m.base, m.size, pattern); 22 | // // console.log("Memory.scanSync() result = \n" + JSON.stringify(results)); -------------------------------------------------------------------------------- /src/java/file.js: -------------------------------------------------------------------------------- 1 | export function hook_file() { 2 | Java.perform(function () { 3 | var File = Java.use('java.io.File'); 4 | // Hook File构造函数 5 | File.$init.overload('java.lang.String').implementation = function (path) { 6 | console.log('File constructor hooked, path: ' + path); 7 | try { 8 | var file_name = this.getName.call(this); 9 | // 输出文件名 10 | console.log('File name: ' + file_name); 11 | } 12 | catch (e) { 13 | // console.log(e) 14 | } 15 | return this.$init.call(this, path); 16 | }; 17 | // Hook File构造函数 18 | File.$init.overload('java.lang.String', 'java.lang.String').implementation = function (dirPath, fileName) { 19 | console.log('File constructor hooked, dirPath: ' + dirPath + ', fileName: ' + fileName); 20 | // 输出文件名 21 | console.log('File name: ' + fileName); 22 | return this.$init.call(this, dirPath, fileName); 23 | }; 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /src/ios/os_log.js: -------------------------------------------------------------------------------- 1 | var m = 'libsystem_trace.dylib'; 2 | // bool os_log_type_enabled(os_log_t oslog, os_log_type_t type); 3 | var isEnabledFunc = Module.findExportByName(m, 'os_log_type_enabled'); 4 | // _os_log_impl(void *dso, os_log_t log, os_log_type_t type, const char *format, uint8_t *buf, unsigned int size); 5 | var logFunc = Module.findExportByName(m, '_os_log_impl'); 6 | 7 | // Enable all logs 8 | Interceptor.attach(isEnabledFunc, { 9 | onLeave: function (ret) { 10 | ret.replace(0x1); 11 | } 12 | }); 13 | 14 | Interceptor.attach(logFunc, { 15 | onEnter: function (a) { 16 | /* 17 | OS_ENUM(os_log_type, uint8_t, 18 | OS_LOG_TYPE_DEFAULT = 0x00, 19 | OS_LOG_TYPE_INFO = 0x01, 20 | OS_LOG_TYPE_DEBUG = 0x02, 21 | OS_LOG_TYPE_ERROR = 0x10, 22 | OS_LOG_TYPE_FAULT = 0x11); 23 | */ 24 | var type = a[2]; 25 | var format = a[3]; 26 | if (type !== 0x2) { 27 | console.log(JSON.stringify({ 28 | type: type, 29 | format: format.readCString(), 30 | //buf: a[4].readPointer().readCString() // TODO 31 | }, null, 2)); 32 | } 33 | } 34 | }) -------------------------------------------------------------------------------- /src/frida-dexdump/.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflows will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: Upload Python Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: '3.x' 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install setuptools wheel twine 25 | sudo apt-get update && DEBIAN_FRONTEND=noninteractive sudo apt-get install -y make 26 | - name: Build and publish 27 | env: 28 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 29 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 30 | run: | 31 | make 32 | twine upload dist/* -------------------------------------------------------------------------------- /src/so/libc_method.js: -------------------------------------------------------------------------------- 1 | // Hook libc.so 2 | Java.perform(function () { 3 | var mkdirat_addr = null; 4 | 5 | var symbols = Process.findModuleByName("libc.so").enumerateSymbols(); 6 | for (var i = 0; i < symbols.length; i++) { 7 | if (symbols[i].name === "mkdirat") { 8 | mkdirat_addr = symbols[i].address; 9 | break; 10 | } 11 | } 12 | 13 | if (mkdirat_addr) { 14 | var output = ""; 15 | 16 | Interceptor.attach(mkdirat_addr, { 17 | onEnter: function (args) { 18 | var dirfd = args[0]; 19 | var pathname = Memory.readUtf8String(args[1]); 20 | var mode = args[2]; 21 | output = "mkdirat() called with dirfd: " + dirfd + ", pathname: " + pathname + ", mode: " + mode; 22 | output += "\nStack trace:\n" + 23 | Thread.backtrace(this.context, Backtracer.ACCURATE) 24 | .map(DebugSymbol.fromAddress).join('\n'); 25 | }, 26 | onLeave: function (retval) { 27 | console.log(output+"\nReturn value: "+retval+"\n\n\n"); 28 | // You can add additional code here if needed 29 | } 30 | }); 31 | } else { 32 | console.log("Failed to find the address of mkdirat"); 33 | } 34 | -------------------------------------------------------------------------------- /src/jni/frida_hook_libart/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 lasting-yang 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 | -------------------------------------------------------------------------------- /src/java/file.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | import { stacktrace,log } from "../utils/log.js"; 3 | 4 | export function hook_file(){ 5 | Java.perform(function () { 6 | var File = Java.use('java.io.File'); 7 | 8 | // Hook File构造函数 9 | File.$init.overload('java.lang.String').implementation = function (path) { 10 | console.log('File constructor hooked, path: ' + path); 11 | 12 | try{ 13 | var file_name = this.getName.call(this); 14 | // 输出文件名 15 | console.log('File name: ' +file_name); 16 | }catch(e){ 17 | // console.log(e) 18 | } 19 | 20 | return this.$init.call(this, path); 21 | }; 22 | 23 | // Hook File构造函数 24 | File.$init.overload('java.lang.String', 'java.lang.String').implementation = function (dirPath, fileName) { 25 | console.log('File constructor hooked, dirPath: ' + dirPath + ', fileName: ' + fileName); 26 | 27 | // 输出文件名 28 | console.log('File name: ' + fileName); 29 | 30 | return this.$init.call(this, dirPath, fileName); 31 | }; 32 | }); 33 | } -------------------------------------------------------------------------------- /src/ios/class _hierarchy.js: -------------------------------------------------------------------------------- 1 | var objc_copyClassNamesForImage = new NativeFunction( 2 | Module.findExportByName(null, 'objc_copyClassNamesForImage'), 3 | 'pointer', 4 | ['pointer', 'pointer'] 5 | ); 6 | var free = new NativeFunction(Module.findExportByName(null, 'free'), 'void', ['pointer']); 7 | var classes = new Array(count); 8 | var p = Memory.alloc(Process.pointerSize); 9 | 10 | Memory.writeUInt(p, 0); 11 | 12 | var path = ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String(); 13 | var pPath = Memory.allocUtf8String(path); 14 | var pClasses = objc_copyClassNamesForImage(pPath, p); 15 | var count = Memory.readUInt(p); 16 | for (var i = 0; i < count; i++) { 17 | var pClassName = Memory.readPointer(pClasses.add(i * Process.pointerSize)); 18 | classes[i] = Memory.readUtf8String(pClassName); 19 | } 20 | 21 | free(pClasses); 22 | 23 | var tree = {}; 24 | classes.forEach(function(name) { 25 | var clazz = ObjC.classes[name]; 26 | var chain = [name]; 27 | while (clazz = clazz.$superClass) { 28 | chain.unshift(clazz.$className); 29 | } 30 | 31 | var node = tree; 32 | chain.forEach(function(clazz) { 33 | node[clazz] = node[clazz] || {}; 34 | node = node[clazz]; 35 | }); 36 | }); 37 | 38 | send(tree); -------------------------------------------------------------------------------- /src/frida-dexdump/agent/src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: hluwa 3 | * HomePage: https://github.com/hluwa 4 | * CreateTime: 2021/6/2 5 | * */ 6 | 7 | import {searchDex} from "./search"; 8 | 9 | function setReadPermission(base: NativePointer, size: number) { 10 | const end = base.add(size); 11 | Process.enumerateRanges("---").forEach(function (range) { 12 | const range_end = range.base.add(range.size) 13 | if (range.base < base || range_end > end) { 14 | return 15 | } 16 | if (!range.protection.startsWith("r")) { 17 | console.log("Set read permission for memory range: " + base + "-" + range_end) 18 | Memory.protect(range.base, range.size, "r" + range.protection.substr(1, 2)) 19 | } 20 | 21 | }) 22 | } 23 | 24 | 25 | rpc.exports = { 26 | memorydump: function (address, size) { 27 | const ptr = new NativePointer(address); 28 | setReadPermission(ptr, size); 29 | return ptr.readByteArray(size); 30 | }, 31 | searchdex: function (enableDeepSearch: boolean) { 32 | return searchDex(enableDeepSearch); 33 | }, 34 | stopthreads: function () { 35 | Process.enumerateThreads().forEach(function (thread) { 36 | 37 | }) 38 | } 39 | }; -------------------------------------------------------------------------------- /src/cert/sslpinning5.js: -------------------------------------------------------------------------------- 1 | function hook_ssl() { 2 | Java.perform(function () { 3 | var ClassName = "com.android.org.conscrypt.Platform"; 4 | var Platform = Java.use(ClassName); 5 | var targetMethod = "checkServerTrusted"; 6 | var len = Platform[targetMethod].overloads.length; 7 | console.log(targetMethod, len); 8 | for (var i = 0; i < len; ++i) { 9 | Platform[targetMethod].overloads[i].implementation = function () { 10 | console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments); 11 | }; 12 | } 13 | var ClassName = "com.android.org.conscrypt.TrustManagerImpl"; 14 | var Platform = Java.use(ClassName); 15 | var targetMethod = "checkTrustedRecursive"; 16 | var len = Platform[targetMethod].overloads.length; 17 | console.log(targetMethod, len); 18 | var ArrayList = Java.use("java.util.ArrayList") 19 | var X509Certificate = Java.use("java.security.cert.X509Certificate"); 20 | for (var i = 0; i < len; ++i) { 21 | Platform[targetMethod].overloads[i].implementation = function () { 22 | console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments); 23 | return ArrayList.$new(); 24 | }; 25 | } 26 | }); 27 | } 28 | hook_ssl(); -------------------------------------------------------------------------------- /src/java/abstract.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | import { trace } from "./trace.js"; 3 | import { log, print_hashmap,print_byte, stacktrace_java } from "../utils/log.js"; 4 | 5 | export function hook_abstract(class_name) { 6 | Java.enumerateClassLoaders({ 7 | onMatch: function(loader) { 8 | try { 9 | if (loader.findClass(class_name)) { 10 | log("Successfully found loader: " + loader); 11 | Java.classFactory.loader = loader; 12 | } 13 | } catch(error) {} 14 | }, 15 | onComplete: function() {} 16 | }); 17 | 18 | Java.enumerateLoadedClasses({ 19 | onMatch: function(className) { 20 | try { 21 | var nameParts = className.split("."); 22 | var targetParts = class_name.split("."); 23 | if (nameParts[0] !== targetParts[0] || nameParts[1] !== targetParts[1]) return; 24 | 25 | var clazz = Java.use(className); 26 | var resultClass = clazz.class.getSuperclass(); 27 | if (resultClass && resultClass.toString().indexOf(class_name) !== -1) { 28 | log(className, resultClass); 29 | trace(resultClass); 30 | } 31 | } catch(e) {} 32 | }, 33 | onComplete: function() { 34 | log("Search Class Completed!"); 35 | } 36 | }); 37 | } -------------------------------------------------------------------------------- /src/java/stringBuilder.js: -------------------------------------------------------------------------------- 1 | export function hook_string() { 2 | // var targetClass = Java.use("java.lang.StringBuilder"); 3 | // targetClass.append.overload('java.lang.String').implementation = function (str) { 4 | // var output = ''; 5 | // output = output.concat("=================String.append===================="); 6 | // output = output.concat("str: " + str + " => " + JSON.stringify(str)); 7 | // output = output.concat("\r\n") 8 | // output = output.concat(stacktrace()); 9 | // output = output.concat("=================String.append===================="); 10 | // if (output.indexOf("AFa1wSDK") != -1) 11 | // log(output); 12 | // var retval = this.append(str); 13 | // return retval; 14 | // }; 15 | const StringBuilder = Java.use('java.lang.StringBuilder'); 16 | StringBuilder.toString.implementation = function () { 17 | var res = this.toString(); 18 | var tmp = ""; 19 | if (res !== null) { 20 | tmp = res.toString().replace("/n", ""); 21 | console.log(tmp); 22 | } 23 | return res; 24 | }; 25 | } 26 | // export function hook_stringBuilder() { 27 | // StringBuilder.$init.overload('java.lang.String').implementation = function (str) { 28 | // var output = str.toString() + '\n' 29 | // output=output.concat(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 30 | // output=output.concat("\r\n"); 31 | // log(output); 32 | // return this.$init(str); 33 | // }; 34 | // } 35 | -------------------------------------------------------------------------------- /src/frida-dexdump/setup.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreateTime: 2021/6/3 4 | 5 | import setuptools 6 | 7 | setuptools.setup( 8 | name="frida-dexdump", 9 | version="2.0.1", 10 | description="Useful and fast android unpacker", 11 | author="hluwa", 12 | author_email="hluwa888@gmail.com", 13 | url="https://github.com/hluwa/frida-dexdump", 14 | install_requires=[ 15 | "click", 16 | "frida-tools", 17 | "wallbreaker" 18 | ], 19 | keywords="frida android dexdump unpacker wallbreaker", 20 | classifiers=[ 21 | "Development Status :: 5 - Production/Stable", 22 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 23 | "Operating System :: MacOS :: MacOS X", 24 | "Operating System :: Microsoft :: Windows", 25 | "Operating System :: POSIX :: Linux", 26 | "Programming Language :: Python :: 3", 27 | "Programming Language :: Python :: 3.4", 28 | "Programming Language :: Python :: 3.5", 29 | "Programming Language :: Python :: 3.6", 30 | "Programming Language :: Python :: 3.7", 31 | "Programming Language :: Python :: 3.8", 32 | "Programming Language :: Python :: 3.9", 33 | ], 34 | packages=setuptools.find_packages(where='.', exclude=(), include=('*',)), 35 | package_data={ 36 | "frida_dexdump.agent": ["agent.js"] 37 | }, 38 | entry_points={ 39 | 'console_scripts': [ 40 | "frida-dexdump = frida_dexdump.__main__:main", 41 | ] 42 | } 43 | ) 44 | -------------------------------------------------------------------------------- /src/ios/trace.js: -------------------------------------------------------------------------------- 1 | function observeClass(name) { 2 | var k = ObjC.classes[name]; 3 | k.$ownMethods.forEach(function(m) { 4 | var impl = k[m].implementation; 5 | console.log('Observing ' + name + ' ' + m); 6 | Interceptor.attach(impl, { 7 | onEnter: function(a) { 8 | this.log = []; 9 | this.log.push('(' + a[0] + ',' + Memory.readUtf8String(a[1]) + ') ' + name + ' ' + m); 10 | if (m.indexOf(':') !== -1) { 11 | var params = m.split(':'); 12 | params[0] = params[0].split(' ')[1]; 13 | for (var i = 0; i < params.length - 1; i++) { 14 | try { 15 | this.log.push(params[i] + ': ' + new ObjC.Object(a[2 + i]).toString()); 16 | } catch (e) { 17 | this.log.push(params[i] + ': ' + a[2 + i].toString()); 18 | } 19 | } 20 | } 21 | 22 | this.log.push( 23 | Thread.backtrace(this.context, Backtracer.ACCURATE) 24 | .map(DebugSymbol.fromAddress) 25 | .join('\n') 26 | ); 27 | }, 28 | 29 | onLeave: function(r) { 30 | try { 31 | this.log.push('RET: ' + new ObjC.Object(r).toString()); 32 | } catch (e) { 33 | this.log.push('RET: ' + r.toString()); 34 | } 35 | 36 | console.log(this.log.join('\n') + '\n'); 37 | } 38 | }); 39 | }); 40 | } -------------------------------------------------------------------------------- /src/java/stringBuilder.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import { stacktrace,log } from "../utils/log.js"; 3 | 4 | export function hook_string(){ 5 | 6 | // var targetClass = Java.use("java.lang.StringBuilder"); 7 | // targetClass.append.overload('java.lang.String').implementation = function (str) { 8 | // var output = ''; 9 | // output = output.concat("=================String.append===================="); 10 | // output = output.concat("str: " + str + " => " + JSON.stringify(str)); 11 | // output = output.concat("\r\n") 12 | // output = output.concat(stacktrace()); 13 | // output = output.concat("=================String.append===================="); 14 | // if (output.indexOf("AFa1wSDK") != -1) 15 | 16 | // log(output); 17 | // var retval = this.append(str); 18 | // return retval; 19 | // }; 20 | 21 | const StringBuilder = Java.use('java.lang.StringBuilder'); 22 | StringBuilder.toString.implementation = function () { 23 | var res = this.toString(); 24 | var tmp = ""; 25 | if (res !== null){ 26 | tmp = res.toString().replace("/n", ""); 27 | console.log(tmp); 28 | } 29 | return res; 30 | }; 31 | } 32 | 33 | // export function hook_stringBuilder() { 34 | 35 | 36 | 37 | // StringBuilder.$init.overload('java.lang.String').implementation = function (str) { 38 | // var output = str.toString() + '\n' 39 | // output=output.concat(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 40 | // output=output.concat("\r\n"); 41 | // log(output); 42 | // return this.$init(str); 43 | // }; 44 | // } -------------------------------------------------------------------------------- /src/jni/JNI-Frida-Hook/README.md: -------------------------------------------------------------------------------- 1 | ## JNI Frida Hook 2 | 3 | Here is a quick script to easily have an overview of JNI called by a function. 4 | It also provide a way to easily hook them 5 | 6 | ## Requirements 7 | 8 | ``` 9 | pip install frida-tools --user 10 | npm install frida-compile -g 11 | npm install frida-compile 12 | ``` 13 | 14 | ## Usage 15 | 16 | Fill library name and function name in `agent.js` 17 | 18 | ```javascript 19 | library_name = "" // ex: libsqlite.so 20 | function_name = "" // ex: JNI_OnLoad 21 | ``` 22 | 23 | Add the functions you want to hook or simply hook all in the `hook_jni` function 24 | 25 | ```javascript 26 | /* 27 | Here you can choose which function to hook 28 | Either you hook all to have an overview of the function called 29 | */ 30 | 31 | jni.hook_all(jnienv_addr) 32 | 33 | /* 34 | Either you hook the one you want by precising what to do with it 35 | */ 36 | 37 | Interceptor.attach(jni.getJNIFunctionAdress(jnienv_addr,"FindClass"),{ 38 | onEnter: function(args){ 39 | console.log("env->FindClass(\"" + Memory.readCString(args[1]) + "\")") 40 | } 41 | }) 42 | ``` 43 | 44 | Once you've filled all the previous informations, compile it with : 45 | 46 | ``` 47 | frida-compile agent.js -o _agent.js 48 | ``` 49 | 50 | And launch it : 51 | 52 | ``` 53 | frida -U -l _agent.js --no-pause -f 54 | ``` 55 | 56 | # Example of usage 57 | 58 | [https://www.aperikube.fr/docs/aperictf_2019/my_backdoored_gallery/](https://www.aperikube.fr/docs/aperictf_2019/my_backdoored_gallery/) 59 | 60 | # Contact 61 | 62 | Feel free to contact me on Twitter : [Areizen](https://twitter.com/Areizen_) 63 | 64 | or by email at : 65 | -------------------------------------------------------------------------------- /src/copy/so/hook_native.js: -------------------------------------------------------------------------------- 1 | function antiAntiFrida() { 2 | var strstr = Module.findExportByName(null, "strstr"); 3 | if (null !== strstr) { 4 | Interceptor.attach(strstr, { 5 | onEnter: function (args) { 6 | this.frida = Boolean(0); 7 | 8 | this.haystack = args[0]; 9 | this.needle = args[1]; 10 | 11 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 12 | if (this.haystack.readCString().indexOf("frida") !== -1 || 13 | this.needle.readCString().indexOf("frida") !== -1 || 14 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 15 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 16 | this.haystack.readCString().indexOf("gmain") !== -1 || 17 | this.needle.readCString().indexOf("gmain") !== -1 || 18 | this.haystack.readCString().indexOf("linjector") !== -1 || 19 | this.needle.readCString().indexOf("linjector") !== -1) { 20 | this.frida = Boolean(1); 21 | } 22 | } 23 | }, 24 | onLeave: function (retval) { 25 | if (this.frida) { 26 | retval.replace(ptr("0x0")); 27 | } 28 | 29 | } 30 | }) 31 | } 32 | } 33 | setImmediate(antiAntiFrida) 34 | function main(){ 35 | var modules = Process.enumerateModules(); 36 | for (var i in modules){ 37 | var module = modules[i]; 38 | console.log(module.name+'--'+module.base); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/java/r0tracer/README.md: -------------------------------------------------------------------------------- 1 | # 2023-6-15更新: 2 | 3 | - 基于最新Frida16 4 | - 新增iOS平台支持且自动判断应用所属平台 5 | - 输出信息非常全面,iOS平台对property的访问也被hook并输出 6 | - 新增hookALL()模式,hook应用的所有类方法重载;(小应用可用,大应用扛不住) 7 | 8 | # r0tracer 9 | 10 | 安卓Java层多功能追踪脚本 11 | 12 | > AKA:精简版 objection + Wallbreaker 13 | 14 | 15 | # 功能: 16 | 17 | - 根据黑白名单批量追踪类的所有方法 18 | 19 | hook("javax.crypto.Cipher", "$"); 20 | 21 | ![](pic/02.png) 22 | 23 | - 在命中方法后打印出该类或对象的所有域值、参数、调用栈和返回值 24 | 25 | ![](pic/03.png) 26 | ![](pic/04.png) 27 | ![](pic/05.png) 28 | 29 | - 极简的文本保存日志机制、易于搜索关键参数 30 | 31 | - 针对加壳应用找不到类时可以切换Classloader 32 | 33 | # 使用方法: 34 | 35 | 1. 修改`r0tracer.js`文件最底部处的代码,开启某一个Hook模式。 36 | 37 | ![](pic/01.png) 38 | 39 | 2. 推荐使用Frida14版本,并且将日志使用`-o`参数进行输出保存 40 | 41 | ``` 42 | $ frida -U -f com.r0ysue.example -l r0tracer.js --no-pause -o saveLog5.txt 43 | ``` 44 | 45 | > "-f"为Spawn模式,去掉"-f"为Attach模式 46 | 47 | 3. Frida版本=<12时,要加上`--runtime=v8`选项 48 | 49 | ``` 50 | $ frida -U com.r0ysue.example -l r0tracer.js --runtime=v8 --no-pause -o saveLog6.txt 51 | ``` 52 | 53 | 54 | # 优势 55 | 56 | - 比`objection`增加延时`spawn` 57 | - 比`objection`增加批量`hook`类\方法\构造函数 58 | - `Wallbreaker`在`frida14`上还是一直崩 59 | - 比`Wallbreaker`增加`hook`看`instance`的`fields` 60 | - `inspectObject`函数可以单独拿出去使用 61 | 62 | 注意点: 63 | 64 | - Frida的崩溃有时候真的是玄学,大项目一崩溃根本不知道是哪里出的问题,这也是小而专的项目也有一丝机会的原因 65 | - Frida自身即会经常崩溃,建议多更换Frida(客/服要配套)版本/安卓版本,`ROOT`采用`Magisk Root` 66 | - 我自己常用的组合是两部手机,Frida12.8.0全家桶+[Google Factoty Image](https://developers.google.com/android/images) Android 8.1.0,和Frida14.2.2全家桶+[Google Factoty Image](https://developers.google.com/android/images) Android 10 67 | 68 | # 致谢 Thanks to 69 | 70 | |项目|链接| 71 | |:-:|:-:| 72 | |objection|https://github.com/sensepost/objection| 73 | |Wallbreaker|https://github.com/hluwa/Wallbreaker| 74 | |hacking-frida|https://awakened1712.github.io/hacking/hacking-frida/| 75 | 76 | -------------------------------------------------------------------------------- /src/frida-dexdump/README.md: -------------------------------------------------------------------------------- 1 | # FRIDA-DEXDump 2 | 3 | `frida-dexdump` is a frida tool to find and dump dex in memory to support security engineers in analyzing malware. 4 | 5 | ## Make Jetbrains Great Again 6 | 7 |

8 | 9 | 10 |

11 | 12 | ## Features 13 | 14 | 1. Support fuzzy search broken header dex(deep search mode). 15 | 2. Compatible with all android version(frida supported). 16 | 3. One click installation, without modifying the system, easy to deploy and use. 17 | 18 | ## Installation 19 | 20 | ``` 21 | pip3 install frida-dexdump 22 | ``` 23 | 24 | ## Usage 25 | 26 | CLI arguments base on [frida-tools](https://github.com/frida/frida-tools), you can quickly dump the foreground application like this: 27 | 28 | ``` 29 | frida-dexdump -FU 30 | ``` 31 | 32 | Or specify and spawn app like this: 33 | 34 | ``` 35 | frida-dexdump -U -f com.app.pkgname 36 | ``` 37 | 38 | Additionally, you can see in `-h` that the new options provided by frida-dexdump are: 39 | 40 | ``` 41 | -o OUTPUT, --output OUTPUT Output folder path, default is './/'. 42 | -d, --deep-search Enable deep search mode. 43 | --sleep SLEEP Waiting times for start, spawn mode default is 5s. 44 | ``` 45 | 46 | When using, I suggest using the `-d, --deep-search` option, which may take more time, but the results will be more complete. 47 | 48 | ![screenshot](screenshot.png) 49 | 50 | ## Build and develop 51 | 52 | ``` 53 | make 54 | ``` 55 | 56 | ### Requires 57 | 58 | See [requirements.txt](https://github.com/hluwa/FRIDA-DEXDump/blob/master/requirements.txt) 59 | 60 | ## Internals 61 | 62 | [《深入 FRIDA-DEXDump 中的矛与盾》](https://mp.weixin.qq.com/s/n2XHGhshTmvt2FhxyFfoMA) -------------------------------------------------------------------------------- /src/java/JsonObject.js: -------------------------------------------------------------------------------- 1 | export function main() { 2 | Java.perform(function () { 3 | var JSONObject = Java.use('org.json.JSONObject'); 4 | JSONObject.toString.overload().implementation = function () { 5 | send("=================org.json.JSONObject.toString===================="); 6 | send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 7 | var data = this.toString(); 8 | send("org.json.JSONObject.toString result:" + data); 9 | return data; 10 | }; 11 | for (var i = 0; i < JSONObject.put.overloads.length; i++) { 12 | JSONObject.put.overloads[i].implementation = function () { 13 | send("=================org.json.JSONObject.put===================="); 14 | if (arguments.length == 2) { 15 | send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 16 | send("key:" + arguments[0]); 17 | send("value:" + arguments[1]); 18 | var retval = this.put(arguments[0], arguments[1]); 19 | return retval; 20 | } 21 | }; 22 | } 23 | for (var i = 0; i < JSONObject.$init.overloads.length; i++) { 24 | JSONObject.$init.overloads[i].implementation = function () { 25 | send("=================org.json.JSONObject.$init===================="); 26 | send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 27 | if (arguments.length == 1) { //只有1个string参数 28 | send("string:" + arguments[0]); 29 | } 30 | else if (arguments.length == 2) { //其他构造函数用到的时候可以继续添加 31 | } 32 | }; 33 | } 34 | }); 35 | } 36 | setTimeout(main, 0); 37 | -------------------------------------------------------------------------------- /src/java/JsonObject.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | import { stacktrace,log } from "../utils/log.js"; 3 | 4 | export function main() { 5 | Java.perform(function () { 6 | var JSONObject = Java.use('org.json.JSONObject'); 7 | JSONObject.toString.overload().implementation = function () { 8 | send("=================org.json.JSONObject.toString===================="); 9 | send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 10 | var data = this.toString(); 11 | send("org.json.JSONObject.toString result:" + data); 12 | return data; 13 | } 14 | for (var i = 0; i < JSONObject.put.overloads.length; i++) { 15 | JSONObject.put.overloads[i].implementation = function () { 16 | send("=================org.json.JSONObject.put===================="); 17 | if (arguments.length == 2) { 18 | send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 19 | send("key:" + arguments[0]); 20 | send("value:" + arguments[1]); 21 | var retval = this.put(arguments[0], arguments[1]); 22 | return retval; 23 | } 24 | } 25 | } 26 | for (var i = 0; i < JSONObject.$init.overloads.length; i++) { 27 | JSONObject.$init.overloads[i].implementation = function () { 28 | send("=================org.json.JSONObject.$init===================="); 29 | send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 30 | if (arguments.length == 1) {//只有1个string参数 31 | send("string:" + arguments[0]); 32 | } else if (arguments.length == 2) { //其他构造函数用到的时候可以继续添加 33 | } 34 | } 35 | } 36 | }) 37 | } 38 | setTimeout(main, 0) -------------------------------------------------------------------------------- /src/cert/ssl_bypass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SSL Certificate Bypass Module 3 | * 用于绕过 SSL 证书验证 4 | */ 5 | 6 | /** 7 | * 监听动态库加载 8 | * @param {string} name - 要监听的库名称 9 | * @param {Function} callback - 加载完成后的回调 10 | */ 11 | function onLoad(name, callback) { 12 | const android_dlopen_ext = Module.findGlobalExportByName("android_dlopen_ext"); 13 | if (android_dlopen_ext != null) { 14 | Interceptor.attach(android_dlopen_ext, { 15 | onEnter: function (args) { 16 | if (args[0].readCString().indexOf(name) !== -1) { 17 | this.hook = true; 18 | } 19 | }, 20 | onLeave: function (retval) { 21 | if (this.hook) { 22 | callback(); 23 | } 24 | } 25 | }); 26 | } 27 | } 28 | 29 | /** 30 | * 绕过 SSL 证书验证 31 | * @param {string} soName - 要 hook 的 so 库名称,默认为 'libsscronet.so' 32 | */ 33 | export function sslBypass(soName = 'libsscronet.so') { 34 | console.log(`[SSL Bypass] 开始监听 ${soName} 加载...`); 35 | 36 | onLoad(soName, () => { 37 | console.log(`[SSL Bypass] ${soName} 已加载`); 38 | 39 | let SSL_CTX_set_custom_verify = Process.getModuleByName(soName).getExportByName('SSL_CTX_set_custom_verify'); 40 | if (SSL_CTX_set_custom_verify != null) { 41 | console.log("[SSL Bypass] 找到 SSL_CTX_set_custom_verify"); 42 | Interceptor.attach(SSL_CTX_set_custom_verify, { 43 | onEnter: function (args) { 44 | Interceptor.attach(args[2], { 45 | onLeave: function (retval) { 46 | if (retval > 0x0) { 47 | console.log("[SSL Bypass] 修改返回值为 0,绕过证书验证"); 48 | retval.replace(0x0); 49 | } 50 | } 51 | }); 52 | } 53 | }); 54 | console.log("[SSL Bypass] SSL 证书验证已成功绕过"); 55 | } else { 56 | console.log(`[SSL Bypass] 未找到 SSL_CTX_set_custom_verify 函数`); 57 | } 58 | }); 59 | } 60 | -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump/banner.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreateTime: 2021/6/3 4 | import logging 5 | import random 6 | 7 | try: 8 | from shutil import get_terminal_size as get_terminal_size 9 | except: 10 | try: 11 | from backports.shutil_get_terminal_size import get_terminal_size as get_terminal_size 12 | except: 13 | pass 14 | try: 15 | import click 16 | except: 17 | class click: 18 | @staticmethod 19 | def secho(message=None, **kwargs): 20 | print(message) 21 | 22 | @staticmethod 23 | def style(**kwargs): 24 | raise Exception("unsupported style") 25 | 26 | banner = """ 27 | --------------------------------------------------------------------------- 28 | __ _ _ _ _ 29 | / _|_ __(_) __| | __ _ __| | _____ ____| |_ _ _ __ ___ _ __ 30 | | |_| '__| |/ _` |/ _` |_____ / _` |/ _ \ \/ / _` | | | | '_ ` _ \| '_ \ 31 | | _| | | | (_| | (_| |_____| (_| | __/> < (_| | |_| | | | | | | |_) | 32 | |_| |_| |_|\__,_|\__,_| \__,_|\___/_/\_\__,_|\__,_|_| |_| |_| .__/ 33 | |_| 34 | https://github.com/hluwa/frida-dexdump 35 | ---------------------------------------------------------------------------\n 36 | """ 37 | 38 | 39 | def show_banner(): 40 | colors = ['bright_red', 'bright_green', 'bright_blue', 'cyan', 'magenta'] 41 | try: 42 | click.style('color test', fg='bright_red') 43 | except: 44 | colors = ['red', 'green', 'blue', 'cyan', 'magenta'] 45 | try: 46 | columns = get_terminal_size().columns 47 | if columns >= len(banner.splitlines()[1]): 48 | for line in banner.splitlines(): 49 | if line: 50 | fill = int((columns - len(line)) / 2 - 1) 51 | line = line[0] * fill + line 52 | line += line[-1] * fill 53 | click.secho(line, fg=random.choice(colors)) 54 | except: 55 | logging.exception("") 56 | -------------------------------------------------------------------------------- /src/frida-dexdump/build/lib/frida_dexdump/banner.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreateTime: 2021/6/3 4 | import logging 5 | import random 6 | 7 | try: 8 | from shutil import get_terminal_size as get_terminal_size 9 | except: 10 | try: 11 | from backports.shutil_get_terminal_size import get_terminal_size as get_terminal_size 12 | except: 13 | pass 14 | try: 15 | import click 16 | except: 17 | class click: 18 | @staticmethod 19 | def secho(message=None, **kwargs): 20 | print(message) 21 | 22 | @staticmethod 23 | def style(**kwargs): 24 | raise Exception("unsupported style") 25 | 26 | banner = """ 27 | --------------------------------------------------------------------------- 28 | __ _ _ _ _ 29 | / _|_ __(_) __| | __ _ __| | _____ ____| |_ _ _ __ ___ _ __ 30 | | |_| '__| |/ _` |/ _` |_____ / _` |/ _ \ \/ / _` | | | | '_ ` _ \| '_ \ 31 | | _| | | | (_| | (_| |_____| (_| | __/> < (_| | |_| | | | | | | |_) | 32 | |_| |_| |_|\__,_|\__,_| \__,_|\___/_/\_\__,_|\__,_|_| |_| |_| .__/ 33 | |_| 34 | https://github.com/hluwa/frida-dexdump 35 | ---------------------------------------------------------------------------\n 36 | """ 37 | 38 | 39 | def show_banner(): 40 | colors = ['bright_red', 'bright_green', 'bright_blue', 'cyan', 'magenta'] 41 | try: 42 | click.style('color test', fg='bright_red') 43 | except: 44 | colors = ['red', 'green', 'blue', 'cyan', 'magenta'] 45 | try: 46 | columns = get_terminal_size().columns 47 | if columns >= len(banner.splitlines()[1]): 48 | for line in banner.splitlines(): 49 | if line: 50 | fill = int((columns - len(line)) / 2 - 1) 51 | line = line[0] * fill + line 52 | line += line[-1] * fill 53 | click.secho(line, fg=random.choice(colors)) 54 | except: 55 | logging.exception("") 56 | -------------------------------------------------------------------------------- /src/so/hook_str.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | import { log,stacktrace_so,printRegisters } from "../utils/log.js"; 3 | 4 | export function hook_str(target_str){ 5 | log('Hooking string functions'); 6 | 7 | // 常见的字符串处理函数列表 8 | const stringFuncs = [ 9 | // "strlen", "strcmp", "strncmp", "strcpy", "strncpy", 10 | // "strcat", "strncat", "strchr", "strrchr", "strstr", 11 | 12 | // "strcpy","strncpy", 13 | // "strcat", 14 | // "strncat", 15 | // "strchr","strrchr","strstr", 16 | // "memcmp", 17 | 18 | "memcpy", 19 | ]; 20 | 21 | // 监控这些函数 22 | stringFuncs.forEach(funcName => { 23 | const funcPtr = Module.findExportByName(null, funcName); 24 | if (funcPtr) { 25 | log(`Hooking ${funcName} @ ${funcPtr}`); 26 | 27 | Interceptor.attach(funcPtr, { 28 | onEnter: function(args) { 29 | this.funcName = funcName; 30 | 31 | // 检查第一个和第二个参数 32 | for (let i = 0; i < 2; i++) { 33 | if (!args[i]) continue; 34 | 35 | try { 36 | // 尝试读取参数作为字符串 37 | const str = Memory.readUtf8String(args[i]); 38 | if (str && str != null && str != ''){ 39 | // log(`[${funcName}] arg${i}: ${str}`); 40 | // if (str && str.includes(target_str)) { 41 | if (str && str.includes("b59feaf6")) { 42 | log(`[${funcName}] arg${i}: ${str}`); 43 | log(stacktrace_so(this.context)); 44 | } 45 | } 46 | } catch (e) { 47 | // 可能不是有效的字符串,继续执行 48 | } 49 | } 50 | } 51 | }); 52 | } 53 | }); 54 | } -------------------------------------------------------------------------------- /src/utils/ioctl.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | var LAST_MSG = ''; 3 | Java.perform(() => { 4 | Interceptor.attach(Module.findExportByName('libbinder.so', 'ioctl'), { 5 | onEnter: function(args) { 6 | var binder_write_read_ptr = args[2]; 7 | if (args[1] == 0xC0306201) { // BINDER_WRITE_READ 8 | var binder_write_read = { 9 | // 'fd': args[0].toInt32(), 10 | 'write_size': binder_write_read_ptr.readU64(), 11 | 'write_consumed': binder_write_read_ptr.add(Process.pointerSize).readU64(), 12 | 'write_buffer': binder_write_read_ptr.add(Process.pointerSize * 2).readPointer(), 13 | } 14 | if (binder_write_read.write_size > 0) { 15 | var ptr = binder_write_read.write_buffer.add(binder_write_read.write_consumed + 4); 16 | switch (binder_write_read.write_buffer.readU32() & 0xff) { 17 | case 0: // BC_TRANSACTION 18 | case 1: // BC_REPLY 19 | var binder_transaction_data = { 20 | 'target': { 21 | 'handle': ptr.readU32(), 22 | 'ptr': ptr.readPointer() 23 | }, 24 | 'cookie': ptr.add(8).readPointer(), 25 | 'code': ptr.add(16).readU32(), 26 | 'flags': ptr.add(20).readU32(), 27 | 'sender_pid': ptr.add(24).readS32(), 28 | 'sender_euid': ptr.add(28).readU32(), 29 | 'data_size': ptr.add(32).readU64(), 30 | 'offsets_size': ptr.add(40).readU64(), 31 | 'data': { 32 | 'ptr': { 33 | 'buffer': ptr.add(48).readPointer(), 34 | 'offsets': ptr.add(56).readPointer() 35 | }, 36 | 'buf': ptr.add(48).readByteArray(8) 37 | } 38 | } 39 | var _log = hexdump(binder_transaction_data.data.ptr.buffer, { length: binder_transaction_data.data_size, ansi: true }); 40 | if (LAST_MSG.toString() != _log.toString()) { 41 | console.log(JSON.stringify(binder_transaction_data, null, 2)); 42 | console.log(_log); 43 | } 44 | break; 45 | } 46 | } 47 | } 48 | } 49 | }); 50 | }); -------------------------------------------------------------------------------- /src/capture/ins.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function hook_proxygen_SSLVerification(library) { 4 | const functionName = "_ZN8proxygen15SSLVerification17verifyWithMetricsEbP17x509_store_ctx_stRKNSt6__ndk112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPNS0_31SSLFailureVerificationCallbacksEPNS0_31SSLSuccessVerificationCallbacksERKNS_15TimeUtilGenericINS3_6chrono12steady_clockEEERNS_10TraceEventE"; 5 | 6 | try { 7 | const f = Module.getExportByName(library.name, functionName); 8 | 9 | Interceptor.attach(f, { 10 | onLeave: function (retvalue) { 11 | retvalue.replace(1); 12 | } 13 | }); 14 | logger(`[*][+] Hooked function: ${functionName}`); 15 | } catch (err) { 16 | logger(`[*][-] Failed to hook function: ${functionName}`); 17 | logger(err.toString()) 18 | } 19 | } 20 | 21 | function waitForModule(moduleName) { 22 | return new Promise(resolve => { 23 | const interval = setInterval(() => { 24 | const module = Process.findModuleByName(moduleName); 25 | if (module != null) { 26 | clearInterval(interval); 27 | resolve(module); 28 | } 29 | }, 300); 30 | }); 31 | } 32 | 33 | function logger(message) { 34 | console.log(message); 35 | Java.perform(function () { 36 | var Log = Java.use("android.util.Log"); 37 | Log.v("INSTAGRAM_SSL_PINNING_BYPASS", message); 38 | }); 39 | } 40 | 41 | 42 | logger("[*][*] Waiting for libliger..."); 43 | waitForModule("libliger.so").then((lib) => { 44 | logger(`[*][+] Found libliger at: ${lib.base}`) 45 | hook_proxygen_SSLVerification(lib); 46 | }); 47 | 48 | //Universal Android SSL Pinning Bypass #2 49 | Java.perform(function () { 50 | try { 51 | var array_list = Java.use("java.util.ArrayList"); 52 | var ApiClient = Java.use('com.android.org.conscrypt.TrustManagerImpl'); 53 | if (ApiClient.checkTrustedRecursive) { 54 | logger("[*][+] Hooked checkTrustedRecursive") 55 | ApiClient.checkTrustedRecursive.implementation = function (a1, a2, a3, a4, a5, a6) { 56 | var k = array_list.$new(); 57 | return k; 58 | } 59 | } else { 60 | logger("[*][-] checkTrustedRecursive not Found") 61 | } 62 | } catch(e) { 63 | logger("[*][-] Failed to hook checkTrustedRecursive") 64 | } 65 | }); -------------------------------------------------------------------------------- /src/Frida-Seccomp/multi_frida_seccomp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import codecs 3 | import frida 4 | import sys 5 | import os 6 | import time 7 | import subprocess 8 | import threading 9 | 10 | package_name = sys.argv[1] 11 | jscode = open("./handleSeccomp.js").read() 12 | dir_path = "" 13 | 14 | device = frida.get_device_manager().enumerate_devices()[-1] 15 | print(device) 16 | 17 | pending = [] 18 | sessions = [] 19 | scripts = [] 20 | event = threading.Event() 21 | 22 | def on_spawned(spawn): 23 | print('on_spawned:', spawn) 24 | pending.append(spawn) 25 | event.set() 26 | 27 | def spawn_added(spawn): 28 | event.set() 29 | if(spawn.identifier.startswith(package_name)): 30 | print('spawn_added:', spawn) 31 | session = device.attach(spawn.pid) 32 | subprocess.Popen(args="adb logcat --pid={} | grep seccomp > {}/{}_{}.log".format(spawn.pid, dir_path, package_name, spawn.pid), stdin=None, stdout=None,stderr=None, shell=True) 33 | script = session.create_script(jscode) 34 | script.on('message', on_message) 35 | script.load() 36 | device.resume(spawn.pid) 37 | 38 | def spawn_removed(spawn): 39 | print('spawn_added:', spawn) 40 | event.set() 41 | 42 | def on_message(spawn, message, data): 43 | print('on_message:', spawn, message, data) 44 | 45 | def on_message(message, data): 46 | if message['type'] == 'send': 47 | print("[*] {0}".format(message['payload'])) 48 | else: 49 | print(message) 50 | 51 | device.on('spawn-added', spawn_added) 52 | device.on('spawn-removed', spawn_removed) 53 | device.on('child-added', on_spawned) 54 | device.on('child-removed', on_spawned) 55 | device.on('process-crashed', on_spawned) 56 | device.on('output', on_spawned) 57 | device.on('uninjected', on_spawned) 58 | device.on('lost', on_spawned) 59 | device.enable_spawn_gating() 60 | event = threading.Event() 61 | print('Enabled spawn gating') 62 | 63 | pid = device.spawn([package_name]) 64 | dir_path = "{}_{}_{}".format(package_name ,pid,time.time()) 65 | os.makedirs(dir_path) 66 | session = device.attach(pid) 67 | print("[*] Attach Application {} pid:".format(package_name),pid) 68 | subprocess.Popen(args="adb logcat --pid={} | grep seccomp > {}/{}_{}.log".format(pid, dir_path, package_name, pid), stdin=None, stdout=None,stderr=None, shell=True) 69 | print("[*] Application onResume") 70 | script = session.create_script(jscode) 71 | script.on('message', on_message) 72 | print('[*] Running Frida-Seccomp') 73 | script.load() 74 | device.resume(pid) 75 | sys.stdin.read() -------------------------------------------------------------------------------- /src/utils/test_chalk.ts: -------------------------------------------------------------------------------- 1 | // import chalk from 'chalk'; 2 | 3 | // console.log(chalk.black('black:Hello world!')); 4 | // console.log(chalk.red('red:Hello world!')); 5 | // console.log(chalk.green('green:Hello world!')); 6 | // console.log(chalk.yellow('yellow:Hello world!')); 7 | // console.log(chalk.blue('blue:Hello world!')); 8 | // console.log(chalk.magenta('magenta:Hello world!')); 9 | // console.log(chalk.cyan('cyan:Hello world!')); 10 | // console.log(chalk.white('white:Hello world!')); 11 | // console.log(chalk.blackBright('blackBright:Hello world!')); 12 | // console.log(chalk.redBright('redBright:Hello world!')); 13 | // console.log(chalk.greenBright('greenBright:Hello world!')); 14 | // console.log(chalk.yellowBright('yellowBright:Hello world!')); 15 | // console.log(chalk.blueBright('blueBright:Hello world!')); 16 | // console.log(chalk.magentaBright('magentaBright:Hello world!')); 17 | // console.log(chalk.cyanBright('cyanBright:Hello world!')); 18 | // console.log(chalk.whiteBright('whiteBright:Hello world!')); 19 | 20 | // console.log(chalk.bgBlack('bgBlack:Hello world!')); 21 | // console.log(chalk.bgRed('bgRed:Hello world!')); 22 | // console.log(chalk.bgGreen('bgGreen:Hello world!')); 23 | // console.log(chalk.bgYellow('bgYellow:Hello world!')); 24 | // console.log(chalk.bgBlue('bgBlue:Hello world!')); 25 | // console.log(chalk.bgMagenta('bgMagenta:Hello world!')); 26 | // console.log(chalk.bgCyan('bgCyan:Hello world!')); 27 | // console.log(chalk.bgWhite('bgWhite:Hello world!')); 28 | // console.log(chalk.bgBlackBright('bgBlackBright:Hello world!')); 29 | // console.log(chalk.bgRedBright('bgRedBright:Hello world!')); 30 | // console.log(chalk.bgGreenBright('bgGreenBright:Hello world!')); 31 | // console.log(chalk.bgYellowBright('bgYellowBright:Hello world!')); 32 | // console.log(chalk.bgBlueBright('bgBlueBright:Hello world!')); 33 | // console.log(chalk.bgMagentaBright('bgMagentaBright:Hello world!')); 34 | // console.log(chalk.bgCyanBright('bgCyanBright:Hello world!')); 35 | // console.log(chalk.bgWhiteBright('bgWhiteBright:Hello world!')); 36 | 37 | // console.log(chalk.bold('bold:Hello world!')); 38 | // console.log(chalk.italic('italic:Hello world!')); 39 | // console.log(chalk.underline('underline:Hello world!')); 40 | // console.log(chalk.inverse('inverse:Hello world!')); 41 | // console.log(chalk.strikethrough('strikethrough:Hello world!')); 42 | // console.log(chalk.dim('dim:Hello world!')); 43 | // console.log(chalk.reset('reset:Hello world!')); 44 | // console.log(chalk.visible('visible:Hello world!')); 45 | // console.log(chalk.hidden('hidden:Hello world!')); 46 | -------------------------------------------------------------------------------- /src/cli.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { program } from "commander"; 4 | import * as compiler from "./compiler.js"; 5 | import fs from "fs"; 6 | import fsPath from "path"; 7 | import { getNodeSystem } from "./system/node.js"; 8 | import ts from "../ext/typescript.js"; 9 | 10 | function main() { 11 | program 12 | .usage("[options] ") 13 | .requiredOption("-o, --output ", "write output to ") 14 | .option("-w, --watch", "watch for changes and recompile") 15 | .option("-S, --no-source-maps", "omit source-maps") 16 | .option("-c, --compress", "compress using terser"); 17 | 18 | program.parse(); 19 | 20 | const opts = program.opts(); 21 | const projectRoot: string = process.cwd(); 22 | const entrypoint: string = program.args[0]; 23 | const outputPath: string = opts.output; 24 | 25 | const fullOutputPath = fsPath.isAbsolute(outputPath) ? outputPath : fsPath.join(projectRoot, outputPath); 26 | const outputDir = fsPath.dirname(fullOutputPath); 27 | 28 | const system = getNodeSystem(); 29 | const assets = compiler.queryDefaultAssets(projectRoot, system); 30 | 31 | const compilerOpts: compiler.Options = { 32 | projectRoot, 33 | entrypoint, 34 | sourceMaps: opts.sourceMaps ? "included" : "omitted", 35 | compression: opts.compress ? "terser" : "none", 36 | assets, 37 | system 38 | }; 39 | 40 | if (opts.watch) { 41 | compiler.watch(compilerOpts) 42 | .on("bundleUpdated", writeBundle); 43 | } else { 44 | const bundle = compiler.build({ 45 | ...compilerOpts, onDiagnostic({ 46 | file, 47 | start, 48 | messageText 49 | }) { 50 | if (file !== undefined) { 51 | const { line, character } = ts.getLineAndCharacterOfPosition(file, start!); 52 | const message = ts.flattenDiagnosticMessageText(messageText, "\n"); 53 | console.log(`${file.fileName} (${line + 1},${character + 1}): ${message}`); 54 | } else { 55 | console.log(ts.flattenDiagnosticMessageText(messageText, "\n")); 56 | } 57 | } 58 | }); 59 | writeBundle(bundle); 60 | } 61 | 62 | function writeBundle(bundle: string): void { 63 | fs.mkdirSync(outputDir, { recursive: true }); 64 | fs.writeFileSync(fullOutputPath, bundle!); 65 | } 66 | } 67 | 68 | try { 69 | main(); 70 | } catch (e) { 71 | console.error(e); 72 | process.exitCode = 1; 73 | } 74 | -------------------------------------------------------------------------------- /src/so/init_array.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | export function init_array() { 3 | if (Process.pointerSize == 4) { 4 | var linker = Process.findModuleByName("linker"); 5 | } else { 6 | var linker = Process.findModuleByName("linker64"); 7 | } 8 | 9 | var addr_call_function =null; 10 | var addr_g_ld_debug_verbosity = null; 11 | var addr_async_safe_format_log = null; 12 | if (linker) { 13 | //console.log("found linker"); 14 | var symbols = linker.enumerateSymbols(); 15 | for (var i = 0; i < symbols.length; i++) { 16 | var name = symbols[i].name; 17 | if (name.indexOf("call_function") >= 0){ 18 | addr_call_function = symbols[i].address; 19 | // console.log("call_function",JSON.stringify(symbols[i])); 20 | } 21 | else if(name.indexOf("g_ld_debug_verbosity") >=0){ 22 | addr_g_ld_debug_verbosity = symbols[i].address; 23 | 24 | ptr(addr_g_ld_debug_verbosity).writeInt(2); 25 | 26 | } else if(name.indexOf("async_safe_format_log") >=0 && name.indexOf('va_list') < 0){ 27 | // console.log("async_safe_format_log",JSON.stringify(symbols[i])); 28 | addr_async_safe_format_log = symbols[i].address; 29 | 30 | } 31 | 32 | } 33 | } 34 | if(addr_async_safe_format_log){ 35 | Interceptor.attach(addr_async_safe_format_log,{ 36 | onEnter: function(args){ 37 | this.log_level = args[0]; 38 | this.tag = ptr(args[1]).readCString() 39 | this.fmt = ptr(args[2]).readCString() 40 | if(this.fmt.indexOf("c-tor") >= 0 && this.fmt.indexOf('Done') < 0){ 41 | this.function_type = ptr(args[3]).readCString(), // func_type 42 | this.so_path = ptr(args[5]).readCString(); 43 | var strs = new Array(); //定义一数组 44 | strs = this.so_path.split("/"); //字符分割 45 | this.so_name = strs.pop(); 46 | this.func_offset = ptr(args[4]).sub(Module.findBaseAddress(this.so_name)) 47 | console.log("func_type:", this.function_type, 48 | '\nso_name:',this.so_name, 49 | '\nso_path:',this.so_path, 50 | '\nfunc_offset:',this.func_offset 51 | ); 52 | // hook代码在这加 53 | } 54 | }, 55 | onLeave: function(retval){ 56 | } 57 | }) 58 | } 59 | 60 | 61 | } 62 | // setTimeout(init_array) -------------------------------------------------------------------------------- /src/so/dump_so.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import frida 3 | import sys 4 | import os 5 | 6 | 7 | def fix_so(arch, origin_so_name, so_name, base, size): 8 | if arch == "arm": 9 | os.system("adb push android/SoFixer32 /data/local/tmp/SoFixer") 10 | elif arch == "arm64": 11 | os.system("adb push android/SoFixer64 /data/local/tmp/SoFixer") 12 | os.system("adb shell chmod +x /data/local/tmp/SoFixer") 13 | os.system("adb push " + so_name + " /data/local/tmp/" + so_name) 14 | print("adb shell /data/local/tmp/SoFixer -m " + base + " -s /data/local/tmp/" + so_name + " -o /data/local/tmp/" + so_name + ".fix.so") 15 | os.system("adb shell /data/local/tmp/SoFixer -m " + base + " -s /data/local/tmp/" + so_name + " -o /data/local/tmp/" + so_name + ".fix.so") 16 | os.system("adb pull /data/local/tmp/" + so_name + ".fix.so " + origin_so_name + "_" + base + "_" + str(size) + "_fix.so") 17 | os.system("adb shell rm /data/local/tmp/" + so_name) 18 | os.system("adb shell rm /data/local/tmp/" + so_name + ".fix.so") 19 | os.system("adb shell rm /data/local/tmp/SoFixer") 20 | 21 | return origin_so_name + "_" + base + "_" + str(size) + "_fix.so" 22 | 23 | 24 | def read_frida_js_source(): 25 | with open("dump_so.js", "r") as f: 26 | return f.read() 27 | 28 | def on_message(message, data): 29 | pass 30 | 31 | if __name__ == "__main__": 32 | device: frida.core.Device = frida.get_usb_device() 33 | #重新连接设备 34 | print(device.get_frontmost_application()) 35 | pid = device.get_frontmost_application().pid 36 | session: frida.core.Session = device.attach(pid) 37 | script = session.create_script(read_frida_js_source()) 38 | script.on('message', on_message) 39 | script.load() 40 | 41 | if len(sys.argv) < 2: 42 | allmodule = script.exports.allmodule() 43 | for module in allmodule: 44 | print(module["name"]) 45 | else: 46 | origin_so_name = sys.argv[1] 47 | module_info = script.exports.findmodule(origin_so_name) 48 | print(module_info) 49 | base = module_info["base"] 50 | size = module_info["size"] 51 | module_buffer = script.exports.dumpmodule(origin_so_name) 52 | if module_buffer != -1: 53 | dump_so_name = origin_so_name + ".dump.so" 54 | with open(dump_so_name, "wb") as f: 55 | f.write(module_buffer) 56 | f.close() 57 | arch = script.exports.arch() 58 | fix_so_name = fix_so(arch, origin_so_name, dump_so_name, base, size) 59 | 60 | print(fix_so_name) 61 | os.remove(dump_so_name) 62 | 63 | -------------------------------------------------------------------------------- /src/ios/万能http-ssl-tls抓包frida脚本(ios).js: -------------------------------------------------------------------------------- 1 | // Convert a byte array to a hex string 2 | function bytesToHex(pointer, len) { 3 | console.log("point: " + pointer + " len: " + len) 4 | if (len === 0 || pointer.toInt32() === 0) { 5 | return "" 6 | } 7 | pointer = new NativePointer(pointer) 8 | for (var hex = [], i = 0; i < len; i++) { 9 | // console.log("+++++++++" + pointer.add(i).readU8()) 10 | var ch = pointer.add(i).readU8() 11 | hex.push((ch >>> 4).toString(16)); 12 | hex.push((ch & 0xF).toString(16)); 13 | } 14 | return hex.join(""); 15 | } 16 | 17 | 18 | function HookOpensslEvp() { 19 | let FBSharedFramework = Module.getBaseAddress("FBSharedFramework") 20 | console.log(`FBSharedFramework : ${FBSharedFramework}`) 21 | var EVP_EncryptUpdate = FBSharedFramework.add(0xB3AC8); 22 | var EVP_EncryptFinal_ex = FBSharedFramework.add(0xB4104); 23 | var EVP_DecryptUpdate = FBSharedFramework.add(0xB1B54); 24 | var EVP_DecryptFinal_ex = FBSharedFramework.add(0xB25B0); 25 | 26 | //encode 27 | Interceptor.attach(EVP_EncryptUpdate, { 28 | onEnter: function (args) { 29 | // console.log("on EVP_EncryptUpdate") 30 | console.log("send: " + bytesToHex(args[3], args[4].toInt32())) 31 | }, 32 | onLeave: function (ret) { 33 | // console.log("on EVP_EncryptUpdate exit") 34 | return 1 35 | } 36 | }); 37 | 38 | Interceptor.attach(EVP_EncryptFinal_ex, { 39 | onEnter: function (args) { 40 | // console.log("on EVP_EncryptFinal_ex") 41 | console.log("send: " + bytesToHex(args[1], args[2].readInt())) 42 | }, 43 | onLeave: function (ret) { 44 | // console.log("on EVP_EncryptFinal_ex exit") 45 | return 1 46 | } 47 | }); 48 | 49 | //decode 50 | Interceptor.attach(EVP_DecryptUpdate, { 51 | onEnter: function (args) { 52 | // console.log("on EVP_DecryptUpdate") 53 | this.a1 = args[1] 54 | this.a2 = args[2] 55 | }, 56 | onLeave: function (ret) { 57 | if (this.a1.toInt32() !== 0) { 58 | console.log("recv: " + bytesToHex(this.a1, this.a2.readInt())) 59 | } 60 | // console.log("on EVP_DecryptUpdate exit") 61 | } 62 | }); 63 | 64 | Interceptor.attach(EVP_DecryptFinal_ex, { 65 | onEnter: function (args) { 66 | // console.log("on EVP_DecryptFinal_ex") 67 | this.a1 = args[1] 68 | this.a2 = args[2] 69 | }, 70 | onLeave: function (ret) { 71 | console.log("recv: " + bytesToHex(this.a1, this.a2.readInt())) 72 | // console.log("on EVP_DecryptFinal_ex exit") 73 | } 74 | }); 75 | } 76 | 77 | HookOpensslEvp() -------------------------------------------------------------------------------- /src/so/BufferUtils.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | // src/utils/buffer.ts 3 | import { log } from "../utils/log.js"; 4 | 5 | interface HexdumpOptions { 6 | showTotal?: boolean; 7 | showAscii?: boolean; 8 | bytesPerLine?: number; 9 | } 10 | 11 | export function hexdumpAdvanced(buffer: any, length: number=500, options: HexdumpOptions = {}) { 12 | const { 13 | showTotal = true, 14 | showAscii = true, 15 | bytesPerLine = 16 16 | } = options; 17 | 18 | let output = ''; 19 | 20 | if (showTotal) { 21 | output += `Total length: ${length} (0x${length.toString(16)})\n`; 22 | } 23 | 24 | // 判断buffer是否为空 25 | if (!buffer) { 26 | log('Buffer is null'); 27 | return; 28 | } 29 | 30 | output += 'Offset | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F'; 31 | if (showAscii) output += ' | ASCII'; 32 | output += '\n' + '-'.repeat(showAscii ? 75 : 58) + '\n'; 33 | 34 | for (let i = 0; i < length; i += bytesPerLine) { 35 | output += `${i.toString(16).padStart(8, '0')} | `; 36 | 37 | let hexPart = ''; 38 | let asciiPart = ''; 39 | 40 | for (let j = 0; j < bytesPerLine; j++) { 41 | if (i + j < length) { 42 | const byte = buffer.add(i + j).readU8(); 43 | hexPart += `${byte.toString(16).padStart(2, '0')} `; 44 | 45 | if (showAscii) { 46 | const char = (byte >= 32 && byte <= 126) ? String.fromCharCode(byte) : '.'; 47 | asciiPart += char; 48 | } 49 | 50 | if (j === 7) hexPart += ' '; 51 | } else { 52 | hexPart += ' '; 53 | if (j === 7) hexPart += ' '; 54 | if (showAscii) asciiPart += ' '; 55 | } 56 | } 57 | 58 | log(output + hexPart + (showAscii ? `| ${asciiPart}` : '')); 59 | output = ''; 60 | } 61 | } 62 | 63 | export function hexdumpAsciiOnly(buffer: any, length: number = 500) { 64 | try{ 65 | let result = ''; 66 | 67 | for (let i = 0; i < length; i++) { 68 | const byte = buffer.add(i).readU8(); 69 | // 只获取可打印的 ASCII 字符 70 | if (byte >= 32 && byte <= 126) { 71 | result += String.fromCharCode(byte); 72 | } 73 | } 74 | 75 | // 输出结果 76 | log(result); 77 | return result; 78 | 79 | }catch(e){ 80 | return ""; 81 | } 82 | 83 | // 如果你需要返回结果而不是直接打印 84 | } 85 | 86 | /** 87 | * 将字节数组转换为十六进制字符串 88 | * @param bytes - 字节数组 89 | * @returns 十六进制字符串 90 | */ 91 | export function toHex(bytes: any) { 92 | let hex = ''; 93 | for (let i = 0; i < bytes.length; i++) { 94 | let byte = bytes[i] & 0xff; 95 | hex += ('0' + byte.toString(16)).slice(-2) -------------------------------------------------------------------------------- /src/jni/all_jni.js: -------------------------------------------------------------------------------- 1 | /* 2 | frida14 3 | 仅在Android 8.1下测试成功,其他版本可能需要重新修改适配 4 | 原作者: Simp1er 5 | */ 6 | const STD_STRING_SIZE = 3 * Process.pointerSize; 7 | 8 | class StdString { 9 | constructor() { 10 | this.handle = Memory.alloc(STD_STRING_SIZE); 11 | } 12 | 13 | dispose() { 14 | const [data, isTiny] = this._getData(); 15 | if (!isTiny) { 16 | Java.api.$delete(data); 17 | } 18 | } 19 | 20 | disposeToString() { 21 | const result = this.toString(); 22 | this.dispose(); 23 | return result; 24 | } 25 | 26 | toString() { 27 | const [data] = this._getData(); 28 | return data.readUtf8String(); 29 | } 30 | 31 | _getData() { 32 | const str = this.handle; 33 | const isTiny = (str.readU8() & 1) === 0; 34 | const data = isTiny ? str.add(1) : str.add(2 * Process.pointerSize).readPointer(); 35 | return [data, isTiny]; 36 | } 37 | } 38 | 39 | 40 | function prettyMethod(method_id, withSignature) { 41 | const result = new StdString(); 42 | Java.api['art::ArtMethod::PrettyMethod'](result, method_id, withSignature ? 1 : 0); 43 | return result.disposeToString(); 44 | } 45 | 46 | function readStdString(str) { 47 | if ((str.readU8() & 1) === 1) { // size LSB (=1) indicates if it's a long string 48 | return str.add(2 * Process.pointerSize).readPointer().readUtf8String(); 49 | } 50 | return str.add(1).readUtf8String(); 51 | } 52 | 53 | function attach(addr) { 54 | Interceptor.attach(addr, { 55 | onEnter: function (args) { 56 | this.arg0 = args[0]; // this 57 | }, 58 | onLeave: function (retval) { 59 | var modulemap = new ModuleMap() 60 | modulemap.update() 61 | var module = modulemap.find(retval) 62 | // var string = Memory.alloc(0x100) 63 | // ArtMethod_PrettyMethod(string, this.arg0, 1) 64 | if (module != null) { 65 | console.log('<' + module.name + '> method_name =>', 66 | prettyMethod(this.arg0, 1), 67 | ',offset=>', ptr(retval).sub(module.base), ',module_name=>', module.name) 68 | } else { 69 | console.log(' method_name =>', readStdString(string), ', addr =>', ptr(retval)) 70 | } 71 | } 72 | }); 73 | } 74 | 75 | function hook_RegisterNative() { 76 | var libart = Process.findModuleByName('libart.so') 77 | var symbols = libart.enumerateSymbols() 78 | for (var i = 0; i < symbols.length; i++) { 79 | if (symbols[i].name.indexOf('RegisterNative') > -1 && symbols[i].name.indexOf('ArtMethod') > -1 && symbols[i].name.indexOf('RuntimeCallbacks') < 0) { 80 | //art::RuntimeCallbacks::RegisterNativeMethod(art::ArtMethod*, void const*, void**) 81 | attach(symbols[i].address) 82 | } 83 | } 84 | 85 | } 86 | 87 | function main() { 88 | hook_RegisterNative() 89 | } 90 | 91 | setImmediate(main) -------------------------------------------------------------------------------- /src/socket/frida-trace_close.js: -------------------------------------------------------------------------------- 1 | // //@ts-nocheck 2 | // /* 3 | // * Auto-generated by Frida. Please modify to match the signature of close. 4 | // * This stub is currently auto-generated from manpages when available. 5 | // * 6 | // * For full API reference, see: https://frida.re/docs/javascript-api/ 7 | // */ 8 | // { 9 | // /** 10 | // * Called synchronously when about to call close. 11 | // * 12 | // * @this {object} - Object allowing you to store state for use in onLeave. 13 | // * @param {function} log - Call this function with a string to be presented to the user. 14 | // * @param {array} args - Function arguments represented as an array of NativePointer objects. 15 | // * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8. 16 | // * It is also possible to modify arguments by assigning a NativePointer object to an element of this array. 17 | // * @param {object} state - Object allowing you to keep state across function calls. 18 | // * Only one JavaScript function will execute at a time, so do not worry about race-conditions. 19 | // * However, do not use this to store function arguments across onEnter/onLeave, but instead 20 | // * use "this" which is an object for keeping state local to an invocation. 21 | // */ 22 | // onEnter(log, args, state) { 23 | // const sockfd = args[0].toInt32(); 24 | // const socktype = Socket.type(sockfd); 25 | // if (!socktype || socktype !== "tcp") return; 26 | // const sockLocal = Socket.localAddress(sockfd) 27 | // const tcpEpLocal = sockLocal && sockLocal.ip ? sockLocal : null 28 | // const sockRemote = Socket.peerAddress(sockfd) 29 | // const tcpEpRemote = sockRemote && sockRemote.ip ? sockRemote : null 30 | // if (tcpEpLocal !== null) { 31 | // log("[*] TcpEpLocal addr: " + tcpEpLocal.ip + " ,port: " + tcpEpLocal.port + " ,lr: " + this.context.lr + " ,path: " + new ModuleMap().find(ptr(this.context.lr)).path); 32 | // } 33 | // if (tcpEpRemote != null) { 34 | // log("[*] TcpEpRemote addr: " + tcpEpRemote.ip + " ,port: " + tcpEpRemote.port + " ,lr: " + this.context.lr + " ,path: " + new ModuleMap().find(ptr(this.context.lr)).path); 35 | // } 36 | // }, 37 | // 38 | // 39 | // /** 40 | // * Called synchronously when about to return from close. 41 | // * 42 | // * See onEnter for details. 43 | // * 44 | // * @this {object} - Object allowing you to access state stored in onEnter. 45 | // * @param {function} log - Call this function with a string to be presented to the user. 46 | // * @param {NativePointer} retval - Return value represented as a NativePointer object. 47 | // * @param {object} state - Object allowing you to keep state across function calls. 48 | // */ 49 | // onLeave(log, retval, state) {} 50 | // } 51 | -------------------------------------------------------------------------------- /src/r0capture/README.md: -------------------------------------------------------------------------------- 1 | # r0capture 2 | 3 | 安卓应用层抓包通杀脚本 4 | 5 | ## 简介 6 | 7 | - 仅限安卓平台,测试安卓7、8、9、10、11、12、13 可用 ; 8 | - 无视所有证书校验或绑定,不用考虑任何证书的事情; 9 | - 通杀TCP/IP四层模型中的应用层中的全部协议; 10 | - 通杀协议包括:Http,WebSocket,Ftp,Xmpp,Imap,Smtp,Protobuf等等、以及它们的SSL版本; 11 | - 通杀所有应用层框架,包括HttpUrlConnection、Okhttp1/3/4、Retrofit/Volley等等; 12 | - 无视加固,不管是整体壳还是二代壳或VMP,不用考虑加固的事情; 13 | - 如果有抓不到的情况欢迎提issue,或者直接加vx:r0ysue,进行反馈~ 14 | 15 | ### June.18th 2023 update:测试Pixel4/安卓13/KernelSU/Frida16 功能工作正常 正常抓包 导出证书 16 | 17 | ### January.14th 2021 update:增加几个辅助功能 18 | 19 | - 增加App收发包函数定位功能 20 | - 增加App客户端证书导出功能 21 | - 新增host连接方式“-H”,用于Frida-server监听在非标准端口时的连接 22 | 23 | ## 用法 24 | 25 | - 推荐环境:[https://github.com/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/A01/README.md](https://github.com/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/A01/README.md) 26 | 27 | 切记仅限安卓平台7、8、9、10、11 可用 ,禁止使用模拟器。 28 | 29 | - Spawn 模式: 30 | 31 | `$ python3 r0capture.py -U -f com.coolapk.market -v` 32 | 33 | - Attach 模式,抓包内容保存成pcap文件供后续分析: 34 | 35 | `$ python3 r0capture.py -U 酷安 -v -p iqiyi.pcap` 36 | 37 | 建议使用`Attach`模式,从感兴趣的地方开始抓包,并且保存成`pcap`文件,供后续使用Wireshark进行分析。 38 | > 老版本Frida使用包名,新版本Frida使用APP名。APP名必须是点开app后,frida-ps -U显示的那个app名字。 39 | 40 | ![](pic/Sample.PNG) 41 | 42 | - 收发包函数定位:`Spawn`和`attach`模式均默认开启; 43 | 44 | > 可以使用`python r0capture.py -U -f cn.soulapp.android -v >> soul3.txt`这样的命令将输出重定向至txt文件中稍后过滤内容 45 | 46 | ![](pic/locator.png) 47 | 48 | - 客户端证书导出功能:默认开启;必须以Spawm模式运行; 49 | 50 | > 运行脚本之前必须手动给App加上存储卡读写权限; 51 | 52 | > 并不是所有App都部署了服务器验证客户端的机制,只有配置了的才会在Apk中包含客户端证书 53 | 54 | > 导出后的证书位于/sdcard/Download/包名xxx.p12路径,导出多次,每一份均可用,密码默认为:r0ysue,推荐使用[keystore-explorer](http://keystore-explorer.org/)打开查看证书。 55 | 56 | ![](pic/clientcer.png) 57 | 58 | - 新增host连接方式“-H”,用于Frida-server监听在非标准端口时的连接。有些App会检测Frida标准端口,因此frida-server开在非标准端口可以绕过检测。 59 | 60 | ![](pic/difport.png) 61 | 62 | ## 感谢[爱吃菠菜](https://bbs.pediy.com/user-760871.htm)巨巨总结的本项目知识点 63 | 64 | ![](pic/summary1.jpg) 65 | ![](pic/summary2.jpg) 66 | 67 | 68 | PS: 69 | 70 | > 这个项目基于[frida_ssl_logger](https://github.com/BigFaceCat2017/frida_ssl_logger),之所以换个名字,只是侧重点不同。 原项目的侧重点在于抓ssl和跨平台,本项目的侧重点是抓到所有的包。 71 | 72 | > 局限:部分开发实力过强的大厂或框架,采用的是自身的SSL框架,比如WebView、小程序或Flutter,这部分目前暂未支持。部分融合App本质上已经不属于安卓App,没有使用安卓系统的框架,无法支持。当然这部分App也是少数。暂不支持HTTP/2、或HTTP/3,该部分API在安卓系统上暂未普及或布署,为App自带,无法进行通用hook。各种模拟器架构、实现、环境较为复杂,建议珍爱生命、使用真机。暂未添加多进程支持,比如:service或:push等子进程,可以使用Frida的Child-gating来支持一下。支持多进程之后要考虑pcap文件的写入锁问题,可以用frida-tool的Reactor线程锁来支持一下。 73 | 74 | ## 以下是原项目的简介: 75 | 76 | [https://github.com/BigFaceCat2017/frida_ssl_logger](https://github.com/BigFaceCat2017/frida_ssl_logger) 77 | 78 | ### frida_ssl_logger 79 | ssl_logger based on frida 80 | for from https://github.com/google/ssl_logger 81 | 82 | ### 修改内容 83 | 1. 优化了frida的JS脚本,修复了在新版frida上的语法错误; 84 | 2. 调整JS脚本,使其适配iOS和macOS,同时也兼容了Android; 85 | 3. 增加了更多的选项,使其能在多种情况下使用; 86 | 87 | ### 安装依赖 88 | ``` 89 | Python版本>=3.6 90 | pip install loguru 91 | pip install click 92 | ``` 93 | ### Usage 94 | ```shell 95 | python3 ./ssl_logger.py -U -f com.bfc.mm 96 | python3 ./ssl_logger.py -v -p test.pcap 6666 97 | ```` 98 | 99 | -------------------------------------------------------------------------------- /src/cert/trust_cert.js: -------------------------------------------------------------------------------- 1 | /* 2 | Android SSL Re-pinning frida script v0.2 030417-pier 3 | $ adb push burpca-cert-der.crt /data/local/tmp/cert-der.crt 4 | $ frida -U -f it.app.mobile -l frida-android-repinning.js --no-pause 5 | https://techblog.mediaservice.net/2017/07/universal-android-ssl-pinning-bypass-with-frida/ 6 | UPDATE 20191605: Fixed undeclared var. Thanks to @oleavr and @ehsanpc9999 ! 7 | */ 8 | setTimeout(function () { 9 | Java.perform(function () { 10 | console.log(""); 11 | console.log("[.] Cert Pinning Bypass/Re-Pinning"); 12 | var CertificateFactory = Java.use("java.security.cert.CertificateFactory"); 13 | var FileInputStream = Java.use("java.io.FileInputStream"); 14 | var BufferedInputStream = Java.use("java.io.BufferedInputStream"); 15 | var X509Certificate = Java.use("java.security.cert.X509Certificate"); 16 | var KeyStore = Java.use("java.security.KeyStore"); 17 | var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory"); 18 | var SSLContext = Java.use("javax.net.ssl.SSLContext"); 19 | // Load CAs from an InputStream 20 | console.log("[+] Loading our CA...") 21 | var cf = CertificateFactory.getInstance("X.509"); 22 | try { 23 | var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt"); 24 | } catch (err) { 25 | console.log("[o] " + err); 26 | } 27 | var bufferedInputStream = BufferedInputStream.$new(fileInputStream); 28 | var ca = cf.generateCertificate(bufferedInputStream); 29 | bufferedInputStream.close(); 30 | var certInfo = Java.cast(ca, X509Certificate); 31 | console.log("[o] Our CA Info: " + certInfo.getSubjectDN()); 32 | // Create a KeyStore containing our trusted CAs 33 | console.log("[+] Creating a KeyStore for our CA..."); 34 | var keyStoreType = KeyStore.getDefaultType(); 35 | var keyStore = KeyStore.getInstance(keyStoreType); 36 | keyStore.load(null, null); 37 | keyStore.setCertificateEntry("ca", ca); 38 | // Create a TrustManager that trusts the CAs in our KeyStore 39 | console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore..."); 40 | var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); 41 | var tmf = TrustManagerFactory.getInstance(tmfAlgorithm); 42 | tmf.init(keyStore); 43 | console.log("[+] Our TrustManager is ready..."); 44 | console.log("[+] Hijacking SSLContext methods now...") 45 | console.log("[-] Waiting for the app to invoke SSLContext.init()...") 46 | SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function (a, b, c) { 47 | console.log("[o] App invoked javax.net.ssl.SSLContext.init..."); 48 | SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c); 49 | console.log("[+] SSLContext initialized with our custom TrustManager!"); 50 | } 51 | }); 52 | }, 0); -------------------------------------------------------------------------------- /src/copy/so/find_func_from_symbols.js: -------------------------------------------------------------------------------- 1 | function antiAntiFrida() { 2 | var strstr = Module.findExportByName(null, "strstr"); 3 | if (null !== strstr) { 4 | Interceptor.attach(strstr, { 5 | onEnter: function (args) { 6 | this.frida = Boolean(0); 7 | 8 | this.haystack = args[0]; 9 | this.needle = args[1]; 10 | 11 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 12 | if (this.haystack.readCString().indexOf("frida") !== -1 || 13 | this.needle.readCString().indexOf("frida") !== -1 || 14 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 15 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 16 | this.haystack.readCString().indexOf("gmain") !== -1 || 17 | this.needle.readCString().indexOf("gmain") !== -1 || 18 | this.haystack.readCString().indexOf("linjector") !== -1 || 19 | this.needle.readCString().indexOf("linjector") !== -1) { 20 | this.frida = Boolean(1); 21 | } 22 | } 23 | }, 24 | onLeave: function (retval) { 25 | if (this.frida) { 26 | retval.replace(ptr("0x0")); 27 | } 28 | 29 | } 30 | }) 31 | } 32 | } 33 | setImmediate(antiAntiFrida) 34 | 35 | function main() { 36 | var randombytes_buf_addr = null; 37 | var symbols = Process.findModuleByName("libart.so").enumerateSymbols(); 38 | for (var i in symbols) { 39 | var symbol = symbols[i]; 40 | if (symbol.name.indexOf("art") >= 0 && 41 | symbol.name.indexOf("JNI") >= 0 && 42 | symbol.name.indexOf("CheckJNI") < 0 43 | ){ 44 | if (symbol.name.indexOf("randombytes_buf") >= 0) { 45 | console.log("find target symbols", symbol.name, "address is ", symbol.address); 46 | randombytes_buf_addr = symbol.address; 47 | } 48 | } 49 | } 50 | 51 | console.log("randombytes_buf_addr is ", randombytes_buf_addr); 52 | 53 | Interceptor.attach(randombytes_buf_addr, { 54 | onEnter: function (args) { 55 | console.log("args0",args[0]) 56 | console.log("args0", args[0], hexdump(args[0])); 57 | console.log("args1", args[1], hexdump(args[1])); 58 | var env = Java.vm.tryGetEnv(); 59 | if (env != null) { 60 | // 直接读取 c 里面的 char 61 | console.log("Memory readCstring is :", Memory.readCString(args[1])); 62 | }else{ 63 | console.log("get env error"); 64 | } 65 | }, 66 | onLeave: function (returnResult) { 67 | console.log("result: ", Java.cast(returnResult, Java.use("java.lang.String"))); 68 | var env = Java.vm.tryGetEnv(); 69 | if (env != null) { 70 | var jstring = env.newStringUtf("修改返回值"); 71 | returnResult.replace(ptr(jstring)); 72 | } 73 | } 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /src/so/inlinehook.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | export function inline_hook(so_name, addr) { 3 | var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext"); 4 | if (android_dlopen_ext != null) { 5 | Interceptor.attach(android_dlopen_ext, { 6 | onEnter: function (args) { 7 | var soName = args[0].readCString(); 8 | if (soName.indexOf(so_name) != -1) { 9 | this.hook = true; 10 | } 11 | }, 12 | onLeave: function (retval) { 13 | if (this.hook) 14 | _inline_hook(so_name, addr) ; 15 | } 16 | }); 17 | } 18 | } 19 | export function _inline_hook(so_name, addr) { 20 | console.log('find so') 21 | var so_addr = Module.findBaseAddress(so_name) 22 | console.log('so_addr: ' + so_addr) 23 | var func = so_addr.add(addr) 24 | console.log("[+] Hooking function: " + func) 25 | 26 | Java.perform(function () { 27 | Interceptor.attach(func, { 28 | onEnter: function (args) { 29 | console.log('enter') 30 | // console.log(hexdump(this.context.PC)) 31 | // console.log("args[0] Intercepted: " + hexdump(args[0])) 32 | // console.log("args[0] Intercepted: " + readStdString(args[1])) 33 | // console.log("args[2] Intercepted: " + args[2]) 34 | // console.log("args[3] Intercepted: " + hexdump(args[3])) 35 | // console.log("args[4] Intercepted: " + hexdump(args[4])) 36 | // console.log("args[5] Intercepted: " + hexdump(args[5])) 37 | // console.log("args[6] Intercepted: " + hexdump(args[6])) 38 | // console.log("args[7] Intercepted: " + hexdump(args[7])) 39 | // console.log("args[8] Intercepted: " + hexdump(args[8])) 40 | // console.log("args[9] Intercepted: " + hexdump(args[9])) 41 | // console.log("args[10] Intercepted: " + hexdump(args[10])) 42 | // console.log("args[11] Intercepted: " + hexdump(args[11])) 43 | // console.log("args[12] Intercepted: " + hexdump(args[12])) 44 | console.log('*********************\nCCCryptorCreate called from:\n*********************' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'); 45 | }, 46 | onLeave: function (retval) { 47 | console.log("[+] Returned: " + hexdump(retval)) 48 | // console.log("retval is :", retval) 49 | return retval; 50 | } 51 | }) 52 | }) 53 | } 54 | 55 | function readStdString(str) { 56 | // console.log(Memory.readCString(str)); 57 | // console.log(Memory.readUtf8String(str)); 58 | return Memory.readUtf8String(str); 59 | } 60 | 61 | function print_dump(addr, size) { 62 | //console(Memory.methods()); 63 | var buf = Memory.readByteArray(addr, size) 64 | console.log("[function] send[*] " + addr.toString() + " " + "length: " + size.toString() + "\n[data]") 65 | console.log(hexdump(buf, { 66 | offset: 0, 67 | length: size, 68 | header: false, 69 | ansi: false 70 | })); 71 | console.log("") 72 | } -------------------------------------------------------------------------------- /src/copy/show-all-classes-methods.js: -------------------------------------------------------------------------------- 1 | // var className = class_loader.split('.')[class_loader.split('.').length - 1] 2 | // setTimeout(main, 10000) 3 | function main() { 4 | console.Blue("start"); 5 | Java.perform(function () { 6 | Java.enumerateClassLoaders({ 7 | onMatch: function (loader) { 8 | try { 9 | Java.classFactory.loader = loader; 10 | Java.enumerateLoadedClasses({ 11 | onMatch: function (class_name) { 12 | //输出所有类 13 | console.log(class_name) 14 | }, onComplete: function () { } 15 | }) 16 | } catch (e) { } 17 | }, 18 | onComplete: function () { 19 | } 20 | }); 21 | }) 22 | } 23 | 24 | (function () { 25 | let Color = { RESET: "\x1b[39;49;00m", Black: "0;01", Blue: "4;01", Cyan: "6;01", Gray: "7;11", "Green": "2;01", Purple: "5;01", Red: "1;01", Yellow: "3;01" }; 26 | let LightColor = { RESET: "\x1b[39;49;00m", Black: "0;11", Blue: "4;11", Cyan: "6;11", Gray: "7;01", "Green": "2;11", Purple: "5;11", Red: "1;11", Yellow: "3;11" }; 27 | var colorPrefix = '\x1b[3', colorSuffix = 'm' 28 | for (let c in Color) { 29 | if (c == "RESET") continue; 30 | console[c] = function (message) { 31 | console.log(colorPrefix + Color[c] + colorSuffix + message + Color.RESET); 32 | } 33 | console["Light" + c] = function (message) { 34 | console.log(colorPrefix + LightColor[c] + colorSuffix + message + Color.RESET); 35 | } 36 | } 37 | })(); 38 | 39 | function antiAntiFrida() { 40 | var strstr = Module.findExportByName(null, "strstr"); 41 | if (null !== strstr) { 42 | Interceptor.attach(strstr, { 43 | onEnter: function (args) { 44 | this.frida = Boolean(0); 45 | 46 | this.haystack = args[0]; 47 | this.needle = args[1]; 48 | 49 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 50 | if (this.haystack.readCString().indexOf("frida") !== -1 || 51 | this.needle.readCString().indexOf("frida") !== -1 || 52 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 53 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 54 | this.haystack.readCString().indexOf("gmain") !== -1 || 55 | this.needle.readCString().indexOf("gmain") !== -1 || 56 | this.haystack.readCString().indexOf("linjector") !== -1 || 57 | this.needle.readCString().indexOf("linjector") !== -1) { 58 | this.frida = Boolean(1); 59 | } 60 | } 61 | }, 62 | onLeave: function (retval) { 63 | if (this.frida) { 64 | retval.replace(ptr("0x0")); 65 | } 66 | 67 | } 68 | }) 69 | // console.log("anti anti-frida"); 70 | } 71 | } 72 | setImmediate(antiAntiFrida) 73 | 74 | var isLite = false; 75 | var ByPassTracerPid = function () { 76 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 77 | var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 78 | Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 79 | var retval = fgets(buffer, size, fp); 80 | var bufstr = Memory.readUtf8String(buffer); 81 | if (bufstr.indexOf("TracerPid:") > -1) { 82 | Memory.writeUtf8String(buffer, "TracerPid:\t0"); 83 | // console.log("tracerpid replaced: " + Memory.readUtf8String(buffer)); 84 | } 85 | return retval; 86 | }, 'pointer', ['pointer', 'int', 'pointer'])); 87 | }; 88 | setImmediate(ByPassTracerPid); -------------------------------------------------------------------------------- /src/java/myscript.js: -------------------------------------------------------------------------------- 1 | 2 | // setTimeout(main, 10000) 3 | main(); 4 | function main() { 5 | mtop() 6 | igw() 7 | } 8 | function mtop() { 9 | var class_loader1 = "anet.channel.session.HttpConnector"; 10 | var target_method1 = 'c' 11 | Java.perform(function () { 12 | Java.enumerateClassLoaders({ 13 | onMatch: function (loader) { 14 | try { 15 | if (loader.findClass(class_loader1)) { 16 | Java.classFactory.loader = loader; 17 | } 18 | } catch (e) { } 19 | }, 20 | onComplete: function () { 21 | } 22 | }); 23 | Java.enumerateLoadedClasses({ 24 | onMatch: function (class_name) { 25 | //输出所有类 26 | // console.log(className) 27 | if (class_name.toString().toLowerCase() === class_loader1.toLowerCase()) { 28 | try { 29 | var hook = Java.use(class_loader1); 30 | var overloads = hook[target_method1].overloads; 31 | for (var i = 0; i < overloads.length; i++) { 32 | overloads[i].implementation = function () { 33 | var url = arguments[0].j().toString(); 34 | if(url.indexOf("us-ummt.alibaba.com")>-1){ 35 | console.log("mtop:succuess") 36 | }else{ 37 | var retval = this[target_method1].apply(this, arguments); 38 | } 39 | return retval; 40 | } 41 | } 42 | } catch (e) { } 43 | } 44 | }, onComplete: function () { } 45 | }) 46 | 47 | }) 48 | } 49 | 50 | function igw(){ 51 | var class_loader2 = "com.alipay.a.a.a.a.l"; 52 | var target_method2 = 'call' 53 | Java.perform(function () { 54 | Java.enumerateClassLoaders({ 55 | onMatch: function (loader) { 56 | try { 57 | if (loader.findClass(class_loader2)) { 58 | Java.classFactory.loader = loader; 59 | } 60 | } catch (e) { } 61 | }, 62 | onComplete: function () { 63 | } 64 | }); 65 | Java.enumerateLoadedClasses({ 66 | onMatch: function (class_name) { 67 | //输出所有类 68 | // console.log(className) 69 | if (class_name.toString().toLowerCase() === class_loader2.toLowerCase()) { 70 | try { 71 | var hook = Java.use(class_loader2); 72 | var overloads = hook[target_method2].overloads; 73 | for (var i = 0; i < overloads.length; i++) { 74 | overloads[i].implementation = function () { 75 | console.log("igw:succuess") 76 | return null; 77 | } 78 | 79 | } 80 | } catch (e) { } 81 | } 82 | }, onComplete: function () { } 83 | }) 84 | 85 | }) 86 | } -------------------------------------------------------------------------------- /src/java/AeBanBi.js: -------------------------------------------------------------------------------- 1 | 2 | // setTimeout(main, 10000) 3 | main(); 4 | function main() { 5 | mtop() 6 | igw() 7 | } 8 | function mtop() { 9 | var class_loader1 = "anet.channel.session.HttpConnector"; 10 | var target_method1 = 'c' 11 | Java.perform(function () { 12 | Java.enumerateClassLoaders({ 13 | onMatch: function (loader) { 14 | try { 15 | if (loader.findClass(class_loader1)) { 16 | Java.classFactory.loader = loader; 17 | } 18 | } catch (e) { } 19 | }, 20 | onComplete: function () { 21 | } 22 | }); 23 | Java.enumerateLoadedClasses({ 24 | onMatch: function (class_name) { 25 | //输出所有类 26 | // console.log(className) 27 | if (class_name.toString().toLowerCase() === class_loader1.toLowerCase()) { 28 | try { 29 | var hook = Java.use(class_loader1); 30 | var overloads = hook[target_method1].overloads; 31 | for (var i = 0; i < overloads.length; i++) { 32 | overloads[i].implementation = function () { 33 | var url = arguments[0].j().toString(); 34 | if(url.indexOf("us-ummt.alibaba.com")>-1){ 35 | console.log("mtop:succuess") 36 | }else{ 37 | var retval = this[target_method1].apply(this, arguments); 38 | } 39 | return retval; 40 | } 41 | } 42 | } catch (e) { } 43 | } 44 | }, onComplete: function () { } 45 | }) 46 | 47 | }) 48 | } 49 | 50 | function igw(){ 51 | var class_loader2 = "com.alipay.a.a.a.a.l"; 52 | var target_method2 = 'call' 53 | Java.perform(function () { 54 | Java.enumerateClassLoaders({ 55 | onMatch: function (loader) { 56 | try { 57 | if (loader.findClass(class_loader2)) { 58 | Java.classFactory.loader = loader; 59 | } 60 | } catch (e) { } 61 | }, 62 | onComplete: function () { 63 | } 64 | }); 65 | Java.enumerateLoadedClasses({ 66 | onMatch: function (class_name) { 67 | //输出所有类 68 | // console.log(className) 69 | if (class_name.toString().toLowerCase() === class_loader2.toLowerCase()) { 70 | try { 71 | var hook = Java.use(class_loader2); 72 | var overloads = hook[target_method2].overloads; 73 | for (var i = 0; i < overloads.length; i++) { 74 | overloads[i].implementation = function () { 75 | console.log("igw:succuess") 76 | return null; 77 | } 78 | 79 | } 80 | } catch (e) { } 81 | } 82 | }, onComplete: function () { } 83 | }) 84 | 85 | }) 86 | } -------------------------------------------------------------------------------- /src/utils/log.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import {hexdumpAdvanced} from "../so/BufferUtils.js" 3 | 4 | export function log(message: string) { 5 | let colorCode; 6 | switch (Math.floor(Math.random() * 6)) { 7 | case 0: 8 | colorCode = '\x1b[31m'; // 红色 9 | break; 10 | case 1: 11 | colorCode = '\x1b[32m'; // 绿色 12 | break; 13 | case 2: 14 | colorCode = '\x1b[33m'; // 黄色 15 | break; 16 | case 3: 17 | colorCode = '\x1b[35m'; // 紫色 18 | break; 19 | case 4: 20 | colorCode = '\x1b[36m'; // 青色 21 | break; 22 | case 5: 23 | colorCode = '\x1b[37m'; // 白色 24 | break; 25 | default: 26 | colorCode = ''; 27 | break; 28 | } 29 | console.log(`${colorCode}${message}\x1b[0m`); 30 | } 31 | 32 | 33 | export function stacktrace_java(){ 34 | return Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()) 35 | } 36 | 37 | export function stacktrace_so(context){ 38 | return 'stacktrace_so called from:\n' +Thread.backtrace(context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'; 39 | } 40 | 41 | export function print_byte(byte){ 42 | var str = Java.use("java.lang.String").$new(byte); 43 | return str; 44 | } 45 | 46 | export function print_hashmap(map) { 47 | var result = ""; 48 | var HashMapNode = Java.use("java.util.HashMap$Node"); 49 | var iterator = map.entrySet().iterator(); 50 | while (iterator.hasNext()) { 51 | console.log("entry", iterator.next()); 52 | var entry = Java.cast(iterator.next(), HashMapNode); 53 | console.log(entry.getKey()); 54 | console.log(entry.getValue()); 55 | result += entry.getValue(); 56 | } 57 | 58 | console.log("result is :", result); 59 | 60 | return result 61 | } 62 | 63 | 64 | 65 | /** 66 | * 打印ARM64寄存器的值 67 | * @param {Array|null} regs - 要打印的寄存器数组,不传或null则打印全部 68 | * @param {number} length - hexdump的长度参数,默认为5000 69 | */ 70 | export function printRegisters(context,regs = null, length = 5000) { 71 | // 定义ARM64架构中的所有通用寄存器 72 | const allRegisters = [ 73 | "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 74 | "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 75 | "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", 76 | "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", "pc" 77 | ]; 78 | 79 | // 如果没有指定寄存器,则使用所有寄存器 80 | const registersToPrint = regs || allRegisters; 81 | 82 | // 遍历并打印每个寄存器的值 83 | for (let i = 0; i < registersToPrint.length; i++) { 84 | const reg = registersToPrint[i]; 85 | try { 86 | // 根据是否提供length参数,决定调用hexdump的方式 87 | if (length !== null) { 88 | log(reg + ":" + hexdump(context[reg], {length: length})); 89 | } else { 90 | log(reg + ":" + hexdump(context[reg])); 91 | } 92 | } catch (error) { 93 | log("无法打印寄存器 " + reg + ": " + error.message); 94 | } 95 | } 96 | } 97 | 98 | // 使用示例: 99 | 100 | // 1. 打印所有寄存器(默认长度5000) 101 | // printRegisters(); 102 | 103 | // 2. 只打印特定寄存器 104 | // printRegisters(["x0", "x1", "x2"]); 105 | 106 | // 3. 使用自定义长度打印特定寄存器 107 | // printRegisters(["x2", "x8"], 1000); 108 | 109 | // 4. 使用默认寄存器列表,但自定义长度 110 | // printRegisters(null, 2000); 111 | // 或者 112 | // printRegisters(undefined, 2000); 113 | -------------------------------------------------------------------------------- /src/child_gating.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import print_function 3 | 4 | import threading 5 | import time 6 | import frida 7 | from frida_tools.application import Reactor 8 | 9 | package = "com.mobilechess.gp" 10 | child_gating = package+":UnityKillsMe" 11 | script_path = "/home/thouger/Desktop/code/frida_script/frida_script/_agent.js" 12 | 13 | class Application(object): 14 | def __init__(self): 15 | self._stop_requested = threading.Event() 16 | self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait()) 17 | 18 | # self._device = frida.get_local_device() 19 | self._device = frida.get_usb_device() 20 | self._sessions = set() 21 | 22 | self._device.on("child-added", lambda child: self._reactor.schedule(lambda: self._on_child_added(child))) 23 | self._device.on("child-removed", lambda child: self._reactor.schedule(lambda: self._on_child_removed(child))) 24 | self._device.on("output", lambda pid, fd, data: self._reactor.schedule(lambda: self._on_output(pid, fd, data))) 25 | 26 | def run(self): 27 | self._reactor.schedule(lambda: self._start()) 28 | self._reactor.run() 29 | 30 | def _start(self): 31 | # argv = ["/system/bin/sh", "-c", "cat /etc/hosts"] 32 | # env = { 33 | # "BADGER": "badger-badger-badger", 34 | # "SNAKE": "mushroom-mushroom", 35 | # } 36 | # # print("✔ spawn(argv={})".format(argv)) 37 | # pid = self._device.spawn(argv, env=env, stdio='pipe') 38 | print("✔ spawn "+package) 39 | pid = self._device.spawn([child_gating]) 40 | self._instrument(pid) 41 | 42 | def _stop_if_idle(self): 43 | if len(self._sessions) == 0: 44 | self._stop_requested.set() 45 | 46 | def _instrument(self, pid): 47 | print("✔ attach(pid={})".format(pid)) 48 | session = self._device.attach(pid) 49 | session.on("detached", lambda reason: self._reactor.schedule(lambda: self._on_detached(pid, session, reason))) 50 | print("✔ enable_child_gating()") 51 | session.enable_child_gating() 52 | print("✔ create_script()") 53 | with open(script_path) as f: 54 | script = session.create_script(f.read()) 55 | script.on("message", lambda message, data: self._reactor.schedule(lambda: self._on_message(pid, message))) 56 | print("✔ load()") 57 | script.load() 58 | print("✔ resume(pid={})".format(pid)) 59 | self._device.resume(pid) 60 | # time.sleep(10) 61 | self._sessions.add(session) 62 | 63 | 64 | def _on_child_added(self, child): 65 | print("⚡ child_added: {}".format(child)) 66 | self._instrument(child.pid) 67 | 68 | def _on_child_removed(self, child): 69 | print("⚡ child_removed: {}".format(child)) 70 | 71 | def _on_output(self, pid, fd, data): 72 | print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data))) 73 | 74 | def _on_detached(self, pid, session, reason): 75 | print("⚡ detached: pid={}, reason='{}'".format(pid, reason)) 76 | self._sessions.remove(session) 77 | self._reactor.schedule(self._stop_if_idle, delay=0.5) 78 | 79 | def _on_message(self, pid, message): 80 | print("⚡ message: pid={}, payload={}".format(pid, message["payload"])) 81 | 82 | 83 | app = Application() 84 | app.run() 85 | -------------------------------------------------------------------------------- /src/java/findClass.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | import { log, print_hashmap, stacktrace } from "../utils/log.js"; 3 | import { _trace } from "./trace"; 4 | 5 | export function findClass(targetClass: string) { 6 | var hook = Java.use("dalvik.system.BaseDexClassLoader"); 7 | var classLoaderInit = "$init"; 8 | var overloadCount = hook[classLoaderInit].overloads.length; 9 | for (var i = 0; i < overloadCount; i++) { 10 | hook[classLoaderInit].overloads[i].implementation = function () { 11 | for (var j = 0; j < arguments.length; j++) { 12 | log("arg[" + j + "]: " + arguments[j] + " => " + JSON.stringify(arguments[j])); 13 | } 14 | var retval = this[classLoaderInit].apply(this, arguments); 15 | if(arguments[3] != null){ 16 | Java.classFactory.loader = arguments; 17 | var classNames = Java.enumerateLoadedClassesSync() 18 | for (let i = 0; i < classNames.length; i++) { 19 | log("class: " + classNames[i]) 20 | } 21 | // Java.enumerateLoadedClasses({ 22 | // onMatch: function (clazz) { 23 | // log(clazz+'---'+clazz.toLowerCase()) 24 | // if (clazz.indexOf(targetClass) >= 0) { 25 | // log('find target class: ' + clazz) 26 | // // _trace(clazz) 27 | // } 28 | // }, 29 | // onComplete: function () { 30 | // } 31 | // }); 32 | } 33 | // var suppressedExceptions = Java.use('java.util.ArrayList').$new(); 34 | // log(this); 35 | // var result = this.pathList.value.findClass(targetClass,suppressedExceptions) 36 | // var targetMethod = '$init' 37 | // var overloadCount = result[targetMethod].overloads.length; 38 | // for (var i = 0; i < overloadCount; i++) { 39 | // result[targetMethod].overloads[i].implementation = function () { 40 | // var output = ""; 41 | 42 | // //画个横线 43 | // for (var p = 0; p < 100; p++) { 44 | // output = output.concat("=="); 45 | // } 46 | // output = output.concat("\n") 47 | 48 | // //域值 49 | // output = inspectObject(this, output); 50 | // // 进入函数 51 | // output = output.concat("*** entered " + unparseMethod + "***\n"); 52 | // for (var j = 0; j < arguments.length; j++) { 53 | // output = output.concat("arg[" + j + "]: " + arguments[j] + " => " + JSON.stringify(arguments[j])); 54 | // output = output.concat("\n") 55 | // } 56 | // //调用栈 57 | // output = output.concat(stacktrace()); 58 | // var retval = this[targetMethod].apply(this, arguments); 59 | // // //返回值 60 | // output = output.concat("\nretval: " + retval + " => " + JSON.stringify(retval)); 61 | 62 | // //离开函数 63 | // output = output.concat("\n*** exiting " + targetClassMethod + '***\n'); 64 | // log(output) 65 | // } 66 | return retval; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/jni/JNI-Frida-Hook/agent.js: -------------------------------------------------------------------------------- 1 | const jni = require("./utils/jni_struct.js") 2 | 3 | var library_name = "libmetasec_ov.so" // ex: libsqlite.so 4 | var function_name = "NewStringUTF" // ex: JNI_OnLoad 5 | var library_loaded = 0 6 | 7 | 8 | // Function that will process the JNICall after calculating it from 9 | // the jnienv pointer in args[0] 10 | function hook_jni(library_name, function_name){ 11 | 12 | // To get the list of exports 13 | Module.enumerateExportsSync(library_name).forEach(function(symbol){ 14 | // console.log('Exported function: ' + symbol.name); 15 | // if(symbol.name == function_name){ 16 | console.log("[...] Hooking : " + library_name + " -> " + function_name + " at " + symbol.address) 17 | 18 | Interceptor.attach(symbol.address,{ 19 | onEnter: function(args){ 20 | 21 | var jnienv_addr = 0x0 22 | Java.perform(function(){ 23 | jnienv_addr = Java.vm.getEnv().handle.readPointer(); 24 | }); 25 | 26 | 27 | console.log("[+] Hooked successfully, JNIEnv base adress :" + jnienv_addr) 28 | 29 | /* 30 | Here you can choose which function to hook 31 | Either you hook all to have an overview of the function called 32 | */ 33 | 34 | jni.hook_all(jnienv_addr) 35 | 36 | /* 37 | Either you hook the one you want by precising what to do with it 38 | */ 39 | 40 | Interceptor.attach(jni.getJNIFunctionAdress(jnienv_addr,"FindClass"),{ 41 | onEnter: function(args){ 42 | console.log("env->FindClass(\"" + Memory.readCString(args[1]) + "\")") 43 | } 44 | }) 45 | }, 46 | onLeave: function(args){ 47 | // Prevent from displaying junk from other functions 48 | Interceptor.detachAll() 49 | console.log("[-] Detaching all interceptors") 50 | } 51 | }) 52 | // } 53 | }) 54 | } 55 | 56 | 57 | 58 | if(library_name == "" || function_name == ""){ 59 | console.log("[-] You must provide a function name and a library name to hook"); 60 | }else{ 61 | 62 | 63 | // First Step : waiting for the application to load the good library 64 | // https://android.googlesource.com/platform/system/core/+/master/libnativeloader/native_loader.cpp#746 65 | // 66 | // OpenNativeLibrary is called when you loadLibrary from Java, it then call android_dlopen_ext 67 | Interceptor.attach(Module.findExportByName(null, 'android_dlopen_ext'),{ 68 | onEnter: function(args){ 69 | // first arg is the path to the library loaded 70 | var library_path = Memory.readCString(args[0]) 71 | // console.log("[+] Library loaded : " + library_path) 72 | 73 | if( library_path.includes(library_name)){ 74 | console.log("[...] Loading library : " + library_path) 75 | library_loaded = 1 76 | } 77 | }, 78 | onLeave: function(args){ 79 | 80 | // if it's the library we want to hook, hooking it 81 | if(library_loaded == 1){ 82 | console.log("[+] Loaded") 83 | hook_jni(library_name, function_name) 84 | library_loaded = 0 85 | } 86 | } 87 | }) 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/so/socket.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | export function hookNativeSocket() { 3 | const tcpSocketFDs = new Map() 4 | 5 | const fSocketConnect = Process.getModuleByName("libc.so").getExportByName("connect") 6 | Interceptor.attach(fSocketConnect, { 7 | onEnter(args) { 8 | this.sockFd = args[0].toInt32() 9 | }, 10 | onLeave(res) { 11 | const sockFd = this.sockFd 12 | const sockType = Socket.type(sockFd) 13 | if (!(sockType === "tcp6" || sockType === "tcp")) return 14 | 15 | const sockLocal = Socket.localAddress(sockFd) 16 | const tcpEpLocal = sockLocal && sockLocal.ip ? sockLocal : undefined 17 | const sockRemote = Socket.peerAddress(sockFd) 18 | const tcpEpRemote = sockRemote && sockRemote.ip ? sockRemote : undefined 19 | 20 | if (!tcpEpLocal) return 21 | // ToDo: if socket FD already exists in the set, a faked 'close' message shall be sent first (currently handled by receiving logic) 22 | tcpSocketFDs.set(sockFd, tcpEpLocal) 23 | let msg = { 24 | socketFd: sockFd, 25 | pid: Process.id, 26 | threadId: this.threadId, 27 | socketEventType: "connect", 28 | type: "socketCall", 29 | result: res 30 | } 31 | 32 | if (tcpEpLocal) { 33 | msg.hostip = tcpEpLocal.ip 34 | msg.port = tcpEpLocal.port 35 | } 36 | if (tcpEpRemote) { 37 | msg.dstIp = tcpEpRemote.ip 38 | msg.dstPort = tcpEpRemote.port 39 | } 40 | 41 | //if (Java.available) { // checks presence of Java runtime in process 42 | if (Java.vm !== null && Java.vm.tryGetEnv() !== null) { 43 | // checks if Thread is JVM attached (JNI env available) 44 | let java_lang_Exception = Java.use("java.lang.Exception") 45 | var exception = java_lang_Exception.$new() 46 | const trace = exception.getStackTrace() 47 | msg.stack = trace.map(traceEl => { 48 | return { 49 | class: traceEl.getClassName(), 50 | file: traceEl.getFileName(), 51 | line: traceEl.getLineNumber(), 52 | method: traceEl.getMethodName(), 53 | isNative: traceEl.isNativeMethod(), 54 | str: traceEl.toString() 55 | } 56 | }) 57 | } 58 | 59 | //send(msg) 60 | console.log(JSON.stringify(msg, null, 4)) 61 | } 62 | }) 63 | 64 | const libcEx = Process.getModuleByName("libc.so").enumerateExports() 65 | const socketExports = libcEx.filter( 66 | expDetails => 67 | expDetails.type === "function" && 68 | ["shutdown", "close"].some(serachStr => serachStr === expDetails.name) 69 | ) 70 | socketExports.forEach(exp => { 71 | Interceptor.attach(exp.address, { 72 | onEnter(args) { 73 | const sockFd = args[0].toInt32() 74 | if (!tcpSocketFDs.has(sockFd)) return 75 | const sockType = Socket.type(sockFd) 76 | if (tcpSocketFDs.has(sockFd)) { 77 | const tcpEP = tcpSocketFDs.get(sockFd) 78 | const msg = { 79 | socketFd: sockFd, 80 | pid: Process.id, 81 | threadId: this.threadId, 82 | socketEventType: exp.name, 83 | hostip: tcpEP.ip, 84 | port: tcpEP.port, 85 | type: "socketCall" 86 | } 87 | tcpSocketFDs.delete(sockFd) 88 | //send(msg) 89 | console.log(JSON.stringify(msg, null, 4)) 90 | } 91 | } 92 | }) 93 | }) 94 | } 95 | -------------------------------------------------------------------------------- /src/java/encryption.ts: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | import {trace} from "./trace"; 3 | 4 | export function encryption(){ 5 | //aes 6 | trace('javax.crypto.Cipher','doFinal') 7 | trace('javax.crypto.Cipher','getEncoded') 8 | 9 | //base64 10 | trace('android.util.Base64','encodeToString') 11 | 12 | //md5、sha1、sha256、sha512 13 | trace('java.security.MessageDigest','digest') 14 | //hmac 15 | trace('javax.crypto.Mac','doFinal') 16 | //rsa 17 | trace('java.security.interfaces.RSAPublicKey','getEncoded') 18 | 19 | // trace('java.io.OutputStream','write') 20 | } 21 | 22 | 23 | function hook_list(){ 24 | var list = Java.use("java.util.ArrayList"); 25 | list.add.implementation = function(value){ 26 | var ret = this.add(value); 27 | console.log("add: " + ret); 28 | return ret; 29 | } 30 | } 31 | function hook_perform_click(){ 32 | var click = Java.use("android.view.View"); 33 | click.performClick.implementation = function(){ 34 | var ret = this.performClick(); 35 | console.log("performClick: " + ret); 36 | return ret; 37 | } 38 | } 39 | function hook_set_text(){ 40 | var text = Java.use("android.widget.TextView"); 41 | text.setText.implementation = function(text){ 42 | var ret = this.setText(text); 43 | console.log("setText: " + ret); 44 | return ret; 45 | } 46 | } 47 | function hook_get_text(){ 48 | var text = Java.use("android.widget.TextView"); 49 | text.getText.implementation = function(){ 50 | var ret = this.getText(); 51 | console.log("getText: " + ret); 52 | return ret; 53 | } 54 | } 55 | function hook_get_package_name(){ 56 | var package_name = Java.use("android.content.Context"); 57 | package_name.getPackageName.implementation = function(){ 58 | var ret = this.getPackageName(); 59 | console.log("getPackageName: " + ret); 60 | return ret; 61 | } 62 | } 63 | //frida byte to string 64 | function hook_byte_to_string(){ 65 | var byte = Java.use("[B"); 66 | byte.toString.implementation = function(){ 67 | var ret = this.toString(); 68 | console.log("toString: " + ret); 69 | return ret; 70 | } 71 | } 72 | //frida string to byte 73 | function hook_string_to_byte(){ 74 | var string = Java.use("java.lang.String"); 75 | string.getBytes.implementation = function(){ 76 | var ret = this.getBytes(); 77 | console.log("getBytes: " + ret); 78 | return ret; 79 | } 80 | } 81 | function hook_response(){ 82 | var response = Java.use("okhttp3.Response"); 83 | response.body.implementation = function(){ 84 | var ret = this.body(); 85 | console.log("body: " + ret); 86 | return ret; 87 | } 88 | } 89 | function hook_request_url(){ 90 | var request = Java.use("okhttp3.Request"); 91 | request.url.implementation = function(){ 92 | var ret = this.url(); 93 | console.log("url: " + ret); 94 | return ret; 95 | } 96 | } 97 | function hook_url(){ 98 | var url = Java.use("java.net.URL"); 99 | url.toString.implementation = function(){ 100 | var ret = this.toString(); 101 | console.log("toString: " + ret); 102 | return ret; 103 | } 104 | } 105 | function hook_url_connection(){ 106 | var url_connection = Java.use("java.net.URLConnection"); 107 | url_connection.getInputStream.implementation = function(){ 108 | var ret = this.getInputStream(); 109 | console.log("getInputStream: " + ret); 110 | return ret; 111 | } 112 | } -------------------------------------------------------------------------------- /src/java/encryption.js: -------------------------------------------------------------------------------- 1 | //@ts-nocheck 2 | import { trace } from "./trace"; 3 | export function encryption() { 4 | //aes 5 | trace('javax.crypto.Cipher', 'doFinal'); 6 | trace('javax.crypto.Cipher', 'getEncoded'); 7 | //base64 8 | trace('android.util.Base64', 'encodeToString'); 9 | //md5、sha1、sha256、sha512 10 | trace('java.security.MessageDigest', 'digest'); 11 | //hmac 12 | trace('javax.crypto.Mac', 'doFinal'); 13 | //rsa 14 | trace('java.security.interfaces.RSAPublicKey', 'getEncoded'); 15 | // trace('java.io.OutputStream','write') 16 | } 17 | function hook_list() { 18 | var list = Java.use("java.util.ArrayList"); 19 | list.add.implementation = function (value) { 20 | var ret = this.add(value); 21 | console.log("add: " + ret); 22 | return ret; 23 | }; 24 | } 25 | function hook_perform_click() { 26 | var click = Java.use("android.view.View"); 27 | click.performClick.implementation = function () { 28 | var ret = this.performClick(); 29 | console.log("performClick: " + ret); 30 | return ret; 31 | }; 32 | } 33 | function hook_set_text() { 34 | var text = Java.use("android.widget.TextView"); 35 | text.setText.implementation = function (text) { 36 | var ret = this.setText(text); 37 | console.log("setText: " + ret); 38 | return ret; 39 | }; 40 | } 41 | function hook_get_text() { 42 | var text = Java.use("android.widget.TextView"); 43 | text.getText.implementation = function () { 44 | var ret = this.getText(); 45 | console.log("getText: " + ret); 46 | return ret; 47 | }; 48 | } 49 | function hook_get_package_name() { 50 | var package_name = Java.use("android.content.Context"); 51 | package_name.getPackageName.implementation = function () { 52 | var ret = this.getPackageName(); 53 | console.log("getPackageName: " + ret); 54 | return ret; 55 | }; 56 | } 57 | //frida byte to string 58 | function hook_byte_to_string() { 59 | var byte = Java.use("[B"); 60 | byte.toString.implementation = function () { 61 | var ret = this.toString(); 62 | console.log("toString: " + ret); 63 | return ret; 64 | }; 65 | } 66 | //frida string to byte 67 | function hook_string_to_byte() { 68 | var string = Java.use("java.lang.String"); 69 | string.getBytes.implementation = function () { 70 | var ret = this.getBytes(); 71 | console.log("getBytes: " + ret); 72 | return ret; 73 | }; 74 | } 75 | function hook_response() { 76 | var response = Java.use("okhttp3.Response"); 77 | response.body.implementation = function () { 78 | var ret = this.body(); 79 | console.log("body: " + ret); 80 | return ret; 81 | }; 82 | } 83 | function hook_request_url() { 84 | var request = Java.use("okhttp3.Request"); 85 | request.url.implementation = function () { 86 | var ret = this.url(); 87 | console.log("url: " + ret); 88 | return ret; 89 | }; 90 | } 91 | function hook_url() { 92 | var url = Java.use("java.net.URL"); 93 | url.toString.implementation = function () { 94 | var ret = this.toString(); 95 | console.log("toString: " + ret); 96 | return ret; 97 | }; 98 | } 99 | function hook_url_connection() { 100 | var url_connection = Java.use("java.net.URLConnection"); 101 | url_connection.getInputStream.implementation = function () { 102 | var ret = this.getInputStream(); 103 | console.log("getInputStream: " + ret); 104 | return ret; 105 | }; 106 | } 107 | -------------------------------------------------------------------------------- /src/so/call_constructor.js: -------------------------------------------------------------------------------- 1 | function get_call_function() { 2 | var call_function_addr = null; 3 | var symbols = Process.getModuleByName("linker").enumerateSymbols(); 4 | for (var m = 0; m < symbols.length; m++) { 5 | if (symbols[m].name == "__dl__ZL13call_functionPKcPFviPPcS2_ES0_") { 6 | call_function_addr = symbols[m].address; 7 | console.log("found call_function_addr => ", call_function_addr) 8 | hook_call_function(call_function_addr) 9 | } 10 | } 11 | } 12 | 13 | function hook_call_function(_call_function_addr){ 14 | console.log("hook call function begin!hooking address :=>",_call_function_addr) 15 | Interceptor.attach(_call_function_addr,{ 16 | onEnter:function(args){ 17 | if(args[2].readCString().indexOf("base.odex")<0){ 18 | console.log("============================") 19 | console.log("function_name =>",args[0].readCString()) 20 | var soPath = args[2].readCString() 21 | console.log("so path : =>",soPath) 22 | var soName = soPath.split("/").pop(); 23 | console.log("function offset =>","0x"+(args[1]-Module.findBaseAddress(soName)).toString(16)) 24 | console.log("============================") 25 | } 26 | },onLeave:function(retval){ 27 | } 28 | }) 29 | } 30 | 31 | setImmediate(get_call_function) 32 | 33 | function hook_constructor() { 34 | if (Process.pointerSize == 4) { 35 | var linker = Process.findModuleByName("linker"); 36 | } else { 37 | var linker = Process.findModuleByName("linker64"); 38 | } 39 | 40 | var addr_call_function =null; 41 | var addr_g_ld_debug_verbosity = null; 42 | var addr_async_safe_format_log = null; 43 | if (linker) { 44 | var symbols = linker.enumerateSymbols(); 45 | for (var i = 0; i < symbols.length; i++) { 46 | var name = symbols[i].name; 47 | if (name.indexOf("call_function") >= 0){ 48 | addr_call_function = symbols[i].address; 49 | } 50 | else if(name.indexOf("g_ld_debug_verbosity") >=0){ 51 | addr_g_ld_debug_verbosity = symbols[i].address; 52 | 53 | ptr(addr_g_ld_debug_verbosity).writeInt(2); 54 | 55 | } else if(name.indexOf("async_safe_format_log") >=0 && name.indexOf('va_list') < 0){ 56 | 57 | addr_async_safe_format_log = symbols[i].address; 58 | 59 | } 60 | 61 | } 62 | } 63 | if(addr_async_safe_format_log){ 64 | Interceptor.attach(addr_async_safe_format_log,{ 65 | onEnter: function(args){ 66 | this.log_level = args[0]; 67 | this.tag = ptr(args[1]).readCString() 68 | this.fmt = ptr(args[2]).readCString() 69 | if(this.fmt.indexOf("c-tor") >= 0 && this.fmt.indexOf('Done') < 0){ 70 | this.function_type = ptr(args[3]).readCString(), // func_type 71 | this.so_path = ptr(args[5]).readCString(); 72 | var strs = new Array(); //定义一数组 73 | strs = this.so_path.split("/"); //字符分割 74 | this.so_name = strs.pop(); 75 | this.func_offset = ptr(args[4]).sub(Module.findBaseAddress(this.so_name)) 76 | console.log("func_type:", this.function_type, 77 | '\nso_name:',this.so_name, 78 | '\nso_path:',this.so_path, 79 | '\nfunc_offset:',this.func_offset 80 | ); 81 | } 82 | }, 83 | onLeave: function(retval){ 84 | 85 | } 86 | }) 87 | } 88 | } 89 | 90 | setImmediate(hook_constructor); -------------------------------------------------------------------------------- /src/jni/frida_hook_libart/hook_RegisterNatives.js: -------------------------------------------------------------------------------- 1 | // ============ 配置区域 ============ 2 | // 设置要监控的 SO 文件,可以配置多个 3 | // 留空数组 [] 表示监控所有 SO 4 | // 例如: ["libEncryptor.so"] 或 ["libEncryptor.so", "libsgmainso.so"] 5 | var TARGET_SO_LIST = ["libEncryptor.so"]; 6 | // =================================== 7 | 8 | function shouldMonitorModule(module) { 9 | if (!module) return false; 10 | if (TARGET_SO_LIST.length === 0) return true; // 空数组表示监控所有 11 | 12 | for (var i = 0; i < TARGET_SO_LIST.length; i++) { 13 | if (module.name.indexOf(TARGET_SO_LIST[i]) >= 0) { 14 | return true; 15 | } 16 | } 17 | return false; 18 | } 19 | 20 | function find_RegisterNatives(params) { 21 | console.log("[*] Target SO List:", TARGET_SO_LIST.length === 0 ? "ALL" : TARGET_SO_LIST.join(", ")); 22 | let module_libart = Process.getModuleByName("libart.so"); 23 | let symbols = module_libart.enumerateSymbols(); 24 | let addrRegisterNatives = null; 25 | for (let i = 0; i < symbols.length; i++) { 26 | let symbol = symbols[i]; 27 | 28 | //_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi 29 | if (symbol.name.indexOf("art") >= 0 && 30 | symbol.name.indexOf("JNI") >= 0 && 31 | symbol.name.indexOf("RegisterNatives") >= 0 && 32 | symbol.name.indexOf("CheckJNI") < 0) { 33 | addrRegisterNatives = symbol.address; 34 | console.log("RegisterNatives is at ", symbol.address, symbol.name); 35 | hook_RegisterNatives(addrRegisterNatives) 36 | } 37 | } 38 | 39 | } 40 | 41 | function hook_RegisterNatives(addrRegisterNatives) { 42 | 43 | if (addrRegisterNatives != null) { 44 | Interceptor.attach(addrRegisterNatives, { 45 | onEnter: function (args) { 46 | let java_class = args[1]; 47 | let class_name = Java.vm.tryGetEnv().getClassName(java_class); 48 | let methods_ptr = ptr(args[2]); 49 | let method_count = parseInt(args[3]); 50 | 51 | // 先检查是否有我们关心的模块 52 | let shouldLog = false; 53 | for (let i = 0; i < method_count; i++) { 54 | let fnPtr_ptr = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2).readPointer(); 55 | let find_module = Process.findModuleByAddress(fnPtr_ptr); 56 | if (shouldMonitorModule(find_module)) { 57 | shouldLog = true; 58 | break; 59 | } 60 | } 61 | 62 | if (!shouldLog) return; 63 | 64 | console.log("[RegisterNatives] method_count:", args[3]); 65 | 66 | for (let i = 0; i < method_count; i++) { 67 | let name_ptr = methods_ptr.add(i * Process.pointerSize * 3).readPointer(); 68 | let sig_ptr = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize).readPointer(); 69 | let fnPtr_ptr = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2).readPointer(); 70 | 71 | let name = name_ptr.readCString(); 72 | let sig = sig_ptr.readCString(); 73 | let symbol = DebugSymbol.fromAddress(fnPtr_ptr); 74 | var find_module = Process.findModuleByAddress(fnPtr_ptr); 75 | 76 | if (shouldMonitorModule(find_module)) { 77 | console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, " fnOffset:", ptr(fnPtr_ptr).sub(find_module.base), " callee:", DebugSymbol.fromAddress(this.returnAddress)," base:",find_module.base); 78 | } 79 | } 80 | } 81 | }); 82 | } 83 | } 84 | 85 | setImmediate(find_RegisterNatives); 86 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | function hook_dlopen(so_name = null, hook_func = null, so_addr = null) { 2 | console.log('hook_dlopen'); 3 | 4 | // Flag to track if we already hooked the first non-system SO 5 | var hookedFirstNonSystemSo = false; 6 | 7 | // Function to check if a path belongs to a system library 8 | function isSystemLibrary(path) { 9 | return path.startsWith("/system/") || 10 | path.startsWith("/apex/") || 11 | path.startsWith("/vendor/"); 12 | } 13 | 14 | // Function to check if a path is a shared object file 15 | function isSharedObject(path) { 16 | return path.endsWith(".so"); 17 | } 18 | 19 | // Function to execute when first non-system SO is detected 20 | function onFirstNonSystemSo() { 21 | if (!hookedFirstNonSystemSo) { 22 | console.log('Hooking first non-system SO'); 23 | hookedFirstNonSystemSo = true; 24 | hookStringFunctions(); 25 | } 26 | } 27 | 28 | // Hook android_dlopen_ext 29 | var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext"); 30 | if (android_dlopen_ext != null) { 31 | Interceptor.attach(android_dlopen_ext, { 32 | onEnter: function (args) { 33 | var soName = args[0].readCString(); 34 | 35 | // Check if this is a non-system shared object library 36 | if (!isSystemLibrary(soName) && isSharedObject(soName) && !hookedFirstNonSystemSo) { 37 | console.log('Found first non-system SO in android_dlopen_ext: ' + soName); 38 | this.hookNonSystemSo = true; 39 | } 40 | 41 | // Also check for the specific SO name if provided 42 | if (so_name && soName.indexOf(so_name) != -1) { 43 | console.log('Found specific SO in android_dlopen_ext: ' + soName); 44 | this.hookSpecificSo = true; 45 | } 46 | }, 47 | onLeave: function (retval) { 48 | // Hook the first non-system SO 49 | if (this.hookNonSystemSo) { 50 | onFirstNonSystemSo(); 51 | } 52 | 53 | // Also call the custom hook function if a specific SO was requested 54 | if (this.hookSpecificSo && hook_func) { 55 | hook_func(so_addr); 56 | } 57 | } 58 | }); 59 | } 60 | 61 | // Hook dlopen 62 | var dlopen = Module.findExportByName(null, "dlopen"); 63 | if (dlopen != null) { 64 | Interceptor.attach(dlopen, { 65 | onEnter: function (args) { 66 | var soName = args[0].readCString(); 67 | 68 | // Check if this is a non-system shared object library 69 | if (!isSystemLibrary(soName) && isSharedObject(soName) && !hookedFirstNonSystemSo) { 70 | console.log('Found first non-system SO in dlopen: ' + soName); 71 | this.hookNonSystemSo = true; 72 | } 73 | 74 | // Also check for the specific SO name if provided 75 | if (so_name && soName.indexOf(so_name) != -1) { 76 | console.log('Found specific SO in dlopen: ' + soName); 77 | this.hookSpecificSo = true; 78 | } 79 | }, 80 | onLeave: function (retval) { 81 | // Hook the first non-system SO 82 | if (this.hookNonSystemSo) { 83 | onFirstNonSystemSo(); 84 | } 85 | 86 | // Also call the custom hook function if a specific SO was requested 87 | if (this.hookSpecificSo && hook_func) { 88 | hook_func(so_addr); 89 | } 90 | } 91 | }); 92 | } 93 | } 94 | 95 | 96 | 97 | hook_dlopen() -------------------------------------------------------------------------------- /src/so/sktrace/sktrace.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | A instruction trace script based on Frida-Stalker. 4 | """ 5 | 6 | import argparse 7 | import binascii 8 | import json 9 | import os 10 | import frida 11 | 12 | from sktracemgr import TraceMgr 13 | 14 | __version__ = "1.0.0" 15 | 16 | def _finish(args, device, pid, scripts): 17 | print('Stopping application (name={}, pid={})...'.format( 18 | args.target, 19 | pid 20 | ), end="") 21 | try: 22 | if args.append: 23 | scripts["append"].unload() 24 | scripts["script"].unload() 25 | if args.prepend: 26 | scripts["prepend"].unload() 27 | device.kill(pid) 28 | except frida.InvalidOperationError: 29 | pass 30 | finally: 31 | print("stopped.") 32 | 33 | 34 | def _custom_script_on_message(message, data): 35 | print(message, data) 36 | 37 | 38 | def _parse_args(): 39 | parser = argparse.ArgumentParser(usage="sktrace [options] -l libname -i symbol|hexaddr target") 40 | parser.add_argument("-m", "--inject-method", choices=["spawn", "attach"], 41 | default="spawn", 42 | help="Specify how frida should inject into the process.") 43 | parser.add_argument("-l", "--libname", required=True, 44 | help="Specify a native library like libnative-lib.so") 45 | parser.add_argument("-i", "--interceptor", required=True, 46 | help="Specity a function (symbol or a hex offset address) to trace.") 47 | parser.add_argument("-p", "--prepend", type=argparse.FileType("r"), 48 | help="Prepend a Frida script to run before sktrace does.") 49 | parser.add_argument("-a", "--append", type=argparse.FileType("r"), 50 | help="Append a Frida script to run after sktrace has started.") 51 | parser.add_argument("-v", "--version", action='version', 52 | version="%(prog)s " + __version__, 53 | help="Show the version.") 54 | parser.add_argument("target", 55 | help="The name of the application to trace.") 56 | args = parser.parse_args() 57 | 58 | return args 59 | 60 | 61 | 62 | def main(): 63 | script_file = os.path.join(os.path.dirname(__file__), "sktrace.js") 64 | try: 65 | script = open(script_file, encoding='utf-8').read() 66 | except: 67 | raise Exception("Read script error.") 68 | 69 | trace_mgr = TraceMgr() 70 | 71 | args = _parse_args() 72 | 73 | config = { 74 | "type": "config", 75 | "payload": {} 76 | } 77 | 78 | config["payload"]["libname"] = args.libname 79 | 80 | if args.interceptor.startswith("0x") or args.interceptor.startswith("0X"): 81 | config["payload"]["offset"] = int(args.interceptor, 16) 82 | else: 83 | config["payload"]["symbol"] = args.interceptor 84 | 85 | device = frida.get_usb_device(1) 86 | if args.inject_method == "spawn": 87 | raise Exception("working for this ...") 88 | pid = device.spawn([args.target]) 89 | config["payload"]["spawn"] = True 90 | else: 91 | pid = device.get_process(args.target).pid 92 | config["payload"]["spawn"] = False 93 | 94 | session = device.attach(pid) 95 | scripts = {} 96 | 97 | if args.prepend: 98 | prepend = session.create_script(args.prepend.read()) 99 | prepend.on("message", _custom_script_on_message) 100 | prepend.load() 101 | args.prepend.close() 102 | scripts["prepend"] = prepend 103 | 104 | script = session.create_script(script) 105 | script.on("message", trace_mgr.on_message) 106 | script.load() 107 | scripts["script"] = script 108 | 109 | script.post(config) 110 | 111 | if args.append: 112 | append = session.create_script(args.append.read()) 113 | append.on("message", _custom_script_on_message) 114 | append.load() 115 | args.append.close() 116 | scripts["append"] = append 117 | 118 | if args.inject_method == "spawn": 119 | device.resume(pid) 120 | 121 | print("Tracing. Press any key to quit...") 122 | 123 | try: 124 | input() 125 | except KeyboardInterrupt: 126 | pass 127 | 128 | # _finish(args, device, pid, scripts) 129 | 130 | if __name__ == '__main__': 131 | main() 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/copy/test.js: -------------------------------------------------------------------------------- 1 | function main() { 2 | Java.perform(function () { 3 | console.log("hook StringBuffer") 4 | var Map = Java.use('java.lang.StringBuffer'); 5 | Map.append.implementation = function (str) { 6 | console.log("=================StringBuffer.put===================="); 7 | var data = this.append(str); 8 | console.log("-----" + str + "-----"); 9 | console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 10 | return data; 11 | } 12 | }) 13 | } 14 | 15 | function antiAntiFrida() { 16 | var strstr = Module.findExportByName(null, "strstr"); 17 | if (null !== strstr) { 18 | Interceptor.attach(strstr, { 19 | onEnter: function (args) { 20 | this.frida = Boolean(0); 21 | 22 | this.haystack = args[0]; 23 | this.needle = args[1]; 24 | 25 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 26 | if (this.haystack.readCString().indexOf("frida") !== -1 || 27 | this.needle.readCString().indexOf("frida") !== -1 || 28 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 29 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 30 | this.haystack.readCString().indexOf("gmain") !== -1 || 31 | this.needle.readCString().indexOf("gmain") !== -1 || 32 | this.haystack.readCString().indexOf("linjector") !== -1 || 33 | this.needle.readCString().indexOf("linjector") !== -1) { 34 | this.frida = Boolean(1); 35 | } 36 | } 37 | }, 38 | onLeave: function (retval) { 39 | if (this.frida) { 40 | retval.replace(ptr("0x0")); 41 | } 42 | 43 | } 44 | }) 45 | } 46 | 47 | 48 | function dis(address, number) { 49 | for (var i = 0; i < number; i++) { 50 | var ins = Instruction.parse(address); 51 | // console.log("address:" + address + "--dis:" + ins.toString()); 52 | address = ins.next; 53 | } 54 | } 55 | //libc->strstr() 从linker里面找到call_function的地址:趁so代码还未执行前就hook 56 | //call_function("DT_INIT", init_func_, get_realpath()); 57 | var linkermodule = Process.getModuleByName("linker"); 58 | var call_function_addr = null; 59 | var symbols = linkermodule.enumerateSymbols(); 60 | for (var i = 0; i < symbols.length; i++) { 61 | var symbol = symbols[i]; 62 | // LogPrint(linkername + "->" + symbol.name + "---" + symbol.address); 63 | if (symbol.name.indexOf("__dl__ZL13call_functionPKcPFviPPcS2_ES0_") != -1) { 64 | call_function_addr = symbol.address; 65 | // console.log("linker->" + symbol.name + "---" + symbol.address) 66 | } 67 | } 68 | Interceptor.attach(call_function_addr, { 69 | onEnter: function (args) { 70 | var type = ptr(args[0]).readUtf8String(); 71 | var address = args[1]; 72 | var sopath = ptr(args[2]).readUtf8String(); 73 | // console.log("loadso:" + sopath + "--addr:" + address + "--type:" + type); 74 | if (sopath.indexOf("libnative-lib.so") != -1) { 75 | var libnativemodule = Process.getModuleByName("xxxx.so");//call_function正在加载目标so,这时就拦截下来 76 | var base = libnativemodule.base; 77 | dis(base.add(0x1234).add(1), 10); 78 | var patchaddr = base.add(0x2345);//改so的机器码,避免待会完全加载后运行时就错过时机了! 79 | Memory.patchCode(patchaddr, 4, patchaddr => { 80 | var cw = new ThumbWriter(patchaddr); 81 | cw.putNop(); 82 | cw = new ThumbWriter(patchaddr.add(0x2)); 83 | cw.putNop(); 84 | cw.flush(); 85 | }); 86 | // console.log("+++++++++++++++++++++++") 87 | dis(base.add(0x1234).add(1), 10); 88 | // console.log("----------------------") 89 | 90 | dis(base.add(0x2345).add(1), 10); 91 | Memory.protect(base.add(0x8E78), 4, 'rwx'); 92 | base.add(0x1234).writeByteArray([0x00, 0xbf, 0x00, 0xbf]); 93 | // console.log("+++++++++++++++++++++++") 94 | dis(base.add(0x2345).add(1), 10); 95 | 96 | 97 | } 98 | } 99 | }) 100 | } 101 | setImmediate(antiAntiFrida) 102 | 103 | var isLite = false; 104 | var ByPassTracerPid = function () { 105 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 106 | var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 107 | Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 108 | var retval = fgets(buffer, size, fp); 109 | var bufstr = Memory.readUtf8String(buffer); 110 | if (bufstr.indexOf("TracerPid:") > -1) { 111 | Memory.writeUtf8String(buffer, "TracerPid:\t0"); 112 | } 113 | return retval; 114 | }, 'pointer', ['pointer', 'int', 'pointer'])); 115 | }; 116 | setImmediate(ByPassTracerPid); -------------------------------------------------------------------------------- /src/copy/StringBuffer.js: -------------------------------------------------------------------------------- 1 | function main() { 2 | Java.perform(function () { 3 | console.log("hook StringBuffer") 4 | var Map = Java.use('java.lang.StringBuffer'); 5 | Map.append.implementation = function (str) { 6 | console.log("=================StringBuffer.put===================="); 7 | var data = this.append(str); 8 | console.log("-----" + str + "-----"); 9 | console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 10 | return data; 11 | } 12 | }) 13 | } 14 | 15 | function antiAntiFrida() { 16 | var strstr = Module.findExportByName(null, "strstr"); 17 | if (null !== strstr) { 18 | Interceptor.attach(strstr, { 19 | onEnter: function (args) { 20 | this.frida = Boolean(0); 21 | 22 | this.haystack = args[0]; 23 | this.needle = args[1]; 24 | 25 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 26 | if (this.haystack.readCString().indexOf("frida") !== -1 || 27 | this.needle.readCString().indexOf("frida") !== -1 || 28 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 29 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 30 | this.haystack.readCString().indexOf("gmain") !== -1 || 31 | this.needle.readCString().indexOf("gmain") !== -1 || 32 | this.haystack.readCString().indexOf("linjector") !== -1 || 33 | this.needle.readCString().indexOf("linjector") !== -1) { 34 | this.frida = Boolean(1); 35 | } 36 | } 37 | }, 38 | onLeave: function (retval) { 39 | if (this.frida) { 40 | retval.replace(ptr("0x0")); 41 | } 42 | 43 | } 44 | }) 45 | } 46 | 47 | 48 | function dis(address, number) { 49 | for (var i = 0; i < number; i++) { 50 | var ins = Instruction.parse(address); 51 | // console.log("address:" + address + "--dis:" + ins.toString()); 52 | address = ins.next; 53 | } 54 | } 55 | //libc->strstr() 从linker里面找到call_function的地址:趁so代码还未执行前就hook 56 | //call_function("DT_INIT", init_func_, get_realpath()); 57 | var linkermodule = Process.getModuleByName("linker"); 58 | var call_function_addr = null; 59 | var symbols = linkermodule.enumerateSymbols(); 60 | for (var i = 0; i < symbols.length; i++) { 61 | var symbol = symbols[i]; 62 | // LogPrint(linkername + "->" + symbol.name + "---" + symbol.address); 63 | if (symbol.name.indexOf("__dl__ZL13call_functionPKcPFviPPcS2_ES0_") != -1) { 64 | call_function_addr = symbol.address; 65 | // console.log("linker->" + symbol.name + "---" + symbol.address) 66 | } 67 | } 68 | Interceptor.attach(call_function_addr, { 69 | onEnter: function (args) { 70 | var type = ptr(args[0]).readUtf8String(); 71 | var address = args[1]; 72 | var sopath = ptr(args[2]).readUtf8String(); 73 | // console.log("loadso:" + sopath + "--addr:" + address + "--type:" + type); 74 | if (sopath.indexOf("libnative-lib.so") != -1) { 75 | var libnativemodule = Process.getModuleByName("xxxx.so");//call_function正在加载目标so,这时就拦截下来 76 | var base = libnativemodule.base; 77 | dis(base.add(0x1234).add(1), 10); 78 | var patchaddr = base.add(0x2345);//改so的机器码,避免待会完全加载后运行时就错过时机了! 79 | Memory.patchCode(patchaddr, 4, patchaddr => { 80 | var cw = new ThumbWriter(patchaddr); 81 | cw.putNop(); 82 | cw = new ThumbWriter(patchaddr.add(0x2)); 83 | cw.putNop(); 84 | cw.flush(); 85 | }); 86 | // console.log("+++++++++++++++++++++++") 87 | dis(base.add(0x1234).add(1), 10); 88 | // console.log("----------------------") 89 | 90 | dis(base.add(0x2345).add(1), 10); 91 | Memory.protect(base.add(0x8E78), 4, 'rwx'); 92 | base.add(0x1234).writeByteArray([0x00, 0xbf, 0x00, 0xbf]); 93 | // console.log("+++++++++++++++++++++++") 94 | dis(base.add(0x2345).add(1), 10); 95 | 96 | 97 | } 98 | } 99 | }) 100 | } 101 | setImmediate(antiAntiFrida) 102 | 103 | var isLite = false; 104 | var ByPassTracerPid = function () { 105 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 106 | var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 107 | Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 108 | var retval = fgets(buffer, size, fp); 109 | var bufstr = Memory.readUtf8String(buffer); 110 | if (bufstr.indexOf("TracerPid:") > -1) { 111 | Memory.writeUtf8String(buffer, "TracerPid:\t0"); 112 | } 113 | return retval; 114 | }, 'pointer', ['pointer', 'int', 'pointer'])); 115 | }; 116 | setImmediate(ByPassTracerPid); -------------------------------------------------------------------------------- /src/copy/HashMap.js: -------------------------------------------------------------------------------- 1 | function antiAntiFrida() { 2 | var strstr = Module.findExportByName(null, "strstr"); 3 | if (null !== strstr) { 4 | Interceptor.attach(strstr, { 5 | onEnter: function (args) { 6 | this.frida = Boolean(0); 7 | 8 | this.haystack = args[0]; 9 | this.needle = args[1]; 10 | 11 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 12 | if (this.haystack.readCString().indexOf("frida") !== -1 || 13 | this.needle.readCString().indexOf("frida") !== -1 || 14 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 15 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 16 | this.haystack.readCString().indexOf("gmain") !== -1 || 17 | this.needle.readCString().indexOf("gmain") !== -1 || 18 | this.haystack.readCString().indexOf("linjector") !== -1 || 19 | this.needle.readCString().indexOf("linjector") !== -1) { 20 | this.frida = Boolean(1); 21 | } 22 | } 23 | }, 24 | onLeave: function (retval) { 25 | if (this.frida) { 26 | retval.replace(ptr("0x0")); 27 | } 28 | 29 | } 30 | }) 31 | } 32 | 33 | 34 | function dis(address, number) { 35 | for (var i = 0; i < number; i++) { 36 | var ins = Instruction.parse(address); 37 | // console.log("address:" + address + "--dis:" + ins.toString()); 38 | address = ins.next; 39 | } 40 | } 41 | //libc->strstr() 从linker里面找到call_function的地址:趁so代码还未执行前就hook 42 | //call_function("DT_INIT", init_func_, get_realpath()); 43 | var linkermodule = Process.getModuleByName("linker"); 44 | var call_function_addr = null; 45 | var symbols = linkermodule.enumerateSymbols(); 46 | for (var i = 0; i < symbols.length; i++) { 47 | var symbol = symbols[i]; 48 | // LogPrint(linkername + "->" + symbol.name + "---" + symbol.address); 49 | if (symbol.name.indexOf("__dl__ZL13call_functionPKcPFviPPcS2_ES0_") != -1) { 50 | call_function_addr = symbol.address; 51 | // console.log("linker->" + symbol.name + "---" + symbol.address) 52 | } 53 | } 54 | Interceptor.attach(call_function_addr, { 55 | onEnter: function (args) { 56 | var type = ptr(args[0]).readUtf8String(); 57 | var address = args[1]; 58 | var sopath = ptr(args[2]).readUtf8String(); 59 | // console.log("loadso:" + sopath + "--addr:" + address + "--type:" + type); 60 | if (sopath.indexOf("libnative-lib.so") != -1) { 61 | var libnativemodule = Process.getModuleByName("xxxx.so");//call_function正在加载目标so,这时就拦截下来 62 | var base = libnativemodule.base; 63 | dis(base.add(0x1234).add(1), 10); 64 | var patchaddr = base.add(0x2345);//改so的机器码,避免待会完全加载后运行时就错过时机了! 65 | Memory.patchCode(patchaddr, 4, patchaddr => { 66 | var cw = new ThumbWriter(patchaddr); 67 | cw.putNop(); 68 | cw = new ThumbWriter(patchaddr.add(0x2)); 69 | cw.putNop(); 70 | cw.flush(); 71 | }); 72 | // console.log("+++++++++++++++++++++++") 73 | dis(base.add(0x1234).add(1), 10); 74 | // console.log("----------------------") 75 | 76 | dis(base.add(0x2345).add(1), 10); 77 | Memory.protect(base.add(0x8E78), 4, 'rwx'); 78 | base.add(0x1234).writeByteArray([0x00, 0xbf, 0x00, 0xbf]); 79 | // console.log("+++++++++++++++++++++++") 80 | dis(base.add(0x2345).add(1), 10); 81 | 82 | 83 | } 84 | } 85 | }) 86 | } 87 | setImmediate(antiAntiFrida) 88 | 89 | var isLite = false; 90 | var ByPassTracerPid = function () { 91 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 92 | var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 93 | Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 94 | var retval = fgets(buffer, size, fp); 95 | var bufstr = Memory.readUtf8String(buffer); 96 | if (bufstr.indexOf("TracerPid:") > -1) { 97 | Memory.writeUtf8String(buffer, "TracerPid:\t0"); 98 | } 99 | return retval; 100 | }, 'pointer', ['pointer', 'int', 'pointer'])); 101 | }; 102 | setImmediate(ByPassTracerPid); 103 | 104 | function main() { 105 | Java.perform(function () { 106 | console.log("hook Map") 107 | var Map = Java.use('java.util.Map'); 108 | Map.put.implementation = function (arg1, arg2) { 109 | console.log("=================Map.put===================="); 110 | var data = this.put(arg1, arg2); 111 | console.log(arg1 + "-----" + arg2); 112 | console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 113 | return data; 114 | } 115 | }) 116 | } 117 | // setTimeout(test, 5000); -------------------------------------------------------------------------------- /src/java/one_method_hook.js: -------------------------------------------------------------------------------- 1 | var class_loader = 'anet.channel.session.HttpConnector'; 2 | var target_method = 'c'; 3 | // var className = class_loader.split('.')[class_loader.split('.').length - 1] 4 | // setTimeout(main, 10000) 5 | main(); 6 | function main() { 7 | console.log("start"); 8 | Java.perform(function () { 9 | Java.enumerateClassLoaders({ 10 | onMatch: function (loader) { 11 | try { 12 | if (loader.findClass(class_loader)) { 13 | console.log("Successfully found loader") 14 | Java.classFactory.loader = loader; 15 | console.log("Switch Classloader Successfully ! ") 16 | } 17 | } catch (e) { } 18 | }, 19 | onComplete: function () { 20 | } 21 | }); 22 | Java.enumerateLoadedClasses({ 23 | onMatch: function (class_name) { 24 | //输出所有类 25 | // console.log(className) 26 | if (class_name.toString().toLowerCase() === class_loader.toLowerCase()) { 27 | try { 28 | var hook = Java.use(class_loader); 29 | var overloads = hook[target_method].overloads; 30 | for (var i = 0; i < overloads.length; i++) { 31 | overloads[i].implementation = function () { 32 | var retval = this[target_method].apply(this, arguments); 33 | // var retval = null; 34 | 35 | //输出函数参数 36 | for (var j = 0; j < arguments.length; j++) { 37 | console.log(arguments[j]) 38 | // print_hashmap(arguments[1]) 39 | } 40 | console.log(retval); 41 | console.log(arguments[0].j().toString()) 42 | return retval; 43 | } 44 | 45 | } 46 | } catch (e) { } 47 | } 48 | }, onComplete: function () { } 49 | }) 50 | 51 | }) 52 | } 53 | 54 | function print_hashmap(hashmap) { 55 | if (!hashmap) { 56 | console.log('Invalid hashmap'); 57 | return; 58 | } 59 | 60 | var output = ""; 61 | 62 | var HashMapNode = Java.use('java.util.HashMap$Node'); 63 | var iterator = hashmap.entrySet().iterator(); 64 | while (iterator.hasNext()) { 65 | var entry = Java.cast(iterator.next(), HashMapNode); 66 | var key = entry.getKey(); 67 | var value = entry.getValue(); 68 | 69 | if(!key) 70 | key='null' 71 | if(!value) 72 | value='null' 73 | output += key.toString() + " => " + value.toString() + "\n"; 74 | } 75 | 76 | console.log(output); // 输出到 Frida 控制台 77 | return output; // 返回输出结果 78 | } 79 | 80 | // function antiAntiFrida() { 81 | // var strstr = Module.findExportByName(null, "strstr"); 82 | // if (null !== strstr) { 83 | // Interceptor.attach(strstr, { 84 | // onEnter: function (args) { 85 | // this.frida = Boolean(0); 86 | 87 | // this.haystack = args[0]; 88 | // this.needle = args[1]; 89 | 90 | // if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 91 | // if (this.haystack.readCString().indexOf("frida") !== -1 || 92 | // this.needle.readCString().indexOf("frida") !== -1 || 93 | // this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 94 | // this.needle.readCString().indexOf("gum-js-loop") !== -1 || 95 | // this.haystack.readCString().indexOf("gmain") !== -1 || 96 | // this.needle.readCString().indexOf("gmain") !== -1 || 97 | // this.haystack.readCString().indexOf("linjector") !== -1 || 98 | // this.needle.readCString().indexOf("linjector") !== -1) { 99 | // this.frida = Boolean(1); 100 | // } 101 | // } 102 | // }, 103 | // onLeave: function (retval) { 104 | // if (this.frida) { 105 | // retval.replace(ptr("0x0")); 106 | // } 107 | 108 | // } 109 | // }) 110 | // // console.log("anti anti-frida"); 111 | // } 112 | // } 113 | // setImmediate(antiAntiFrida) 114 | 115 | // var isLite = false; 116 | // var ByPassTracerPid = function () { 117 | // var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 118 | // var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 119 | // Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 120 | // var retval = fgets(buffer, size, fp); 121 | // var bufstr = Memory.readUtf8String(buffer); 122 | // if (bufstr.indexOf("TracerPid:") > -1) { 123 | // Memory.writeUtf8String(buffer, "TracerPid:\t0"); 124 | // // console.log("tracerpid replaced: " + Memory.readUtf8String(buffer)); 125 | // } 126 | // return retval; 127 | // }, 'pointer', ['pointer', 'int', 'pointer'])); 128 | // }; 129 | // setImmediate(ByPassTracerPid); -------------------------------------------------------------------------------- /src/frida-dexdump/frida_dexdump/__main__.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreateTime: 2021/6/3 4 | __version__ = "2.0.1" 5 | 6 | import argparse 7 | import hashlib 8 | import logging 9 | import os.path 10 | import time 11 | 12 | from frida_tools.application import ConsoleApplication 13 | from wallbreaker.connection import Connection 14 | 15 | from frida_dexdump.agent import DexDumpAgent 16 | from frida_dexdump.banner import show_banner 17 | 18 | logger = logging.getLogger("frida-dexdump") 19 | md5 = lambda bs: hashlib.md5(bs).hexdigest() 20 | 21 | 22 | class SessionConnection(Connection): 23 | 24 | def __init__(self, device, session): 25 | self.device = device 26 | self.session = session 27 | self.process = str(self.session) 28 | 29 | 30 | def _fixup_version(parser: argparse.ArgumentParser): 31 | if not hasattr(parser, "_actions"): return 32 | 33 | for action in parser._actions: 34 | if "--version" in action.option_strings \ 35 | and action.dest == "version": 36 | action.version = __version__ 37 | 38 | 39 | class DexDumpApplication(ConsoleApplication): 40 | agent = None 41 | 42 | def _needs_target(self): 43 | return True 44 | 45 | def _usage(self): 46 | return "Usage see: frida-dexdump -h" 47 | 48 | def _add_options(self, parser): 49 | # fixup frida-tools#75 47d020ad1e51a1a5037c630e2de7136b867e86aa 50 | if not hasattr(parser, "add_argument") and hasattr(parser, "add_option"): 51 | setattr(parser, "add_argument", getattr(parser, "add_option")) 52 | 53 | _fixup_version(parser) 54 | 55 | parser.add_argument("-o", "--output", help="Output folder path, default is './/'.", 56 | type=str, action='store') 57 | parser.add_argument("-d", "--deep-search", help="Enable deep search mode.", 58 | action='store_true', dest="enable_deep", default=False) 59 | parser.add_argument("--sleep", help="Waiting times for start, spawn mode default is 5s.", 60 | type=int, action='store', default=None) 61 | 62 | def _initialize(self, parser, options, args): 63 | show_banner() 64 | self.mds = set() 65 | self.output = options.output 66 | self.enable_deep = options.enable_deep 67 | self.sleep = options.sleep 68 | # spawn mode 69 | if self.sleep is None and self._target[0] == "file": 70 | self.sleep = 5 71 | 72 | def _start(self): 73 | self.connection = SessionConnection(self._device, self._session) 74 | self.agent = DexDumpAgent(self.connection) 75 | self.package_name = self.get_package_name() 76 | if not self.output: 77 | self.output = os.path.join(os.getcwd(), self.package_name.replace(":", "-")) 78 | os.makedirs(self.output, exist_ok=True) 79 | self._resume() 80 | if self.sleep: 81 | logger.info("Waiting {}s...".format(self.sleep)) 82 | time.sleep(self.sleep) 83 | self.dump() 84 | self._exit(0) 85 | 86 | def dump(self): 87 | logger.info("[+] Searching...") 88 | st = time.time() 89 | ranges = self.agent.search_dex(enable_deep_search=self.enable_deep) 90 | et = time.time() 91 | logger.info("[*] Successful found {} dex, used {} time.".format(len(ranges), int(et - st))) 92 | logger.info("[+] Starting dump to '{}'...".format(self.output)) 93 | idx = 1 94 | for dex in ranges: 95 | try: 96 | bs = self.agent.memory_dump(dex['addr'], dex['size']) 97 | md = md5(bs) 98 | if md in self.mds: 99 | continue 100 | self.mds.add(md) 101 | bs = fix_header(bs) 102 | out_path = os.path.join(self.output, "classes{}.dex".format('%d' % idx if idx != 1 else '')) 103 | with open(out_path, 'wb') as out: 104 | out.write(bs) 105 | logger.info("[+] DexMd5={}, SavePath={}, DexSize={}" 106 | .format(md, out_path, hex(dex['size']))) 107 | idx += 1 108 | except Exception as e: 109 | logger.exception("[-] {}: {}".format(e, dex)) 110 | logger.info("[*] All done...") 111 | 112 | def get_package_name(self): 113 | try: 114 | pid = self._session._impl.pid 115 | for process in self._device.enumerate_processes(): 116 | if process.pid == pid: 117 | return process.name 118 | return "dexdump.unnamed.{}".format(pid) 119 | except: 120 | return "dexdump.unnamed" 121 | 122 | 123 | def fix_header(dex_bytes): 124 | import struct 125 | dex_size = len(dex_bytes) 126 | 127 | if dex_bytes[:4] != b"dex\n": 128 | dex_bytes = b"dex\n035\x00" + dex_bytes[8:] 129 | 130 | if dex_size >= 0x24: 131 | dex_bytes = dex_bytes[:0x20] + struct.Struct("= 0x28: 134 | dex_bytes = dex_bytes[:0x24] + struct.Struct("= 0x2C and dex_bytes[0x28:0x2C] not in [b'\x78\x56\x34\x12', b'\x12\x34\x56\x78']: 137 | dex_bytes = dex_bytes[:0x28] + b'\x78\x56\x34\x12' + dex_bytes[0x2C:] 138 | 139 | return dex_bytes 140 | 141 | 142 | def main(): 143 | logging.basicConfig(level=logging.INFO) 144 | DexDumpApplication().run() 145 | 146 | 147 | if __name__ == "__main__": 148 | main() 149 | -------------------------------------------------------------------------------- /src/frida-dexdump/build/lib/frida_dexdump/__main__.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreateTime: 2021/6/3 4 | __version__ = "2.0.1" 5 | 6 | import argparse 7 | import hashlib 8 | import logging 9 | import os.path 10 | import time 11 | 12 | from frida_tools.application import ConsoleApplication 13 | from wallbreaker.connection import Connection 14 | 15 | from frida_dexdump.agent import DexDumpAgent 16 | from frida_dexdump.banner import show_banner 17 | 18 | logger = logging.getLogger("frida-dexdump") 19 | md5 = lambda bs: hashlib.md5(bs).hexdigest() 20 | 21 | 22 | class SessionConnection(Connection): 23 | 24 | def __init__(self, device, session): 25 | self.device = device 26 | self.session = session 27 | self.process = str(self.session) 28 | 29 | 30 | def _fixup_version(parser: argparse.ArgumentParser): 31 | if not hasattr(parser, "_actions"): return 32 | 33 | for action in parser._actions: 34 | if "--version" in action.option_strings \ 35 | and action.dest == "version": 36 | action.version = __version__ 37 | 38 | 39 | class DexDumpApplication(ConsoleApplication): 40 | agent = None 41 | 42 | def _needs_target(self): 43 | return True 44 | 45 | def _usage(self): 46 | return "Usage see: frida-dexdump -h" 47 | 48 | def _add_options(self, parser): 49 | # fixup frida-tools#75 47d020ad1e51a1a5037c630e2de7136b867e86aa 50 | if not hasattr(parser, "add_argument") and hasattr(parser, "add_option"): 51 | setattr(parser, "add_argument", getattr(parser, "add_option")) 52 | 53 | _fixup_version(parser) 54 | 55 | parser.add_argument("-o", "--output", help="Output folder path, default is './/'.", 56 | type=str, action='store') 57 | parser.add_argument("-d", "--deep-search", help="Enable deep search mode.", 58 | action='store_true', dest="enable_deep", default=False) 59 | parser.add_argument("--sleep", help="Waiting times for start, spawn mode default is 5s.", 60 | type=int, action='store', default=None) 61 | 62 | def _initialize(self, parser, options, args): 63 | show_banner() 64 | self.mds = set() 65 | self.output = options.output 66 | self.enable_deep = options.enable_deep 67 | self.sleep = options.sleep 68 | # spawn mode 69 | if self.sleep is None and self._target[0] == "file": 70 | self.sleep = 5 71 | 72 | def _start(self): 73 | self.connection = SessionConnection(self._device, self._session) 74 | self.agent = DexDumpAgent(self.connection) 75 | self.package_name = self.get_package_name() 76 | if not self.output: 77 | self.output = os.path.join(os.getcwd(), self.package_name.replace(":", "-")) 78 | os.makedirs(self.output, exist_ok=True) 79 | self._resume() 80 | if self.sleep: 81 | logger.info("Waiting {}s...".format(self.sleep)) 82 | time.sleep(self.sleep) 83 | self.dump() 84 | self._exit(0) 85 | 86 | def dump(self): 87 | logger.info("[+] Searching...") 88 | st = time.time() 89 | ranges = self.agent.search_dex(enable_deep_search=self.enable_deep) 90 | et = time.time() 91 | logger.info("[*] Successful found {} dex, used {} time.".format(len(ranges), int(et - st))) 92 | logger.info("[+] Starting dump to '{}'...".format(self.output)) 93 | idx = 1 94 | for dex in ranges: 95 | try: 96 | bs = self.agent.memory_dump(dex['addr'], dex['size']) 97 | md = md5(bs) 98 | if md in self.mds: 99 | continue 100 | self.mds.add(md) 101 | bs = fix_header(bs) 102 | out_path = os.path.join(self.output, "classes{}.dex".format('%d' % idx if idx != 1 else '')) 103 | with open(out_path, 'wb') as out: 104 | out.write(bs) 105 | logger.info("[+] DexMd5={}, SavePath={}, DexSize={}" 106 | .format(md, out_path, hex(dex['size']))) 107 | idx += 1 108 | except Exception as e: 109 | logger.exception("[-] {}: {}".format(e, dex)) 110 | logger.info("[*] All done...") 111 | 112 | def get_package_name(self): 113 | try: 114 | pid = self._session._impl.pid 115 | for process in self._device.enumerate_processes(): 116 | if process.pid == pid: 117 | return process.name 118 | return "dexdump.unnamed.{}".format(pid) 119 | except: 120 | return "dexdump.unnamed" 121 | 122 | 123 | def fix_header(dex_bytes): 124 | import struct 125 | dex_size = len(dex_bytes) 126 | 127 | if dex_bytes[:4] != b"dex\n": 128 | dex_bytes = b"dex\n035\x00" + dex_bytes[8:] 129 | 130 | if dex_size >= 0x24: 131 | dex_bytes = dex_bytes[:0x20] + struct.Struct("= 0x28: 134 | dex_bytes = dex_bytes[:0x24] + struct.Struct("= 0x2C and dex_bytes[0x28:0x2C] not in [b'\x78\x56\x34\x12', b'\x12\x34\x56\x78']: 137 | dex_bytes = dex_bytes[:0x28] + b'\x78\x56\x34\x12' + dex_bytes[0x2C:] 138 | 139 | return dex_bytes 140 | 141 | 142 | def main(): 143 | logging.basicConfig(level=logging.INFO) 144 | DexDumpApplication().run() 145 | 146 | 147 | if __name__ == "__main__": 148 | main() 149 | -------------------------------------------------------------------------------- /src/jni/frida_hook_libart/hook_artmethod.js: -------------------------------------------------------------------------------- 1 | 2 | // ============ 配置区域 ============ 3 | // 设置要监控的 SO 文件,可以配置多个 4 | // 留空数组 [] 表示监控所有 SO 5 | // 例如: ["libEncryptor.so"] 或 ["libEncryptor.so", "libsgmainso.so"] 6 | var TARGET_SO_LIST = ["libEncryptor.so"]; 7 | 8 | // 是否启用 Java 类过滤(过滤掉 java.* 和 android.* 开头的类) 9 | var FILTER_SYSTEM_CLASSES = true; 10 | // =================================== 11 | 12 | function shouldMonitorModule(module) { 13 | if (!module) return false; 14 | if (TARGET_SO_LIST.length === 0) return true; // 空数组表示监控所有 15 | 16 | for (var i = 0; i < TARGET_SO_LIST.length; i++) { 17 | if (module.name.indexOf(TARGET_SO_LIST[i]) >= 0) { 18 | return true; 19 | } 20 | } 21 | return false; 22 | } 23 | 24 | const STD_STRING_SIZE = 3 * Process.pointerSize; 25 | class StdString { 26 | constructor() { 27 | this.handle = Memory.alloc(STD_STRING_SIZE); 28 | } 29 | 30 | dispose() { 31 | const [data, isTiny] = this._getData(); 32 | if (!isTiny) { 33 | Java.api.$delete(data); 34 | } 35 | } 36 | 37 | disposeToString() { 38 | const result = this.toString(); 39 | this.dispose(); 40 | return result; 41 | } 42 | 43 | toString() { 44 | const [data] = this._getData(); 45 | return data.readUtf8String(); 46 | } 47 | 48 | _getData() { 49 | const str = this.handle; 50 | const isTiny = (str.readU8() & 1) === 0; 51 | const data = isTiny ? str.add(1) : str.add(2 * Process.pointerSize).readPointer(); 52 | return [data, isTiny]; 53 | } 54 | } 55 | 56 | function prettyMethod(method_id, withSignature) { 57 | const result = new StdString(); 58 | Java.api['art::ArtMethod::PrettyMethod'](result, method_id, withSignature ? 1 : 0); 59 | return result.disposeToString(); 60 | } 61 | 62 | function hook_dlopen(module_name, fun) { 63 | var android_dlopen_ext = Module.findGlobalExportByName("android_dlopen_ext"); 64 | 65 | if (android_dlopen_ext) { 66 | Interceptor.attach(android_dlopen_ext, { 67 | onEnter: function (args) { 68 | var pathptr = args[0]; 69 | if (pathptr) { 70 | this.path = pathptr.readCString(); 71 | if (this.path.indexOf(module_name) >= 0) { 72 | this.canhook = true; 73 | console.log("android_dlopen_ext:", this.path); 74 | } 75 | } 76 | }, 77 | onLeave: function (retval) { 78 | if (this.canhook) { 79 | fun(); 80 | } 81 | } 82 | }); 83 | } 84 | var dlopen = Module.findGlobalExportByName("dlopen"); 85 | if (dlopen) { 86 | Interceptor.attach(dlopen, { 87 | onEnter: function (args) { 88 | var pathptr = args[0]; 89 | if (pathptr) { 90 | this.path = pathptr.readCString(); 91 | if (this.path.indexOf(module_name) >= 0) { 92 | this.canhook = true; 93 | console.log("dlopen:", this.path); 94 | } 95 | } 96 | }, 97 | onLeave: function (retval) { 98 | if (this.canhook) { 99 | fun(); 100 | } 101 | } 102 | }); 103 | } 104 | console.log("android_dlopen_ext:", android_dlopen_ext, "dlopen:", dlopen); 105 | } 106 | 107 | 108 | function hook_native() { 109 | console.log("[*] Target SO List:", TARGET_SO_LIST.length === 0 ? "ALL" : TARGET_SO_LIST.join(", ")); 110 | 111 | var module_libart = Process.findModuleByName("libart.so"); 112 | var symbols = module_libart.enumerateSymbols(); 113 | var ArtMethod_Invoke = null; 114 | for (var i = 0; i < symbols.length; i++) { 115 | var symbol = symbols[i]; 116 | var address = symbol.address; 117 | var name = symbol.name; 118 | var indexArtMethod = name.indexOf("ArtMethod"); 119 | var indexInvoke = name.indexOf("Invoke"); 120 | var indexThread = name.indexOf("Thread"); 121 | if (indexArtMethod >= 0 122 | && indexInvoke >= 0 123 | && indexThread >= 0 124 | && indexArtMethod < indexInvoke 125 | && indexInvoke < indexThread) { 126 | console.log(name); 127 | ArtMethod_Invoke = address; 128 | } 129 | } 130 | if (ArtMethod_Invoke) { 131 | Interceptor.attach(ArtMethod_Invoke, { 132 | onEnter: function (args) { 133 | var method_name = prettyMethod(args[0], 0); 134 | if (!FILTER_SYSTEM_CLASSES || !(method_name.indexOf("java.") == 0 || method_name.indexOf("android.") == 0)) { 135 | var stackTraceMsg = Thread.backtrace(this.context, Backtracer.ACCURATE) 136 | .map(DebugSymbol.fromAddress).join('\n'); 137 | 138 | // 检查调用栈是否包含目标 SO 139 | if (TARGET_SO_LIST.length === 0) { 140 | // 监控所有 141 | console.log("ArtMethod Invoke:" + method_name + ' called from:\n' + stackTraceMsg + '\n'); 142 | } else { 143 | // 检查调用栈中是否包含目标 SO 144 | var shouldLog = false; 145 | for (var i = 0; i < TARGET_SO_LIST.length; i++) { 146 | if (stackTraceMsg.indexOf(TARGET_SO_LIST[i]) >= 0) { 147 | shouldLog = true; 148 | break; 149 | } 150 | } 151 | if (shouldLog) { 152 | console.log("ArtMethod Invoke:" + method_name + ' called from:\n' + stackTraceMsg + '\n'); 153 | } 154 | } 155 | } 156 | } 157 | }); 158 | } 159 | } 160 | 161 | function main() { 162 | hook_dlopen("libart.so", hook_native); 163 | hook_native(); 164 | } 165 | 166 | setImmediate(main); -------------------------------------------------------------------------------- /src/copy/anti_frida.js: -------------------------------------------------------------------------------- 1 | function antiAntiFrida() { 2 | var strstr = Module.findExportByName(null, "strstr"); 3 | if (null !== strstr) { 4 | Interceptor.attach(strstr, { 5 | onEnter: function (args) { 6 | this.frida = Boolean(0); 7 | 8 | this.haystack = args[0]; 9 | this.needle = args[1]; 10 | 11 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 12 | if (this.haystack.readCString().indexOf("frida") !== -1 || 13 | this.needle.readCString().indexOf("frida") !== -1 || 14 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 15 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 16 | this.haystack.readCString().indexOf("gmain") !== -1 || 17 | this.needle.readCString().indexOf("gmain") !== -1 || 18 | this.haystack.readCString().indexOf("linjector") !== -1 || 19 | this.needle.readCString().indexOf("linjector") !== -1) { 20 | this.frida = Boolean(1); 21 | } 22 | } 23 | }, 24 | onLeave: function (retval) { 25 | if (this.frida) { 26 | retval.replace(ptr("0x0")); 27 | } 28 | 29 | } 30 | }) 31 | } 32 | 33 | 34 | function dis(address, number) { 35 | for (var i = 0; i < number; i++) { 36 | var ins = Instruction.parse(address); 37 | // console.log("address:" + address + "--dis:" + ins.toString()); 38 | address = ins.next; 39 | } 40 | } 41 | //libc->strstr() 从linker里面找到call_function的地址:趁so代码还未执行前就hook 42 | //call_function("DT_INIT", init_func_, get_realpath()); 43 | var linkermodule = Process.getModuleByName("linker"); 44 | var call_function_addr = null; 45 | var symbols = linkermodule.enumerateSymbols(); 46 | for (var i = 0; i < symbols.length; i++) { 47 | var symbol = symbols[i]; 48 | // LogPrint(linkername + "->" + symbol.name + "---" + symbol.address); 49 | if (symbol.name.indexOf("__dl__ZL13call_functionPKcPFviPPcS2_ES0_") != -1) { 50 | call_function_addr = symbol.address; 51 | // console.log("linker->" + symbol.name + "---" + symbol.address) 52 | } 53 | } 54 | Interceptor.attach(call_function_addr, { 55 | onEnter: function (args) { 56 | var type = ptr(args[0]).readUtf8String(); 57 | var address = args[1]; 58 | var sopath = ptr(args[2]).readUtf8String(); 59 | // console.log("loadso:" + sopath + "--addr:" + address + "--type:" + type); 60 | if (sopath.indexOf("libnative-lib.so") != -1) { 61 | var libnativemodule = Process.getModuleByName("xxxx.so");//call_function正在加载目标so,这时就拦截下来 62 | var base = libnativemodule.base; 63 | dis(base.add(0x1234).add(1), 10); 64 | var patchaddr = base.add(0x2345);//改so的机器码,避免待会完全加载后运行时就错过时机了! 65 | Memory.patchCode(patchaddr, 4, patchaddr => { 66 | var cw = new ThumbWriter(patchaddr); 67 | cw.putNop(); 68 | cw = new ThumbWriter(patchaddr.add(0x2)); 69 | cw.putNop(); 70 | cw.flush(); 71 | }); 72 | // console.log("+++++++++++++++++++++++") 73 | dis(base.add(0x1234).add(1), 10); 74 | // console.log("----------------------") 75 | 76 | dis(base.add(0x2345).add(1), 10); 77 | Memory.protect(base.add(0x8E78), 4, 'rwx'); 78 | base.add(0x1234).writeByteArray([0x00, 0xbf, 0x00, 0xbf]); 79 | // console.log("+++++++++++++++++++++++") 80 | dis(base.add(0x2345).add(1), 10); 81 | 82 | 83 | } 84 | } 85 | }) 86 | } 87 | setImmediate(antiAntiFrida) 88 | 89 | var isLite = false; 90 | var ByPassTracerPid = function () { 91 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 92 | var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 93 | Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 94 | var retval = fgets(buffer, size, fp); 95 | var bufstr = Memory.readUtf8String(buffer); 96 | if (bufstr.indexOf("TracerPid:") > -1) { 97 | Memory.writeUtf8String(buffer, "TracerPid:\t0"); 98 | } 99 | return retval; 100 | }, 'pointer', ['pointer', 'int', 'pointer'])); 101 | }; 102 | setImmediate(ByPassTracerPid); 103 | 104 | (function () { 105 | let Color = { RESET: "\x1b[39;49;00m", Black: "0;01", Blue: "4;01", Cyan: "6;01", Gray: "7;11", "Green": "2;01", Purple: "5;01", Red: "1;01", Yellow: "3;01" }; 106 | let LightColor = { RESET: "\x1b[39;49;00m", Black: "0;11", Blue: "4;11", Cyan: "6;11", Gray: "7;01", "Green": "2;11", Purple: "5;11", Red: "1;11", Yellow: "3;11" }; 107 | var colorPrefix = '\x1b[3', colorSuffix = 'm' 108 | for (let c in Color) { 109 | if (c == "RESET") continue; 110 | console[c] = function (message) { 111 | console.log(colorPrefix + Color[c] + colorSuffix + message + Color.RESET); 112 | } 113 | console["Light" + c] = function (message) { 114 | console.log(colorPrefix + LightColor[c] + colorSuffix + message + Color.RESET); 115 | } 116 | } 117 | })(); 118 | 119 | 120 | function printStack() { 121 | Java.perform(function () { 122 | var Exception = Java.use("java.lang.Exception"); 123 | var ins = Exception.$new("Exception"); 124 | var straces = ins.getStackTrace(); 125 | if (straces != undefined && straces != null) { 126 | var strace = straces.toString(); 127 | var replaceStr = strace.replace(/,/g, "\r\n"); 128 | console.Green( 129 | "============================= Stack start =======================" 130 | ); 131 | console.Blue(replaceStr); 132 | console.Green( 133 | "============================= Stack end =======================\r\n" 134 | ); 135 | Exception.$dispose(); 136 | } 137 | }); 138 | } -------------------------------------------------------------------------------- /src/copy/so.js: -------------------------------------------------------------------------------- 1 | function antiAntiFrida() { 2 | var strstr = Module.findExportByName(null, "strstr"); 3 | if (null !== strstr) { 4 | Interceptor.attach(strstr, { 5 | onEnter: function (args) { 6 | this.frida = Boolean(0); 7 | 8 | this.haystack = args[0]; 9 | this.needle = args[1]; 10 | 11 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 12 | if (this.haystack.readCString().indexOf("frida") !== -1 || 13 | this.needle.readCString().indexOf("frida") !== -1 || 14 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 15 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 16 | this.haystack.readCString().indexOf("gmain") !== -1 || 17 | this.needle.readCString().indexOf("gmain") !== -1 || 18 | this.haystack.readCString().indexOf("linjector") !== -1 || 19 | this.needle.readCString().indexOf("linjector") !== -1) { 20 | this.frida = Boolean(1); 21 | } 22 | } 23 | }, 24 | onLeave: function (retval) { 25 | if (this.frida) { 26 | retval.replace(ptr("0x0")); 27 | } 28 | 29 | } 30 | }) 31 | } 32 | } 33 | setImmediate(antiAntiFrida) 34 | 35 | var isLite = false; 36 | var ByPassTracerPid = function () { 37 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 38 | var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 39 | Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 40 | var retval = fgets(buffer, size, fp); 41 | var bufstr = Memory.readUtf8String(buffer); 42 | if (bufstr.indexOf("TracerPid:") > -1) { 43 | Memory.writeUtf8String(buffer, "TracerPid:\t0"); 44 | } 45 | return retval; 46 | }, 'pointer', ['pointer', 'int', 'pointer'])); 47 | }; 48 | setImmediate(ByPassTracerPid); 49 | 50 | function dis(address, number) { 51 | for (var i = 0; i < number; i++) { 52 | var ins = Instruction.parse(address); 53 | // console.log("address:" + address + "--dis:" + ins.toString()); 54 | address = ins.next; 55 | } 56 | } 57 | 58 | //libc->strstr() 从linker里面找到call_function的地址:趁so代码还未执行前就hook 59 | function hook() { 60 | //call_function("DT_INIT", init_func_, get_realpath()); 61 | var linkermodule = Process.getModuleByName("linker"); 62 | var call_function_addr = null; 63 | var symbols = linkermodule.enumerateSymbols(); 64 | for (var i = 0; i < symbols.length; i++) { 65 | var symbol = symbols[i]; 66 | // LogPrint(linkername + "->" + symbol.name + "---" + symbol.address); 67 | if (symbol.name.indexOf("__dl__ZL13call_functionPKcPFviPPcS2_ES0_") != -1) { 68 | call_function_addr = symbol.address; 69 | // console.log("linker->" + symbol.name + "---" + symbol.address) 70 | } 71 | } 72 | Interceptor.attach(call_function_addr, { 73 | onEnter: function (args) { 74 | var type = ptr(args[0]).readUtf8String(); 75 | var address = args[1]; 76 | var sopath = ptr(args[2]).readUtf8String(); 77 | // console.log("loadso:" + sopath + "--addr:" + address + "--type:" + type); 78 | if (sopath.indexOf("libnative-lib.so") != -1) { 79 | var libnativemodule = Process.getModuleByName("xxxx.so");//call_function正在加载目标so,这时就拦截下来 80 | var base = libnativemodule.base; 81 | dis(base.add(0x1234).add(1), 10); 82 | var patchaddr = base.add(0x2345);//改so的机器码,避免待会完全加载后运行时就错过时机了! 83 | Memory.patchCode(patchaddr, 4, patchaddr => { 84 | var cw = new ThumbWriter(patchaddr); 85 | cw.putNop(); 86 | cw = new ThumbWriter(patchaddr.add(0x2)); 87 | cw.putNop(); 88 | cw.flush(); 89 | }); 90 | // console.log("+++++++++++++++++++++++") 91 | dis(base.add(0x1234).add(1), 10); 92 | // console.log("----------------------") 93 | 94 | dis(base.add(0x2345).add(1), 10); 95 | Memory.protect(base.add(0x8E78), 4, 'rwx'); 96 | base.add(0x1234).writeByteArray([0x00, 0xbf, 0x00, 0xbf]); 97 | // console.log("+++++++++++++++++++++++") 98 | dis(base.add(0x2345).add(1), 10); 99 | 100 | 101 | } 102 | } 103 | }) 104 | } 105 | 106 | function main() { 107 | hook(); 108 | } 109 | 110 | setImmediate(main); 111 | 112 | 113 | function so_imports() { 114 | Java.perform(function () { 115 | var process_Obj_Module_Arr = Process.enumerateModules(); 116 | for (var i = 0; i < process_Obj_Module_Arr.length; i++) { 117 | var name = process_Obj_Module_Arr[i].name; 118 | if (name.indexOf('.so') != -1) { 119 | const hooks = Module.load(name); 120 | var Imports = hooks.enumerateImports(); 121 | for (var i = 0; i < Imports.length; i++) { 122 | var Import = Imports[i]; 123 | //so名字,函数类型,函数名称,属于的模块,函数地址 124 | console.log("so:", name, "type:", Import.type, 'name:', Import.name, "module:", Import.module, "address:", Import.address) 125 | } 126 | } 127 | } 128 | }); 129 | } 130 | 131 | 132 | function so_exports() { 133 | Java.perform(function () { 134 | var process_Obj_Module_Arr = Process.enumerateModules(); 135 | for (var i = 0; i < process_Obj_Module_Arr.length; i++) { 136 | var name = process_Obj_Module_Arr[i].name; 137 | if (name.indexOf('.so') != -1) { 138 | const hooks = Module.load(name); 139 | var Imports = hooks.enumerateExports(); 140 | for (var i = 0; i < Imports.length; i++) { 141 | var Import = Imports[i]; 142 | //so名字,函数类型,函数名称,属于的模块,函数地址 143 | console.log("so:", name, "type:", Import.type, 'name:', Import.name, "module:", Import.module, "address:", Import.address) 144 | } 145 | } 146 | } 147 | }); 148 | } 149 | 150 | // setTimeout(frida_Process, 5000); -------------------------------------------------------------------------------- /src/copy/JSONObject.js: -------------------------------------------------------------------------------- 1 | function antiAntiFrida() { 2 | var strstr = Module.findExportByName(null, "strstr"); 3 | if (null !== strstr) { 4 | Interceptor.attach(strstr, { 5 | onEnter: function (args) { 6 | this.frida = Boolean(0); 7 | 8 | this.haystack = args[0]; 9 | this.needle = args[1]; 10 | 11 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 12 | if (this.haystack.readCString().indexOf("frida") !== -1 || 13 | this.needle.readCString().indexOf("frida") !== -1 || 14 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 15 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 16 | this.haystack.readCString().indexOf("gmain") !== -1 || 17 | this.needle.readCString().indexOf("gmain") !== -1 || 18 | this.haystack.readCString().indexOf("linjector") !== -1 || 19 | this.needle.readCString().indexOf("linjector") !== -1) { 20 | this.frida = Boolean(1); 21 | } 22 | } 23 | }, 24 | onLeave: function (retval) { 25 | if (this.frida) { 26 | retval.replace(ptr("0x0")); 27 | } 28 | 29 | } 30 | }) 31 | } 32 | 33 | 34 | function dis(address, number) { 35 | for (var i = 0; i < number; i++) { 36 | var ins = Instruction.parse(address); 37 | // console.log("address:" + address + "--dis:" + ins.toString()); 38 | address = ins.next; 39 | } 40 | } 41 | //libc->strstr() 从linker里面找到call_function的地址:趁so代码还未执行前就hook 42 | //call_function("DT_INIT", init_func_, get_realpath()); 43 | var linkermodule = Process.getModuleByName("linker"); 44 | var call_function_addr = null; 45 | var symbols = linkermodule.enumerateSymbols(); 46 | for (var i = 0; i < symbols.length; i++) { 47 | var symbol = symbols[i]; 48 | // LogPrint(linkername + "->" + symbol.name + "---" + symbol.address); 49 | if (symbol.name.indexOf("__dl__ZL13call_functionPKcPFviPPcS2_ES0_") != -1) { 50 | call_function_addr = symbol.address; 51 | // console.log("linker->" + symbol.name + "---" + symbol.address) 52 | } 53 | } 54 | Interceptor.attach(call_function_addr, { 55 | onEnter: function (args) { 56 | var type = ptr(args[0]).readUtf8String(); 57 | var address = args[1]; 58 | var sopath = ptr(args[2]).readUtf8String(); 59 | // console.log("loadso:" + sopath + "--addr:" + address + "--type:" + type); 60 | if (sopath.indexOf("libnative-lib.so") != -1) { 61 | var libnativemodule = Process.getModuleByName("xxxx.so");//call_function正在加载目标so,这时就拦截下来 62 | var base = libnativemodule.base; 63 | dis(base.add(0x1234).add(1), 10); 64 | var patchaddr = base.add(0x2345);//改so的机器码,避免待会完全加载后运行时就错过时机了! 65 | Memory.patchCode(patchaddr, 4, patchaddr => { 66 | var cw = new ThumbWriter(patchaddr); 67 | cw.putNop(); 68 | cw = new ThumbWriter(patchaddr.add(0x2)); 69 | cw.putNop(); 70 | cw.flush(); 71 | }); 72 | // console.log("+++++++++++++++++++++++") 73 | dis(base.add(0x1234).add(1), 10); 74 | // console.log("----------------------") 75 | 76 | dis(base.add(0x2345).add(1), 10); 77 | Memory.protect(base.add(0x8E78), 4, 'rwx'); 78 | base.add(0x1234).writeByteArray([0x00, 0xbf, 0x00, 0xbf]); 79 | // console.log("+++++++++++++++++++++++") 80 | dis(base.add(0x2345).add(1), 10); 81 | 82 | 83 | } 84 | } 85 | }) 86 | } 87 | setImmediate(antiAntiFrida) 88 | 89 | var isLite = false; 90 | var ByPassTracerPid = function () { 91 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 92 | var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 93 | Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 94 | var retval = fgets(buffer, size, fp); 95 | var bufstr = Memory.readUtf8String(buffer); 96 | if (bufstr.indexOf("TracerPid:") > -1) { 97 | Memory.writeUtf8String(buffer, "TracerPid:\t0"); 98 | } 99 | return retval; 100 | }, 'pointer', ['pointer', 'int', 'pointer'])); 101 | }; 102 | setImmediate(ByPassTracerPid); 103 | 104 | 105 | function main() { 106 | Java.perform(function () { 107 | var JSONObject = Java.use('org.json.JSONObject'); 108 | JSONObject.toString.overload().implementation = function () { 109 | send("=================org.json.JSONObject.toString===================="); 110 | send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 111 | var data = this.toString(); 112 | send("org.json.JSONObject.toString result:" + data); 113 | return data; 114 | } 115 | for (var i = 0; i < JSONObject.put.overloads.length; i++) { 116 | JSONObject.put.overloads[i].implementation = function () { 117 | send("=================org.json.JSONObject.put===================="); 118 | if (arguments.length == 2) { 119 | send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 120 | send("key:" + arguments[0]); 121 | send("value:" + arguments[1]); 122 | var data = this.put(arguments[0], arguments[1]); 123 | return data; 124 | } 125 | } 126 | } 127 | for (var i = 0; i < JSONObject.$init.overloads.length; i++) { 128 | JSONObject.$init.overloads[i].implementation = function () { 129 | send("=================org.json.JSONObject.$init===================="); 130 | send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 131 | if (arguments.length == 1) {//只有1个string参数 132 | send("string:" + arguments[0]); 133 | } else if (arguments.length == 2) { //其他构造函数用到的时候可以继续添加 134 | } 135 | } 136 | } 137 | }) 138 | } --------------------------------------------------------------------------------