├── README.md ├── trace ├── jnitrace-chame1eon │ └── jnitrace │ │ ├── jnitrace │ │ ├── __init__.py │ │ └── src │ │ │ └── utils │ │ │ ├── method_data.ts │ │ │ ├── java_method.ts │ │ │ └── types.ts │ │ ├── MANIFEST.in │ │ ├── requirements.txt │ │ ├── tsconfig.json │ │ ├── .eslintrc.json │ │ ├── package.json │ │ ├── LICENSE │ │ ├── .travis.yml │ │ ├── setup.py │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ └── README.md ├── frida-smali-trace-master │ ├── frida_scripts │ │ ├── .gitignore │ │ ├── tsconfig.json │ │ ├── agent │ │ │ ├── logger.ts │ │ │ ├── util.ts │ │ │ ├── helper.ts │ │ │ └── index.ts │ │ ├── README.md │ │ └── package.json │ ├── .gitignore │ ├── images │ │ ├── Snipaste_2022-01-16_22-55-59.png │ │ ├── Snipaste_2022-01-16_22-58-05.png │ │ ├── Snipaste_2022-01-16_23-12-27.png │ │ ├── Snipaste_2022-05-14_17-11-53.png │ │ ├── Snipaste_2022-05-14_17-15-31.png │ │ ├── Snipaste_2022-05-21_18-25-27.png │ │ ├── Snipaste_2022-05-21_19-16-15.png │ │ ├── Snipaste_2022-05-21_19-49-58.png │ │ ├── Snipaste_2022-05-21_20-17-12.png │ │ ├── Snipaste_2022-05-21_20-21-20.png │ │ ├── Snipaste_2022-05-21_20-38-11.png │ │ ├── Snipaste_2022-05-21_20-39-20.png │ │ ├── Snipaste_2022-05-21_20-41-05.png │ │ ├── Snipaste_2022-05-21_20-46-41.png │ │ ├── Snipaste_2022-05-21_20-55-12.png │ │ ├── Snipaste_2022-05-21_21-02-06.png │ │ ├── Snipaste_2022-05-21_21-12-09.png │ │ ├── Snipaste_2022-05-21_21-24-24.png │ │ ├── Snipaste_2022-05-21_21-25-51.png │ │ ├── Snipaste_2022-05-21_21-33-24.png │ │ ├── Snipaste_2022-05-21_21-59-35.png │ │ ├── Snipaste_2022-05-21_22-26-07.png │ │ ├── Snipaste_2022-05-21_22-28-30.png │ │ ├── Snipaste_2022-05-21_22-30-25.png │ │ ├── Snipaste_2022-05-21_22-32-29.png │ │ ├── Snipaste_2022-05-21_22-36-52.png │ │ ├── Snipaste_2022-05-21_22-48-36.png │ │ ├── Snipaste_2022-05-21_22-49-13.png │ │ ├── Snipaste_2022-05-21_22-51-33.png │ │ ├── Snipaste_2022-05-21_23-03-53.png │ │ ├── Snipaste_2022-05-21_23-06-55.png │ │ ├── Snipaste_2022-05-21_23-13-06.png │ │ ├── Snipaste_2022-05-21_23-15-33.png │ │ ├── Snipaste_2022-05-21_23-30-06.png │ │ └── Snipaste_2022-05-21_23-50-43.png │ └── README.md ├── r0tracer-main │ ├── pic │ │ ├── 01.png │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ └── 05.png │ ├── README.md │ └── r0tracer.js ├── raptor_frida_android_trace.js └── raptor_frida_android_trace_fixed.js ├── .DS_Store ├── 脱壳 ├── FRIDA-DEXDump │ ├── requirements.txt │ ├── screenshot.png │ ├── setup.py │ ├── frida_dexdump │ │ ├── __init__.py │ │ ├── agent.js │ │ └── main.py │ └── README.md ├── frida-unpack-master │ └── frida-unpack-master │ │ ├── inject.sh │ │ ├── LICENSE │ │ ├── OpenMemory.js │ │ ├── README.md │ │ └── frida_unpack.py ├── README.md ├── frida_dump-r0ysue │ └── frida_dump │ │ ├── dump_so.js │ │ ├── README.md │ │ └── dump_dex.js ├── unpack.js └── unpackdex.js ├── 其他 ├── .DS_Store ├── 查看内存中类的属性和具体参数 │ ├── .idea │ │ ├── .gitignore │ │ ├── misc.xml │ │ ├── vcs.xml │ │ ├── modules.xml │ │ └── 查看内存中类的属性和具体参数.iml │ └── 1.js ├── getintent查看内容 │ ├── .DS_Store │ └── 1.js ├── 打印[object object]的具体类名 │ └── 1.js ├── 插件化apk替换classloader │ └── 1.js ├── 打印常见数据结构 │ └── index.js ├── 栈回溯 │ └── 1.js └── 不可见类名字符hook │ └── 1.js ├── hook ├── Il2CppHookScripts-master │ └── Il2CppHookScripts-master │ │ ├── Il2cppHook(ts) │ │ └── README.md │ │ ├── imgs │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── hookc.png │ │ ├── u3d_0.png │ │ ├── u3d_1.png │ │ ├── u3d_10.png │ │ ├── u3d_2.png │ │ ├── u3d_3.png │ │ ├── u3d_4.png │ │ ├── u3d_5.png │ │ ├── u3d_6.png │ │ ├── u3d_7.png │ │ ├── u3d_8.png │ │ └── u3d_9.png │ │ ├── Others │ │ ├── FTS │ │ │ ├── README.md │ │ │ ├── MD5_SHA.js │ │ │ └── fts.js │ │ └── IDAScript.py │ │ ├── README.md │ │ ├── Scripts │ │ ├── README.md │ │ ├── dps.py │ │ └── bpoints.js │ │ └── Il2cppHook │ │ └── README.md ├── dlopen后第一时间劫持 │ └── exp.js └── hook_libart脚本 │ ├── hook_registerNatives.js │ ├── hook_artmethod.js │ └── hook_art.js ├── antidebug └── anti-tracepid │ └── index.ts └── objection使用 └── objection.md /README.md: -------------------------------------------------------------------------------- 1 | 主要记录我在逆向时用到的一些脚本,主要是对别人脚本的整合 -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/jnitrace/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/frida_scripts/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include jnitrace/build/jnitrace.js -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/.DS_Store -------------------------------------------------------------------------------- /脱壳/FRIDA-DEXDump/requirements.txt: -------------------------------------------------------------------------------- 1 | click 2 | frida 3 | backports.shutil-get-terminal-size -------------------------------------------------------------------------------- /其他/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/其他/.DS_Store -------------------------------------------------------------------------------- /其他/查看内存中类的属性和具体参数/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.id0 3 | *.id1 4 | *.id2 5 | *.nam 6 | *.til -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/requirements.txt: -------------------------------------------------------------------------------- 1 | frida>=14.0.5 2 | colorama 3 | hexdump 4 | 5 | pylint 6 | -------------------------------------------------------------------------------- /其他/getintent查看内容/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/其他/getintent查看内容/.DS_Store -------------------------------------------------------------------------------- /trace/r0tracer-main/pic/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/r0tracer-main/pic/01.png -------------------------------------------------------------------------------- /trace/r0tracer-main/pic/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/r0tracer-main/pic/02.png -------------------------------------------------------------------------------- /trace/r0tracer-main/pic/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/r0tracer-main/pic/03.png -------------------------------------------------------------------------------- /trace/r0tracer-main/pic/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/r0tracer-main/pic/04.png -------------------------------------------------------------------------------- /trace/r0tracer-main/pic/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/r0tracer-main/pic/05.png -------------------------------------------------------------------------------- /脱壳/FRIDA-DEXDump/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/脱壳/FRIDA-DEXDump/screenshot.png -------------------------------------------------------------------------------- /脱壳/frida-unpack-master/frida-unpack-master/inject.sh: -------------------------------------------------------------------------------- 1 | echo "Usage: ./inject.sh packageName xx.js" 2 | 3 | frida -U -f $1 -l $2 --no-pause -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/Il2cppHook(ts)/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # todo 4 | 5 | - 使用ts重写ufun.js 6 | 7 | 参见ts分支 8 | 9 | 10 | -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/1.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/2.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/3.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/hookc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/hookc.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_0.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_1.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_10.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_2.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_3.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_4.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_5.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_6.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_7.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_8.png -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/hook/Il2CppHookScripts-master/Il2CppHookScripts-master/imgs/u3d_9.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-01-16_22-55-59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-01-16_22-55-59.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-01-16_22-58-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-01-16_22-58-05.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-01-16_23-12-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-01-16_23-12-27.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-14_17-11-53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-14_17-11-53.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-14_17-15-31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-14_17-15-31.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_18-25-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_18-25-27.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_19-16-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_19-16-15.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_19-49-58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_19-49-58.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-17-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-17-12.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-21-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-21-20.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-38-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-38-11.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-39-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-39-20.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-41-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-41-05.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-46-41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-46-41.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-55-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_20-55-12.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-02-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-02-06.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-12-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-12-09.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-24-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-24-24.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-25-51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-25-51.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-33-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-33-24.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-59-35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_21-59-35.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-26-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-26-07.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-28-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-28-30.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-30-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-30-25.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-32-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-32-29.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-36-52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-36-52.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-48-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-48-36.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-49-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-49-13.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-51-33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_22-51-33.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-03-53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-03-53.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-06-55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-06-55.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-13-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-13-06.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-15-33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-15-33.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-30-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-30-06.png -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-50-43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/20000s/frida-script-collection/HEAD/trace/frida-smali-trace-master/images/Snipaste_2022-05-21_23-50-43.png -------------------------------------------------------------------------------- /其他/查看内存中类的属性和具体参数/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /其他/查看内存中类的属性和具体参数/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/frida_scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "lib": ["es2020"], 5 | "allowJs": true, 6 | "noEmit": true, 7 | "strict": true, 8 | "esModuleInterop": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/frida_scripts/agent/logger.ts: -------------------------------------------------------------------------------- 1 | import { rpc_mode } from "./index"; 2 | 3 | export function log(message: string): void { 4 | if(rpc_mode){ 5 | send({"type": "log", info: message}); 6 | } 7 | else{ 8 | console.log(message); 9 | } 10 | } -------------------------------------------------------------------------------- /其他/打印[object object]的具体类名/1.js: -------------------------------------------------------------------------------- 1 | 打印 [object object] 2 | 3 | 方法 1:先确认 object 是什么类型,比如要打印 p,先 console.log(p.$className) 查看 p 是什么数据类型,然后用 Java.cast 把 p 强制转为对应类型,强制转换之后,在调用转换后类型的输出方法,通常为 toString() 4 | 方法 2:使用 js 里面的 json 类,尝试 console.log(JSON.stringify(p)),可能打印不出来字符串,一般能打印出 p 的字节数组 5 | 方法 3:使用 objection 插件 wallbreak 6 | -------------------------------------------------------------------------------- /其他/查看内存中类的属性和具体参数/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "lib": ["esnext"], 5 | "allowJs": true, 6 | "noEmit": true, 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "resolveJsonModule": true, 10 | "moduleResolution": "node" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/Others/FTS/README.md: -------------------------------------------------------------------------------- 1 | # Il2CppDumperTool 2 | 3 | hookC用来断点c函数便于寻找反调试的点 4 |
 5 | frida -U -f  -l hookC.js --no-pause
 6 | 
7 | 8 | ![hookc.png](https://github.com/axhlzy/Il2CppDumperTool/blob/master/imgs/hookc.png) 9 | 10 | 11 | 12 | 13 | 14 | https://gtoad.github.io/2017/06/25/Android-Anti-Debug/ 15 | -------------------------------------------------------------------------------- /其他/查看内存中类的属性和具体参数/.idea/查看内存中类的属性和具体参数.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/README.md: -------------------------------------------------------------------------------- 1 | ## Scripts 2 | 该文件目录下的脚本用作Il2CppDumper生成的script.json,筛选函数dps.py 用作bpoints.js进行批量断点 3 | 4 | ## Il2cppHook 5 | libil2cpp.so 解析脚本 6 | [参考简书的说明](https://www.jianshu.com/p/230f51dc09c0) 7 | 8 | ## MonoHook 9 | libmono.so 解析脚本 10 | 11 | ## Others 12 | 一些其他的脚本 13 | 14 | 15 | 16 | 21 | 22 | -------------------------------------------------------------------------------- /其他/插件化apk替换classloader/1.js: -------------------------------------------------------------------------------- 1 | Java.enumerateClassLoaders({ 2 | "onMatch": function(loader) { 3 | if (loader.toString().startsWith("com.tencent.shadow.core.loader.classloaders.PluginClassLoader")) { 4 | Java.classFactory.loader = loader; // 将当前class factory中的loader指定为我们需要的 5 | } 6 | }, 7 | "onComplete": function() { 8 | // console.log("success :" + Java.classFactory.loader); 9 | } 10 | }); -------------------------------------------------------------------------------- /脱壳/README.md: -------------------------------------------------------------------------------- 1 | unpack.js 2 | 3 | 原理: 4 | 5 | 把所有的方法 类加载一遍 再hook openmemory 6 | 7 | 可以应对第二代壳(指令提取) 8 | 9 | 10 | unpackdex.js是hook openmemory opencommpn dalvikopen的 11 | 12 | 只能脱整体壳 指令提取是空壳 13 | 14 | frida -U -f com.xxx.xxx.xxx -l dumpDex.js --no-pause 15 | 16 | 17 | 18 | frida_dump 19 | 20 | hook defineclass 21 | 22 | 23 | 24 | frida-dexdump 25 | 26 | 内存遍历寻找dex035或是深度搜索 符合dex文件结构 27 | 28 | 29 | frida_unpack 30 | frida hook opencommn openmemory 有完整签名 android 7 android 10 测试过 (360壳) 31 | -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/frida_scripts/README.md: -------------------------------------------------------------------------------- 1 | ### How to compile & load 2 | 3 | ```sh 4 | $ git clone git://github.com/oleavr/frida-agent-example.git 5 | $ cd frida-agent-example/ 6 | $ npm install 7 | $ frida -U -f com.example.android --no-pause -l _agent.js 8 | ``` 9 | 10 | ### Development workflow 11 | 12 | To continuously recompile on change, keep this running in a terminal: 13 | 14 | ```sh 15 | $ npm run watch 16 | ``` 17 | 18 | And use an editor like Visual Studio Code for code completion and instant 19 | type-checking feedback. 20 | -------------------------------------------------------------------------------- /其他/打印常见数据结构/index.js: -------------------------------------------------------------------------------- 1 | // 打印list 2 | var iterator = rootHosts.iterator(); 3 | while (iterator.hasNext()) { 4 | var element = iterator.next(); 5 | console.log(element); 6 | } 7 | 8 | //打印map 9 | var Map = Java.use('java.util.Map'); 10 | 11 | var mapInstance = Java.cast(result, Map); 12 | 13 | var keySet = mapInstance.keySet(); 14 | var iterator = keySet.iterator(); 15 | while (iterator.hasNext()) { 16 | var key = iterator.next(); 17 | var value = mapInstance.get(key); 18 | console.log('Key:', key, 'Value:', value); 19 | } -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/frida_scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frida-agent-example", 3 | "version": "1.0.0", 4 | "description": "Example Frida agent written in TypeScript", 5 | "private": true, 6 | "main": "agent/index.ts", 7 | "scripts": { 8 | "prepare": "npm run build", 9 | "build": "frida-compile agent/index.ts -o _agent.js -c", 10 | "watch": "frida-compile agent/index.ts -o _agent.js -w" 11 | }, 12 | "devDependencies": { 13 | "@types/frida-gum": "^17.1.0", 14 | "@types/node": "^16.4.8", 15 | "frida-compile": "^10.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/Scripts/README.md: -------------------------------------------------------------------------------- 1 | # Il2CppDumperTool 2 | 该脚本用来批量断点libil2cpp.so的函数 3 |
 4 | 1. dps.py
 5 | 
 6 | 主要用来为Il2CppDumper生成的script.json提供一个关键字搜索,并转换为地址与名称对应关系,便于bpoints.js使用
 7 | 
 8 | 2. bpoints.js
 9 | 
10 | frida使用的js脚本,用到dlopen来获得加载时机,并注入断点
11 | 
12 | 13 | ###### python脚本的使用 14 | ![1.png](../imgs/1.png) "bpoints.js") 15 | 16 | cp上述结果到 bpoints.js 中替换对应的部分,再用frida去加载这段js即可批量断点以上函数 17 | 18 | ###### 添加对libil2cpp.so的函数断点 19 | ![2.png](../imgs/2.png "dps.py") 20 | 21 | ###### 点击按钮触发函数回调 22 | ![3.png](../imgs/3.png "dps.py") 23 | 24 | ###### 这三个暴力使用,容易崩,不建议使用 25 | HookExports,HookImports,HookSymbols 26 | -------------------------------------------------------------------------------- /antidebug/anti-tracepid/index.ts: -------------------------------------------------------------------------------- 1 | function hook_tridepid(){ 2 | var fgets_ptr = Module.getExportByName("libc.so","fgets"); 3 | var fgets = new NativeFunction(fgets_ptr,"pointer",["pointer","int","pointer"]); 4 | 5 | Interceptor.replace(fgets_ptr, new NativeCallback(function (buffer,n,filestream){ 6 | var ret = fgets(buffer,n,filestream); 7 | var line = buffer.readUtf8String(); 8 | if(line.indexOf("TracerPid") != -1){ 9 | console.log("hook gets " + line + "'"); 10 | buffer.writeUtf8String("TracerPid:\t0\n"); 11 | }else{ 12 | 13 | } 14 | return ret; 15 | },"pointer",["pointer","int","pointer"])); 16 | 17 | 18 | 19 | } -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "project": "./tsconfig.json" 4 | }, 5 | "parser": "@typescript-eslint/parser", 6 | "plugins": [ 7 | "@typescript-eslint" 8 | ], 9 | "extends": [ 10 | "plugin:@typescript-eslint/all" 11 | ], 12 | "rules": { 13 | "@typescript-eslint/no-this-alias": [ 14 | "error", 15 | { 16 | "allowDestructuring": true, 17 | "allowedNames": ["self"] 18 | } 19 | ], 20 | "@typescript-eslint/prefer-readonly-parameter-types": "off", 21 | "@typescript-eslint/no-base-to-string": "off" 22 | } 23 | } -------------------------------------------------------------------------------- /其他/栈回溯/1.js: -------------------------------------------------------------------------------- 1 | function showStacks3(str_tag) 2 | { 3 | var Exception= Java.use("java.lang.Exception"); 4 | var ins = Exception.$new("Exception"); 5 | var straces = ins.getStackTrace(); 6 | 7 | if (undefined == straces || null == straces) 8 | { 9 | return; 10 | } 11 | 12 | console.log("=============================" + str_tag + " Stack strat======================="); 13 | console.log(""); 14 | 15 | for (var i = 0; i < straces.length; i++) 16 | { 17 | var str = " " + straces[i].toString(); 18 | console.log(str); 19 | } 20 | 21 | console.log(""); 22 | console.log("=============================" + str_tag + " Stack end=======================\r\n"); 23 | Exception.$dispose(); 24 | }; -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jnitrace", 3 | "version": "3.2.0", 4 | "description": "A tool for tracing use of the JNI in Android apps", 5 | "private": true, 6 | "main": "jnitrace/src/main.js", 7 | "scripts": { 8 | "prepare": "npm run build", 9 | "build": "frida-compile jnitrace/src/main.ts -o jnitrace/build/jnitrace.js -c", 10 | "watch": "frida-compile jnitrace/src/main.ts -o jnitrace/build/jnitrace.js -cw", 11 | "lint": "eslint jnitrace/src/**/*.ts" 12 | }, 13 | "dependencies": { 14 | "jnitrace-engine": "^1.1.0" 15 | }, 16 | "devDependencies": { 17 | "@types/frida-gum": "^16.2.0", 18 | "@types/node": "^14.14.5", 19 | "@typescript-eslint/eslint-plugin": "^2.27.0", 20 | "@typescript-eslint/parser": "^2.27.0", 21 | "eslint": "^6.8.0", 22 | "eslint-utils": "^2.0.0", 23 | "frida-compile": "^10.0.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /脱壳/frida_dump-r0ysue/frida_dump/dump_so.js: -------------------------------------------------------------------------------- 1 | function dump_so(so_name) { 2 | Java.perform(function () { 3 | var currentApplication = Java.use("android.app.ActivityThread").currentApplication(); 4 | var dir = currentApplication.getApplicationContext().getFilesDir().getPath(); 5 | var libso = Process.getModuleByName(so_name); 6 | console.log("[name]:", libso.name); 7 | console.log("[base]:", libso.base); 8 | console.log("[size]:", ptr(libso.size)); 9 | console.log("[path]:", libso.path); 10 | var file_path = dir + "/" + libso.name + "_" + libso.base + "_" + ptr(libso.size) + ".so"; 11 | var file_handle = new File(file_path, "wb"); 12 | if (file_handle && file_handle != null) { 13 | Memory.protect(ptr(libso.base), libso.size, 'rwx'); 14 | var libso_buffer = ptr(libso.base).readByteArray(libso.size); 15 | file_handle.write(libso_buffer); 16 | file_handle.flush(); 17 | file_handle.close(); 18 | console.log("[dump]:", file_path); 19 | } 20 | }); 21 | } -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 chame1eon 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 | -------------------------------------------------------------------------------- /脱壳/frida-unpack-master/frida-unpack-master/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Nishanth Shanmugham 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. -------------------------------------------------------------------------------- /脱壳/frida-unpack-master/frida-unpack-master/OpenMemory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * 此脚本在以下环境测试通过 4 | * android os: 7.1.2 32bit (64位可能要改OpenMemory的签名) 5 | * legu: libshella-2.8.so 6 | * 360:libjiagu.so 7 | */ 8 | Interceptor.attach(Module.findExportByName("libart.so", "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_"), { 9 | onEnter: function (args) { 10 | 11 | //dex起始位置 12 | var begin = args[1] 13 | //打印magic 14 | console.log("magic : " + Memory.readUtf8String(begin)) 15 | //dex fileSize 地址 16 | var address = parseInt(begin,16) + 0x20 17 | //dex 大小 18 | var dex_size = Memory.readInt(ptr(address)) 19 | 20 | console.log("dex_size :" + dex_size) 21 | //dump dex 到/data/data/pkg/目录下 22 | var file = new File("/data/data/xxx.xxx.xxx/" + dex_size + ".dex", "wb") 23 | file.write(Memory.readByteArray(begin, dex_size)) 24 | file.flush() 25 | file.close() 26 | }, 27 | onLeave: function (retval) { 28 | if (retval.toInt32() > 0) { 29 | /* do something */ 30 | } 31 | } 32 | }); -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - 3.6 5 | 6 | install: 7 | - pip install -r requirements.txt 8 | - pip install . 9 | - nvm install 12.7.0 10 | - npm install 11 | 12 | before_script: 13 | - touch jnitrace/build/__init__.py 14 | 15 | script: 16 | - pylint jnitrace/jnitrace.py 17 | - npm run lint 18 | 19 | deploy: 20 | provider: pypi 21 | user: chame1eon 22 | password: 23 | secure: PkNiWyAivXABjKf0Qhf6tTboiEfbELApF7FYbpbEW1jwZ8+L9xcjVyUqfKFV/KXC4BBjp5x0vsL7T0O89A1+puzxIMFDvT8Gr/DXTNGQqcAzSsJv4k5X8VD8bgfCpj3rP4SpdfosDsYmwqFSZxkTLTPkSsggybNVCYocfYR5/aWW9XXzFBFld4AJ0LmqvUSMhxjAC5aekWYRjhqLJO2fs2tLmQn1ClPAi6c6d++aM9Q5SnTEA91kh/EXOcGvME3DLQ6v/DlefqjFlQ3ncanJ93cnjbNnRf2kah7gW4Hcq9/9aS6XyHAr6e5fq7QD1DlC6qJiY0m91Q1OcGCZwWiVfcrrJTotQj3ObAMQv5s//My36ge2uduuByXPsQ4++RUmTpFScCcI1obmsJs4jL97lc/sdes6phaUallx5XUxTFgYLBiHtD5eCkn4TAM3a4HWpC7IlN5C95cBMg6/5BhYKpKsEFCb8KOMviDP5xYJ4VgEyUSf7wTcmg+ZI61LJnwnGT67gZ64EMM05d3zAp0oEg1yVZ0v285knn0bneJQVBh3N4JUiFnDzdxVlA1En327EFZ4FLsKmSZlplhlAKF8BdGjWTbNM3Q/Q8HxYbhyUmGNMuxqsZ7YmJp4IwgV7TmUOiRfTL9AITUPmUrQbMkLNUhI92nR8VDbmyeT/JhgY58= 24 | skip_cleanup: true 25 | skip_existing: true 26 | on: 27 | tags: true 28 | -------------------------------------------------------------------------------- /其他/不可见类名字符hook/1.js: -------------------------------------------------------------------------------- 1 | //来自http://91fans.com.cn/post/findclassname/#gsc.tab=0 2 | // 这个包下的类都遍历出来,这样不就可以知道这个类名的UTF-8 编码的转义了吗? 3 | Java.enumerateLoadedClasses({ 4 | onMatch: function(className) { 5 | if(className.indexOf('com.google.android.material.tooltip') >=0 ){ 6 | console.log(className.toString()); 7 | console.log(encodeURIComponent(className.toString())); 8 | } 9 | }, 10 | onComplete:function(){ 11 | } 12 | }); 13 | 14 | // decodeURIComponent hook 15 | var hookCls = Java.use(decodeURIComponent('com.google.android.material.tooltip.%DB%A4%DB%A4%DB%9F%DB%A6')); 16 | //遍历方法名 17 | //var hookCls = Java.use(decodeURIComponent('com.google.android.material.tooltip.%DB%A4%DB%A4%DB%9F%DB%A6')); 18 | var methods = hookCls.class.getDeclaredMethods(); 19 | 20 | for (var i in methods) { 21 | console.log(methods[i].toString()); 22 | console.log(encodeURIComponent(methods[i].toString().replace(/^.*?\.([^\s\.\(\)]+)\(.*?$/, "$1"))); 23 | } 24 | 25 | //Hook这个成员函数的代码 26 | hookCls[decodeURIComponent("%DB%9F%DB%A3%DB%A5%DB%9F%DB%A3")] 27 | .implementation = function () { 28 | console.log("m1344 =============== "); 29 | return "xxx"; 30 | 31 | } -------------------------------------------------------------------------------- /objection使用/objection.md: -------------------------------------------------------------------------------- 1 | objection连接: 2 | 3 | usb: objection -g 包名 explore 4 | 5 | 搜加载的so文件:memory list modules 6 | 7 | 查看库的导出函数:memory list exports libssl.so 8 | 9 | 在内存堆中搜索与执行:android heap search instances xxx.xxx.xxx.类名 10 | 11 | 调用 android heap execute 堆地址 方法名 12 | 13 | 在实例上执行js代码: android heap evaluate 堆地址 后就可以输入js 14 | 15 | 启动activity或者service android intent launch_activity 包名.活动名 16 | 17 | ​ 查看当前可用的activity android hooking list activities 18 | 19 | 查看可用的services service: android hooking list services 20 | 21 | ​ 启动service android intent launch_service 包名.活动名 22 | 23 | 列出内存中所有的类:android hooking list classes 24 | 25 | 内存中搜索所有的类: android hooking search classes 关键词 26 | 27 | 内存中搜索所有的方法:android hooking search methods 关键词 28 | 29 | 列出类的所有方法 : android hooking list class_methods 类名 30 | 31 | hook类的所有方法 : android hooking watch class 类名 32 | 33 | hook方法的参数,返回值和调用栈 : android hooking watch class_method 方法名 --dump-args --dump-return --dump-backtrace 34 | 35 | hook 方法的所有重载 : objection自动加载 36 | 37 | 暴力搜索所有dalvik.system.DexClassLoader : **android** **heap** **search** **instances** **dalvik**.system.DexClassLoader 38 | 39 | 暴力搜内存: memory search "64 65 78 0a 30 33 35 00" 40 | 41 | 把它拷贝下来 : memory dump from_base 地址 大小 文件名 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | ​ -------------------------------------------------------------------------------- /其他/getintent查看内容/1.js: -------------------------------------------------------------------------------- 1 | Activity["getIntent"].implementation = function() { 2 | let result = this["getIntent"](); 3 | var tmp = result.getExtras() 4 | if(tmp != null) { 5 | console.log("---------------- bundle contents--------------------") 6 | console.log("getintent :data " + result.getData() + " " + this) 7 | console.log("getintent.getExtras : " + tmp) 8 | console.log('---Bundle contents:---'); 9 | var keySet = tmp.keySet(); 10 | var iterator = keySet.iterator(); 11 | while (iterator.hasNext()) { 12 | var key = iterator.next(); 13 | var value = tmp.get(key); 14 | console.log(key + ': ' + value); 15 | if(value != null){ 16 | if(value.toString().indexOf("Bundle") != -1) { 17 | console.log(value + '---Bundle contents:---'); 18 | var value12 = Java.cast(value,Java.use('android.os.Bundle')) 19 | var keySet1 = value12.keySet(); 20 | var iterator1 = keySet1.iterator(); 21 | while (iterator1.hasNext()) { 22 | var key1 = iterator1.next(); 23 | var value1 = value12.get(key1); 24 | console.log(key1 + ': ' + value1); 25 | } 26 | console.log(value + '---Bundle contents end---'); 27 | } 28 | } 29 | } 30 | console.log("---------------- bundle content end--------------------") 31 | } 32 | return result 33 | } 34 | -------------------------------------------------------------------------------- /脱壳/frida-unpack-master/frida-unpack-master/README.md: -------------------------------------------------------------------------------- 1 | # frida-unpack 2 | 基于Frida的脱壳工具 3 | ## 0x0 frida环境搭建 4 | frida环境搭建,参考frida官网:[frida](https://www.frida.re)。 5 | 6 | ## 0x2 原理说明 7 | 利用frida hook libart.so中的OpenMemory方法,拿到内存中dex的地址,计算出dex文件的大小,从内存中将dex导出。 8 | ps:查看OpenMemory的导出名称,可以将手机中的libart.so通过adb pull命令导出到电脑,然后利用: 9 | `nm libart.so |grep OpenMemory`命令来查看到出名。 10 | 其中android 10为`/apex/com.android.runtime/lib/libdexfile.so`方法为`OpenCommon`。 11 | 12 | ## 0x3 脚本用法 13 | - 在手机上启动frida server端 14 | - 执行脱壳脚本 15 | ``` 16 | 执行./inject.sh 要脱壳的应用的包名 OpenMemory.js 17 | ``` 18 | - 脱壳后的dex保存在`/data/data/应用包名/`目录下 19 | 20 | ## 0x4 脚本测试环境 21 | 此脚本在以下环境测试通过 22 | * android os: 7.1.2 32bit (64位可能要改OpenMemory的签名) 23 | * legu: libshella-2.8.so 24 | * 360: libjiagu.so 25 | 26 | ## 0x5 参考链接 27 | - [frida](https://www.frida.re) 28 | 29 | ## 0x06 python脚本支持 30 | `python frida_unpack.py 应用包名` 31 | 32 | ## 0x07 相关技巧 33 | - 利用`c++filt`命令还原C++ name managling之后的函数名 34 | 35 | ``` 36 | c++filt _ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_ 37 | 38 | 输出: 39 | art::DexFile::OpenMemory(unsigned char const*, unsigned int, std::__1::basic_string, std::__1::allocator > const&, unsigned int, art::MemMap*, art::OatDexFile const*, std::__1::basic_string, std::__1::allocator >*) 40 | ``` -------------------------------------------------------------------------------- /其他/查看内存中类的属性和具体参数/1.js: -------------------------------------------------------------------------------- 1 | // Java.perform(function(){ 2 | // var clz = Java.use("com.tencent.wework.foundation.model.pb.WwLoginKeys$LoginKeys") 3 | // var JavaString = Java.use("java.lang.String"); 4 | // clz.mergeFrom.overload('com.google.protobuf.nano.CodedInputByteBufferNano').implementation = function(){ 5 | // console.log("mergeFrom arg0:" + arguments[0]) 6 | // // console.log("CalcCST arg0:") 7 | // var fields = Java.cast(arguments[0].getClass(),Java.use('java.lang.Class')).getDeclaredFields(); 8 | // //console.log(fields); 9 | // for (var j = 0; j < fields.length; j++) { 10 | // var field = fields[j]; 11 | // field.setAccessible(true); 12 | // var name = field.getName(); 13 | // var value =field.get(arguments[0]) 14 | // console.log("\t\tname:"+name+"\tvalue:"+value)} 15 | // return this.mergeFrom.apply(this,arguments) 16 | // } 17 | // }) 18 | 19 | 对于java 原生类 还可以用gson (自己写的 还没尝试看看) 20 | 21 | 使用Frida时,想要打印Java对象的内容,可以使用谷歌的gson包,可以非常优秀的将Java对象的内容,以json的格式打印出来。 22 | 23 | 但是有些时候,如果原apk里面,已经包含了该gson包,再Java.use就会重名取到原apk里的包,非常不方便。 24 | 25 | 26 | 27 | 我自己编译了个版本,改了包名,这样Java.use的时候就不会重名出错了,效果如下图: 28 | 29 | 30 | 31 | 使用方法: 32 | 33 | 解压,adb push到fridaserver同目录下之后 34 | 代码: 35 | 复制代码 隐藏代码 36 | Java.openClassFile("/data/local/tmp/r0gson.dex").load(); 37 | const gson = Java.use('com.r0ysue.gson.Gson'); 38 | console.log(gson.$new().toJson(xxx)); -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/Scripts/dps.py: -------------------------------------------------------------------------------- 1 | import json 2 | from getopt import getopt 3 | from sys import argv 4 | 5 | if __name__ == '__main__': 6 | 7 | options, remainder = getopt(argv[1:], "i:s:") 8 | 9 | input_file_path = str() 10 | searchStr = str() 11 | 12 | for opt, arg in options: 13 | if opt == "-i": 14 | input_file_path = arg 15 | elif opt == "-s": 16 | searchStr = arg 17 | 18 | if not input_file_path: 19 | print("\nUsage: python3 dps.py [-i input_file_path] [-s search_str]") 20 | print("\t-i path to input image file") 21 | print("\t-s keywords need to search") 22 | else: 23 | json_obj = json.load(open(input_file_path, encoding='utf-8')) 24 | ScriptMethod = json_obj['ScriptMethod'] 25 | ScriptMetadataMethod = json_obj['ScriptMetadataMethod'] 26 | 27 | temp_name = [] 28 | temp_addr = [] 29 | 30 | for temp in ScriptMethod: 31 | if searchStr in temp["Name"]: 32 | temp_name.append(temp["Name"]) 33 | temp_addr.append(hex(temp["Address"])) 34 | 35 | print("\n----------------------------------------") 36 | print('Found : ' + str(len(temp_name)) + ' Functions (By search "'+searchStr+'")') 37 | print('----------------------------------------\n') 38 | print("var arrayAddr = ") 39 | print(temp_addr) 40 | print("\nvar arrayName = ") 41 | print(temp_name) 42 | print('\n----------------------------------------') 43 | -------------------------------------------------------------------------------- /hook/dlopen后第一时间劫持/exp.js: -------------------------------------------------------------------------------- 1 | function hookcallback(p){ 2 | var fun = new NativeFunction(p,'int',['pointer','pointer']) 3 | var self = new NativeCallback(function(arg1,arg2){ 4 | console.log("sasasas", fun(arg1,arg2)) 5 | 6 | return 0; 7 | },'int',['pointer','pointer']) 8 | 9 | Interceptor.replace(fun,self) 10 | } 11 | function dlopentodo(){ 12 | var cronet = Module.findBaseAddress("libsscronet.so") 13 | var ver = Module.findExportByName("libttboringssl.so","SSL_CTX_set_custom_verify"); 14 | var custom_verify = new NativeFunction(ver,'pointer',['pointer','int','pointer']); 15 | var funarr = []; 16 | var index = 0; 17 | var self = new NativeCallback(function(arg1,arg2,arg3){ 18 | hookcallback(arg3) 19 | console.log("custom verify called",arg2,arg3) 20 | return custom_verify(arg1,0,arg3) 21 | },'pointer',['pointer','int','pointer']) 22 | 23 | Interceptor.replace(ver,self) 24 | } 25 | 26 | function main2(){ 27 | var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext"); 28 | console.log(android_dlopen_ext) 29 | if(android_dlopen_ext != null){ 30 | Interceptor.attach(android_dlopen_ext,{ 31 | onEnter:function(args){ 32 | var soName = args[0].readCString() 33 | if(soName.indexOf("libsscronet.so") != -1){ 34 | this.hook = true 35 | } 36 | }, 37 | onLeave:function(retval){ 38 | if(this.hook){ 39 | dlopentodo() 40 | } 41 | } 42 | }) 43 | } 44 | } 45 | main2() -------------------------------------------------------------------------------- /trace/r0tracer-main/README.md: -------------------------------------------------------------------------------- 1 | # r0tracer 2 | 3 | 安卓Java层多功能追踪脚本 4 | 5 | > AKA:精简版 objection + Wallbreaker 6 | 7 | 8 | # 功能: 9 | 10 | - 根据黑白名单批量追踪类的所有方法 11 | 12 | hook("javax.crypto.Cipher", "$"); 13 | 14 | ![](pic/02.png) 15 | 16 | - 在命中方法后打印出该类或对象的所有域值、参数、调用栈和返回值 17 | 18 | ![](pic/03.png) 19 | ![](pic/04.png) 20 | ![](pic/05.png) 21 | 22 | - 极简的文本保存日志机制、易于搜索关键参数 23 | 24 | - 针对加壳应用找不到类时可以切换Classloader 25 | 26 | # 使用方法: 27 | 28 | 1. 修改`r0tracer.js`文件最底部处的代码,开启某一个Hook模式。 29 | 30 | ![](pic/01.png) 31 | 32 | 2. 推荐使用Frida14版本,并且将日志使用`-o`参数进行输出保存 33 | 34 | ``` 35 | $ frida -U -f com.r0ysue.example -l r0tracer.js --no-pause -o saveLog5.txt 36 | ``` 37 | 38 | > "-f"为Spawn模式,去掉"-f"为Attach模式 39 | 40 | 3. Frida版本=<12时,要加上`--runtime=v8`选项 41 | 42 | ``` 43 | $ frida -U com.r0ysue.example -l r0tracer.js --runtime=v8 --no-pause -o saveLog6.txt 44 | ``` 45 | 46 | # 优势 47 | 48 | - 比`objection`增加延时`spawn` 49 | - 比`objection`增加批量`hook`类\方法\构造函数 50 | - `Wallbreaker`在`frida14`上还是一直崩 51 | - 比`Wallbreaker`增加`hook`看`instance`的`fields` 52 | - `inspectObject`函数可以单独拿出去使用 53 | 54 | 注意点: 55 | 56 | - Frida的崩溃有时候真的是玄学,大项目一崩溃根本不知道是哪里出的问题,这也是小而专的项目也有一丝机会的原因 57 | - Frida自身即会经常崩溃,建议多更换Frida(客/服要配套)版本/安卓版本,`ROOT`采用`Magisk Root` 58 | - 我自己常用的组合是两部手机,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 59 | 60 | # 致谢 Thanks to 61 | 62 | |项目|链接| 63 | |:-:|:-:| 64 | |objection|https://github.com/sensepost/objection| 65 | |Wallbreaker|https://github.com/hluwa/Wallbreaker| 66 | |hacking-frida|https://awakened1712.github.io/hacking/hacking-frida/| 67 | 68 | -------------------------------------------------------------------------------- /脱壳/FRIDA-DEXDump/setup.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreatedTime: 8/14/20 23:05 4 | 5 | import setuptools 6 | 7 | with open("README.md", "r") as fh: 8 | long_description = fh.read() 9 | 10 | setuptools.setup( 11 | name="frida-dexdump", 12 | version="1.0.2", 13 | description="Fast dex dump in memory based on frida.", 14 | long_description=long_description, 15 | long_description_content_type="text/markdown", 16 | author="hluwa", 17 | author_email="hluwa888@gmail.com", 18 | url="https://github.com/hluwa/FRIDA-DEXDump", 19 | install_requires=[ 20 | "frida", 21 | "click" 22 | ], 23 | keywords="frida android unpack dex dynamic", 24 | classifiers=[ 25 | "Development Status :: 5 - Production/Stable", 26 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 27 | "Operating System :: MacOS :: MacOS X", 28 | "Operating System :: Microsoft :: Windows", 29 | "Operating System :: POSIX :: Linux", 30 | "Programming Language :: Python :: 3", 31 | "Programming Language :: Python :: 3.4", 32 | "Programming Language :: Python :: 3.5", 33 | "Programming Language :: Python :: 3.6", 34 | "Programming Language :: Python :: 3.7", 35 | "Programming Language :: Python :: 3.8", 36 | "Programming Language :: JavaScript", 37 | ], 38 | packages=["frida_dexdump"], 39 | package_data={ 40 | "frida_dexdump": ["agent.js"], 41 | }, 42 | entry_points={ 43 | 'console_scripts': [ 44 | "frida-dexdump = frida_dexdump.main:entry" 45 | ] 46 | } 47 | ) -------------------------------------------------------------------------------- /脱壳/frida_dump-r0ysue/frida_dump/README.md: -------------------------------------------------------------------------------- 1 | # frida_dump 2 | 3 | ## 1. 使用dump_so 4 | 5 | ```Text 6 | > frida -U packagename -l dump_so.js 7 | ____ 8 | / _ | Frida 12.4.8 - A world-class dynamic instrumentation toolkit 9 | | (_| | 10 | > _ | Commands: 11 | /_/ |_| help -> Displays the help system 12 | . . . . object? -> Display information about 'object' 13 | . . . . exit/quit -> Exit 14 | . . . . 15 | . . . . More info at http://www.frida.re/docs/home/ 16 | 17 | [LGE AOSP on HammerHead::packagename]-> dump_so("name.so") 18 | [name]: name.so 19 | [base]: 0x99adf000 20 | [size]: 0x2d4000 21 | [path]: /data/app/packagename-2/lib/arm/name.so 22 | [dump]: /data/user/0/packagename/files/name.so_0x99adf000_0x2d4000.so 23 | undefined 24 | [LGE AOSP on HammerHead::packagename]-> 25 | ``` 26 | 27 | ## 2. 使用dump_dex 28 | 29 | 更新了查找DefineClass的函数签名 30 | 31 | ```Text 32 | frida -U --no-pause -f packagename -l dump_dex.js 33 | ____ 34 | / _ | Frida 12.4.8 - A world-class dynamic instrumentation toolkit 35 | | (_| | 36 | > _ | Commands: 37 | /_/ |_| help -> Displays the help system 38 | . . . . object? -> Display information about 'object' 39 | . . . . exit/quit -> Exit 40 | . . . . 41 | . . . . More info at http://www.frida.re/docs/home/ 42 | Spawned `packagename`. Resuming main thread! 43 | [Google Pixel XL::packagename]-> [dlopen:] libart.so 44 | _ZN3art11ClassLinker11DefineClassEPNS_6ThreadEPKcmNS_6HandleINS_6mirror11ClassLoaderEEERKNS_7DexFileERKNS9_8ClassDefE 0x7ac6dc4f74 45 | [DefineClass:] 0x7ac6dc4f74 46 | [dump dex]: /data/data/packagename/files/7aab800000_8341c4.dex 47 | ``` 48 | -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/jnitrace/src/utils/method_data.ts: -------------------------------------------------------------------------------- 1 | import { JNIMethod } from "jnitrace-engine"; 2 | 3 | import { JavaMethod } from "jnitrace-engine"; 4 | 5 | class MethodData { 6 | private readonly _method: JNIMethod; 7 | 8 | private readonly _jmethod: JavaMethod | undefined; 9 | 10 | private readonly _args: NativeArgumentValue[]; 11 | 12 | private readonly _jparams: string[]; 13 | 14 | private readonly _ret: NativeReturnValue; 15 | 16 | public constructor ( 17 | method: JNIMethod, 18 | args: NativeArgumentValue[], 19 | ret: NativeReturnValue, 20 | jmethod?: JavaMethod 21 | ) { 22 | this._method = method; 23 | this._jmethod = jmethod; 24 | this._args = args; 25 | this._ret = ret; 26 | if (jmethod === undefined) { 27 | this._jparams = []; 28 | } else { 29 | this._jparams = jmethod.nativeParams; 30 | } 31 | } 32 | 33 | public get method (): JNIMethod { 34 | return this._method; 35 | } 36 | 37 | public get javaMethod (): JavaMethod | undefined { 38 | return this._jmethod; 39 | } 40 | 41 | public get args (): NativeArgumentValue[] { 42 | return this._args; 43 | } 44 | 45 | public getArgAsPtr (i: number): NativePointer { 46 | return this._args[i] as NativePointer; 47 | } 48 | 49 | public getArgAsNum (i: number): number { 50 | return this._args[i] as number; 51 | } 52 | 53 | public get jParams (): string[] { 54 | return this._jparams; 55 | } 56 | 57 | public get ret (): NativeReturnValue { 58 | return this._ret; 59 | } 60 | } 61 | 62 | export { MethodData }; -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from os import path 3 | 4 | here = path.abspath(path.dirname(__file__)) 5 | 6 | with open(path.join(here, 'README.md'), encoding='utf-8') as f: 7 | long_description = f.read() 8 | 9 | setup( 10 | name='jnitrace', 11 | version='3.2.0', 12 | description='A tool for tracing use of the JNI in Android apps', 13 | long_description=long_description, 14 | long_description_content_type='text/markdown', 15 | url='https://github.com/chame1eon/jnitrace', 16 | author='chame1eon', 17 | classifiers=[ 18 | 'Development Status :: 5 - Production/Stable', 19 | 20 | 'Intended Audience :: Developers', 21 | 22 | 'Topic :: Software Development :: Debuggers', 23 | 24 | 'License :: OSI Approved :: MIT License', 25 | 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 | ], 32 | keywords='frida jni sre android tracing', 33 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), 34 | python_requires='>=3.0, <4', 35 | install_requires=[ 36 | 'frida>=14.0.5', 37 | 'colorama', 38 | 'hexdump' 39 | ], 40 | package_data={ 41 | '': ['jnitrace.js'], 42 | }, 43 | include_package_data=True, 44 | entry_points={ 45 | 'console_scripts': [ 46 | 'jnitrace=jnitrace.jnitrace:main', 47 | ], 48 | }, 49 | project_urls={ 50 | 'Bug Reports': 'https://github.com/chame1eon/jnitrace/issues', 51 | }, 52 | ) 53 | -------------------------------------------------------------------------------- /脱壳/FRIDA-DEXDump/frida_dexdump/__init__.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreatedTime: 2020/3/5 19:14 4 | 5 | def in_objection(): 6 | try: 7 | import objection 8 | return objection.state.connection.state_connection.get_api() 9 | except: 10 | return False 11 | 12 | 13 | if in_objection(): 14 | __description__ = "a objection plugin to fast search and dump dex on memory." 15 | 16 | from .main import * 17 | from objection.state.connection import state_connection 18 | from objection.utils.plugin import Plugin 19 | 20 | 21 | class DEXDump(Plugin): 22 | 23 | def __init__(self, ns): 24 | """ 25 | Creates a new instance of the plugin 26 | :param ns: 27 | """ 28 | 29 | self.script_path = os.path.join(os.path.dirname(__file__), "agent.js") 30 | 31 | implementation = { 32 | 'meta': 'fast search and dump dex on memory.', 33 | 'commands': { 34 | 'search': { 35 | 'meta': 'search all dex', 36 | 'exec': self.search 37 | }, 38 | 'dump': { 39 | 'meta': 'dump all dex', 40 | 'exec': self.dump 41 | } 42 | } 43 | } 44 | 45 | super().__init__(__file__, ns, implementation) 46 | 47 | self.inject() 48 | 49 | def search(self, args=None): 50 | main.search(self.api) 51 | 52 | def dump(self, args=None): 53 | """ 54 | """ 55 | main.dump(state_connection.gadget_name, self.api) 56 | 57 | 58 | namespace = 'dexdump' 59 | plugin = DEXDump 60 | -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | node_modules 107 | -------------------------------------------------------------------------------- /脱壳/FRIDA-DEXDump/README.md: -------------------------------------------------------------------------------- 1 | # FRIDA-DEXDump 2 | 3 | ![screenshot](screenshot.png) 4 | 5 | 6 | ## Features 7 | 1. support fuzzy search broken header dex. 8 | 2. fix struct data of dex-header. 9 | 3. compatible with all android version(frida supported). 10 | 4. support loading as objection plugin ~ 11 | 5. pypi package has been released ~ 12 | 13 | ## Requires 14 | 15 | - [frida](https://www.github.com/frida/frida): `pip install frida` 16 | - [optional] [click](https://pypi.org/project/click/) `pip install click` 17 | 18 | ## Installation 19 | 20 | ### From pypi 21 | 22 | pip3 install frida-dexdump 23 | frida-dexdump -h 24 | 25 | ### From source 26 | 27 | git clone https://github.com/hluwa/FRIDA-DEXDump 28 | cd FRIDA-DEXDump/frida-dexdump 29 | python3 main.py -h 30 | 31 | ## Usage 32 | 33 | - Run `frida-dexdump` or `python3 main.py` to attach current frontmost application and dump dexs. 34 | 35 | - Or, use command arguments: 36 | ``` 37 | -n: [Optional] Specify target process name, when spawn mode, it requires an application package name. If not specified, use frontmost application. 38 | -p: [Optional] Specify pid when multiprocess. If not specified, dump all. 39 | -f: [Optional] Use spawn mode, default is disable. 40 | -s: [Optional] When spawn mode, start dump work after sleep few seconds. default is 10s. 41 | -d: [Optional] Enable deep search maybe detected more dex, but speed will be slower. 42 | -h: show help. 43 | ``` 44 | 45 | - Or, loading as objection plugin 46 | 47 | 1. clone this repo and move `frida_dexdump` into your plugins folder, eg: 48 | ``` 49 | git clone https://github.com/hluwa/FRIDA-DEXDump ~/Downloads/FRIDA-DEXDump; 50 | mv ~/Downloads/FRIDA-DEXDump/frida_dexdump ~/.objection/plugins/dexdump 51 | ``` 52 | 2. start objection with `-P` or `--plugin-folder` your plugins folder, eg: 53 | ``` 54 | objection -g com.app.name explore -P ~/.objection/plugins 55 | ``` 56 | 3. run command: 57 | 1. ` plugin dexdump search ` to search and print all dex 58 | 2. ` plugin dexdump dump ` to dump all found dex. 59 | -------------------------------------------------------------------------------- /hook/hook_libart脚本/hook_registerNatives.js: -------------------------------------------------------------------------------- 1 | function hook_RegisterNatives(){ 2 | var symbols = Module.enumerateSymbolsSync("libart.so"); 3 | var addRegisterNatives = null; 4 | //搜索在art中加载native的函数 名字这么丑 因为c++名称粉碎 5 | for(var i = 0 ; i < symbols.length; ++i){ 6 | var symbol = symbols[i]; 7 | 8 | //_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi 9 | if(symbol.name.indexOf("art") >= 0 && 10 | symbol.name.indexOf("JNI") >=0 && 11 | symbol.name.indexOf("RegisterNatives") >= 0 && 12 | symbol.name.indexOf("CheckJNI") < 0){ 13 | addRegisterNatives = symbol.address; 14 | console.log("RegisterNatives is at ",symbol.address,symbol.name); 15 | } 16 | } 17 | //这里就是根据函数的参数读取了 18 | if(addRegisterNatives != null){ 19 | Interceptor.attach(addRegisterNatives,{ 20 | onEnter: function(args){ 21 | console.log("[RegisterNatives] method_count:",args[3]); 22 | var env = args[0] 23 | var java_class = args[1] 24 | var class_name = Java.vm.tryGetEnv().getClassName(java_class); 25 | var methods_ptr = ptr(args[2]); 26 | 27 | var method_count = parseInt(args[3]); 28 | for(var i = 0 ; i < method_count ; ++i){ 29 | var name_ptr = Memory.readPointer(methods_ptr.add(i*Process.pointerSize*3)); 30 | var sig_ptr = Memory.readPointer(methods_ptr.add(i*Process.pointerSize*3+ Process.pointerSize)); 31 | var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i*Process.pointerSize*3+ 2* Process.pointerSize)); 32 | 33 | var name = Memory.readCString(name_ptr); 34 | var sig = Memory.readCString(sig_ptr); 35 | var find_module = Process.findModuleByAddress(fnPtr_ptr); 36 | console.log("[RegisterNatives] java_class:",class_name,"name:",name,"sig:",sig,"fnPtr:", 37 | fnPtr_ptr,"module_name:",find_module.name,"module_base:",find_module.base,"offset:",ptr(fnPtr_ptr) 38 | .sub(find_module.base)); 39 | } 40 | } 41 | }); 42 | } 43 | 44 | } 45 | hook_RegisterNatives(); -------------------------------------------------------------------------------- /hook/hook_libart脚本/hook_artmethod.js: -------------------------------------------------------------------------------- 1 | //这个完全没看懂。。。。。。。 2 | function hook_native(){ 3 | var module_libart = Process.findModuleByName("libart.so"); 4 | var symbols = module_libart.enumerateSymbols(); 5 | var ArtMethod_Invoke = null; 6 | var ArtMethod_PrettyMethod = null; 7 | for(var i= 0; i < symbols.length ; ++i){ 8 | var symbol = symbols[i]; 9 | var address = symbol.address; 10 | var name = symbol.name; 11 | var indexArtMethod = name.indexOf("ArtMethod"); 12 | var indexInvoke = name.indexOf("Invoke"); 13 | var indexThread = name.indexOf("Thread"); 14 | if(indexArtMethod >= 0 15 | && indexInvoke >=0 16 | && indexThread >= 0 17 | && indexArtMethod < indexInvoke 18 | && indexInvoke < indexThread){ 19 | console.log(name); 20 | ArtMethod_Invoke = address; 21 | } 22 | if(indexArtMethod >= 0 && name.indexOf("PrettyMethod") >=0 && name.indexOf("Eb") >= 0 ){ 23 | console.log(name); 24 | ArtMethod_PrettyMethod=address; 25 | } 26 | } 27 | var module_libext = null; 28 | 29 | if(Process.arch == "arm64"){ 30 | module_libext = Module.load("/data/app/libext64.so"); 31 | }else if(Process.arch == "arm"){ 32 | module_libext = Module.load("/data/app/libext.so"); 33 | } 34 | if(module_libext != null){ 35 | var addr_PrettyMethod = module_libext.finExportByName("PrettyMethod"); 36 | var PrettyMethod = new NativeFunction(addr_PrettyMethod,"void",["pointer","pointer","pointer","int"]); 37 | 38 | if(ArtMethod_Invoke){ 39 | var foo_ArtMethod_PrettyMethod = new NativeFunction(ArtMethod_PrettyMethod,"pointer",["pointer","int"]); 40 | console.log(foo_ArtMethod_PrettyMethod); 41 | Interceptor.attach(ArtMethod_Invoke,{ 42 | onEnter : function(args){ 43 | try{ 44 | var result = Memory.alloc(0x100); 45 | PrettyMethod(ArtMethod_PrettyMethod,args[0],result,0x100); 46 | console.log(result.readCString()); 47 | }catch(error){ 48 | console.log(error); 49 | } 50 | }, onLeave:function(retval){} 51 | }); 52 | } 53 | 54 | } 55 | } -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/Others/FTS/MD5_SHA.js: -------------------------------------------------------------------------------- 1 | // MD2 2 | // MD5 3 | // SHA-1 4 | // SHA-256 5 | // SHA-384 6 | // SHA-512 7 | 8 | var algorithm = 'SHA-512'; 9 | 10 | if(Java.available) 11 | { 12 | Java.perform(function(){ 13 | var MessageDigest= Java.use('java.security.MessageDigest'); 14 | var digest1 = MessageDigest.digest.overload("[B","int","int"); 15 | digest1.implementation=function(buf,offset,len){ 16 | var ret = digest2.call(this,buf); 17 | parseIn(this,buf); 18 | parseOut(this,ret); 19 | return ret; 20 | } 21 | 22 | var digest2 = MessageDigest.digest.overload("[B"); 23 | digest2.implementation=function(buf){ 24 | var ret = digest2.call(this,buf); 25 | parseIn(this,buf); 26 | parseOut(this,ret); 27 | return ret; 28 | } 29 | }); 30 | 31 | } 32 | 33 | function parseIn(digest,input){ 34 | var Integer= Java.use('java.lang.Integer'); 35 | var String= Java.use('java.lang.String'); 36 | if(digest.getAlgorithm() != algorithm){ 37 | return; 38 | } 39 | try{ 40 | console.log("original:"+String.$new(input)); 41 | } 42 | catch(e){ 43 | console.log(parseHex(input)); 44 | } 45 | } 46 | 47 | function parseOut(digest,ret){ 48 | var Integer= Java.use('java.lang.Integer'); 49 | var String= Java.use('java.lang.String'); 50 | var result = ""; 51 | for(var i = 0;i 0) { 54 | } 55 | } 56 | }); 57 | """%(package) 58 | 59 | script = session.create_script(src) 60 | 61 | script.on("message" , on_message) 62 | 63 | script.load() 64 | device.resume(pid) 65 | sys.stdin.read() 66 | -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/Others/IDAScript.py: -------------------------------------------------------------------------------- 1 | import idautils 2 | import idc 3 | import idaapi 4 | import struct 5 | 6 | def AddBpt_init(): 7 | has_art = False 8 | module_base = GetFirstModule() 9 | while module_base != None: 10 | module_name = GetModuleName(module_base) 11 | if module_name.find('linker') >= 0: 12 | has_art = True 13 | break 14 | 15 | module_base = GetNextModule(module_base) 16 | 17 | if has_art == False: 18 | print '[*]unable to find libart.so module base' 19 | return 20 | 21 | module_size = GetModuleSize(module_base) 22 | 23 | print '[*]found linker base => 0x%08X, Size = 0x%08X' % (module_base, module_size) 24 | 25 | # DT_INIT_ARRAY / DT_INIT / Calling c-tor %s @ %p for '%s' 26 | init_func_ea = module_base + 0x18996 27 | init_array_ea = module_base + 0x18BB6 28 | 29 | AddBpt(init_func_ea) 30 | AddBpt(init_array_ea) 31 | 32 | print "\t[-]set breakpoint INIT => 0x%08X INIT_ARRAY => 0x%08X" % (init_func_ea, init_array_ea) 33 | 34 | 35 | def AddBpt_jni_onload(): 36 | has_art = False 37 | module_base = GetFirstModule() 38 | while module_base != None: 39 | module_name = GetModuleName(module_base) 40 | if module_name.find('libart.so') >= 0: 41 | has_art = True 42 | break 43 | 44 | module_base = GetNextModule(module_base) 45 | 46 | if has_art == False: 47 | print '[*]unable to find libart.so module base' 48 | return 49 | 50 | module_size = GetModuleSize(module_base) 51 | print '[*]found libart.so base => 0x%08X, Size = 0x%08X' % (module_base, module_size) 52 | 53 | # Calling JNI_OnLoad in 54 | blx_ea = module_base + 0x234D78 55 | AddBpt(blx_ea) 56 | print ("\t[-]set breakpoint JNI_OnLoad addr => 0x%X") % blx_ea 57 | 58 | 59 | def Dump_Memory(start_addr, end_addr): 60 | 61 | print '[*]begin to dump memory' 62 | handle_f = open('d:/dump.so', 'wb') 63 | for byte_addr in range(start_addr, end_addr): 64 | byte_value = idaapi.get_byte(byte_addr) 65 | handle_f.write(struct.pack('B',byte_value)) 66 | handle_f.close() 67 | print '[-]dump memory save to d:/dump.so' 68 | print '[*]script finish' 69 | 70 | def Search_Memory(start_addr, end_addr, value): 71 | print '[*]script Start' 72 | for ea_offset in range(start_addr, end_addr): 73 | cur_dword = idaapi.get_dword(ea_offset) 74 | #cur_dword = idaapi.get_long(ea_offset) 75 | #cur_dword = idaapi.get_word(ea_offset) 76 | 77 | if cur_dword != None and cur_dword == value: 78 | print('found target = %x' % ea_offset) 79 | print '[*]script End' 80 | 81 | 82 | def main(): 83 | # 添加init,init_arrary断点 84 | AddBpt_init() 85 | # 添加jni_onload断点 86 | AddBpt_jni_onload() 87 | # 内存dump 88 | #Dump_Memory(0xED6EABB6,0xED6EEBB6) 89 | # 内存搜索 90 | #Search_Memory(0xED6EABB6,0xED6EEBB6,0xfe75f06c) 91 | 92 | main() 93 | -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/jnitrace/src/utils/java_method.ts: -------------------------------------------------------------------------------- 1 | import { Types } from "./types"; 2 | 3 | const SEMI_COLON_OFFSET = 1; 4 | 5 | class JavaMethod { 6 | private readonly __: string; 7 | 8 | private readonly _params: string[]; 9 | 10 | private readonly _ret: string; 11 | 12 | public constructor (signature: string) { 13 | const primitiveTypes = ["B", "S", "I", "J", "F", "D", "C", "Z", "V"]; 14 | let isArray = false; 15 | let isRet = false; 16 | 17 | const jParamTypes: string[] = []; 18 | let jRetType = "unknown"; 19 | 20 | for (var i = 0; i < signature.length; i++) { 21 | if (signature.charAt(i) === "(") { 22 | continue; 23 | } 24 | 25 | if (signature.charAt(i) === ")") { 26 | isRet = true; 27 | continue; 28 | } 29 | 30 | if (signature.charAt(i) === "[") { 31 | isArray = true; 32 | continue; 33 | } 34 | 35 | let jtype = "unknown"; 36 | 37 | if (primitiveTypes.includes(signature.charAt(i))) { 38 | jtype = signature.charAt(i); 39 | } else if (signature.charAt(i) === "L") { 40 | var end = signature.indexOf(";", i) + SEMI_COLON_OFFSET; 41 | jtype = signature.substring(i, end); 42 | i = end - SEMI_COLON_OFFSET; 43 | } 44 | 45 | // ? 46 | if (isArray) { 47 | jtype = "[" + jtype; 48 | } 49 | 50 | if (!isRet) { 51 | jParamTypes.push(jtype); 52 | } else { 53 | jRetType = jtype; 54 | } 55 | 56 | isArray = false; 57 | } 58 | 59 | this.__ = signature; 60 | this._params = jParamTypes; 61 | this._ret = jRetType; 62 | } 63 | 64 | public get params (): string[] { 65 | return this._params; 66 | } 67 | 68 | public get nativeParams (): string[] { 69 | const nativeParams: string[] = []; 70 | this._params.forEach((p: string): void => { 71 | const nativeJType = Types.convertJTypeToNativeJType(p); 72 | 73 | nativeParams.push(nativeJType); 74 | }); 75 | return nativeParams; 76 | } 77 | 78 | public get fridaParams (): string[] { 79 | const fridaParams: string[] = []; 80 | this._params.forEach((p: string): void => { 81 | const nativeJType = Types.convertJTypeToNativeJType(p); 82 | const fridaType = Types.convertNativeJTypeToFridaType(nativeJType); 83 | 84 | fridaParams.push(fridaType); 85 | }); 86 | return fridaParams; 87 | } 88 | 89 | public get ret (): string { 90 | return this._ret; 91 | } 92 | 93 | public get fridaRet (): string { 94 | const jTypeRet = Types.convertJTypeToNativeJType(this._ret); 95 | return Types.convertNativeJTypeToFridaType(jTypeRet); 96 | } 97 | } 98 | 99 | export { JavaMethod }; 100 | -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/frida_scripts/agent/util.ts: -------------------------------------------------------------------------------- 1 | import { GetObsoleteDexCache_func, PrettyMethod } from "./helper"; 2 | import { log } from "./logger"; 3 | 4 | export class SwitchImplContext { 5 | 6 | pointer: NativePointer; 7 | thread_ptr: NativePointer; 8 | accessor: CodeItemDataAccessor; 9 | shadow_frame: ShadowFrame; 10 | 11 | constructor (pointer: NativePointer){ 12 | this.pointer = pointer; 13 | this.thread_ptr = this.pointer.readPointer(); 14 | this.accessor = new CodeItemDataAccessor(this.pointer.add(Process.pointerSize).readPointer()); 15 | this.shadow_frame = new ShadowFrame(this.pointer.add(Process.pointerSize * 2).readPointer()); 16 | } 17 | 18 | } 19 | 20 | 21 | export class CodeItemDataAccessor { 22 | 23 | pointer: NativePointer; 24 | insns: NativePointer; 25 | 26 | constructor (pointer: NativePointer){ 27 | this.pointer = pointer; 28 | this.insns = this.pointer.add(Process.pointerSize).readPointer(); 29 | } 30 | 31 | Insns(): NativePointer { 32 | return this.insns; 33 | } 34 | 35 | } 36 | 37 | export class ShadowFrame { 38 | 39 | pointer: NativePointer; 40 | method: ArtMethod; 41 | 42 | constructor (pointer: NativePointer){ 43 | this.pointer = pointer; 44 | this.method = new ArtMethod(this.pointer.add(Process.pointerSize).readPointer()); 45 | } 46 | 47 | toString(): string{ 48 | return this.pointer.toString(); 49 | } 50 | 51 | GetDexPC(): number { 52 | let dex_pc_ptr_ = this.pointer.add(Process.pointerSize * 3).readPointer(); 53 | if (!dex_pc_ptr_.equals(ptr(0x0))){ 54 | let dex_instructions_ = this.pointer.add(Process.pointerSize * 4).readPointer(); 55 | return Number(dex_pc_ptr_.sub(dex_instructions_).toString()); 56 | } 57 | else{ 58 | return this.pointer.add(Process.pointerSize * 6 + 4).readU32(); 59 | } 60 | 61 | } 62 | 63 | } 64 | 65 | export class ArtMethod { 66 | 67 | pointer: NativePointer; 68 | 69 | constructor (pointer: NativePointer){ 70 | this.pointer = pointer; 71 | } 72 | 73 | toString(): string { 74 | return this.pointer.toString(); 75 | } 76 | 77 | PrettyMethod(): string | null { 78 | return PrettyMethod(this.pointer); 79 | } 80 | 81 | GetObsoleteDexCache(): NativePointer{ 82 | // mirror_ptr ??? 83 | return GetObsoleteDexCache_func(this.pointer); 84 | // return ptr(0x0); 85 | } 86 | 87 | GetDexFile(): NativePointer { 88 | let access_flags = this.pointer.add(0x4).readU32(); 89 | // IsObsolete() => (GetAccessFlags() & kAccObsoleteMethod) != 0; 90 | if ((access_flags & 0x40000) != 0){ 91 | log(`flag => ${access_flags}`); 92 | return this.GetObsoleteDexCache(); 93 | } 94 | else{ 95 | let declaring_class_ptr = ptr(this.pointer.readU32()); 96 | let dex_cache_ptr = ptr(declaring_class_ptr.add(0x10).readU32()); 97 | let dex_file_ptr = dex_cache_ptr.add(0x10).readPointer(); 98 | return dex_file_ptr; 99 | } 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/frida_scripts/agent/helper.ts: -------------------------------------------------------------------------------- 1 | import { log } from "./logger"; 2 | 3 | export function get_PrettyMethod(){ 4 | // let PrettyMethod_ptr = Module.findExportByName("libart.so", "_ZN3art9ArtMethod12PrettyMethodEPS0_b"); 5 | let PrettyMethod_ptr = Module.findExportByName("libart.so", "_ZN3art9ArtMethod12PrettyMethodEb"); 6 | if (PrettyMethod_ptr == null){ 7 | log(`libart.so PrettyMethod_ptr is null`); 8 | return; 9 | } 10 | log(`PrettyMethod_ptr => ${PrettyMethod_ptr}`); 11 | let PrettyMethod_func = new NativeFunction(PrettyMethod_ptr, ["pointer", "pointer", "pointer"], ["pointer", "bool"]); 12 | return PrettyMethod_func; 13 | } 14 | 15 | export function get_GetObsoleteDexCache(){ 16 | let GetObsoleteDexCache_ptr = Module.findExportByName("libart.so", "_ZN3art9ArtMethod19GetObsoleteDexCacheEv"); 17 | if (GetObsoleteDexCache_ptr == null){ 18 | log(`libart.so GetObsoleteDexCache_ptr is null`); 19 | return; 20 | } 21 | log(`GetObsoleteDexCache_ptr => ${GetObsoleteDexCache_ptr}`); 22 | let GetObsoleteDexCache_func = new NativeFunction(GetObsoleteDexCache_ptr, "pointer", ["pointer"]); 23 | return GetObsoleteDexCache_func; 24 | } 25 | 26 | export function get_DumpString(){ 27 | let DumpString_ptr = Module.findExportByName("libdexfile.so", "_ZNK3art11Instruction10DumpStringEPKNS_7DexFileE"); 28 | if (DumpString_ptr == null){ 29 | log(`libart.so DumpString_ptr is null`); 30 | return; 31 | } 32 | log(`DumpString_ptr => ${DumpString_ptr}`); 33 | let DumpString_func = new NativeFunction(DumpString_ptr, ["pointer", "pointer", "pointer"], ["pointer", "pointer"]); 34 | return DumpString_func; 35 | } 36 | 37 | export function PrettyMethod(art_method_ptr: NativePointer){ 38 | let results: NativePointer[] = PrettyMethod_func(art_method_ptr, 0); 39 | return readStdString(results); 40 | } 41 | 42 | export function PrettyInstruction(inst_ptr: NativePointer, dexfile_ptr: NativePointer){ 43 | let results: NativePointer[] = DumpString_func(inst_ptr, dexfile_ptr); 44 | return readStdString(results); 45 | } 46 | 47 | 48 | // export function readStdString(pointers: NativePointer[]) { 49 | // let str = Memory.alloc(Process.pointerSize * 3); 50 | // str.writePointer(pointers[0]); 51 | // str.add(Process.pointerSize * 1).writePointer(pointers[1]); 52 | // str.add(Process.pointerSize * 2).writePointer(pointers[2]); 53 | // let isTiny = (str.readU8() & 1) === 0; 54 | // if (isTiny) { 55 | // return str.add(1).readUtf8String(); 56 | // } 57 | // return str.add(2 * Process.pointerSize).readPointer().readUtf8String(); 58 | // } 59 | 60 | export function readStdString(pointers: NativePointer[]){ 61 | let str = Memory.alloc(Process.pointerSize * 3); 62 | str.writePointer(pointers[0]); 63 | let isTiny = (str.readU8() & 1) === 0; 64 | if (isTiny) { 65 | str.add(Process.pointerSize * 1).writePointer(pointers[1]); 66 | str.add(Process.pointerSize * 2).writePointer(pointers[2]); 67 | return str.add(1).readUtf8String(); 68 | } 69 | else{ 70 | return pointers[2].readUtf8String(); 71 | } 72 | } 73 | 74 | export let PrettyMethod_func: any = get_PrettyMethod(); 75 | export let DumpString_func: any = get_DumpString(); 76 | export let GetObsoleteDexCache_func: any = get_GetObsoleteDexCache(); -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/jnitrace/src/utils/types.ts: -------------------------------------------------------------------------------- 1 | const ARRAY_TYPE_INDEX = 1; 2 | const TYPE_SIZE_64_BIT = 8; 3 | const TYPE_SIZE_CHAR = 1; 4 | 5 | const Types = { 6 | isComplexObjectType (type: string): boolean { 7 | const JOBJECT = [ 8 | "jobject", 9 | "jclass", 10 | "jweak" 11 | ]; 12 | 13 | return JOBJECT.includes(type); 14 | }, 15 | sizeOf (type: string): number { 16 | if (type === "double" || type === "float" || type === "int64") { 17 | return TYPE_SIZE_64_BIT; 18 | } else if (type === "char") { 19 | return TYPE_SIZE_CHAR; 20 | } else { 21 | return Process.pointerSize; 22 | } 23 | }, 24 | convertNativeJTypeToFridaType (jtype: string): string { 25 | if (jtype.endsWith("*")) { 26 | return "pointer"; 27 | } 28 | if (jtype === "va_list") { 29 | return "pointer"; 30 | } 31 | if (jtype === "jmethodID") { 32 | return "pointer"; 33 | } 34 | if (jtype === "jfieldID") { 35 | return "pointer"; 36 | } 37 | if (jtype === "va_list") { 38 | return "va_list"; 39 | } 40 | if (jtype === "jweak") { 41 | jtype = "jobject"; 42 | } 43 | if (jtype === "jthrowable") { 44 | jtype = "jobject"; 45 | } 46 | if (jtype.includes("Array")) { 47 | jtype = "jarray"; 48 | } 49 | if (jtype === "jarray") { 50 | jtype = "jobject"; 51 | } 52 | if (jtype === "jstring") { 53 | jtype = "jobject"; 54 | } 55 | if (jtype === "jclass") { 56 | jtype = "jobject"; 57 | } 58 | if (jtype === "jobject") { 59 | return "pointer"; 60 | } 61 | if (jtype === "jsize") { 62 | jtype = "jint"; 63 | } 64 | if (jtype === "jdouble") { 65 | return "double"; 66 | } 67 | if (jtype === "jfloat") { 68 | return "float"; 69 | } 70 | if (jtype === "jchar") { 71 | return "uint16"; 72 | } 73 | if (jtype === "jboolean") { 74 | return "char"; 75 | } 76 | if (jtype === "jlong") { 77 | return "int64"; 78 | } 79 | if (jtype === "jint") { 80 | return "int"; 81 | } 82 | if (jtype === "jshort") { 83 | return "int16"; 84 | } 85 | if (jtype === "jbyte") { 86 | return "char"; 87 | } 88 | 89 | return jtype; 90 | }, 91 | convertJTypeToNativeJType (jtype: string): string { 92 | let result = ""; 93 | let isArray = false; 94 | 95 | if (jtype.startsWith("[")) { 96 | isArray = true; 97 | jtype = jtype.substring(ARRAY_TYPE_INDEX); 98 | } 99 | 100 | if (jtype === "B") { 101 | result += "jbyte"; 102 | } else if (jtype === "S") { 103 | result += "jshort"; 104 | } else if (jtype === "I") { 105 | result += "jint"; 106 | } else if (jtype === "J") { 107 | result += "jlong"; 108 | } else if (jtype === "F") { 109 | result += "jfloat"; 110 | } else if (jtype === "D") { 111 | result += "jdouble"; 112 | } else if (jtype === "C") { 113 | result += "jchar"; 114 | } else if (jtype === "Z") { 115 | result += "jboolean"; 116 | } else if (jtype.startsWith("L")) { 117 | if (jtype === "Ljava/lang/String;") { 118 | result += "jstring"; 119 | } else if (jtype === "Ljava/lang/Class;") { 120 | result += "jclass"; 121 | } else { 122 | result += "jobject"; 123 | } 124 | } 125 | 126 | if (isArray) { 127 | if (result === "jstring") { 128 | result = "jobject"; 129 | } 130 | result += "Array"; 131 | } 132 | 133 | return result; 134 | } 135 | }; 136 | 137 | export { Types }; 138 | -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # jnitrace Change Log 2 | 3 | ## 3.2.0 4 | - Added support for connecting to a remote Frida server 5 | 6 | ## 3.1.0 7 | - Support for Frida 14 and QuickJS - Thanks oleavr 8 | - Fixed linting errors from new typescript version 9 | 10 | ## 3.0.8 11 | - Changed the required version of Frida in the setup.py file to be 12.5.0 12 | 13 | ## 3.0.7 14 | - Fixed a bug where local JNI references were not being deleted. The result was reuse by the runtime of reference values led to other arguments/return values being incorrectly named 15 | 16 | ## 3.0.6 17 | - Bumped versions of all JavaScript dependencies to latest and fixed linter errors 18 | - Bug fix where all JavaVM calls were being labeled as JNIEnv calls 19 | 20 | ## 3.0.5 21 | - Bumped version of acorn to 7.1.1 to fix vulnerability CVE-2020-7598 22 | 23 | ## 3.0.4 24 | - Updated version of jnitrace-engine to include fixes to use the config options provided by a user, such as library to trace 25 | - Added support for displaying custom errors messages generated by the engine 26 | 27 | ## 3.0.3 28 | - Updated version of jnitrace-engine to get new bug fixes 29 | 30 | ## 3.0.2 31 | - Updated version of jnitrace-engine to get new bug fixes 32 | 33 | ## 3.0.1 34 | - Updated version of jnitrace-engine to get new bug fixes 35 | 36 | ## 3.0.0 37 | - Extracted the engine in jnitrace to a new project so that the API can be used by developers 38 | 39 | ## 2.2.3 40 | - Improved the backtrace output when no DebugSymbol is found for an address. 41 | 42 | ## 2.2.2 43 | - Bug fix to handle when a DebugSymbol look up has failed for an address. 44 | 45 | ## 2.2.1 46 | - Sorted the alignment of the backtraces so they are right justified 47 | - Fixed a bug when tracing ReleaseElements where all types were assumed to be the size of a pointer 48 | - Upgraded eslint-package to patch security vulnerability 49 | - Stopped trying to kill Frida session if it was already dead 50 | 51 | ## 2.2.0 52 | - Changed backtrace output to include debug symbols, where possible 53 | 54 | ## 2.1.0 55 | - Added two new command line arguments to filter the library exports from the trace 56 | - Changed the way object data was associated with output to ensure it is still visible if the method is not being traced 57 | 58 | ## 2.0.1 59 | - Fix a bug preventing frida attach from working 60 | - Updated README 61 | 62 | ## 2.0.0 63 | - General code refactoring, including upgrading codebase to TypeScript 64 | - Added tracing of the JavaVM struct by default 65 | - Added method filters to include or exclude certain methods from the trace 66 | - Added options to allow custom Frida scripts to be loaded before and after jnitrace is loaded 67 | - Added option to export all traced data to a json formatted file 68 | - Added options to switch off tracking of the whole JavaVM or JNIEnv 69 | - Application is now killed when the tracer is finished to prevent crashes 70 | - Log messages have been added to show when a tracked library is loaded 71 | - Added support to capture floating point return values on X86 devices 72 | - jnitrace now also displays the values of jvalue* and va_list for method calls 73 | - Bugfix for crashes on arm 32 bit devices 74 | 75 | 76 | ## 1.3.5 77 | - Bug fix - Backtraces are now printed correctly for variadic functions 78 | - jboolean values now print true/false as well as the integer value 79 | - Updated README 80 | 81 | ## 1.3.4 82 | - Bug fix - Used Interceptor.replace to ensure that the CpuContext is populated for use by the Backtracer 83 | - Bug fix - Updated the JNI function definitions to set the return type of GetArrayElements to be a pointer rather than a primitive 84 | 85 | ## 1.3.3 86 | - Bug fix - Checked whether the this context exists before using it 87 | 88 | ## 1.3.2 89 | - Bug fix - Use Process.findRangeByAddress instead of Process.findModuleByAddress for checking the validity of the stack pointer 90 | 91 | ## 1.3.1 92 | - Travis integration 93 | 94 | ## 1.3.0 95 | - Added a command argument to get the version of jnitrace 96 | - jnitrace now intercepts calls to GetJavaVM, returning a shadowJavaVM 97 | - Added support for extracting arguments stored in jvalue arrays 98 | 99 | ## 1.2.1 100 | - Bug fix - CallStaticObjectMethod was the only va args method intercepted 101 | 102 | ## 1.2.0 103 | - Added arm64 architecture support 104 | - Modified how dlopen is intercepted to support Android 7 and above 105 | -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/Il2cppHook/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### 简述 3 | 1. 降低u3d游戏找关键函数难度(按img/cls添加批量断点) 4 | 2. 单独提出一些常用函数的通用Hook 5 | 3. 方便函数调用测试,函数动态参数解析 6 | 4. 对class指针解析内存数据(fields) 7 | 8 | ### 使用 9 | 1. 在U3d游戏启动之后,使用 **frida -FU -l ...\Ufun.js** 进行attach 10 | 2. B() 即可对程序集Assembly-CSharp中的方法进行全部断点,也可自行使用 i() , a() 进行添加后在使用 B("Filter") 进行断点 11 | 3. 一些常用的hook都使用 Hook... 开头命名 (欢迎各位大佬继续拓展) 12 | 4. 函数调用使用 callfunction() ,第一个参数为函数地址,后面的参数是参数值; setFunctionValue() 快速的修改函数返回值 13 | 5. breakWithArgs() 断点函数并显示指定个数参数; breakInline() 任意位置 14 | 6. 还有一个 b() 方法会用的比较频繁,b()方法的参数是一个methodinfo指针,用于对参数的识别和解析,find_method()和B()断点括号用的都能找到 15 | 7. 还有一系列的get/set方法用来操作gameobj/transform等等 16 | 8. SeeTypeToString() 帮我们快速的判断当前指针的类型, m() 参数也是一个cls指针,帮我们确认类方法 17 | 9. listClsFromMethodInfo() 通过一个类方法的methodinfo回溯到它对应的cls下的其他方法信息 18 | 19 | 以上为一些个人总结的比较常用的api 20 | 21 | #### tips: 22 | 23 | 使用的两个数组是兼容之前使用python脚本查找function的方法 24 | 可以多次使用AddBP(img/cls)添加多个类或者img的方法到这个两个数组 25 | 方法添加完成后建议使用print_list_result()列出当前方法,然后手动替换掉开始部分的arrayAddr和arrayName 26 | 27 | --- 28 |
 29 | /**
 30 |  * --------------------------------------------------------------------------------------------
 31 |  * 常用
 32 |  * ---------------------
 33 |  * i()      list_Images()
 34 |  * c()      list_Classes(image,isShowClass) // 遍历调用
 35 |  * C()      list_Classes(imgOrPtr)          // 反射调用
 36 |  * m()      list_Methods(klass,isShowMore)
 37 |  * f()      listFieldsFromCls(klass)
 38 |  * F()      find_method(ImageName,ClassName,functionName,ArgsCount,isRealAddr)
 39 |  * n()      nopfunction(ptr)
 40 |  * nn()     cancel nopfunction(ptr)
 41 |  * nnn()    cancel all nop/replace function
 42 |  * d()      Interceptor.detachAll() / d(mPtr) detach mPtr
 43 |  * a()      addBreakPoints(imgOrCls)
 44 |  * b()      breakPoint(mPtr)
 45 |  * P()      printCtx(pointer,range)
 46 |  * B()      breakPoints(filter)
 47 |  * D()      detachAll and reset arrays
 48 |  * p()      print_list_result(filter)
 49 |  * --------------------------------------------------------------------------------------------
 50 |  * 拓展方法
 51 |  * ---------------------
 52 |  * HookSetActive()
 53 |  * HookOnPointerClick()
 54 |  * HookPlayerPrefs()
 55 |  * HookDebugLog()
 56 |  * HookLoadScene()
 57 |  * HookGetSetText()
 58 |  * PrintHierarchy()
 59 |  * getUnityInfo()
 60 |  * getApkInfo()
 61 |  * GotoScene(str)
 62 |  * callFunction(mPtr,arg0,arg1,arg2,arg3)
 63 |  * SeeTypeToString(obj)
 64 |  * FuckKnownType(strType,mPtr)
 65 |  * Toast(msg)
 66 |  * getLibPath()
 67 |  * print_deserted_methods()
 68 |  * 
 69 |  * --- 用作动态Hook去掉指定gameObj
 70 |  * setClick()
 71 |  * HideClickedObj()
 72 |  * HookMotionEvent()
 73 |  * 
 74 |  * --- 查看对象
 75 |  * showEventData(eventData)
 76 |  * showTransform(transform)
 77 |  * showEventData(eventData)
 78 |  * 
 79 |  * --- 修改属性
 80 |  * destroyObj(gameObj)
 81 |  * setActive(gameObj,visible)
 82 |  * setPosition(mTransform,x,y,z)
 83 |  * setLocalScale(mTransform,x,y,z)
 84 |  * setLocalPosition(mTransform,x,y,z)
 85 |  * setLocalRotation(mTransform,x,y,z,w)
 86 |  * ----------------------------------------------------------------------
 87 |  * SharedPrefs                                                          |
 88 |  * ---------------------------------------------------------------------|
 89 |  * SetInt(key,value)    | SetFloat(key,value)   | SetString(key,value)  |
 90 |  * GetInt(key)          | GetFloat(key)         | GetString(key)        |
 91 |  * ----------------------------------------------------------------------
 92 |  * PS:  分清楚 MethodInfo,Transform,GameObject 指针类型, 调用函数的时候不要瞎传参数
 93 |  *      如果使用了gadgat,使用-FU先把应用跑起来再进行注入该脚本, 整个脚本对spawn方式启动的兼容性不好
 94 |  * --------------------------------------------------------------------------------------------
 95 |  */
 96 | 
97 | 98 | ``` 99 | // 2021.2.7f1c1 100 | // typedef struct MethodInfo { 101 | // Il2CppMethodPointer methodPointer; 102 | // Il2CppMethodPointer virtualMethodPointer; 103 | // InvokerMethod invoker_method; 104 | // const char * name; 105 | // Il2CppClass * klass; 106 | // const Il2CppType * return_type; 107 | // const Il2CppType ** parameters; 108 | 109 | ** 遇到不可用的时候 MethodInfoOffset 可尝试修改为 0x0 / 0x1 ** 110 | var MethodInfoOffset = 0x0 111 | ``` 112 | 113 | 114 | ### 用例 115 | 1. **list_Images() === i()** 116 | 117 | ![](../imgs/u3d_0.png) 118 | 119 | 2. **list_Classes(image,isShowClass) === c()** 120 | 121 | ![](../imgs/u3d_1.png) 122 | 123 | 3. **list_Methods(klass,isShowMore) === m()** 124 | 125 | ![](../imgs/u3d_2.png) 126 | 127 | ![](../imgs/u3d_3.png) 128 | 129 | 4. **find_method(ImageName,ClassName,functionName,ArgsCount,isRealAddr) === f()** 130 | 131 | ![](../imgs/u3d_4.png) 132 | 133 | 5. **addBP(imgOrCls) === a()** 134 | 135 | ![](../imgs/u3d_5.png) 136 | 137 | 6. **breakPoints(filter) === B()** 138 | 139 | ![](../imgs/u3d_6.png) 140 | 141 | 7. **breakPoint(ptr) === b()** 142 | 143 | ![](../imgs/u3d_7.png) 144 | 145 | 8. **Interceptor.detachAll() === d()** 146 | 147 | 9. **HookOnPointerClick()** 148 | 149 | ![](../imgs/u3d_8.png) 150 | 151 | 10. **Info()** 152 | 153 | ![](../imgs/u3d_9.png) 154 | 155 | 10. **FindObjectsOfType()** 156 | 157 | ![](../imgs/u3d_10.png) 158 | 159 | .... 160 | -------------------------------------------------------------------------------- /脱壳/frida_dump-r0ysue/frida_dump/dump_dex.js: -------------------------------------------------------------------------------- 1 | function get_self_process_name() { 2 | var openPtr = Module.getExportByName('libc.so', 'open'); 3 | var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']); 4 | 5 | var readPtr = Module.getExportByName("libc.so", "read"); 6 | var read = new NativeFunction(readPtr, "int", ["int", "pointer", "int"]); 7 | 8 | var closePtr = Module.getExportByName('libc.so', 'close'); 9 | var close = new NativeFunction(closePtr, 'int', ['int']); 10 | 11 | var path = Memory.allocUtf8String("/proc/self/cmdline"); 12 | var fd = open(path, 0); 13 | if (fd != -1) { 14 | var buffer = Memory.alloc(0x1000); 15 | 16 | var result = read(fd, buffer, 0x1000); 17 | close(fd); 18 | result = ptr(buffer).readCString(); 19 | return result; 20 | } 21 | 22 | return "-1"; 23 | } 24 | 25 | function dump_dex() { 26 | var libart = Process.findModuleByName("libart.so"); 27 | var addr_DefineClass = null; 28 | var symbols = libart.enumerateSymbols(); 29 | for (var index = 0; index < symbols.length; index++) { 30 | var symbol = symbols[index]; 31 | var symbol_name = symbol.name; 32 | //这个DefineClass的函数签名是Android9的 33 | //_ZN3art11ClassLinker11DefineClassEPNS_6ThreadEPKcmNS_6HandleINS_6mirror11ClassLoaderEEERKNS_7DexFileERKNS9_8ClassDefE 34 | if (symbol_name.indexOf("ClassLinker") >= 0 && 35 | symbol_name.indexOf("DefineClass") >= 0 && 36 | symbol_name.indexOf("Thread") >= 0 && 37 | symbol_name.indexOf("DexFile") >= 0 ) { 38 | console.log(symbol_name, symbol.address); 39 | addr_DefineClass = symbol.address; 40 | } 41 | } 42 | var dex_maps = {}; 43 | 44 | console.log("[DefineClass:]", addr_DefineClass); 45 | if (addr_DefineClass) { 46 | Interceptor.attach(addr_DefineClass, { 47 | onEnter: function (args) { 48 | var dex_file = args[5]; 49 | //ptr(dex_file).add(Process.pointerSize) is "const uint8_t* const begin_;" 50 | //ptr(dex_file).add(Process.pointerSize + Process.pointerSize) is "const size_t size_;" 51 | var base = ptr(dex_file).add(Process.pointerSize).readPointer(); 52 | var size = ptr(dex_file).add(Process.pointerSize + Process.pointerSize).readUInt(); 53 | 54 | if (dex_maps[base] == undefined) { 55 | dex_maps[base] = size; 56 | var magic = ptr(base).readCString(); 57 | if (magic.indexOf("dex") == 0) { 58 | var process_name = get_self_process_name(); 59 | if (process_name != "-1") { 60 | var dex_path = "/data/data/" + process_name + "/files/" + base.toString(16) + "_" + size.toString(16) + ".dex"; 61 | console.log("[find dex]:", dex_path); 62 | var fd = new File(dex_path, "wb"); 63 | if (fd && fd != null) { 64 | var dex_buffer = ptr(base).readByteArray(size); 65 | fd.write(dex_buffer); 66 | fd.flush(); 67 | fd.close(); 68 | console.log("[dump dex]:", dex_path); 69 | 70 | } 71 | } 72 | } 73 | } 74 | }, onLeave: function (retval) { 75 | } 76 | }); 77 | } 78 | } 79 | 80 | var is_hook_libart = false; 81 | 82 | function hook_dlopen() { 83 | Interceptor.attach(Module.findExportByName(null, "dlopen"), { 84 | onEnter: function (args) { 85 | var pathptr = args[0]; 86 | if (pathptr !== undefined && pathptr != null) { 87 | var path = ptr(pathptr).readCString(); 88 | //console.log("dlopen:", path); 89 | if (path.indexOf("libart.so") >= 0) { 90 | this.can_hook_libart = true; 91 | console.log("[dlopen:]", path); 92 | } 93 | } 94 | }, 95 | onLeave: function (retval) { 96 | if (this.can_hook_libart && !is_hook_libart) { 97 | dump_dex(); 98 | is_hook_libart = true; 99 | } 100 | } 101 | }) 102 | 103 | Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), { 104 | onEnter: function (args) { 105 | var pathptr = args[0]; 106 | if (pathptr !== undefined && pathptr != null) { 107 | var path = ptr(pathptr).readCString(); 108 | //console.log("android_dlopen_ext:", path); 109 | if (path.indexOf("libart.so") >= 0) { 110 | this.can_hook_libart = true; 111 | console.log("[android_dlopen_ext:]", path); 112 | } 113 | } 114 | }, 115 | onLeave: function (retval) { 116 | if (this.can_hook_libart && !is_hook_libart) { 117 | dump_dex(); 118 | is_hook_libart = true; 119 | } 120 | } 121 | }); 122 | } 123 | 124 | 125 | setImmediate(hook_dlopen); 126 | -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/README.md: -------------------------------------------------------------------------------- 1 | # frida-smali-trace 2 | 3 | 通过frida hook追踪所有smali指令执行情况 4 | 5 | 在Pixel4 Android 11下运行【64位】APP进行测试,版本号`RQ3A.210805.001.A1` 6 | 7 | 效果示意 8 | 9 | ![](./images/Snipaste_2022-05-21_23-30-06.png) 10 | 11 | 实现过程 12 | 13 | - [纯frida实现smali追踪](https://blog.seeflower.dev/archives/84/) 14 | 15 | # 使用 16 | 17 | ## 命令示意 18 | 19 | ```bash 20 | frida -U -n LibChecker -l _agent.js -o trace.log 21 | ``` 22 | 23 | 如果使用frida 15之前的版本,`-n`后面是包名 24 | 25 | ```bash 26 | frida -U -n com.absinthe.libchecker -l _agent.js -o trace.log 27 | ``` 28 | 29 | ## 准备工作 30 | 31 | 安装库,并进行编译测试 32 | 33 | ``` 34 | cd frida_scripts 35 | npm install 36 | npm run watch 37 | ``` 38 | 39 | 如果只是简单使用,那么后面都不用管 40 | 41 | --- 42 | 43 | 在正式使用此脚本之前,需要先找到关键位置,以及几个关键寄存器 44 | 45 | 从手机中提取libart.so 46 | 47 | ```bash 48 | adb pull /apex/com.android.art/lib64/libart.so 49 | ``` 50 | 51 | 用IDA打开libart.so,让IDA反汇编 52 | 53 | 将`index.ts`中的`hook_mterp`改为`false` 54 | 55 | 在`trace_interpreter_enrty`的`ExecuteSwitchImplCpp`日志打印中添加`${offset}` 56 | 57 | ![](./images/Snipaste_2022-05-21_23-50-43.png) 58 | 59 | 开启frida-server,运行命令注入脚本,具体APP请自行选择 60 | 61 | ![](./images/Snipaste_2022-05-21_22-26-07.png) 62 | 63 | 随便滑动、点击下APP,脚本会给出一个偏移位置,比如我这里是`0x169d48` 64 | 65 | IDA中按`G`,`粘贴`地址,`回车`跳转,就会进入到其中一个`ExecuteSwitchImplCpp`实现 66 | 67 | 按`F5`查看伪代码 68 | 69 | ![](./images/Snipaste_2022-05-21_22-28-30.png) 70 | 71 | 往下翻,找到第一个while处,按`TAB`键跳转到汇编窗口 72 | 73 | ![](./images/Snipaste_2022-05-21_22-30-25.png) 74 | 75 | 然后检查特征,关键特征是和`0xFF`相与,以及`BR`指令 76 | 77 | ![](./images/Snipaste_2022-05-21_22-32-29.png) 78 | 79 | 特征确定后,那么记录下此处的偏移,比如我这里是`0x169EB4` 80 | 81 | 和`0xFF`相与的是`opcode`,而`opcode`是从`inst(Instruction)`取的 82 | 83 | 根据这个规则,可以推测图中`X28`是`opcode`,`X26`是`inst` 84 | 85 | 现在回到函数开头,将`a1`命名为`ctx`,其偏移`16`也就是两个指针大小(64位下就是2 * 8 = 16)的取值就是`shadow_frame`,那么对应寄存器在后续也是`shadow_frame`,我这里是`x19` 86 | 87 | ![](./images/Snipaste_2022-05-21_22-36-52.png) 88 | 89 | 现在将`index.ts`中的`trace_interpreter_switch`注释取消掉,把上面分析得到的`0x169EB4`、`x19`、`x26`对应修改 90 | 91 | ```JavaScript 92 | // 参数二是 while 循环中 inst 赋值给 next 的偏移 93 | // 参数三是存 shadow_frame 的寄存器 94 | // 参数四是存 inst(Instruction) 的寄存器 95 | trace_interpreter_switch(libart, 0x169EB4, 'x19', 'x26'); 96 | ``` 97 | 98 | 然后将`hook_switch`和`hook_mterp`改为`false`,编译新的js,进行测试 99 | 100 | 如果没有问题,现在IDA搜索`ExecuteMterpImpl`,跳转到对应函数,按F5查看伪代码,应该长这样 101 | 102 | 第一个参数是`thread` 103 | 104 | ![](./images/Snipaste_2022-05-21_22-48-36.png) 105 | 106 | 按`TAB`查看汇编代码,看看`x0`给哪个寄存器了,我这里是`x22`,记录下来,那么`x22`就是`thread` 107 | 108 | ![](./images/Snipaste_2022-05-21_22-49-13.png) 109 | 110 | 然后直接在汇编窗口往下翻,找一个符号是`mterp_op_`开头的代码(除了`mterp_op_nop`) 111 | 112 | 然后找一个和`0xFF`相与的寄存器,再往几行前看下是哪个寄存器读取来的,比如我这和`0xFF`相与的是`x23`,`x23`是由`x20`读取来的,那么`x20`就是`inst` 113 | 114 | ![](./images/Snipaste_2022-05-21_22-51-33.png) 115 | 116 | 现在将`index.ts`中的`trace_interpreter_mterp_op`注释取消掉,把上面分析得到的`x22`、`x20`对应修改 117 | 118 | ```JavaScript 119 | // 参数二是存 thread 的寄存器 120 | // 参数三是存 inst(Instruction) 的寄存器 121 | trace_interpreter_mterp_op(libart, "x22", "x20"); 122 | ``` 123 | 124 | 编译新的js,进行测试 125 | 126 | 如果顺利,那么现在能够trace 64位APP的smali执行详情了 127 | 128 | 如果检查找后面的参数太麻烦,也可以注释掉`trace_interpreter_switch`和`trace_interpreter_mterp_op` 129 | 130 | 将`hook_switch`和`hook_mterp`改为`true`,这样只会做简单的trace 131 | 132 | --- 133 | 134 | 如果通过静态分析的方法无法确定寄存器,可以自行修改脚本,打印全部寄存器情况 135 | 136 | 比如要检查`switch`在`while`处的`shadow_frame`是哪个寄存器,修改代码如下 137 | 138 | ```JavaScript 139 | // main 140 | let hook_switch = true; 141 | let hook_mterp = false; 142 | trace_interpreter_enrty(libart, hook_switch, hook_mterp); 143 | // trace_interpreter_enrty ExecuteSwitchImplCpp 日志添加一个 ${shadow_frame} 144 | log(`[switch] ${Process.getCurrentThreadId()} ${shadow_frame} ${offset} ${method_name} ${inst_str}`); 145 | // trace_interpreter_switch 146 | log(`[${id}] [switch] ${JSON.stringify(ctx)}`); 147 | ``` 148 | 149 | `trace_interpreter_switch`只打印寄存器信息日志 150 | 151 | ![](./images/Snipaste_2022-05-21_23-03-53.png) 152 | 153 | 这样也能定位出`shadow_frame`存在哪个寄存器,确定后再修改`trace_interpreter_switch`具体参数,还原代码 154 | 155 | ![](./images/Snipaste_2022-05-21_23-06-55.png) 156 | 157 | 类似的,将关键代码修改如下,测试查看`thread`是在哪个寄存器 158 | 159 | ```JavaScript 160 | // main 161 | let hook_switch = false; 162 | let hook_mterp = true; 163 | trace_interpreter_enrty(libart, hook_switch, hook_mterp); 164 | // trace_interpreter_enrty ExecuteMterpImpl 日志添加一个 ${args[0]} 165 | log(`[mterp] ${Process.getCurrentThreadId()} ${args[0]} ${method_name} ${inst_str}`); 166 | // trace_interpreter_mterp_op 只打印一个指令的 避免过多输出 167 | if (symbol.name != "mterp_op_move") continue; 168 | // hook_mterp_op 169 | log(`[${id}] [mterp] ${JSON.stringify(ctx)}`); 170 | ``` 171 | 172 | ![](./images/Snipaste_2022-05-21_23-13-06.png) 173 | 174 | ![](./images/Snipaste_2022-05-21_23-15-33.png) 175 | 176 | --- 177 | 178 | 还有一个问题,需要确定`thread`中`managed_stack`的偏移 179 | 180 | 但是`managed_stack`在`Thread`中的偏移就比较麻烦了,主要是因为`Thread`比较复杂 181 | 182 | 经过一番查阅后,发现在`art::StackVisitor::WalkStack`里面有调用`GetManagedStack()` 183 | 184 | - `void art::StackVisitor::WalkStack<(art::StackVisitor::CountTransitions)0>(bool)` 185 | 186 | ![](./images/Snipaste_2022-05-21_21-24-24.png) 187 | 188 | 并且这个函数的符号还在,于是结合源代码,和IDA对比便能知道`GetManagedStack()`实际的偏移 189 | 190 | 注意这个偏移每个版本、手机的可能都不同,比如我这里是`184`也就是`0xB8` 191 | 192 | ![](./images/Snipaste_2022-05-21_21-25-51.png) 193 | 194 | 确定偏移之后记得修改`get_shadow_frame_ptr_by_thread_ptr`里面计算`managed_stack`的偏移 195 | 196 | --- 197 | 198 | 注意,由于hook指令详细情况的位置里入口可能太近,除了上面的测试过程,其他时候 199 | 200 | - 使用了 trace_interpreter_switch 则 hook_switch 应当为 false 201 | - 使用了 trace_interpreter_mterp_op 则 hook_mterp 应当为 false 202 | 203 | 如果感兴趣详细实现过程,请查看[纯frida实现smali追踪](./纯frida实现smali追踪.md) -------------------------------------------------------------------------------- /trace/raptor_frida_android_trace.js: -------------------------------------------------------------------------------- 1 | /* 2 | * raptor_frida_android_trace.js - Code tracer for Android 3 | * Copyright (c) 2017 Marco Ivaldi 4 | * 5 | * Frida.re JS script to trace arbitrary Java Methods and 6 | * Module functions for debugging and reverse engineering. 7 | * See https://www.frida.re/ and https://codeshare.frida.re/ 8 | * for further information on this powerful tool. 9 | * 10 | * "We want to help others achieve interop through reverse 11 | * engineering" -- @oleavr 12 | * 13 | * Many thanks to @inode-, @federicodotta, @leonjza, and 14 | * @dankluev. 15 | * 16 | * Example usage: 17 | * # frida -U -f com.target.app -l raptor_frida_android_trace.js --no-pause 18 | * 19 | * Get the latest version at: 20 | * https://github.com/0xdea/frida-scripts/ 21 | */ 22 | 23 | // generic trace 24 | function trace(pattern) 25 | { 26 | var type = (pattern.toString().indexOf("!") === -1) ? "java" : "module"; 27 | 28 | if (type === "module") { 29 | 30 | // trace Module 31 | var res = new ApiResolver("module"); 32 | var matches = res.enumerateMatchesSync(pattern); 33 | var targets = uniqBy(matches, JSON.stringify); 34 | targets.forEach(function(target) { 35 | traceModule(target.address, target.name); 36 | }); 37 | 38 | } else if (type === "java") { 39 | 40 | // trace Java Class 41 | var found = false; 42 | Java.enumerateLoadedClasses({ 43 | onMatch: function(aClass) { 44 | if (aClass.match(pattern)) { 45 | found = true; 46 | var className = aClass.match(/[L](.*);/)[1].replace(/\//g, "."); 47 | traceClass(className); 48 | } 49 | }, 50 | onComplete: function() {} 51 | }); 52 | 53 | // trace Java Method 54 | if (!found) { 55 | try { 56 | traceMethod(pattern); 57 | } 58 | catch(err) { // catch non existing classes/methods 59 | console.error(err); 60 | } 61 | } 62 | } 63 | } 64 | 65 | // find and trace all methods declared in a Java Class 66 | function traceClass(targetClass) 67 | { 68 | var hook = Java.use(targetClass); 69 | var methods = hook.class.getDeclaredMethods(); 70 | hook.$dispose; 71 | 72 | var parsedMethods = []; 73 | methods.forEach(function(method) { 74 | parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]); 75 | }); 76 | 77 | var targets = uniqBy(parsedMethods, JSON.stringify); 78 | targets.forEach(function(targetMethod) { 79 | traceMethod(targetClass + "." + targetMethod); 80 | }); 81 | } 82 | 83 | // trace a specific Java Method 84 | function traceMethod(targetClassMethod) 85 | { 86 | var delim = targetClassMethod.lastIndexOf("."); 87 | if (delim === -1) return; 88 | 89 | var targetClass = targetClassMethod.slice(0, delim) 90 | var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length) 91 | 92 | var hook = Java.use(targetClass); 93 | var overloadCount = hook[targetMethod].overloads.length; 94 | 95 | console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]"); 96 | 97 | for (var i = 0; i < overloadCount; i++) { 98 | 99 | hook[targetMethod].overloads[i].implementation = function() { 100 | console.warn("\n*** entered " + targetClassMethod); 101 | 102 | // print backtrace 103 | // Java.perform(function() { 104 | // var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()); 105 | // console.log("\nBacktrace:\n" + bt); 106 | // }); 107 | 108 | // print args 109 | if (arguments.length) console.log(); 110 | for (var j = 0; j < arguments.length; j++) { 111 | console.log("arg[" + j + "]: " + arguments[j]); 112 | } 113 | 114 | // print retval 115 | var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?) 116 | console.log("\nretval: " + retval); 117 | console.warn("\n*** exiting " + targetClassMethod); 118 | return retval; 119 | } 120 | } 121 | } 122 | 123 | // trace Module functions 124 | function traceModule(impl, name) 125 | { 126 | console.log("Tracing " + name); 127 | 128 | Interceptor.attach(impl, { 129 | 130 | onEnter: function(args) { 131 | 132 | // debug only the intended calls 133 | this.flag = false; 134 | // var filename = Memory.readCString(ptr(args[0])); 135 | // if (filename.indexOf("XYZ") === -1 && filename.indexOf("ZYX") === -1) // exclusion list 136 | // if (filename.indexOf("my.interesting.file") !== -1) // inclusion list 137 | this.flag = true; 138 | 139 | if (this.flag) { 140 | console.warn("\n*** entered " + name); 141 | 142 | // print backtrace 143 | console.log("\nBacktrace:\n" + Thread.backtrace(this.context, Backtracer.ACCURATE) 144 | .map(DebugSymbol.fromAddress).join("\n")); 145 | } 146 | }, 147 | 148 | onLeave: function(retval) { 149 | 150 | if (this.flag) { 151 | // print retval 152 | console.log("\nretval: " + retval); 153 | console.warn("\n*** exiting " + name); 154 | } 155 | } 156 | 157 | }); 158 | } 159 | 160 | // remove duplicates from array 161 | function uniqBy(array, key) 162 | { 163 | var seen = {}; 164 | return array.filter(function(item) { 165 | var k = key(item); 166 | return seen.hasOwnProperty(k) ? false : (seen[k] = true); 167 | }); 168 | } 169 | 170 | // usage examples 171 | setTimeout(function() { // avoid java.lang.ClassNotFoundException 172 | 173 | Java.perform(function() { 174 | 175 | // trace("com.target.utils.CryptoUtils.decrypt"); 176 | // trace("com.target.utils.CryptoUtils"); 177 | // trace("CryptoUtils"); 178 | // trace(/crypto/i); 179 | // trace("exports:*!open*"); 180 | 181 | }); 182 | }, 0); -------------------------------------------------------------------------------- /trace/raptor_frida_android_trace_fixed.js: -------------------------------------------------------------------------------- 1 | /* 2 | * raptor_frida_android_trace.js - Code tracer for Android 3 | * Copyright (c) 2017 Marco Ivaldi 4 | * 5 | * Frida.re JS script to trace arbitrary Java Methods and 6 | * Module functions for debugging and reverse engineering. 7 | * See https://www.frida.re/ and https://codeshare.frida.re/ 8 | * for further information on this powerful tool. 9 | * 10 | * "We want to help others achieve interop through reverse 11 | * engineering" -- @oleavr 12 | * 13 | * Many thanks to @inode-, @federicodotta, @leonjza, and 14 | * @dankluev. 15 | * 16 | * Example usage: 17 | * # frida -U -f com.target.app -l raptor_frida_android_trace.js --no-pause 18 | * 19 | * Get the latest version at: 20 | * https://github.com/0xdea/frida-scripts/ 21 | */ 22 | 23 | // generic trace 24 | function trace(pattern) 25 | { 26 | var type = (pattern.toString().indexOf("!") === -1) ? "java" : "module"; 27 | 28 | if (type === "module") { 29 | console.log("module") 30 | 31 | // trace Module 32 | var res = new ApiResolver("module"); 33 | var matches = res.enumerateMatchesSync(pattern); 34 | var targets = uniqBy(matches, JSON.stringify); 35 | targets.forEach(function(target) { 36 | try{ 37 | traceModule(target.address, target.name); 38 | } 39 | catch(err){} 40 | }); 41 | 42 | } else if (type === "java") { 43 | 44 | console.log("java") 45 | 46 | // trace Java Class 47 | var found = false; 48 | Java.enumerateLoadedClasses({ 49 | onMatch: function(aClass) { 50 | if (aClass.match(pattern)) { 51 | found = true; 52 | console.log("found is true") 53 | 54 | console.log("before:"+aClass) 55 | //var className = aClass.match(/[L](.*);/)[1].replace(/\//g, "."); 56 | var className = aClass.match(/[L]?(.*);?/)[1].replace(/\//g, "."); 57 | console.log("after:"+className) 58 | traceClass(className); 59 | 60 | 61 | } 62 | }, 63 | onComplete: function() {} 64 | }); 65 | 66 | // trace Java Method 67 | if (!found) { 68 | try { 69 | traceMethod(pattern); 70 | } 71 | catch(err) { // catch non existing classes/methods 72 | console.error(err); 73 | } 74 | } 75 | } 76 | } 77 | 78 | // find and trace all methods declared in a Java Class 79 | function traceClass(targetClass) 80 | { 81 | 82 | console.log("entering traceClass") 83 | 84 | var hook = Java.use(targetClass); 85 | var methods = hook.class.getDeclaredMethods(); 86 | hook.$dispose(); 87 | 88 | console.log("entering pasedMethods") 89 | 90 | var parsedMethods = []; 91 | methods.forEach(function(method) { 92 | try{ 93 | parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]); 94 | } 95 | catch(err){} 96 | }); 97 | 98 | console.log("entering traceMethods") 99 | 100 | 101 | var targets = uniqBy(parsedMethods, JSON.stringify); 102 | targets.forEach(function(targetMethod) { 103 | try{ 104 | traceMethod(targetClass + "." + targetMethod); 105 | } 106 | catch(err){} 107 | }); 108 | } 109 | 110 | // trace a specific Java Method 111 | function traceMethod(targetClassMethod) 112 | { 113 | var delim = targetClassMethod.lastIndexOf("."); 114 | if (delim === -1) return; 115 | 116 | var targetClass = targetClassMethod.slice(0, delim) 117 | var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length) 118 | 119 | var hook = Java.use(targetClass); 120 | var overloadCount = hook[targetMethod].overloads.length; 121 | 122 | console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]"); 123 | 124 | for (var i = 0; i < overloadCount; i++) { 125 | 126 | hook[targetMethod].overloads[i].implementation = function() { 127 | console.warn("\n*** entered " + targetClassMethod); 128 | 129 | // print backtrace 130 | // Java.perform(function() { 131 | // var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()); 132 | // console.log("\nBacktrace:\n" + bt); 133 | // }); 134 | 135 | // print args 136 | if (arguments.length) console.log(); 137 | for (var j = 0; j < arguments.length; j++) { 138 | console.log("arg[" + j + "]: " + arguments[j]); 139 | } 140 | 141 | // print retval 142 | var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?) 143 | console.log("\nretval: " + retval); 144 | console.warn("\n*** exiting " + targetClassMethod); 145 | return retval; 146 | } 147 | } 148 | } 149 | 150 | 151 | // trace Module functions 152 | function traceModule(impl, name) 153 | { 154 | console.log("Tracing " + name); 155 | 156 | Interceptor.attach(impl, { 157 | 158 | onEnter: function(args) { 159 | 160 | // debug only the intended calls 161 | this.flag = false; 162 | // var filename = Memory.readCString(ptr(args[0])); 163 | // if (filename.indexOf("XYZ") === -1 && filename.indexOf("ZYX") === -1) // exclusion list 164 | // if (filename.indexOf("my.interesting.file") !== -1) // inclusion list 165 | this.flag = true; 166 | 167 | if (this.flag) { 168 | console.warn("\n*** entered " + name); 169 | 170 | // print backtrace 171 | console.log("\nBacktrace:\n" + Thread.backtrace(this.context, Backtracer.ACCURATE) 172 | .map(DebugSymbol.fromAddress).join("\n")); 173 | } 174 | }, 175 | 176 | onLeave: function(retval) { 177 | 178 | if (this.flag) { 179 | // print retval 180 | console.log("\nretval: " + retval); 181 | console.warn("\n*** exiting " + name); 182 | } 183 | } 184 | 185 | }); 186 | } 187 | 188 | // remove duplicates from array 189 | function uniqBy(array, key) 190 | { 191 | var seen = {}; 192 | return array.filter(function(item) { 193 | var k = key(item); 194 | return seen.hasOwnProperty(k) ? false : (seen[k] = true); 195 | }); 196 | } 197 | 198 | // usage examples 199 | setTimeout(function() { // avoid java.lang.ClassNotFoundException 200 | 201 | Java.perform(function() { 202 | 203 | console.log("first entering selector") 204 | trace("com.example.mysecondapp.MainActivity"); 205 | //trace("exports:*!open*"); 206 | //trace("exports:*!write*"); 207 | //trace("exports:*!malloc*"); 208 | //trace("exports:*!free*"); 209 | 210 | }); 211 | }, 0); -------------------------------------------------------------------------------- /脱壳/FRIDA-DEXDump/frida_dexdump/agent.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: hluwa 3 | * HomePage: https://github.com/hluwa 4 | * CreatedTime: 2020/1/7 20:44 5 | * */ 6 | 7 | 8 | var enable_deep_search = false; 9 | 10 | function verify_by_maps(dexptr, mapsptr) { 11 | var maps_offset = dexptr.add(0x34).readUInt(); 12 | var maps_size = mapsptr.readUInt(); 13 | for (var i = 0; i < maps_size; i++) { 14 | var item_type = mapsptr.add(4 + i * 0xC).readU16(); 15 | if (item_type === 4096) { 16 | var map_offset = mapsptr.add(4 + i * 0xC + 8).readUInt(); 17 | if (maps_offset === map_offset) { 18 | return true; 19 | } 20 | } 21 | } 22 | return false; 23 | } 24 | 25 | 26 | function get_dex_real_size(dexptr, range_base, range_end) { 27 | var dex_size = dexptr.add(0x20).readUInt(); 28 | 29 | var maps_address = get_maps_address(dexptr, range_base, range_end); 30 | if (!maps_address) { 31 | return dex_size; 32 | } 33 | 34 | var maps_end = get_maps_end(maps_address, range_base, range_end); 35 | if (!maps_end) { 36 | return dex_size; 37 | } 38 | 39 | return maps_end - dexptr 40 | } 41 | 42 | function get_maps_address(dexptr, range_base, range_end) { 43 | var maps_offset = dexptr.add(0x34).readUInt(); 44 | if (maps_offset === 0) { 45 | return null; 46 | } 47 | 48 | var maps_address = dexptr.add(maps_offset); 49 | if (maps_address < range_base || maps_address > range_end) { 50 | return null; 51 | } 52 | 53 | return maps_address; 54 | } 55 | 56 | function get_maps_end(maps, range_base, range_end) { 57 | var maps_size = maps.readUInt(); 58 | if (maps_size < 2 || maps_size > 50) { 59 | return null; 60 | } 61 | var maps_end = maps.add(maps_size * 0xC + 4); 62 | if (maps_end < range_base || maps_end > range_end) { 63 | return null; 64 | } 65 | 66 | return maps_end; 67 | } 68 | 69 | 70 | function verify(dexptr, range, enable_verify_maps) { 71 | 72 | if (range != null) { 73 | var range_end = range.base.add(range.size); 74 | // verify header_size 75 | if (dexptr.add(0x70) > range_end) { 76 | return false; 77 | } 78 | 79 | // In runtime, the fileSize is can to be clean, so it's not trust. 80 | // verify file_size 81 | // var dex_size = dexptr.add(0x20).readUInt(); 82 | // if (dexptr.add(dex_size) > range_end) { 83 | // return false; 84 | // } 85 | 86 | if (enable_verify_maps) { 87 | 88 | var maps_address = get_maps_address(dexptr, range.base, range_end); 89 | if (!maps_address) { 90 | return false; 91 | } 92 | 93 | var maps_end = get_maps_end(maps_address, range.base, range_end); 94 | if (!maps_end) { 95 | return false; 96 | } 97 | return verify_by_maps(dexptr, maps_address) 98 | } else { 99 | return dexptr.add(0x3C).readUInt() === 0x70; 100 | } 101 | } 102 | 103 | return false; 104 | 105 | 106 | } 107 | 108 | rpc.exports = { 109 | memorydump: function memorydump(address, size) { 110 | return new NativePointer(address).readByteArray(size); 111 | }, 112 | switchmode: function switchmode(bool) { 113 | enable_deep_search = bool; 114 | }, 115 | scandex: function scandex() { 116 | var result = []; 117 | Process.enumerateRanges('r--').forEach(function (range) { 118 | try { 119 | Memory.scanSync(range.base, range.size, "64 65 78 0a 30 ?? ?? 00").forEach(function (match) { 120 | 121 | if (range.file && range.file.path 122 | && (// range.file.path.startsWith("/data/app/") || 123 | range.file.path.startsWith("/data/dalvik-cache/") || 124 | range.file.path.startsWith("/system/"))) { 125 | return; 126 | } 127 | 128 | if (verify(match.address, range, false)) { 129 | var dex_size = get_dex_real_size(match.address, range.base, range.base.add(range.size)); 130 | result.push({ 131 | "addr": match.address, 132 | "size": dex_size 133 | }); 134 | 135 | var max_size = range.size - match.address.sub(range.base); 136 | if (enable_deep_search && max_size != dex_size) { 137 | result.push({ 138 | "addr": match.address, 139 | "size": max_size 140 | }); 141 | } 142 | } 143 | }); 144 | 145 | if (enable_deep_search) { 146 | Memory.scanSync(range.base, range.size, "70 00 00 00").forEach(function (match) { 147 | var dex_base = match.address.sub(0x3C); 148 | if (dex_base < range.base) { 149 | return 150 | } 151 | if (dex_base.readCString(4) != "dex\n" && verify(dex_base, range, true)) { 152 | var real_dex_size = get_dex_real_size(dex_base, range.base, range.base.add(range.size)); 153 | result.push({ 154 | "addr": dex_base, 155 | "size": real_dex_size 156 | }); 157 | var max_size = range.size - dex_base.sub(range.base); 158 | if (max_size != real_dex_size) { 159 | result.push({ 160 | "addr": match.address, 161 | "size": max_size 162 | }); 163 | } 164 | } 165 | }) 166 | } else { 167 | if (range.base.readCString(4) != "dex\n" && verify(range.base, range, true)) { 168 | var real_dex_size = get_dex_real_size(range.base, range.base, range.base.add(range.size)); 169 | result.push({ 170 | "addr": range.base, 171 | "size": real_dex_size 172 | }); 173 | } 174 | } 175 | 176 | } catch (e) { 177 | } 178 | }); 179 | 180 | return result; 181 | } 182 | }; 183 | -------------------------------------------------------------------------------- /hook/hook_libart脚本/hook_art.js: -------------------------------------------------------------------------------- 1 | /* 2 | GetFieldID is at 0xe39b87c5 _ZN3art3JNI10GetFieldIDEP7_JNIEnvP7_jclassPKcS6_ 3 | GetMethodID is at 0xe39a1a19 _ZN3art3JNI11GetMethodIDEP7_JNIEnvP7_jclassPKcS6_ 4 | NewStringUTF is at 0xe39cff25 _ZN3art3JNI12NewStringUTFEP7_JNIEnvPKc 5 | RegisterNatives is at 0xe39e08fd _ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi 6 | GetStaticFieldID is at 0xe39c9635 _ZN3art3JNI16GetStaticFieldIDEP7_JNIEnvP7_jclassPKcS6_ 7 | GetStaticMethodID is at 0xe39be0ed _ZN3art3JNI17GetStaticMethodIDEP7_JNIEnvP7_jclassPKcS6_ 8 | GetStringUTFChars is at 0xe39d06e5 _ZN3art3JNI17GetStringUTFCharsEP7_JNIEnvP8_jstringPh 9 | FindClass is at 0xe399ae5d _ZN3art3JNI9FindClassEP7_JNIEnvPKc 10 | */ 11 | //这是找libart的所有函数的包括注册的 这个功能更多。。。但我不知道 要知道其他的来干嘛 估计我的知识还是不够 12 | 13 | function hook_libart(){ 14 | var symbols = Module.enumerateSymbolsSync("libart.so"); 15 | var addrGetStringUTFChars = null; 16 | var addrNewStringUTF = null; 17 | var addrFindClass = null; 18 | var addrGetMethodID = null; 19 | var addrGetStaticMethodID = null; 20 | var addrGetFieldID = null; 21 | var addrGetStaticFieldID = null; 22 | var addrRegisterNatives = null; 23 | 24 | for(var i = 0 ;i < symbols.length ; ++i){ 25 | var symbol = symbols[i]; 26 | if(symbol.name.indexOf("art") >= 0 && 27 | symbol.name.indexOf("JNI") >=0 && 28 | symbol.name.indexOf("CheckJNI")< 0){ 29 | if(symbol.name.indexOf("GetStringUTFChars") >=0){ 30 | addrGetStringUTFChars = symbol.address; 31 | console.log("GetStringUTFChars is at",symbol.address,symbol.name); 32 | }else if(symbol.name.indexOf("FindClass") >=0){ 33 | addrFindClass = symbol.address; 34 | console.log("FindClass is at",symbol.address,symbol.name); 35 | }else if(symbol.name.indexOf("GetStaticMethodID") >=0){ 36 | addrGetStaticMethodID = symbol.address; 37 | console.log("GetStaticMethodID is at",symbol.address,symbol.name);; 38 | 39 | }else if(symbol.name.indexOf("GetStaticFieldID") >= 0){ 40 | addrGetStaticFieldID = symbol.address; 41 | console.log("GetStaticFieldID is at",symbol.address,symbol.name);; 42 | 43 | }else if(symbol.name.indexOf("RegisterNatives") >= 0){ 44 | addrRegisterNatives = symbol.address; 45 | console.log("RegisterNatives is at",symbol.address,symbol.name);; 46 | 47 | }else if(symbol.name.indexOf("NewStringUTF") >= 0){ 48 | addrNewStringUTF = symbol.address; 49 | console.log("NewStringUTF is at",symbol.address,symbol.name); 50 | }else if(symbol.name.indexOf("GetMethodID") >= 0){ 51 | addrGetMethodID = symbol.address; 52 | console.log("GetMethodId is at",symbol.address,symbol.name); 53 | }else if(symbol.name.indexOf("GetFieldID") >= 0){ 54 | addrGetFieldID = symbol.address; 55 | console.log("GetFieldID is at",symbol.address,symbol.name) 56 | } 57 | } 58 | } 59 | 60 | if(addrGetStringUTFChars != null){ 61 | Interceptor.attach(addrGetStringUTFChars,{ 62 | onEnter : function(args){ 63 | 64 | }, 65 | onLeave: function(retval){ 66 | if(retval != null){ 67 | var bytes = Memory.readCString(retval); 68 | console.log("[GetStringUTFChars] result:"+ bytes); 69 | } 70 | } 71 | }); 72 | } 73 | if(addrNewStringUTF != null){ 74 | Interceptor.attach(addrNewStringUTF,{ 75 | onEnter : function(args){ 76 | if(args[1] != null){ 77 | var string = Memory.readCString(args[1]); 78 | console.log("[NewStringUTF] bytes:" + string); 79 | } 80 | }, 81 | onLeave: function(retval){} 82 | }); 83 | } 84 | if(addrFindClass != null){ 85 | Interceptor.attach(addrFindClass,{ 86 | onEnter: function(args){ 87 | if(args[1] != null){ 88 | var name = Memory.readCString(args[1]); 89 | console.log("[FindClass] name:" + name); 90 | } 91 | }, 92 | onLeave: function(retval){} 93 | }); 94 | } 95 | if(addrGetMethodID != null){ 96 | Interceptor.attach(addrGetMethodID,{ 97 | onEnter: function(args){ 98 | if(args[2] != null){ 99 | var name = Memory.readCString(args[2]); 100 | if(args[3] != null){ 101 | var sig = Memory.readCString(args[3]); 102 | console.log("[GetMethodID] name:" + name + ",sig: "+ sig); 103 | }else{ 104 | console.log("[GetMethodId] name :" + name); 105 | } 106 | } 107 | }, 108 | onLeave: function(retval){} 109 | }); 110 | } 111 | if(addrGetStaticMethodID != null){ 112 | Interceptor.attach(addrGetStaticMethodID,{ 113 | onEnter : function(args){ 114 | if(args[2] != null){ 115 | var name = Memory.readCString(args[2]); 116 | if(args[3] != null){ 117 | var sig = Memory.readCString(args[3]); 118 | console.log("[GetStaticMethod] name:"+ name + ",sig=" +sig); 119 | 120 | }else{ 121 | console.log("[GetStaticMethod] name:"+ name); 122 | } 123 | } 124 | }, 125 | onLeave: function(retval){} 126 | }); 127 | } 128 | 129 | if(addrGetFieldID != null){ 130 | Interceptor.attach(addrGetFieldID,{ 131 | onEnter: function(args){ 132 | if(args[2] != null){ 133 | var name = Memory.readCString(args[2]); 134 | if(args[3] != null){ 135 | var sig = Memory.readCString(args[3]); 136 | console.log("[GetFieldId] name:" + name+",sig:" + sig); 137 | }else{ 138 | console.log("[GetFieldld] name:" + name); 139 | } 140 | } 141 | }, 142 | onLeave: function(retval){} 143 | }); 144 | } 145 | if(addrGetStaticFieldID != null){ 146 | Interceptor.attach(addrGetStaticFieldID,{ 147 | onEnter: function(args){ 148 | if(args[2] != null){ 149 | var name = Memory.readCString(args[2]); 150 | if(args[3] != null){ 151 | var sig = Memory.readCString(args[3]); 152 | console.log("[GetstaticFieldId] name:"+ name + ",sig:" + sig); 153 | }else{ 154 | console.log("[GetstaticFieldId] name:" + name ); 155 | } 156 | } 157 | } 158 | }); 159 | } 160 | if(addrRegisterNatives != 0){ 161 | Interceptor.attach(addrRegisterNatives,{ 162 | onEnter: function(args){ 163 | console.log("[RegisterNatives] method_count:",args[3]); 164 | var env = args[0]; 165 | var java_class = args[1]; 166 | var class_name = Java.vm.tryGetEnv().getClassName(java_class); 167 | var methods_ptr = ptr(args[2]); 168 | 169 | var method_count = parseInt(args[3]); 170 | for(var i = 0 ; i < method_count ; ++i){ 171 | var name_ptr = Memory.readPointer(methods_ptr.add(3*i*Process.pointerSize)); 172 | var sig_ptr = Memory.readPointer(methods_ptr.add(3*i*Process.pointerSize + Process.pointerSize)); 173 | var fnPtr_ptr = Memory.readPointer(methods_ptr.add(3*i*Process.pointerSize) + 2*Process.pointerSize); 174 | 175 | var name = Memory.readCString(name_ptr); 176 | var sig = Memory.readCString(sig_ptr); 177 | var find_module = Process.findRangeByAddress(fnPtr_ptr); 178 | console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base)); 179 | } 180 | }, 181 | onLeave: function(retval){} 182 | }); 183 | } 184 | 185 | } -------------------------------------------------------------------------------- /脱壳/unpack.js: -------------------------------------------------------------------------------- 1 | 2 | var DEX_MAGIC = 0x0A786564; 3 | var dexrec = []; 4 | 5 | var openmemory = Module.findExportByName("libart.so", "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_"); 6 | if(openmemory != undefined) { 7 | console.log("openmemory at" + openmemory); 8 | Interceptor.attach(openmemory, { 9 | onEnter: function (args) { 10 | if(Memory.readU32(args[1]) == DEX_MAGIC) { 11 | dexrec.push(args[1]); 12 | } 13 | }, 14 | onLeave: function (retval) { 15 | 16 | } 17 | }); 18 | } 19 | 20 | if(Java.available) { 21 | Java.perform(function(){ 22 | 23 | var dexBase64 = "ZGV4CjAzNQCjsh5+52qOBRMl1aMHk33QkLmfsSbOla5wDwAAcAAAAHhWNBIAAAAAAAAAAKAOAABpAAAAcAAAABwAAAAUAgAAGgAAAIQCAAABAAAAvAMAACUAAADEAwAAAQAAAOwEAABkCgAADAUAAAwFAAAPBQAAEgUAABcFAAAfBQAAIwUAADgFAABGBQAASQUAAE0FAABSBQAAVQUAAFkFAABeBQAAYwUAAHcFAACXBQAAtgUAAM8FAADiBQAA+AUAABEGAAAoBgAATAYAAG4GAACCBgAAlgYAALEGAADIBgAA4wYAAP4GAAAaBwAAMQcAAEgHAABzBwAAjAcAAKUHAADSBwAA6AcAAPoHAAD/BwAAAggAAAYIAAAKCAAADQgAABEIAAAlCAAAOggAAE8IAABsCAAAcQgAAHkIAACGCAAAlQgAAKAIAACnCAAAqggAALcIAADKCAAA0wgAANYIAADaCAAA4wgAAPEIAAD5CAAAAAkAAAsJAAAQCQAAGgkAACwJAABDCQAAVQkAAGkJAAB0CQAAfQkAAI0JAACgCQAArwkAAMAJAADJCQAAzAkAANQJAADeCQAA7AkAAPoJAAAFCgAADQoAABYKAAAcCgAAJgoAACwKAAA5CgAAQQoAAEcKAABQCgAAWgoAAGsKAABzCgAAggoAAIgKAACOCgAAlwoAAKAKAACqCgAAwAoAAAcAAAAOAAAADwAAABAAAAARAAAAEgAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACIAAAAjAAAAJQAAACYAAAAoAAAAKwAAAC0AAAAuAAAALwAAADAAAAAHAAAAAAAAAAAAAAAIAAAAAAAAAMgKAAAJAAAAAAAAAAgLAAAKAAAABQAAAAAAAAALAAAABQAAAOgKAAAKAAAACgAAAAAAAAALAAAACgAAAMgKAAAMAAAACgAAANAKAAANAAAACgAAANgKAAANAAAACgAAAOAKAAAKAAAACwAAAAAAAAALAAAADAAAAOgKAAALAAAADwAAAOgKAAALAAAAEQAAAPAKAAAKAAAAEwAAAAAAAAAKAAAAFAAAAAAAAAAoAAAAFgAAAAAAAAApAAAAFgAAAPAKAAApAAAAFgAAAPgKAAAqAAAAFgAAAAALAAArAAAAFwAAAAAAAAAsAAAAFwAAAMgKAAAKAAAAGAAAAAAAAAALAAAAGQAAABALAAALAAAAGgAAAPAKAAAKAAAAGwAAAAAAAAACAAsAJwAAAAEAAgA3AAAAAgAQAAMAAAACAA0ARAAAAAIAGABFAAAAAgAIAEoAAAACABEAUwAAAAQADgA9AAAABQAMAEYAAAAFABkARwAAAAUACgBJAAAABQADAEwAAAAGAAQAVAAAAAgAEABfAAAACQAQAF8AAAAKABAAAwAAAAoAAwBDAAAACwAVAD8AAAAMABAAAwAAAAwACwAyAAAADAAKAGYAAAAOAAcAQgAAAA4AAQBIAAAADwAGAEIAAAAPABMAYQAAABAACgBJAAAAEAAWAEsAAAAQAAkAUAAAABEAEAADAAAAEQAVADEAAAARAA8AUQAAABEAAABiAAAAEQAXAGUAAAASABIAYwAAABMAFABNAAAAEwAFAFoAAAAUABQATgAAABQABQBZAAAAAgAAAAEAAAAKAAAAAAAAAAUAAAA8CwAAhA4AABYLAAABKAABKQADLS0+AAY8aW5pdD4AAj47ABNFbnVtZXJhdGVDbGFzcy5qYXZhAAxGUmlEQV9VTlBBQ0sAAUkAAklMAANJTEwAAUwAAkxMAANMTEkAA0xMTAASTGFuZHJvaWQvdXRpbC9Mb2c7AB5MY29tL3NtYXJ0ZG9uZS9FbnVtZXJhdGVDbGFzczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWduYXR1cmU7ABdMZGFsdmlrL3N5c3RlbS9EZXhGaWxlOwARTGphdmEvbGFuZy9DbGFzczsAFExqYXZhL2xhbmcvQ2xhc3M8Kj47ABdMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwAVTGphdmEvbGFuZy9FeGNlcHRpb247ACJMamF2YS9sYW5nL0lsbGVnYWxBY2Nlc3NFeGNlcHRpb247ACBMamF2YS9sYW5nL05vU3VjaEZpZWxkRXhjZXB0aW9uOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsAFUxqYXZhL2xhbmcvVGhyb3dhYmxlOwAZTGphdmEvbGFuZy9yZWZsZWN0L0FycmF5OwAZTGphdmEvbGFuZy9yZWZsZWN0L0ZpZWxkOwAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsAFUxqYXZhL3V0aWwvQXJyYXlMaXN0OwAVTGphdmEvdXRpbC9BcnJheUxpc3Q8AClMamF2YS91dGlsL0FycmF5TGlzdDxMamF2YS9sYW5nL1N0cmluZzs+OwAXTGphdmEvdXRpbC9Db2xsZWN0aW9uczsAF0xqYXZhL3V0aWwvRW51bWVyYXRpb247ACtMamF2YS91dGlsL0VudW1lcmF0aW9uPExqYXZhL2xhbmcvU3RyaW5nOz47ABRMamF2YS91dGlsL0l0ZXJhdG9yOwAQTGphdmEvdXRpbC9MaXN0OwADVEFHAAFWAAJWTAACVloAAVoAAlpMABJbTGphdmEvbGFuZy9DbGFzczsAE1tMamF2YS9sYW5nL09iamVjdDsAE1tMamF2YS9sYW5nL1N0cmluZzsAG1tMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwADYWRkAAZhcHBlbmQAC2NsYXNzTG9hZGVyAA1jbGFzc05hbWVMaXN0AAljbGFzc2xpc3QABWNsYXp6AAFkAAtkZXhFbGVtZW50cwARZGV4RWxlbWVudHNMZW5ndGgAB2RleEZpbGUAAWUAAmUyAAdlbnRyaWVzAAxlbnVtZXJhdGlvbnMABmVxdWFscwAFZmllbGQACWZpZWxkTmFtZQADZ2V0AAhnZXRDbGFzcwAQZ2V0Q2xhc3NOYW1lTGlzdAAVZ2V0Q2xhc3NOYW1lTGlzdEFycmF5ABBnZXREZWNsYXJlZEZpZWxkABJnZXREZWNsYXJlZE1ldGhvZHMACWdldExlbmd0aAAHZ2V0TmFtZQAOZ2V0T2JqZWN0RmllbGQAEWdldFBhcmFtZXRlclR5cGVzAA1nZXRTdXBlcmNsYXNzAA9oYXNNb3JlRWxlbWVudHMAB2hhc05leHQAAWkABmludm9rZQAIaXRlcmF0b3IADGxvYWQgY2xhc3M6IAAMbG9hZEFsbENsYXNzAAlsb2FkQ2xhc3MABm1ldGhvZAAHbWV0aG9kcwAEbmFtZQAIbmFtZWxpc3QABG5leHQAC25leHRFbGVtZW50AAZvYmplY3QABG9ianMAB3Bhcm1sZW4ACHBhdGhMaXN0AA9wcmludFN0YWNrVHJhY2UABnJldHZhbAANc2V0QWNjZXNzaWJsZQAEc2l6ZQAEc29ydAAHc3VjY2VzcwAHdG9BcnJheQAIdG9TdHJpbmcAFHRyeSB0byBsb2FkIG1ldGhvZDogAAV2YWx1ZQAAAQAAAAoAAAACAAAACgAAAAIAAAAKAAsAAgAAAAoAGQABAAAACwAAAAEAAAAGAAAAAQAAABUAAAABAAAAFwAAAAIAAAALAAsAAQAAABkAARcGAgMBaBwGFwAXFBcBFyAXGRcEAAAAAAAAAAAAAQAAABkLAAAAAAAAAAAAAAEAAAAAAAAAAgAAADQLAAAOAA4AJAE0DlsEADUSIsMDATkLSwMCOgEdAwNQAS3/BAQ/FCVpoQUEQgUBBQIFAxwfPAA1ATQOSwQAWRIiaQMBYRs8ABMCXEIOSwMANwYBEBBLAwFBEEtdBQEeAwE9CTsFARkeAwE8CjxNBQEfAD0BNA5LBAA2EiL/AwJYDEsEAzcGFEsDBFccARoPaQMHVhFaAwheAS0DCV0aASYPSwJ7dwUHBQgFCUIFAgUDBQQgBQAbIAABAAEAAQAAAFQLAAAEAAAAcBAOAAAADgAHAAEAAgABAFgLAABBAAAAIgARAHAQGwAAABoBXgBxIAQAFgAMARoCOABxIAQAIQAMAXEQFQABAAoCEgM1IyUAcSAUADEADAQaBToAcSAEAFQADAQfBAQAbhAGAAQADARyECEABAAKBTgFDAByECIABAAMBR8FCwBuIBwAUAAo8dgDAwEo3CgCDQFxECAAAAARAAAABQAAADIAAQABAQc8AwABAAIAAACHCwAADgAAAHEQAgACAAwAbhAeAAAACgEjERoAbiAfABAAEQEFAAIAAgABAJgLAAAxAAAAbhAPAAMADABuEAkAAAAMARwCCgBuEAkAAgAMAm4gEAAhAAoBOQEdAG4gBwBAAAwBEhJuIBcAIQBuIBYAMQAMAhECDQFuEAwAAQAoCQ0BbhANAAEAbhAKAAAADAAo1hIBEQEAABQAAAAMAAEAAQIJJgghAAAOAAEAAwABAMILAAB7AAAAcRACAA0ADABuEB0AAAAMAXIQIwABAAoCOAJsAHIQJAABAAwCHwILAG4gCwAtAAwDbhAIAAMADAQaBQYAIgYMAHAQEQAGABoHUgBuIBIAdgBuEAkAAwAMB24gEgB2AG4QEwAGAAwGcSAAAGUAIUUSBjVWPwBGBwQGbhAZAAcADAghiCOJGQAaCgYAIgsMAHAQEQALABoMZwBuIBIAywBuEAkAAwAMDG4gEgDLABoMAgBuIBIAywBuEBgABwAMDG4gEgDLAG4QEwALAAwLcSAAALoAEgpuMBoApwkaCgYAGgtkAHEgAAC6ANgGBgEowiiRKAINAA4AAAAAAAAAdAABAAEBDXkBAAUAABoBgYAEiBgBCaAYAQnAGQEJ7BkBCfAaEQAAAAAAAAABAAAAAAAAAAEAAABpAAAAcAAAAAIAAAAcAAAAFAIAAAMAAAAaAAAAhAIAAAQAAAABAAAAvAMAAAUAAAAlAAAAxAMAAAYAAAABAAAA7AQAAAIgAABpAAAADAUAAAEQAAAKAAAAyAoAAAUgAAABAAAAFgsAAAQgAAABAAAAGQsAAAMQAAADAAAALAsAAAYgAAABAAAAPAsAAAMgAAAFAAAAVAsAAAEgAAAFAAAACAwAAAAgAAABAAAAhA4AAAAQAAABAAAAoA4AAA=="; 24 | var application = Java.use("android.app.Application"); 25 | var BaseDexClassLoader = Java.use("dalvik.system.BaseDexClassLoader"); 26 | var Base64 = Java.use("android.util.Base64"); 27 | var FileOutputStream = Java.use("java.io.FileOutputStream"); 28 | var DexClassLoader = Java.use("dalvik.system.DexClassLoader"); 29 | 30 | var reflectField = Java.use("java.lang.reflect.Field"); 31 | var reflectMethod = Java.use("java.lang.reflect.Method"); 32 | var reflectObject = Java.use("java.lang.Object"); 33 | var reflectClass = Java.use("java.lang.Class"); 34 | var reflectString = Java.use("java.lang.String"); 35 | var reflectClassloader = Java.use("java.lang.ClassLoader"); 36 | 37 | 38 | if(application != undefined) { 39 | application.attach.overload('android.content.Context').implementation = function(context) { 40 | var result = this.attach(context); 41 | var classloader = context.getClassLoader(); 42 | var filesDir = context.getFilesDir(); 43 | var codeCacheDir = context.getCodeCacheDir(); 44 | console.log("files dir: " + filesDir); 45 | console.log("code cache dir: " + codeCacheDir); 46 | if(classloader != undefined) { 47 | var casedloader = Java.cast(classloader, BaseDexClassLoader); 48 | var dexbytes = Base64.decode(dexBase64, 0); 49 | var dexpath = filesDir + "/emmm.dex"; 50 | var fout = FileOutputStream.$new(dexpath); 51 | fout.write(dexbytes, 0, dexbytes.length); 52 | fout.close(); 53 | console.log("write dex to " + dexpath); 54 | 55 | var dexstr = dexpath.toString(); 56 | var cachestr = codeCacheDir.toString(); 57 | 58 | var dyndex = DexClassLoader.$new(dexstr, cachestr, cachestr, classloader); 59 | console.log(dyndex.toString()); 60 | var EnumerateClass = dyndex.loadClass("com.smartdone.EnumerateClass"); 61 | var castedEnumerateClass = Java.cast(EnumerateClass, reflectClass); 62 | var methods = castedEnumerateClass.getDeclaredMethods(); 63 | // loadAllClass 64 | var loadAllClass = undefined; 65 | for(var i in methods) { 66 | console.log(methods[i].getName()); 67 | if(methods[i].getName() == "loadAllClass") { 68 | console.log("find loadAllClass"); 69 | loadAllClass = methods[i]; 70 | } 71 | } 72 | if(loadAllClass != undefined) { 73 | console.log("loadAllClass: " + loadAllClass.toString()); 74 | var args = Java.array('Ljava.lang.Object;',[classloader]); 75 | var classlist = loadAllClass.invoke(null , args); 76 | console.log("start dump dex "); 77 | for(var i in dexrec) { 78 | if(Memory.readU32(dexrec[i]) == DEX_MAGIC) { 79 | var dex_len = Memory.readU32(dexrec[i].add(0x20)); 80 | var dumppath = filesDir.toString() + "/" + dex_len.toString(0x10) + ".dex"; 81 | console.log(dumppath); 82 | var dumpdexfile = new File(dumppath, "wb"); 83 | dumpdexfile.write(Memory.readByteArray(dexrec[i], dex_len)); 84 | dumpdexfile.close(); 85 | console.log("write file to " + dumppath); 86 | } 87 | } 88 | } 89 | 90 | 91 | } else { 92 | console.error("unable get classloader"); 93 | } 94 | return result; 95 | } 96 | } 97 | }); 98 | } -------------------------------------------------------------------------------- /trace/frida-smali-trace-master/frida_scripts/agent/index.ts: -------------------------------------------------------------------------------- 1 | import { PrettyInstruction } from "./helper"; 2 | import { ShadowFrame, SwitchImplContext } from "./util"; 3 | 4 | import { log } from "./logger"; 5 | 6 | function enable_rpc_mode(flag: Boolean){ 7 | rpc_mode = flag; 8 | } 9 | 10 | function get_method_name(shadow_frame: ShadowFrame){ 11 | let method_key = shadow_frame.method.toString(); 12 | let method_name: any = method_name_cache[method_key]; 13 | if (!method_name){ 14 | method_name = shadow_frame.method.PrettyMethod(); 15 | if (method_name){ 16 | method_name_cache[method_key] = method_name; 17 | } 18 | } 19 | return method_name; 20 | } 21 | 22 | function trace_interpreter_enrty(libart: Module, hook_switch: boolean, hook_mterp: boolean){ 23 | libart.enumerateSymbols().forEach(function(symbol: ModuleSymbolDetails){ 24 | let name = symbol.name; 25 | let address = symbol.address; 26 | if(name.includes("ExecuteSwitchImplCpp") && hook_switch){ 27 | log(`start hook ${name}`); 28 | let offset = symbol.address.sub(libart.base); 29 | Interceptor.attach(address, { 30 | onEnter(args) { 31 | let ctx = new SwitchImplContext(args[0]); 32 | let shadow_frame = ctx.shadow_frame; 33 | let method_key = shadow_frame.method.toString(); 34 | let method_name: any = method_name_cache[method_key]; 35 | if (!method_name){ 36 | method_name = shadow_frame.method.PrettyMethod(); 37 | if (method_name){ 38 | method_name_cache[method_key] = method_name; 39 | } 40 | } 41 | let dexfile_ptr = shadow_frame.method.GetDexFile(); 42 | let dex_pc = shadow_frame.GetDexPC(); 43 | // const Instruction* next = Instruction::At(insns + dex_pc); 44 | let inst_ptr = ctx.accessor.insns.add(dex_pc); 45 | let inst_str = PrettyInstruction(inst_ptr, dexfile_ptr); 46 | log(`[switch] ${Process.getCurrentThreadId()} ${method_name} ${inst_str}`); 47 | } 48 | }); 49 | } 50 | if(name.includes("ExecuteMterpImpl") && hook_mterp){ 51 | log(`start hook ${name}`); 52 | Interceptor.attach(address, { 53 | onEnter(args) { 54 | let inst_ptr = args[1]; 55 | let shadow_frame = new ShadowFrame(args[2]); 56 | let method_name = get_method_name(shadow_frame); 57 | let dexfile_ptr = shadow_frame.method.GetDexFile(); 58 | let inst_str = PrettyInstruction(inst_ptr, dexfile_ptr); 59 | log(`[mterp] ${Process.getCurrentThreadId()} ${method_name} ${inst_str}`); 60 | // send({ 61 | // type: "Mterp", 62 | // info: { 63 | // tid: Process.getCurrentThreadId(), 64 | // function_name: function_name, 65 | // inst_string: inst_string 66 | // } 67 | // }) 68 | } 69 | }); 70 | } 71 | }) 72 | } 73 | 74 | function trace_interpreter_switch(libart: Module, offset: number, frame_reg: string, inst_reg: string) { 75 | Interceptor.attach(libart.base.add(offset), { 76 | onEnter(args) { 77 | let id = switch_count; 78 | switch_count += 1; 79 | let ctx = this.context as Arm64CpuContext; 80 | let shadow_frame = new ShadowFrame(ctx[frame_reg as keyof typeof ctx]); 81 | // 通过 thread 获取到当前的 shadow_frame 82 | // let thread_ptr = ctx.sp.add(0x210).sub(0x168).readPointer(); 83 | // let shadow_frame = get_shadow_frame_ptr_by_thread_ptr(thread_ptr); 84 | let method_name = get_method_name(shadow_frame); 85 | let dexfile_ptr = shadow_frame.method.GetDexFile(); 86 | let inst_ptr = ctx[inst_reg as keyof typeof ctx]; 87 | let inst_str = PrettyInstruction(inst_ptr, dexfile_ptr); 88 | log(`[${id}] [switch] ${method_name} ${inst_str}`); 89 | } 90 | }); 91 | } 92 | 93 | function hook_mterp_op(address: NativePointer, offset: NativePointer, thread_reg: string, inst_reg: string) { 94 | Interceptor.attach(address, { 95 | onEnter(args) { 96 | let id = mterp_count; 97 | mterp_count += 1; 98 | let ctx = this.context as Arm64CpuContext; 99 | let thread_ptr = ctx[thread_reg as keyof typeof ctx]; 100 | let shadow_frame = get_shadow_frame_ptr_by_thread_ptr(thread_ptr); 101 | let method_name = get_method_name(shadow_frame); 102 | let dexfile_ptr = shadow_frame.method.GetDexFile(); 103 | let inst_ptr = ctx[inst_reg as keyof typeof ctx]; 104 | let inst_str = PrettyInstruction(inst_ptr, dexfile_ptr); 105 | log(`[${id}] [mterp] ${Process.getCurrentThreadId()} ${method_name} ${inst_str}`); 106 | } 107 | }); 108 | } 109 | 110 | function trace_interpreter_mterp_op(libart: Module, thread_reg: string, inst_reg: string) { 111 | let op_count = 0; 112 | let symbols = libart.enumerateSymbols(); 113 | for (let index = 0; index < symbols.length; index++) { 114 | const symbol = symbols[index]; 115 | // 过滤不符合要求的符号 116 | if (!symbol.name.startsWith("mterp_op_")) continue; 117 | if (symbol.name.endsWith("_helper")) continue; 118 | if (symbol.name.endsWith("_quick")) continue; 119 | if (symbol.name.endsWith("_no_barrier")) continue; 120 | if (symbol.name.includes("unused")) continue; 121 | // nop 对应位置的指令太短 hook 会失败 跳过 122 | if (symbol.name == "mterp_op_nop") continue; 123 | op_count += 1; 124 | let hook_addr = symbol.address; 125 | // return 相关的指令起始就是一个BL frida hook 会失败 需要把hook点向后挪4字节 126 | if (symbol.name.startsWith("mterp_op_return")) { 127 | hook_addr = symbol.address.add(0x4); 128 | } 129 | let offset = hook_addr.sub(libart.base); 130 | log(`[mterp_op] ${symbol.name} ${symbol.address} ${hook_addr} ${offset}`); 131 | // 正式 hook 132 | hook_mterp_op(hook_addr, offset, thread_reg, inst_reg); 133 | } 134 | log(`[mterp_op] op_count ${op_count}`); 135 | } 136 | 137 | function get_shadow_frame_ptr_by_thread_ptr(thread_ptr: NativePointer) : ShadowFrame { 138 | // 0xB8 是 managed_stack 在 Thread 中的偏移 需要结合IDA分析 139 | // 如何定位这个偏移 140 | // void art::StackVisitor::WalkStack<(art::StackVisitor::CountTransitions)0>(bool) 141 | // _ZN3art12StackVisitor9WalkStackILNS0_16CountTransitionsE0EEEvb 142 | // 找到这个函数 然后反编译 在开头找到一个 与 0xFFFFFFFFFFFFFFFELL 相与的变量 143 | // 然后回溯 可以发现它时由传入参数通过偏移取指针再偏移 这个就是 managed_stack 的偏移 144 | // http://aospxref.com/android-11.0.0_r21/xref/art/runtime/stack.cc#835 145 | // let managed_stack = thread_ptr.readPointer().add(0xB8); 146 | let managed_stack = thread_ptr.add(0xB8); 147 | // 0x10 是 top_shadow_frame_ 在 ManagedStack 中的偏移 结合源码或者IDA可以分析出来 148 | let cur_frame_ptr = managed_stack.add(0x10).readPointer(); 149 | return new ShadowFrame(cur_frame_ptr); 150 | } 151 | 152 | function main(){ 153 | let libart = Process.findModuleByName("libart.so"); 154 | if (libart == null) { 155 | log(`libart is null`); 156 | return; 157 | } 158 | 159 | let hook_switch = true; 160 | let hook_mterp = true; 161 | // 仅对 ExecuteSwitchImplCpp 和 ExecuteMterpImpl 调用时 hook 可以得到一些基本调用轨迹 且对APP运行影响很小 162 | trace_interpreter_enrty(libart, hook_switch, hook_mterp); 163 | 164 | // 对 ExecuteSwitchImplCpp 实际进行 opcode 判断跳转的位置进行 hook 这样可以得到一个函数内具体执行了什么 165 | // 通过静态分析可以知道 166 | // - x19 是 shadow_frame 167 | // - x26 是 inst 168 | // 调用了 trace_interpreter_switch 记得将 hook_switch 设为 false 避免重复 169 | // trace_interpreter_switch(libart, 0x169EB4, 'x19', 'x26'); 170 | 171 | // 进入 ExecuteMterpImpl 后的逻辑就是 172 | // - 计算opcode 跳转实际处理位置 执行处理 173 | // - 再立刻计算下一个opcode 马上跳转实际处理位置 174 | // - 直到执行结束 175 | // 对每个 opcode 实际处理的位置进行 hook 176 | // 通过静态分析和实际测试可以知道 177 | // - x22 是 self 也就是 thread 178 | // - x20 是 inst 179 | // trace_interpreter_mterp_op(libart, "x22", "x20"); 180 | 181 | } 182 | 183 | export let rpc_mode: Boolean = false; 184 | 185 | let method_name_cache: {[key: string]: string} = {}; 186 | let switch_count = 0; 187 | let mterp_count = 0; 188 | 189 | setImmediate(main); 190 | 191 | rpc.exports = { 192 | go: main, 193 | enablerpcmode: enable_rpc_mode, 194 | } 195 | 196 | // frida -U -n LibChecker -l _agent.js -o trace.log 197 | // frida -U -n com.absinthe.libchecker -l _agent.js -o trace.log 198 | // frida -U -f com.absinthe.libchecker -l _agent.js -o trace.log --no-pause -------------------------------------------------------------------------------- /脱壳/unpackdex.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Author: guoqiangck 5 | * Create: 2019/6/11 6 | * Dump dex file for packaged apk 7 | * Hook art/runtime/dex_file.cc OpenMemory or OpenCommon 8 | * Support Version: Android 4.4 and later versions 9 | */ 10 | 11 | function LogPrint(log) { 12 | var theDate = new Date(); 13 | var hour = theDate.getHours(); 14 | var minute = theDate.getMinutes(); 15 | var second = theDate.getSeconds(); 16 | var mSecond = theDate.getMilliseconds() 17 | 18 | hour < 10 ? hour = "0" + hour : hour; 19 | minute < 10 ? minute = "0" + minute : minute; 20 | second < 10 ? second = "0" + second : second; 21 | mSecond < 10 ? mSecond = "00" + mSecond : mSecond < 100 ? mSecond = "0" + mSecond : mSecond; 22 | 23 | var time = hour + ":" + minute + ":" + second + ":" + mSecond; 24 | console.log("[" + time + "] " + log); 25 | } 26 | 27 | function getAndroidVersion(){ 28 | var version = 0; 29 | 30 | if(Java.available){ 31 | var versionStr = Java.androidVersion; 32 | version = versionStr.slice(0,1); 33 | }else{ 34 | LogPrint("Error: cannot get android version"); 35 | } 36 | LogPrint("Android Version: " + version); 37 | return version; 38 | } 39 | 40 | function getFunctionName(){ 41 | var i = 0; 42 | var functionName = ""; 43 | 44 | // Android 4: hook dvmDexFileOpenPartial 45 | // Android 5: hook OpenMemory 46 | // after Android 5: hook OpenCommon 47 | if(getAndroidVersion() > 4){ // android 5 and later version 48 | var artExports = Module.enumerateExportsSync("libart.so"); 49 | for(i = 0; i< artExports.length; i++){ 50 | if(artExports[i].name.indexOf("OpenMemory") !== -1){ 51 | functionName = artExports[i].name; 52 | LogPrint("index " + i + " function name: "+ functionName); 53 | break; 54 | }else if(artExports[i].name.indexOf("OpenCommon") !== -1){ 55 | functionName = artExports[i].name; 56 | LogPrint("index " + i + " function name: "+ functionName); 57 | break; 58 | } 59 | } 60 | }else{ //android 4 61 | var dvmExports = Module.enumerateExportsSync("libdvm.so"); 62 | if(dvmExports.length !== 0){ // check libdvm.so first 63 | for(i = 0; i< dvmExports.length; i++){ 64 | if(dvmExports[i].name.indexOf("dexFileParse") !== -1){ 65 | functionName = dvmExports[i].name; 66 | LogPrint("index " + i + " function name: "+ functionName); 67 | break; 68 | } 69 | } 70 | }else{ // if not load libdvm.so, check libart.so 71 | dvmExports = Module.enumerateExportsSync("libart.so"); 72 | for(i = 0; i< dvmExports.length; i++){ 73 | if(dvmExports[i].name.indexOf("OpenMemory") !== -1){ 74 | functionName = dvmExports[i].name; 75 | LogPrint("index " + i + " function name: "+ functionName); 76 | break; 77 | } 78 | } 79 | } 80 | } 81 | return functionName; 82 | } 83 | 84 | function getProcessName(){ 85 | var processName = ""; 86 | 87 | var fopenPtr = Module.findExportByName("libc.so", "fopen"); 88 | var fopenFunc = new NativeFunction(fopenPtr, 'pointer', ['pointer', 'pointer']); 89 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 90 | var fgetsFunc = new NativeFunction(fgetsPtr, 'int', ['pointer', 'int', 'pointer']); 91 | var fclosePtr = Module.findExportByName("libc.so", "fclose"); 92 | var fcloseFunc = new NativeFunction(fclosePtr, 'int', ['pointer']); 93 | 94 | var pathPtr = Memory.allocUtf8String("/proc/self/cmdline"); 95 | var openFlagsPtr = Memory.allocUtf8String("r"); 96 | 97 | var fp = fopenFunc(pathPtr, openFlagsPtr); 98 | if(fp.isNull() === false){ 99 | var buffData = Memory.alloc(128); 100 | var ret = fgetsFunc(buffData, 128, fp); 101 | if(ret !== 0){ 102 | processName = Memory.readCString(buffData); 103 | LogPrint("processName " + processName); 104 | } 105 | fcloseFunc(fp); 106 | } 107 | return processName; 108 | } 109 | 110 | function arraybuffer2hexstr(buffer) 111 | { 112 | var hexArr = Array.prototype.map.call( 113 | new Uint8Array(buffer), 114 | function (bit) { 115 | return ('00' + bit.toString(16)).slice(-2) 116 | } 117 | ); 118 | return hexArr.join(' '); 119 | } 120 | 121 | function checkDexMagic(dataAddr){ 122 | var magicMatch = true; 123 | var magicFlagHex = [0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00]; 124 | 125 | for(var i = 0; i < 8; i++){ 126 | if(Memory.readU8(ptr(dataAddr).add(i)) !== magicFlagHex[i]){ 127 | magicMatch = false; 128 | break; 129 | } 130 | } 131 | 132 | return magicMatch; 133 | } 134 | 135 | function checkOdexMagic(dataAddr){ 136 | var magicMatch = true; 137 | var magicFlagHex = [0x64, 0x65, 0x79, 0x0a, 0x30, 0x33, 0x36, 0x00]; 138 | 139 | for(var i = 0; i < 8; i++){ 140 | if(Memory.readU8(ptr(dataAddr).add(i)) !== magicFlagHex[i]){ 141 | magicMatch = false; 142 | break; 143 | } 144 | } 145 | 146 | return magicMatch; 147 | } 148 | 149 | function dumpDex(moduleFuncName, processName){ 150 | console.log(moduleFucntionName,processName) 151 | if(moduleFuncName !== ""){ 152 | var hookFunction; 153 | if(getAndroidVersion() > 4){ // android 5 and later version 154 | hookFunction = Module.findExportByName("libart.so", moduleFuncName); 155 | }else{ // android 4 156 | hookFunction = Module.findExportByName("libdvm.so", moduleFuncName); // check libdvm.so first 157 | if(hookFunction == null) { 158 | hookFunction = Module.findExportByName("libart.so", moduleFuncName); //// if not load libdvm.so, check libart.so 159 | } 160 | } 161 | Interceptor.attach(hookFunction,{ 162 | onEnter: function(args){ 163 | console.log("cfdsffdfds") 164 | var begin = 0; 165 | var dexMagicMatch = false; 166 | var odexMagicMatch = false; 167 | 168 | dexMagicMatch = checkDexMagic(args[0]); 169 | if(dexMagicMatch === true){ 170 | begin = args[0]; 171 | }else{ 172 | odexMagicMatch = checkOdexMagic(args[0]); 173 | if(odexMagicMatch === true){ 174 | begin = args[0]; 175 | } 176 | } 177 | 178 | if(begin === 0){ 179 | dexMagicMatch = checkDexMagic(args[1]); 180 | if(dexMagicMatch === true){ 181 | begin = args[1]; 182 | }else{ 183 | odexMagicMatch = checkOdexMagic(args[1]); 184 | if(odexMagicMatch === true){ 185 | begin = args[1]; 186 | } 187 | } 188 | } 189 | 190 | if(dexMagicMatch === true){ 191 | LogPrint("magic : " + Memory.readUtf8String(begin)); 192 | //console.log(hexdump(begin, { offset: 0, header: false, length: 64, ansi: false })); 193 | var address = parseInt(begin,16) + 0x20; 194 | var dex_size = Memory.readInt(ptr(address)); 195 | LogPrint("dex_size :" + dex_size); 196 | var dex_path = "/data/data/" + processName + "/" + dex_size + ".dex"; 197 | var dex_file = new File(dex_path, "wb"); 198 | dex_file.write(Memory.readByteArray(begin, dex_size)); 199 | dex_file.flush(); 200 | dex_file.close(); 201 | LogPrint("dump dex success, saved path: " + dex_path + "\n"); 202 | }else if(odexMagicMatch === true){ 203 | LogPrint("magic : " + Memory.readUtf8String(begin)); 204 | //console.log(hexdump(begin, { offset: 0, header: false, length: 64, ansi: false })); 205 | var address = parseInt(begin,16) + 0x0C; 206 | var odex_size = Memory.readInt(ptr(address)); 207 | LogPrint("odex_size :" + odex_size); 208 | var odex_path = "/data/data/" + processName + "/" + odex_size + ".odex"; 209 | var odex_file = new File(odex_path, "wb"); 210 | odex_file.write(Memory.readByteArray(begin, odex_size)); 211 | odex_file.flush(); 212 | odex_file.close(); 213 | LogPrint("dump odex success, saved path: " + odex_path + "\n"); 214 | } 215 | }, 216 | onLeave: function(retval){ 217 | } 218 | }); 219 | }else{ 220 | LogPrint("Error: cannot find correct module function."); 221 | } 222 | } 223 | 224 | //start dump dex file 225 | var moduleFucntionName = getFunctionName(); 226 | var processName = getProcessName(); 227 | if(moduleFucntionName !== "" && processName !== ""){ 228 | dumpDex(moduleFucntionName, processName); 229 | } 230 | -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/Others/FTS/fts.js: -------------------------------------------------------------------------------- 1 | function anti_fgets() { 2 | show_log("anti_fgets"); 3 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 4 | var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 5 | Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 6 | var retval = fgets(buffer, size, fp); 7 | var bufstr = Memory.readUtf8String(buffer); 8 | if (bufstr.indexOf("TracerPid:") > -1) { 9 | Memory.writeUtf8String(buffer, "TracerPid:\t0"); 10 | // dmLogout("tracerpid replaced: " + Memory.readUtf8String(buffer)); 11 | } 12 | return retval; 13 | }, 'pointer', ['pointer', 'int', 'pointer'])); 14 | }; 15 | 16 | function CheckPoen(){ 17 | 18 | var popen = Module.findExportByName("libc.so","popen") 19 | console.log("popen addr : "+popen) 20 | Interceptor.attach(popen,{ 21 | onEnter:function(args){ 22 | console.warn("\n-----------------------") 23 | console.log("Called "+'\x1b[3' + '6;01' + 'm', "popen", '\x1b[39;49;00m'); 24 | console.log("===>\t"+args[0].readCString()+"\t"+args[1].readCString()) 25 | console.log("===>\t"+"called from:"+ 26 | Thread.backtrace(this.context,Backtracer.ACCURATE) 27 | .map(DebugSymbol.fromAddress).join("\n")); 28 | if(args[0].readCString().indexOf("5D8A")!=-1){ 29 | args[0] = Memory.allocUtf8String(args[0].readCString().replace("5D8A","-5D8A")) 30 | this.isCheck = true 31 | } 32 | }, 33 | onLeave:function(retval){ 34 | if(this.isCheck){ 35 | console.error("反调试类型 ---> 端口检测") 36 | } 37 | } 38 | }) 39 | 40 | } 41 | 42 | //sprintf(file_name, "/proc/%d/status",pid) 43 | //sprintf(name,"/proc/%d/cmdline",statue); 44 | //strstr(nameline,"android_server") 45 | //fp = fopen(file_name,"r"); 46 | //int statue =atoi(&line[10]); 47 | function CheckTracePid(){ 48 | var atoi = Module.findExportByName(null,"atoi") 49 | var sprintf = Module.findExportByName(null,"sprintf") 50 | console.log("sprintf addr : "+sprintf) 51 | Interceptor.attach(sprintf,{ 52 | onEnter:function(args){ 53 | if(args[1].readCString().indexOf("proc")!=-1&&args[1].readCString().indexOf("status")!=-1){ 54 | this.isCheck1 = true 55 | } 56 | if(args[1].readCString().indexOf("proc")!=-1&&args[1].readCString().indexOf("cmdline")!=-1){ 57 | this.isCheck2 = true 58 | } 59 | if(args[1].readCString().indexOf("proc")!=-1&&args[1].readCString().indexOf("maps")!=-1){ 60 | this.isCheck3 = true 61 | } 62 | if(this.arg1||this.arg2||this.arg3){ 63 | console.warn("\n-----------------------") 64 | console.log("Called "+'\x1b[3' + '6;01' + 'm', "sprintf", '\x1b[39;49;00m'); 65 | console.log("===>\t"+args[1].readCString()+"\t") 66 | console.log("===>\t"+"called from:"+ 67 | Thread.backtrace(this.context,Backtracer.ACCURATE) 68 | .map(DebugSymbol.fromAddress).join("\n")); 69 | } 70 | this.arg1 = args[1] 71 | }, 72 | onLeave:function(retval){ 73 | if(this.isCheck1){ 74 | this.arg1 = Memory.allocUtf8String("/proc/1/status") 75 | console.log("--->\t"+this.arg1.readCString()) 76 | console.error("反调试类型 ---> TracePid") 77 | } 78 | if(this.isCheck2){ 79 | this.arg1 = Memory.allocUtf8String("/proc/1/cmdline") 80 | console.log("--->\t"+this.arg1.readCString()) 81 | console.error("反调试类型 ---> 进程名称检测") 82 | } 83 | if(this.isCheck2){ 84 | this.arg1 = Memory.allocUtf8String("/proc/1/maps") 85 | console.log("--->\t"+this.arg1.readCString()) 86 | } 87 | } 88 | }) 89 | } 90 | 91 | //签名校验 92 | //GetMethodID(j_clz,"getPackageManager","()Landroid/content/pm/PackageManager;"); 93 | //env->GetMethodID(j_clz, "getPackageName", "()Ljava/lang/String;"); 94 | //env->GetMethodID(j_clz,"getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); 95 | //env->GetFieldID(j_clz,"signatures","[Landroid/content/pm/Signature;"); 96 | //JNI函数原型 97 | //jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig); 98 | //jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig); 99 | 100 | function CheckSignature(){ 101 | Java.perform(function(){ 102 | var env = Java.vm.getEnv(); 103 | var pSize = Process.pointerSize; 104 | var GetMethodID = 33 , GetFieldID = 94 105 | 106 | function getNativeAddress(idx) { 107 | return env.handle.readPointer().add(idx * pSize).readPointer(); 108 | } 109 | 110 | Interceptor.attach(getNativeAddress(GetMethodID),{ 111 | onEnter:function(args){ 112 | var tempstr = args[2].readCString() 113 | if(tempstr.indexOf("getPackageManager")!=-1||tempstr.indexOf("getPackageInfo")!=-1|| 114 | tempstr.indexOf("getPackageName")!=-1){ 115 | console.warn("\n-----------------------") 116 | console.log("Called "+'\x1b[3' + '6;01' + 'm', "GetMethodID", '\x1b[39;49;00m'); 117 | console.log("===>\t"+args[2].readCString()+"\t"+args[3].readCString()) 118 | console.log("===>\t"+"called from:"+ 119 | Thread.backtrace(this.context,Backtracer.ACCURATE) 120 | .map(DebugSymbol.fromAddress).join("\n")); 121 | } 122 | }, 123 | onLeave:function(retval){} 124 | }) 125 | 126 | Interceptor.attach(getNativeAddress(GetFieldID),{ 127 | onEnter:function(args){ 128 | if(args[2].readCString().indexOf("signatures")!=-1){ 129 | this.isCheck = true 130 | console.warn("\n-----------------------") 131 | console.log("Called "+'\x1b[3' + '6;01' + 'm', "GetMethodID", '\x1b[39;49;00m'); 132 | console.log("===>\t"+args[2].readCString()+"\t"+args[3].readCString()) 133 | console.log("===>\t"+"called from:"+ 134 | Thread.backtrace(this.context,Backtracer.ACCURATE) 135 | .map(DebugSymbol.fromAddress).join("\n")); 136 | } 137 | }, 138 | onLeave:function(retval){ 139 | if(this.isCheck){ 140 | retval.replace(env.newStringUtf("asdfasdfasdf1f65s15d6f156s")) 141 | console.error("反调试类型 ---> Native签名校验") 142 | } 143 | } 144 | }) 145 | 146 | Java.use("android.content.pm.PackageManager").getPackageInfo 147 | .overload('java.lang.String', 'int') 148 | .implementation = function(packageName,flag){ 149 | var ret = this.getPackageInfo(packageName,flag) 150 | console.log("called getPackageInfo : "+ret) 151 | return ret 152 | } 153 | }) 154 | } 155 | 156 | function CheckProceesName(){ 157 | var strstr = Module.findExportByName(null,"strstr") 158 | var strcmp = Module.findExportByName(null,"strcmp") 159 | const str_aim = "android_server" 160 | 161 | Interceptor.attach(strstr,{ 162 | onEnter:function(args){ 163 | if(args[0].readCString().indexOf(str_aim)!=-1||args[1].readCString().indexOf(str_aim)!=-1){ 164 | this.isCheck = true 165 | console.warn("\n-----------------------") 166 | console.log("Called "+'\x1b[3' + '6;01' + 'm', "strstr", '\x1b[39;49;00m'); 167 | console.log("===>\t"+args[0].readCString()+"\t"+args[1].readCString()) 168 | console.log("===>\t"+"called from:"+ 169 | Thread.backtrace(this.context,Backtracer.ACCURATE) 170 | .map(DebugSymbol.fromAddress).join("\n")); 171 | }else if(args[0].readCString().indexOf("com.saurik.substrate")!=-1 172 | ||args[1].readCString().indexOf("com.saurik.substrate")!=-1 173 | ||args[0].readCString().indexOf("io.va.exposed")!=-1 174 | ||args[1].readCString().indexOf("io.va.exposed")!=-1 175 | ||args[0].readCString().indexOf("de.robv.android.xposed")!=-1 176 | ||args[1].readCString().indexOf("de.robv.android.xposed")!=-1){ 177 | this.isCheck1 = true 178 | return 179 | } 180 | }, 181 | onLeave:function(retval){ 182 | if(this.isCheck){ 183 | console.error("反调试类型 ---> 名称(android_server)校验") 184 | } 185 | if(this.isCheck1){ 186 | 187 | } 188 | } 189 | }) 190 | 191 | Interceptor.attach(strcmp,{ 192 | onEnter:function(args){ 193 | if(args[0].readCString().indexOf(str_aim)!=-1||args[1].readCString().indexOf(str_aim)!=-1){ 194 | this.isCheck = true 195 | console.warn("\n-----------------------") 196 | console.log("Called "+'\x1b[3' + '6;01' + 'm', "strcmp", '\x1b[39;49;00m'); 197 | console.log("===>\t"+args[0].readCString()+"\t"+args[1].readCString()) 198 | console.log("===>\t"+"called from:"+ 199 | Thread.backtrace(this.context,Backtracer.ACCURATE) 200 | .map(DebugSymbol.fromAddress).join("\n")); 201 | } 202 | }, 203 | onLeave:function(retval){ 204 | if(this.isCheck){ 205 | console.error("反调试类型 ---> 名称(android_server)校验") 206 | } 207 | } 208 | }) 209 | } 210 | 211 | setImmediate(CheckPoen(),CheckTracePid(),CheckSignature(),CheckProceesName()) 212 | -------------------------------------------------------------------------------- /hook/Il2CppHookScripts-master/Il2CppHookScripts-master/Scripts/bpoints.js: -------------------------------------------------------------------------------- 1 | // 结合Il2CppDumper使用,用于批量快速下断点,跟踪native函数调用 2 | // frida -U -f -l C:\Users\lzy\utils\bpoints.js --no-pause 3 | 4 | setImmediate(hook_dlopen()) 5 | //setImmediate(hookJava(),hookNative()) 6 | 7 | const soName = "libil2cpp.so" 8 | 9 | //使用的时候使用dsp.py生成的两个地址名称替换调这里的两个即可 10 | const arrayAddr = 11 | ['0x71541c', '0x715b38', '0x715be4', '0x715c61'] 12 | 13 | const arrayName = 14 | ['GameManager$$Awake', 'GameManager$$GetParam', 'GameManager$$SaveParam', 'GameManager$$ActivatePrivacyButton'] 15 | 16 | function breakPoints(){ 17 | 18 | const soAddr = Module.findBaseAddress(soName); 19 | console.error('\nsoAddr:' + soAddr + "\n"); 20 | 21 | Java.perform(function(){ 22 | arrayAddr 23 | .map(function(temp){return soAddr.add(temp)}) 24 | .forEach(function(value,index,array){ 25 | console.log("-------------------------"); 26 | console.log('currentAddr:' + value); 27 | try{ 28 | funcTmp(value,index,arrayName); 29 | }catch(e){ 30 | //Thumb指令集地址要加一 31 | funcTmp(value.add(1),soAddr,index,arrayName); 32 | } 33 | console.log("\t\t---->"+index,value.add(soAddr)+" is prepared "); 34 | }) 35 | console.log("\n") 36 | }) 37 | 38 | function funcTmp(currentAddr,index,arrayName){ 39 | Interceptor.attach(currentAddr, { 40 | onEnter: function(args){ 41 | console.log("called : "+arrayName[index]+" ----- addr : " + currentAddr.sub(soAddr) +"\n"); 42 | this.temp = currentAddr.sub(soAddr); 43 | if(this.temp === 0xef3080) { 44 | console.log('CCCryptorCreate called from:\n' + 45 | Thread.backtrace(this.context, Backtracer.ACCURATE) 46 | .map(DebugSymbol.fromAddress).join('\n') + '\n'); 47 | } 48 | }, 49 | onLeave: function(retval){ 50 | 51 | } 52 | }); 53 | } 54 | } 55 | 56 | function hook_dlopen() { 57 | // const dlopen = Module.findExportByName(null, "dlopen"); 58 | const dlopen = Module.findExportByName(null, "android_dlopen_ext"); 59 | 60 | if (dlopen != null) { 61 | Interceptor.attach(dlopen, { 62 | onEnter: function (args) { 63 | var l_soName = args[0].readCString() 64 | console.log(l_soName) 65 | if (l_soName.indexOf(soName) != -1) { 66 | this.hook = true 67 | } 68 | }, 69 | onLeave: function (retval) { 70 | if (this.hook) { 71 | console.warn("\nLoaded "+soName + " add break points") 72 | breakPoints() 73 | } 74 | } 75 | }) 76 | } 77 | } 78 | 79 | //HookExports,HookSymbols,HookSymbols 这三个玩意儿谨慎使用Hook到某些函数会崩掉 80 | //这三个也是针对有时候想找找关键函数调用的时候用一下,不太推荐用这个 81 | function HookExports(name,mdname,ishook){ 82 | 83 | //java堆栈 84 | const isShowPrintStack = false 85 | //native堆栈 86 | const isShowPrintStackN = true 87 | soName = mdname == undefined || mdname == "" ? soName : mdname 88 | Interceptor.detachAll() 89 | 90 | var md = NULL 91 | var addr = NULL 92 | try{ 93 | var md = Process.findModuleByName(soName) 94 | addr = md.base 95 | }catch(e){ 96 | console.error(soName + " not found!") 97 | return 98 | } 99 | console.error(soName+" at "+addr) 100 | 101 | md.enumerateExports().forEach(function(item){ 102 | if(item.name.indexOf(name)!=-1){ 103 | console.log(JSON.stringify(item)) 104 | if(ishook!=undefined)hook_item(item) 105 | } 106 | }) 107 | 108 | function hook_item(item){ 109 | console.log("add break points at "+item.address) 110 | try{ 111 | Interceptor.attach(item.address,{ 112 | onEnter:function(args){ 113 | console.log("\n\x1b[96mA called "+item.address+" ===> "+item.address.sub(addr)+"\t"+item.name+"\x1b[0m") 114 | if(isShowPrintStack) PrintStackTrace() 115 | if(isShowPrintStackN) PrintStackTraceN(this.context) 116 | }, 117 | onLeave:function(retval){ 118 | 119 | } 120 | }) 121 | }catch(e){ 122 | try{ 123 | Interceptor.attach(item.address.add(1),{ 124 | onEnter:function(args){ 125 | console.log("\n\x1b[96mT Called "+item.address+" ===> "+item.address.add(1).sub(addr)+"\t"+item.name+"\x1b[0m") 126 | if(isShowPrintStack) PrintStackTrace() 127 | if(isShowPrintStackN) PrintStackTraceN(this.context) 128 | }, 129 | onLeave:function(retval){ 130 | 131 | } 132 | }) 133 | }catch(e){ 134 | console.log(e) 135 | } 136 | } 137 | } 138 | } 139 | 140 | function HookImports(name,mdname,ishook){ 141 | //java堆栈 142 | const isShowPrintStack = false 143 | //native堆栈 144 | const isShowPrintStackN = true 145 | Interceptor.detachAll() 146 | soName = mdname == undefined || mdname == "" ? soName : mdname 147 | var md = NULL 148 | var addr = NULL 149 | try{ 150 | var md = Process.findModuleByName(soName) 151 | addr = md.base 152 | }catch(e){ 153 | console.error(soName + " not found!") 154 | return 155 | } 156 | 157 | md.enumerateImports().forEach(function(item){ 158 | if(item.name.indexOf(name)!=-1){ 159 | console.log(JSON.stringify(item)) 160 | if(ishook!=undefined)hook_item(item) 161 | } 162 | }) 163 | 164 | function hook_item(item){ 165 | console.log("add break points at "+item.address) 166 | try{ 167 | Interceptor.attach(item.address,{ 168 | onEnter:function(args){ 169 | console.log("\n\x1b[96mA called "+item.address+" ===> "+item.address.sub(addr)+"\t"+item.name+"\x1b[0m") 170 | if(isShowPrintStack) PrintStackTrace() 171 | if(isShowPrintStackN) PrintStackTraceN(this.context) 172 | }, 173 | onLeave:function(retval){ 174 | 175 | } 176 | }) 177 | }catch(e){ 178 | try{ 179 | Interceptor.attach(item.address.add(1),{ 180 | onEnter:function(args){ 181 | console.log("\n\x1b[96mT Called "+item.address+" ===> "+item.address.add(1).sub(addr)+"\t"+item.name+"\x1b[0m") 182 | if(isShowPrintStack) PrintStackTrace() 183 | if(isShowPrintStackN) PrintStackTraceN(this.context) 184 | }, 185 | onLeave:function(retval){ 186 | 187 | } 188 | }) 189 | }catch(e){ 190 | console.log(e) 191 | } 192 | } 193 | } 194 | } 195 | 196 | function HookSymbols(name,mdname,ishook){ 197 | //java堆栈 198 | const isShowPrintStack = false 199 | //native堆栈 200 | const isShowPrintStackN = true 201 | Interceptor.detachAll() 202 | soName = mdname == undefined || mdname == "" ? soName : mdname 203 | var md = NULL 204 | var addr = NULL 205 | try{ 206 | var md = Process.findModuleByName(soName) 207 | addr = md.base 208 | }catch(e){ 209 | console.error(soName + " not found!") 210 | return 211 | } 212 | 213 | md.enumerateSymbols().forEach(function(item){ 214 | if(item.name.indexOf(name)!=-1){ 215 | console.log(JSON.stringify(item)) 216 | if(ishook!=undefined)hook_item(item) 217 | if(ishook == 1) return item.address 218 | } 219 | }) 220 | 221 | function hook_item(item){ 222 | console.log("add break points at "+item.address) 223 | try{ 224 | Interceptor.attach(item.address,{ 225 | onEnter:function(args){ 226 | console.log("\n\x1b[96mA called "+item.address+" ===> "+item.address.sub(addr)+"\t"+item.name+"\x1b[0m") 227 | if(isShowPrintStack) PrintStackTrace() 228 | if(isShowPrintStackN) PrintStackTraceN(this.context) 229 | }, 230 | onLeave:function(retval){ 231 | 232 | } 233 | }) 234 | }catch(e){ 235 | try{ 236 | Interceptor.attach(item.address.add(1),{ 237 | onEnter:function(args){ 238 | console.log("\n\x1b[96mT Called "+item.address+" ===> "+item.address.add(1).sub(addr)+"\t"+item.name+"\x1b[0m") 239 | if(isShowPrintStack) PrintStackTrace() 240 | if(isShowPrintStackN) PrintStackTraceN(this.context) 241 | }, 242 | onLeave:function(retval){ 243 | 244 | } 245 | }) 246 | }catch(e){ 247 | console.log(e) 248 | } 249 | } 250 | } 251 | } 252 | 253 | //java 堆栈 254 | function PrintStackTrace(){ 255 | console.log("\x1b[36m"+ 256 | Java.use("android.util.Log") 257 | .getStackTraceString(Java.use("java.lang.Throwable") 258 | .$new())+"\x1b[0m"); 259 | } 260 | 261 | //native 堆栈 262 | function PrintStackTraceN(ctx){ 263 | console.log("\x1b[36m Called from:\n"+ 264 | Thread.backtrace(ctx,Backtracer.ACCURATE) 265 | // .slice(0,6) 266 | // .reverse() 267 | .map(DebugSymbol.fromAddress).join("\n")+"\x1b[0m"); 268 | } 269 | 270 | //frida的更多使用参见:https://www.jianshu.com/p/4291ee42c412 271 | function hookJava(){ 272 | //java 方法的 hook 273 | Java.perform(function(){ 274 | Java.use("xxxxxxx").Testfunc.implementation = function(){ 275 | return this.Testfunc.apply(this,arguments) 276 | } 277 | }) 278 | //java实例的查找 279 | Java.choose("xxxxx",{ 280 | onMatch:function(obj){ 281 | 282 | }, 283 | onComplete:function(){ 284 | 285 | } 286 | }) 287 | } 288 | 289 | function hookNative(){ 290 | 291 | var addr = Module.findBaseAddress(soName) 292 | //方法调用 293 | var func = new NativeFunction(addr.add(0x123),'void','pointer') 294 | func(ptr(0)) 295 | //方法拦截 296 | Interceptor.attach(addr.add(0x123),{ 297 | onEnter:function(args){ 298 | 299 | }, 300 | onLeave:function(retval){ 301 | 302 | } 303 | }) 304 | //方法替换 305 | Interceptor.replace(func,new NativeCallback(function(arg){ 306 | 307 | },'void',['pointer','pointer'])) 308 | 309 | } 310 | -------------------------------------------------------------------------------- /trace/jnitrace-chame1eon/jnitrace/README.md: -------------------------------------------------------------------------------- 1 | # jnitrace 2 | 3 | _A Frida based tool to trace use of the JNI API in Android apps._ 4 | 5 | Native libraries contained within Android Apps often make use of the JNI API to 6 | utilize the Android Runtime. Tracking those calls through 7 | manual reverse engineering can be a slow and painful process. `jnitrace` works 8 | as a dynamic analysis tracing tool similar to frida-trace or strace but for 9 | the JNI. 10 | 11 | ![JNITrace Output](https://i.ibb.co/ZJ04cBB/jnitrace-1.png) 12 | 13 | ## Installation: 14 | 15 | The easiest way to get running with `jnitrace` is to install using pip: 16 | 17 | `pip install jnitrace` 18 | 19 | ###### Dependencies: 20 | * arm, arm64, x86, or x64 Android device 21 | * Frida installed on the Android device 22 | * Frida support > 12 23 | * Linux, Mac, or Windows Host with Python 3 and pip 24 | 25 | ## Running: 26 | 27 | After a pip install it is easy to run `jnitrace`: 28 | 29 | `jnitrace -l libnative-lib.so com.example.myapplication` 30 | 31 | `jnitrace` requires a minimum of two parameters to run a trace: 32 | * `-l libnative-lib.so` - is used to specify the libraries to trace. This argument can be used multiple times or `*` can be used to track all libraries. For example, `-l libnative-lib.so -l libanother-lib.so` or `-l *`. 33 | * `com.example.myapplication` - is the Android package to trace. This package must already be installed on the device. 34 | 35 | Optional arguments are listed below: 36 | * `-R :` - is used to specify the network location of the remote Frida server. If a : is unspecified, localhost:27042 is used by deafult. 37 | * `-m ` - is used to specify the Frida attach mechanism to use. It can either be spawn or attach. Spawn is the default and recommended option. 38 | * `-b ` - is used to control backtrace output. By default `jnitrace` will run the 39 | backtracer in `accurate` mode. This option can be changed to `fuzzy` mode or used to stop the backtrace 40 | by using the `none` option. See the Frida docs for an explanation on the differences. 41 | * `-i ` - is used to specify the method names that should be traced. This can be helpful for reducing the noise in particularly large JNI apps. The option can be supplied multiple times. For example, `-i Get -i RegisterNatives` would include 42 | only JNI methods that contain Get or RegisterNatives in their name. 43 | * `-e ` - is used to specify the method names that should be ignored in the trace. This can be helpful for reducing the noise in particularly large JNI apps. The option can be supplied multiple times. For example, `-e ^Find -e GetEnv` would exclude from 44 | the results all JNI method names that begin Find or contain GetEnv. 45 | * `-I ` - is used to specify the exports from a library that should be traced. This is useful for libraries where you only 46 | want to trace a small number of methods. The functions jnitrace considers exported are any functions that are directly callable 47 | from the Java side, as such, that includes methods bound using RegisterNatives. The option can be supplied multiple times. For example, 48 | `-I stringFromJNI -I nativeMethod([B)V` could be used to include an export from the library called `Java_com_nativetest_MainActivity_stringFromJNI` and a method bound using RegisterNames with the signature of `nativeMethod([B)V`. 49 | * `-E ` is used to specify the exports from a library that should not be traced. This is useful for libraries where you 50 | have a group of busy native calls that you want to ignore. The functions jnitrace considers exported are any functions that are directly callable from the Java side, as such, that includes methods bound using RegisterNatives. The option can be supplied multiple times. For example, `-E JNI_OnLoad -E nativeMethod` would exclude from the trace the `JNI_OnLoad` function call and any methods 51 | with the name `nativeMethod`. 52 | * `-o path/output.json` - is used to specify an output path where `jnitrace` will store all traced data. The information is stored in JSON format to allow later post-processing of the trace data. 53 | * `-p path/to/script.js` - the path provided is used to load a Frida script into the target process before the `jnitrace` script has loaded. This can be used for defeating anti-frida or anti-debugging code before `jnitrace` starts. 54 | * `-a path/to/script.js` - the path provided is used to load Frida script into the target process after `jnitrace` has been loaded. 55 | * `--hide-data` - used to reduce the quantity of output displayed in the console. This option will hide additional data that is displayed as hexdumps or as string de-references. 56 | * `--ignore-env` - using this option will hide all calls the app is making using the JNIEnv struct. 57 | * `--ignore-vm` - using this option will hide all calls the app is making using the JavaVM struct. 58 | * `--aux ` - used to pass custom parameters when spawning an application. For example `--aux='uid=(int)10'` will spawn the application for user 10 instead of default user 0. 59 | 60 | ***Note*** 61 | 62 | Remember frida-server must be running before running `jnitrace`. If the default 63 | instructions for installing frida have been followed, the following command will start the server ready for `jnitrace`: 64 | 65 | `adb shell /data/local/tmp/frida-server` 66 | 67 | ## API: 68 | The engine that powers jnitrace is available as a separate project. That project allows you to import jnitrace to track individual JNI API calls, in a method familiar to using the Frida `Interceptor` to attach to functions and addresses. 69 | 70 | ```javascript 71 | import { JNIInterceptor } from "jnitrace-engine"; 72 | 73 | JNIInterceptor.attach("FindClass", { 74 | onEnter(args) { 75 | console.log("FindClass method called"); 76 | this.className = Memory.readCString(args[1]); 77 | }, 78 | onLeave(retval) { 79 | console.log("\tLoading Class:", this.className); 80 | console.log("\tClass ID:", retval.get()); 81 | } 82 | }); 83 | 84 | ``` 85 | 86 | More information: https://github.com/chame1eon/jnitrace-engine 87 | 88 | ## Building: 89 | 90 | Building `jnitrace` from source requires that `node` first be installed. 91 | After installing `node`, the following commands need to be run: 92 | 93 | * `npm install` 94 | * `npm run watch` 95 | 96 | `npm run watch` will run `frida-compile` in the background compiling the source to the output 97 | file, `build/jnitrace.js`. `jnitrace.py` loads from `build/jnitrace.js` by default, so no other 98 | changes are required to run the updates. 99 | 100 | ## Output: 101 | ![JNITrace Output](https://i.ibb.co/WfDq1cy/jnitrace-2.png) 102 | 103 | Like frida-trace, output is colored based on the API call thread. 104 | 105 | Immediately below the thread ID in the display is the JNI API method name. 106 | Method names match exactly with those seen in the `jni.h` header file. 107 | 108 | Subsequent lines contain a list of arguments indicated by a `|-`. After the 109 | `|-` characters are the argument type followed by the argument value. For 110 | jmethods, jfields and jclasses the Java type will be displayed in curly 111 | braces. This is dependent on `jnitrace` having seen the original method, 112 | field, or class lookup. For any methods passing buffers, `jnitrace` will 113 | extract the buffers from the arguments and display it as a hexdump below the 114 | argument value. 115 | 116 | Return values are displayed at the bottom of the list as `|=` and will not 117 | be present for void methods. 118 | 119 | If the backtrace is enabled, a Frida backtrace will be displayed below the 120 | method call. Please be aware, as per the Frida docs, the fuzzy backtrace is 121 | not always accurate and the accurate backtrace may provide limited results. 122 | 123 | ## Details: 124 | The goal of this project was to create a tool that could trace JNI API calls 125 | efficiently for most Android applications. 126 | 127 | Unfortunately, the simplest approach of attaching to all function pointers in 128 | the JNIEnv structure overloads the application. It causes a crash based on the 129 | sheer number of function calls made by other unrelated libraries also using 130 | the same functions in `libart.so`. 131 | 132 | To deal with that performance barrier, `jnitrace` creates a shadow JNIEnv that 133 | it can supply to libraries it wants to track. That JNIEnv contains a series 134 | of function trampolines that bounce the JNI API calls through some custom 135 | Frida NativeCallbacks to track the input and output of those functions. 136 | 137 | The generic Frida API does a great job of providing a platform to build 138 | those function trampolines with minimal effort. However, that simple approach 139 | does not work for all of the JNIEnv API. The key problem with tracing all of 140 | the methods is the use of variadic arguments in the API. It is not possible to 141 | create the NativeCallback for these functions ahead of time, as it is not known 142 | beforehand all the different combinations of Java methods that will be called. 143 | 144 | The solution is to monitor the process for calls to `GetMethodID` or 145 | `GetStaticMethodID`, used to look up method identifiers from the runtime. 146 | Once `jnitrace` sees a `jmethodID` lookup it has a known mapping of 147 | ID to method signature. Later, when a JNI Java method call is made, an initial 148 | NativeCallback is used to extract the method ID in the call. That method 149 | signature is then parsed to extract the method arguments. Once `jnitrace` has 150 | extracted the arguments in the method, it can dynamically create a 151 | NativeCallback for that method. That new NativeCallback is returned and a 152 | little bit of architecture specific shellcode deals with setting up the stack 153 | and registers to allow that call to run successfully. Those NativeCallbacks 154 | for specific methods are cached to allow the callback to run more efficiently 155 | if a method if called multiple times. 156 | 157 | The other place where a simple NativeCallback is not sufficient for 158 | extracting the arguments from a method call, is for calls using a 159 | va_args pointer as the final argument. In this case `jnitrace` uses some code 160 | to extract the arguments from the pointer provided. Again this is architecture 161 | specific. 162 | 163 | All data traced in these function calls is sent to the python console 164 | application that formats and displays it to the user. 165 | 166 | ## Recommendations: 167 | Most testing of this tool has been done on an Android x86_64 emulator running 168 | Marshmallow. Any issues experienced running on another device, please file an 169 | issue, but also, if possible, it is recommended to try running on a similar 170 | emulator. 171 | 172 | ## Issues: 173 | For any issues experienced running `jnitrace` please create an issue on 174 | GitHub. Please include the following information in the filed issue: 175 | * Device you were running on 176 | * Version of Frida you were using 177 | * Application you were running against 178 | * Any displayed error messages 179 | -------------------------------------------------------------------------------- /trace/r0tracer-main/r0tracer.js: -------------------------------------------------------------------------------- 1 | var isLite = false; 2 | var ByPassTracerPid = function () { 3 | var fgetsPtr = Module.findExportByName("libc.so", "fgets"); 4 | var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']); 5 | Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) { 6 | var retval = fgets(buffer, size, fp); 7 | var bufstr = Memory.readUtf8String(buffer); 8 | if (bufstr.indexOf("TracerPid:") > -1) { 9 | Memory.writeUtf8String(buffer, "TracerPid:\t0"); 10 | console.log("tracerpid replaced: " + Memory.readUtf8String(buffer)); 11 | } 12 | return retval; 13 | }, 'pointer', ['pointer', 'int', 'pointer'])); 14 | }; 15 | setImmediate(ByPassTracerPid); 16 | 17 | (function(){ 18 | 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"}; 19 | 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"}; 20 | var colorPrefix = '\x1b[3', colorSuffix = 'm' 21 | for (let c in Color){ 22 | if (c == "RESET") continue; 23 | console[c] = function(message){ 24 | console.log(colorPrefix + Color[c] + colorSuffix + message + Color.RESET); 25 | } 26 | console["Light" + c] = function(message){ 27 | console.log(colorPrefix + LightColor[c] + colorSuffix + message + Color.RESET); 28 | } 29 | } 30 | })(); 31 | function uniqBy(array, key) { 32 | var seen = {}; 33 | return array.filter(function (item) { 34 | var k = key(item); 35 | return seen.hasOwnProperty(k) ? false : (seen[k] = true); 36 | }); 37 | } 38 | function hasOwnProperty(obj, name) { 39 | try { 40 | return obj.hasOwnProperty(name) || name in obj; 41 | } catch (e) { 42 | return obj.hasOwnProperty(name); 43 | } 44 | } 45 | function getHandle(object) { 46 | if (hasOwnProperty(object, '$handle')) { 47 | if (object.$handle != undefined) { 48 | return object.$handle; 49 | } 50 | } 51 | if (hasOwnProperty(object, '$h')) { 52 | if (object.$h != undefined) { 53 | return object.$h; 54 | } 55 | } 56 | return null; 57 | } 58 | //查看域值 59 | function inspectObject(obj, input) { 60 | var isInstance = false; 61 | var obj_class = null; 62 | if (getHandle(obj) === null) { 63 | obj_class = obj.class; 64 | } else { 65 | var Class = Java.use("java.lang.Class"); 66 | obj_class = Java.cast(obj.getClass(), Class); 67 | isInstance = true; 68 | } 69 | input = input.concat("Inspecting Fields: => ", isInstance, " => ", obj_class.toString()); 70 | input = input.concat("\r\n") 71 | var fields = obj_class.getDeclaredFields(); 72 | for (var i in fields) { 73 | if (isInstance || Boolean(fields[i].toString().indexOf("static ") >= 0)) { 74 | // output = output.concat("\t\t static static static " + fields[i].toString()); 75 | var className = obj_class.toString().trim().split(" ")[1]; 76 | // console.Red("className is => ",className); 77 | var fieldName = fields[i].toString().split(className.concat(".")).pop(); 78 | var fieldType = fields[i].toString().split(" ").slice(-2)[0]; 79 | var fieldValue = undefined; 80 | if (!(obj[fieldName] === undefined)) 81 | fieldValue = obj[fieldName].value; 82 | input = input.concat(fieldType + " \t" + fieldName + " => ", fieldValue + " => ", JSON.stringify(fieldValue)); 83 | input = input.concat("\r\n") 84 | } 85 | } 86 | return input; 87 | } 88 | 89 | // trace单个类的所有静态和实例方法包括构造方法 trace a specific Java Method 90 | function traceMethod(targetClassMethod) { 91 | var delim = targetClassMethod.lastIndexOf("."); 92 | if (delim === -1) return; 93 | var targetClass = targetClassMethod.slice(0, delim) 94 | var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length) 95 | var hook = Java.use(targetClass); 96 | var overloadCount = hook[targetMethod].overloads.length; 97 | console.Red("Tracing Method : " + targetClassMethod + " [" + overloadCount + " overload(s)]"); 98 | for (var i = 0; i < overloadCount; i++) { 99 | hook[targetMethod].overloads[i].implementation = function () { 100 | //初始化输出 101 | var output = ""; 102 | //画个横线 103 | for (var p = 0; p < 100; p++) { 104 | output = output.concat("=="); 105 | } 106 | //域值 107 | if (!isLite) { output = inspectObject(this, output); } 108 | //进入函数 109 | output = output.concat("\n*** entered " + targetClassMethod); 110 | output = output.concat("\r\n") 111 | // if (arguments.length) console.Black(); 112 | //参数 113 | var retval = this[targetMethod].apply(this, arguments); 114 | if (!isLite) { 115 | for (var j = 0; j < arguments.length; j++) { 116 | output = output.concat("arg[" + j + "]: " + arguments[j] + " => " + JSON.stringify(arguments[j])); 117 | output = output.concat("\r\n") 118 | } 119 | //调用栈 120 | output = output.concat(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 121 | //返回值 122 | output = output.concat("\nretval: " + retval + " => " + JSON.stringify(retval)); 123 | } 124 | // inspectObject(this) 125 | //离开函数 126 | output = output.concat("\n*** exiting " + targetClassMethod); 127 | //最终输出 128 | // console.Black(output); 129 | var r = parseInt((Math.random() * 7).toFixed(0)); 130 | var i = r; 131 | var printOutput = null; 132 | switch (i) { 133 | case 1: 134 | printOutput = console.Red; 135 | break; 136 | case 2: 137 | printOutput = console.Yellow; 138 | break; 139 | case 3: 140 | printOutput = console.Green; 141 | break; 142 | case 4: 143 | printOutput = console.Cyan; 144 | break; 145 | case 5: 146 | printOutput = console.Blue; 147 | break; 148 | case 6: 149 | printOutput = console.Gray; 150 | break; 151 | default: 152 | printOutput = console.Purple; 153 | } 154 | printOutput(output); 155 | return retval; 156 | } 157 | } 158 | } 159 | 160 | function traceClass(targetClass) { 161 | //Java.use是新建一个对象哈,大家还记得么? 162 | var hook = Java.use(targetClass); 163 | //利用反射的方式,拿到当前类的所有方法 164 | var methods = hook.class.getDeclaredMethods(); 165 | //建完对象之后记得将对象释放掉哈 166 | hook.$dispose; 167 | //将方法名保存到数组中 168 | var parsedMethods = []; 169 | var output = ""; 170 | output = output.concat("\tSpec: => \r\n") 171 | methods.forEach(function (method) { 172 | output = output.concat(method.toString()) 173 | output = output.concat("\r\n") 174 | parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]); 175 | }); 176 | //去掉一些重复的值 177 | var Targets = uniqBy(parsedMethods, JSON.stringify); 178 | // targets = []; 179 | var constructors = hook.class.getDeclaredConstructors(); 180 | if (constructors.length > 0) { 181 | constructors.forEach(function (constructor) { 182 | output = output.concat("Tracing ", constructor.toString()) 183 | output = output.concat("\r\n") 184 | }) 185 | Targets = Targets.concat("$init") 186 | } 187 | //对数组中所有的方法进行hook, 188 | Targets.forEach(function (targetMethod) { 189 | traceMethod(targetClass + "." + targetMethod); 190 | }); 191 | //画个横线 192 | for (var p = 0; p < 100; p++) { 193 | output = output.concat("+"); 194 | } 195 | console.Green(output); 196 | } 197 | function hook(white, black, target = null) { 198 | console.Red("start") 199 | if (!(target === null)) { 200 | console.LightGreen("Begin enumerateClassLoaders ...") 201 | Java.enumerateClassLoaders({ 202 | onMatch: function (loader) { 203 | try { 204 | if (loader.findClass(target)) { 205 | console.Red("Successfully found loader") 206 | console.Blue(loader); 207 | Java.classFactory.loader = loader; 208 | console.Red("Switch Classloader Successfully ! ") 209 | } 210 | } 211 | catch (error) { 212 | console.Red(" continuing :" + error) 213 | } 214 | }, 215 | onComplete: function () { 216 | console.Red("EnumerateClassloader END") 217 | } 218 | }) 219 | } 220 | console.Red("Begin Search Class...") 221 | var targetClasses = new Array(); 222 | Java.enumerateLoadedClasses({ 223 | onMatch: function (className) { 224 | if (className.toString().toLowerCase().indexOf(white.toLowerCase()) >= 0 && 225 | (black == null || black == '' || className.toString().toLowerCase().indexOf(black.toLowerCase()) < 0)) { 226 | console.Black("Found Class => " + className) 227 | targetClasses.push(className); 228 | traceClass(className); 229 | } 230 | }, onComplete: function () { 231 | console.Black("Search Class Completed!") 232 | } 233 | }) 234 | var output = "On Total Tracing :"+String(targetClasses.length)+" classes :\r\n"; 235 | targetClasses.forEach(function(target){ 236 | output = output.concat(target); 237 | output = output.concat("\r\n") 238 | }) 239 | console.Green(output+"Start Tracing ...") 240 | } 241 | function main() { 242 | Java.perform(function () { 243 | console.Purple("r0tracer begin ... !") 244 | //0. 增加精简模式,就是以彩虹色只显示进出函数。默认是关闭的,注释此行打开精简模式。 245 | //isLite = true; 246 | /* 247 | //以下三种模式,取消注释某一行以开启 248 | */ 249 | //A. 简易trace单个函数 250 | traceClass("javax.crypto.Cipher") 251 | //B. 黑白名单trace多个函数,第一个参数是白名单(包含关键字),第二个参数是黑名单(不包含的关键字) 252 | // hook("javax.crypto.Cipher", "$"); 253 | //C. 报某个类找不到时,将某个类名填写到第三个参数,比如找不到com.roysue.check类。(前两个参数依旧是黑白名单) 254 | // hook("com.roysue.check"," ","com.roysue.check"); 255 | }) 256 | } 257 | /* 258 | //setImmediate是立即执行函数,setTimeout是等待毫秒后延迟执行函数 259 | //二者在attach模式下没有区别 260 | //在spawn模式下,hook系统API时如javax.crypto.Cipher建议使用setImmediate立即执行,不需要延时 261 | //在spawn模式下,hook应用自己的函数或含壳时,建议使用setTimeout并给出适当的延时(500~5000) 262 | */ 263 | setImmediate(main) 264 | // 265 | // setTimeout(main, 2000); 266 | 267 | 268 | // 玄之又玄,众妙之门 269 | // Frida的崩溃有时候真的是玄学,大项目一崩溃根本不知道是哪里出的问题,这也是小而专的项目也有一丝机会的原因 270 | // Frida自身即会经常崩溃,建议多更换Frida(客/服要配套)版本/安卓版本,我自己常用的组合是两部手机,Frida12.8.0全家桶+安卓8.1.0,和Frida14.2.2全家桶+安卓10 271 | -------------------------------------------------------------------------------- /脱壳/FRIDA-DEXDump/frida_dexdump/main.py: -------------------------------------------------------------------------------- 1 | # Author: hluwa 2 | # HomePage: https://github.com/hluwa 3 | # CreatedTime: 2020/1/7 20:57 4 | import hashlib 5 | import os 6 | import random 7 | import sys 8 | import getopt 9 | import time 10 | import frida 11 | import logging 12 | import traceback 13 | 14 | try: 15 | from shutil import get_terminal_size as get_terminal_size 16 | except: 17 | try: 18 | from backports.shutil_get_terminal_size import get_terminal_size as get_terminal_size 19 | except: 20 | pass 21 | try: 22 | import click 23 | except: 24 | class click: 25 | 26 | @staticmethod 27 | def secho(message=None, **kwargs): 28 | print(message) 29 | 30 | @staticmethod 31 | def style(**kwargs): 32 | raise Exception("unsupported style") 33 | 34 | logging.basicConfig(level=logging.INFO, 35 | format="%(asctime)s %(levelname)s %(message)s", 36 | datefmt='%m-%d/%H:%M:%S') 37 | 38 | banner = """ 39 | ---------------------------------------------------------------------------------------- 40 | ____________ ___________ ___ ______ _______ _______ 41 | | ___| ___ \_ _| _ \/ _ \ | _ \ ___\ \ / / _ \ 42 | | |_ | |_/ / | | | | | / /_\ \______| | | | |__ \ V /| | | |_ _ _ __ ___ _ __ 43 | | _| | / | | | | | | _ |______| | | | __| / \| | | | | | | '_ ` _ \| '_ \ 44 | | | | |\ \ _| |_| |/ /| | | | | |/ /| |___/ /^\ \ |/ /| |_| | | | | | | |_) | 45 | \_| \_| \_|\___/|___/ \_| |_/ |___/ \____/\/ \/___/ \__,_|_| |_| |_| .__/ 46 | | | 47 | |_| 48 | https://github.com/hluwa/FRIDA-DEXDump 49 | ----------------------------------------------------------------------------------------\n 50 | """ 51 | 52 | md5 = lambda bs: hashlib.md5(bs).hexdigest() 53 | 54 | 55 | def dex_fix(dex_bytes): 56 | import struct 57 | dex_size = len(dex_bytes) 58 | 59 | if dex_bytes[:4] != b"dex\n": 60 | dex_bytes = b"dex\n035\x00" + dex_bytes[8:] 61 | 62 | if dex_size >= 0x24: 63 | dex_bytes = dex_bytes[:0x20] + struct.Struct("= 0x28: 66 | 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']: 69 | dex_bytes = dex_bytes[:0x28] + b'\x78\x56\x34\x12' + dex_bytes[0x2C:] 70 | 71 | return dex_bytes 72 | 73 | 74 | def show_banner(): 75 | colors = ['bright_red', 'bright_green', 'bright_blue', 'cyan', 'magenta'] 76 | try: 77 | click.style('color test', fg='bright_red') 78 | except: 79 | colors = ['red', 'green', 'blue', 'cyan', 'magenta'] 80 | try: 81 | columns = get_terminal_size().columns 82 | if columns >= len(banner.splitlines()[1]): 83 | for line in banner.splitlines(): 84 | if line: 85 | fill = int((columns - len(line)) / 2) 86 | line = line[0] * fill + line 87 | line += line[-1] * fill 88 | click.secho(line, fg=random.choice(colors)) 89 | except: 90 | pass 91 | 92 | 93 | def get_all_process(device, pkgname): 94 | return [process for process in device.enumerate_processes() if pkgname in process.name] 95 | 96 | 97 | def search(api): 98 | """ 99 | """ 100 | 101 | matches = api.scandex() 102 | for info in matches: 103 | click.secho("[DEXDump] Found: DexAddr={}, DexSize={}" 104 | .format(info['addr'], hex(info['size'])), fg='green') 105 | return matches 106 | 107 | 108 | def dump(pkg_name, api, mds=None): 109 | """ 110 | """ 111 | if mds is None: 112 | mds = [] 113 | matches = api.scandex() 114 | for info in matches: 115 | try: 116 | bs = api.memorydump(info['addr'], info['size']) 117 | md = md5(bs) 118 | if md in mds: 119 | click.secho("[DEXDump]: Skip duplicate dex {}<{}>".format(info['addr'], md), fg="blue") 120 | continue 121 | mds.append(md) 122 | if not os.path.exists("./" + pkg_name + "/"): 123 | os.mkdir("./" + pkg_name + "/") 124 | bs = dex_fix(bs) 125 | with open(pkg_name + "/" + info['addr'] + ".dex", 'wb') as out: 126 | out.write(bs) 127 | click.secho("[DEXDump]: DexSize={}, DexMd5={}, SavePath={}/{}/{}.dex" 128 | .format(hex(info['size']), md, os.getcwd(), pkg_name, info['addr']), fg='green') 129 | except Exception as e: 130 | click.secho("[Except] - {}: {}".format(e, info), bg='yellow') 131 | 132 | 133 | def stop_other(pid, processes, is_emulator): 134 | try: 135 | for process in processes: 136 | if process.pid == pid: 137 | if is_emulator: 138 | os.system("adb shell \"su 0 kill -18 {}\"".format(process.pid)) 139 | else : 140 | os.system("adb shell \"su -c 'kill -18 {}'\"".format(process.pid)) 141 | else: 142 | if is_emulator: 143 | os.system("adb shell \"su 0 kill -19 {}\"".format(process.pid)) 144 | else: 145 | os.system("adb shell \"su -c 'kill -19 {}'\"".format(process.pid)) 146 | except: 147 | pass 148 | 149 | 150 | def choose(pid=None, pkg=None, spawn=False, device=None): 151 | if pid is None and pkg is None: 152 | target = device.get_frontmost_application() 153 | return target.pid, target.identifier 154 | 155 | for process in device.enumerate_processes(): 156 | if (pid and process.pid == pid) or (pkg and process.name == pkg): 157 | if not spawn: 158 | return process.pid, process.name 159 | else: 160 | pkg = process.name 161 | break 162 | 163 | if pkg and spawn and device: 164 | pid = device.spawn(pkg) 165 | device.resume(pid) 166 | return pid, pkg 167 | raise Exception("Cannot found <{}> process".format(pid)) 168 | 169 | 170 | def show_help(): 171 | help_str = "Usage: frida-dexdump -n -p -f[enable spawn mode] -s -d[enable deep search] -P -A \n\n" \ 172 | " -n: [Optional] Specify target process name, when spawn mode, it requires an application package name. If not specified, use frontmost application.\n" \ 173 | " -p: [Optional] Specify pid when multiprocess. If not specified, dump all.\n" \ 174 | " -f: [Optional] Use spawn mode, default is disable.\n" \ 175 | " -s: [Optional] When spawn mode, start dump work after sleep few seconds. default is 10s.\n" \ 176 | " -d: [Optional] Enable deep search maybe detected more dex, but speed will be slower.\n" \ 177 | " -P: [Optional] Prepend a Frida script to run before dexdump does.\n" \ 178 | " -A: [Optional] Append a Frida script to run after dexdump done.\n" \ 179 | " -E: [Optional] Changes 'su -c cmd' to 'su 0 cmd' for emulators.\n" \ 180 | " -h: show help.\n" 181 | print(help_str) 182 | 183 | 184 | def connect_device(timeout=15): 185 | try: 186 | device = frida.get_usb_device(timeout=timeout) 187 | except: 188 | device = frida.get_remote_device() 189 | 190 | return device 191 | 192 | 193 | def entry(): 194 | show_banner() 195 | 196 | process = None 197 | pid = None 198 | enable_spawn_mode = False 199 | delay_second = 10 200 | enable_deep_search = False 201 | prepend_script_path = None 202 | append_script_path = None 203 | enable_emulator_mode = False 204 | 205 | try: 206 | opts, args = getopt.getopt(sys.argv[1:], "hn:p:fEs:dP:A:") 207 | 208 | def arg2int(v): 209 | try: 210 | return int(v) 211 | except: 212 | return int(v.replace('0x', ''), 16) 213 | 214 | for arg, value in opts: 215 | if arg == '-n': 216 | process = value 217 | elif arg == '-p': 218 | pid = arg2int(value) 219 | elif arg == '-f': 220 | enable_spawn_mode = True 221 | elif arg == '-s': 222 | delay_second = arg2int(value) 223 | elif arg == "-d": 224 | enable_deep_search = True 225 | elif arg == "-P": 226 | prepend_script_path = value 227 | elif arg == "-A": 228 | append_script_path = value 229 | elif arg == '-h': 230 | show_help() 231 | exit(0) 232 | elif arg == '-E': 233 | enable_emulator_mode = True 234 | 235 | except getopt.GetoptError: 236 | show_help() 237 | exit(2) 238 | 239 | if enable_spawn_mode and pid is not None: 240 | pid = None 241 | 242 | def forward_frida(): 243 | os.system("adb forward tcp:27042 tcp:27042") 244 | os.system("adb forward tcp:27043 tcp:27043") 245 | 246 | try: 247 | device = connect_device() 248 | if not device: 249 | raise Exception("Unable to connect.") 250 | except: 251 | forward_frida() 252 | device = connect_device() 253 | 254 | if not device: 255 | click.secho("[Except] - Unable to connect to device.", bg='red') 256 | exit() 257 | 258 | pname = None 259 | try: 260 | _, pname = choose(device=device, pkg=process, pid=pid, spawn=enable_spawn_mode) 261 | if enable_spawn_mode: 262 | logging.info("[DEXDump]: sleep {}s".format(delay_second)) 263 | time.sleep(delay_second) 264 | except Exception as e: 265 | click.secho("[Except] - Unable to inject into process: {} in \n{}".format(e, traceback.format_tb( 266 | sys.exc_info()[2])[-1]), bg='red') 267 | exit() 268 | 269 | processes = get_all_process(device, pname) 270 | mds = [] 271 | for process in processes: 272 | 273 | if pid is not None and process.pid != pid: 274 | continue 275 | 276 | logging.info("[DEXDump]: found target [{}] {}".format(process.pid, process.name)) 277 | stop_other(process.pid, processes, enable_emulator_mode) 278 | 279 | try: 280 | session = device.attach(process.pid) 281 | 282 | # same as jnitrace: https://github.com/chame1eon/jnitrace/blob/27d3ffec9b56d1cad7ccfb78572e076ce04461a2/jnitrace/jnitrace.py#L495-L498 283 | if prepend_script_path: 284 | prepend_script = session.create_script(open(prepend_script_path).read()) 285 | prepend_script.load() 286 | 287 | path = os.path.dirname(__file__) 288 | script = session.create_script(open(os.path.join(path, "agent.js")).read()) 289 | script.load() 290 | 291 | if enable_deep_search: 292 | script.exports.switchmode(True) 293 | logging.info("[DEXDump]: deep search mode is enable, maybe wait long time.") 294 | 295 | dump(pname, script.exports, mds=mds) 296 | 297 | if append_script_path: 298 | append_script = session.create_script(open(append_script_path).read()) 299 | append_script.load() 300 | 301 | if prepend_script_path: prepend_script.unload() 302 | script.unload() 303 | if append_script_path: append_script.unload() 304 | 305 | session.detach() 306 | except Exception as e: 307 | click.secho("[Except] - Unable dump dex: {} in \n{}".format(e, traceback.format_tb( 308 | sys.exc_info()[2])[-1]), bg='red') 309 | continue 310 | exit() 311 | 312 | 313 | if __name__ == "__main__": 314 | entry() 315 | --------------------------------------------------------------------------------