日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

frida hook so层方法大全

發(fā)布時(shí)間:2024/4/11 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 frida hook so层方法大全 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章轉(zhuǎn)載,僅供學(xué)習(xí),如有需要請(qǐng)支持原文章創(chuàng)作:https://kevinspider.github.io/fridahookso/

1.感謝

2. frida env

https://github.com/frida/frida-java-bridge/blob/master/lib/env.js

3.IDA 判斷 Thumb 指令集和 Arm 指令集

  • IDA - Options - General - number of opcode bytes - 設(shè)置為 4
  • 此時(shí)查看 IDA VIew 中 opcode 的長(zhǎng)度, 如果出現(xiàn) 2 個(gè)字節(jié)和 4 個(gè)字節(jié)的, 說(shuō)明為 thumb 指令集
  • 如果都是 4 個(gè)字節(jié)的, 說(shuō)明是 arm 指令集;
  • 在 Thumb 指令集下, inline hook 的偏移地址需要進(jìn)行 +1 操作;

4.枚舉內(nèi)存中的 so 文件

用于查看目標(biāo) module 是否被正常加載, 使用 Process.enumerateModules() 將當(dāng)前加載的所有 so 文件打印出來(lái)

function hook_native(){var modules = Process.enumerateModules();for (var i in modules){var module = modules[i];console.log(module.name);if (module.name.indexOf("target.so") > -1 ){console.log(module.base);}} }

5. 獲取指定 so 文件的基地址

function hook_module() {var baseAddr = Module.findBaseAddress("libnative-lib.so");console.log("baseAddr", baseAddr); }

6.獲取指定 so 文件的函數(shù)

6.1通過(guò)導(dǎo)出函數(shù)名定位 native 方法

function hook_func_from_exports(){var add_c_addr = Module.findExportByName("libnative-lib.so", "add_c");console.log("add_c_addr is :",add_c_addr); }

6.2通過(guò) symbols 符號(hào)定位 native 方法

function find_func_from_symbols() {var NewStringUTF_addr = null;var symbols = Process.findModuleByName("libart.so").enumerateSymbols();for (var i in symbols) {var symbol = symbols[i];if (symbol.name.indexOf("art") >= 0 &&symbol.name.indexOf("JNI") >= 0 &&symbol.name.indexOf("CheckJNI") < 0){if (symbol.name.indexOf("NewStringUTF") >= 0) {console.log("find target symbols", symbol.name, "address is ", symbol.address);NewStringUTF_addr = symbol.address;}}}console.log("NewStringUTF_addr is ", NewStringUTF_addr);Interceptor.attach(NewStringUTF_addr, {onEnter: function (args) {console.log("args0",args[0])console.log("args0", args[0], hexdump(args[0]));console.log("args1", args[1], hexdump(args[1]));var env = Java.vm.tryGetEnv();if (env != null) {// 直接讀取 c 里面的 charconsole.log("Memory readCstring is :", Memory.readCString(args[1]));}else{console.log("get env error");}},onLeave: function (returnResult) {console.log("result: ", Java.cast(returnResult, Java.use("java.lang.String")));var env = Java.vm.tryGetEnv();if (env != null) {var jstring = env.newStringUtf("修改返回值");returnResult.replace(ptr(jstring));}}}) }

6.3通過(guò)地址偏移 inline-hook 任意函數(shù)

function main(){// get base address of target so;var libnative_lib_addr = Module.findBaseAddress("libnative-lib.so");console.log("base module addr ->", libnative_lib_addr);if (libnative_lib_addr){var add_addr1 = Module.findExportByName("libnative-lib.so", "_Z5r0addii");var add_addr2 = libnative_lib_addr.add(0x94B2 + 1); // 32位需要加1console.log(add_addr1);console.log(add_addr2);}// 主動(dòng)調(diào)用var add1 = new NativeFunction(add_addr1, "int", ["int", "int"]);var add2 = new NativeFunction(add_addr2, "int", ["int", "int"]);console.log("add1 result is ->" + add1(10, 20));console.log("add2 result is ->" + add2(10, 20));}setImmediate(main);/* base module addr -> 0xd430b000 0xd43144b3 0xd43144b3 add1 result is ->30 add2 result is ->30 */

7.通過(guò) Intercept 攔截器打印 native 方法參數(shù)和返回值, 并修改返回值

  • onEnter: 函數(shù)(args) : 回調(diào)函數(shù), 給定一個(gè)參數(shù) args, 用于讀取或者寫入?yún)?shù)作為 NativePointer 對(duì)象的指針;
  • onLeave: 函數(shù)(retval) : 回調(diào)函數(shù)給定一個(gè)參數(shù) retval, 該參數(shù)是包含原始返回值的 NativePointer 派生對(duì)象; 可以調(diào)用 retval.replace(1234) 以整數(shù) 1234 替換返回值, 或者調(diào)用retval.replace(ptr("0x1234")) 以替換為指針;
  • 注意: retval 對(duì)象會(huì)在 onLeave 調(diào)用中回收, 因此不要將其存儲(chǔ)在回調(diào)之外使用, 如果需要存儲(chǔ)包含的值, 需要制作深拷貝, 如 ptr(retval.toString())
function find_func_from_exports() {var add_c_addr = Module.findExportByName("libnative-lib.so", "add_c");console.log("add_c_addr is :",add_c_addr);// 添加攔截器Interceptor.attach(add_c_addr,{// 打印入?yún)nEnter: function (args) {console.log("add_c called");console.log("arg1:",args[0].toInt32());console.log("arg2", args[1].toInt32());},// 打印返回值onLeave: function (returnValue) {console.log("add_c result is :", returnValue.toInt32());// 修改返回值returnValue.replace(100);}}) }

8.通過(guò) Intercept 攔截器替換原方法

function frida_Interceptor() {Java.perform(function () {//這個(gè)c_getSum方法有兩個(gè)int參數(shù)、返回結(jié)果為兩個(gè)參數(shù)相加//這里用NativeFunction函數(shù)自己定義了一個(gè)c_getSum函數(shù)var add_method = new NativeFunction(Module.findExportByName('libhello.so', 'c_getSum'), 'int',['int','int']);//輸出結(jié)果 那結(jié)果肯定就是 3console.log("result:",add_method(1,2));//這里對(duì)原函數(shù)的功能進(jìn)行替換實(shí)現(xiàn)Interceptor.replace(add_method, new NativeCallback(function (a, b) {//h不論是什么參數(shù)都返回123return 123;}, 'int', ['int', 'int']));//再次調(diào)用 則返回123console.log("result:",add_method(1,2));}); }

9.so 層方法注冊(cè)到 js 中, 主動(dòng)調(diào)用

new NativeFunction(address, returnType, argTypes[, options])
  • address : 函數(shù)地址
  • returnType : 指定返回類型
  • argTypes : 數(shù)組指定參數(shù)類型
  • 類型可選: void, pointer, int, uint, long, ulong, char, uchar, float, double, int8, uint8, int16, int32, uint32, int64, uint64; 參照函數(shù)所需的 type 來(lái)定義即可;
function invoke_native_func() {var baseAddr = Module.findBaseAddress("libnative-lib.so");console.log("baseAddr", baseAddr);var offset = 0x0000A28C + 1;var add_c_addr = baseAddr.add(offset);var add_c_func = new NativeFunction(add_c_addr, "int", ["int","int"]);var result = add_c_func(1, 2);console.log(result); } Java.perform(function () {// 獲取 so 文件基地址var base = Module.findBaseAddress("libnative-lib.so");// 獲取目標(biāo)函數(shù)偏移var sub_834_addr = base.add(0x835) // thumb 需要 +1// 使用 new NativeFunction 將函數(shù)注冊(cè)到 jsvar sub_834 = new NativeFunction(sub_834_addr, 'pointer', ['pointer']);// 開辟內(nèi)存, 創(chuàng)建入?yún)ar arg0 = Memory.alloc(10);ptr(arg0).writeUtf8String("123");var result = sub_834(arg0);console.log("result is :", hexdump(result)); })

10.hook libart 中的 jni 方法

jni 全部定在在 /system/lib(64)/libart.so 文件中, 通過(guò)枚舉 symbols 篩選出指定的方法

function hook_libart() {var GetStringUTFChars_addr = null;// jni 系統(tǒng)函數(shù)都在 libart.so 中var module_libart = Process.findModuleByName("libart.so");var symbols = module_libart.enumerateSymbols();for (var i = 0; i < symbols.length; i++) {var name = symbols[i].name;if ((name.indexOf("JNI") >= 0) && (name.indexOf("CheckJNI") == -1) && (name.indexOf("art") >= 0)) {if (name.indexOf("GetStringUTFChars") >= 0) {console.log(name);// 獲取到指定 jni 方法地址GetStringUTFChars_addr = symbols[i].address;}}}Java.perform(function(){Interceptor.attach(GetStringUTFChars_addr, {onEnter: function(args){// console.log("args[0] is : ", args[0]);// console.log("args[1] is : ", args[1]);console.log("native args[1] is :",Java.vm.getEnv().getStringUtfChars(args[1],null).readCString());console.log('GetStringUTFChars onEnter called from:\n' +Thread.backtrace(this.context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join('\n') + '\n');// console.log("native args[1] is :", Java.cast(args[1], Java.use("java.lang.String")));// console.log("native args[1] is :", Memory.readCString(Java.vm.getEnv().getStringUtfChars(args[1],null)));}, onLeave: function(retval){// retval const char*console.log("GetStringUTFChars onLeave : ", ptr(retval).readCString());}})}) }

11.hook libc 中的系統(tǒng)方法

/system/lib(64)/libc.so 導(dǎo)出的符號(hào)沒(méi)有進(jìn)行 namemanline , 直接過(guò)濾篩選即可

// hook libc.so var pthread_create_addr = null;// console.log(JSON.stringify(Process.enumerateModules())); // Process.enumerateModules() 枚舉加載的so文件 var symbols = Process.findModuleByName("libc.so").enumerateSymbols(); for (var i = 0; i < symbols.length; i++){if (symbols[i].name === "pthread_create"){// console.log("symbols name is -> " + symbols[i].name);// console.log("symbols address is -> " + symbols[i].address);pthread_create_addr = symbols[i].address;} }Interceptor.attach(pthread_create_addr,{onEnter: function(args){console.log("args is ->" + args[0], args[1], args[2],args[3]);},onLeave: function(retval){console.log(retval);} });}

libc.so 中方法替換

// hook 檢測(cè)frida 的方法 function main() {// var exports = Process.findModuleByName("libnative-lib.so").enumerateExports(); 導(dǎo)出// var imports = Process.findModuleByName("libnative-lib.so").enumerateImports(); 導(dǎo)入// var symbols = Process.findModuleByName("libnative-lib.so").enumerateSymbols(); 符號(hào)var pthread_create_addr = null;var symbols = Process.getModuleByName("libc.so").enumerateSymbols();for (var i = 0; i < symbols.length; i++) {var symbol = symbols[i];if (symbol.name === "pthread_create") {pthread_create_addr = symbol.address;console.log("pthread_create name is ->", symbol.name);console.log("pthread_create address is ->", pthread_create_addr);}}Java.perform(function(){// 定義方法 之后主動(dòng)調(diào)用的時(shí)候使用var pthread_create = new NativeFunction(pthread_create_addr, 'int', ['pointer', 'pointer','pointer','pointer'])Interceptor.replace(pthread_create_addr,new NativeCallback(function (a0, a1, a2, a3) {var result = null;var detect_frida_loop = Module.findExportByName("libnative-lib.so", "_Z17detect_frida_loopPv");console.log("a0,a1,a2,a3 ->",a0,a1,a2,a3);if (String(a2) === String(detect_frida_loop)) {result = 0;console.log("阻止frida反調(diào)試啟動(dòng)");} else {result = pthread_create(a0,a1,a2,a3);console.log("正常啟動(dòng)");}return result;}, 'int', ['pointer', 'pointer','pointer','pointer']));}) }

12.hook native 調(diào)用棧

Interceptor.attach(f, {onEnter: function (args) {console.log('RegisterNatives called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');} });

13.jnitrace

13.1安裝

jnitrace: https://github.com/chame1eon/jnitrace

python` : `pip install jnitrace

13.2基礎(chǔ)用法

ndk 開發(fā)是沒(méi)有辦法脫離 [libc.so](http://libc.so) 和 [libart.so](http://libart.so) 進(jìn)行開發(fā), 所以只要降維打擊, 通過(guò) trace 的方式就可以監(jiān)控到 so 層

啟動(dòng)命令

jnitrace [options] -l libname packagename

例如: jnitrace -l [libnative-lib.so](http://libnative-lib.so) com.example.myapplication

必要參數(shù)

  • -l libname : 指定要trace的.so文件, 可以同時(shí)trace多個(gè).so文件, 直接使用 *來(lái)trace所有的.so文件; 如: -l libnative-lib.so -l libanother-lib.so or -l *
  • packagename : 指定要trace的package name

可選參數(shù)

  • -m: 指定是spawn還是attach
  • -b: 指定是fuzzy還是accurate
  • -i : 指定一個(gè)正則表達(dá)式來(lái)過(guò)濾出方法名, 例如: -i Get -i RegisterNatives 就只會(huì)打印出名字里包含Get或者RegisterNatives的JNI methods
  • -e 和i相反,同樣通過(guò)正則表達(dá)式來(lái)過(guò)濾,但這次會(huì)將指定的內(nèi)容忽略掉
  • -I <string>trace導(dǎo)出的方法,jnitrace認(rèn)為導(dǎo)出的函數(shù)應(yīng)該是從Java端能夠直接調(diào)用的函數(shù),所以可以包括使用RegisterNatives來(lái)注冊(cè)的函數(shù),例如I stringFromJNI -I nativeMethod([B)V,就包括導(dǎo)出名里有stringFromJNI,以及使用RegisterNames來(lái)注冊(cè),并帶有nativeMethod([B)V簽名的函數(shù)。
  • -o path/output.json,導(dǎo)出輸出到文件里。
  • -p path/to/script.js,用于在加載jnitrace腳本之前將指定路徑的Frida腳本加載到目標(biāo)進(jìn)程中,這可以用于在jnitrace啟動(dòng)之前對(duì)抗反調(diào)試。
  • -a path/to/script.js,用于在加載jnitrace腳本之后將指定路徑的Frida腳本加載到目標(biāo)進(jìn)程中
  • -ignore-env,不打印所有的JNIEnv函數(shù)
  • -ignore-vm,不打印所有的JavaVM函數(shù)

啟動(dòng)方式

默認(rèn)使用 spawn 啟動(dòng), 可以通過(guò) -m attach 設(shè)置通過(guò) attach 啟動(dòng)

jnitrace -m attach -l[libnative-lib.so](http://libnative-lib.so) com.kevin.demoso1

設(shè)置回溯器

默認(rèn)情況下使用 accurate的精確模式來(lái)進(jìn)行回溯, 可以通過(guò) -b fuzzy 修改為模糊模式

jnitrace -l [libnative-lib.so](http://libnative-lib.so) -b fuzzy com.kevin.demoso1

監(jiān)控指定規(guī)則的方法

用于指定應(yīng)該跟蹤的方法名, 該選項(xiàng)可以多次提供;

jnitrace -l libnative-lib.so -i RegisterNatives com.kevin.demoso1

只過(guò)濾出RegisterNatives相關(guān)的內(nèi)容

忽略指定規(guī)則的方法

用于指定在跟蹤中應(yīng)被忽略的方法名, 這個(gè)選項(xiàng)可以被多次提供;

忽略以Find開頭的所有方法;

jnitrace -l libnative-lib.so -e ^Find com.kevin.demoso

13.3 jnitace 計(jì)算偏移地址


0x8e4f3b1 是方法 initSN 方法的絕對(duì)地址

0xd8e4e000 是 libmyjni.so 基地址

使用使用 initSN()V的絕對(duì)地址 0xd8e4f3b1 減去 libmyjni.so 的基地址 0xd8e4e000 , 得到偏移 0x13B1

g 進(jìn)行跳轉(zhuǎn)到 0x13B1 即可進(jìn)入方法

14.frida trace

文檔地址: https://frida.re/docs/frida-trace/

options

Usage: frida-trace [options] targetOptions:--version show program's version number and exit-h, --help show this help message and exit-D ID, --device=ID connect to device with the given ID-U, --usb connect to USB device-R, --remote connect to remote frida-server-H HOST, --host=HOST connect to remote frida-server on HOST-f FILE, --file=FILE spawn FILE-F, --attach-frontmost attach to frontmost application-n NAME, --attach-name=NAME attach to NAME-p PID, --attach-pid=PID attach to PID--stdio=inherit|pipe stdio behavior when spawning (defaults to “inherit”)--runtime=duk|v8 script runtime to use (defaults to “duk”)--debug enable the Node.js compatible script debugger-I MODULE, --include-module=MODULE include MODULE-X MODULE, --exclude-module=MODULE exclude MODULE-i FUNCTION, --include=FUNCTION include FUNCTION-x FUNCTION, --exclude=FUNCTION exclude FUNCTION-a MODULE!OFFSET, --add=MODULE!OFFSET add MODULE!OFFSET-T, --include-imports include program's imports-t MODULE, --include-module-imports=MODULE include MODULE imports-m OBJC_METHOD, --include-objc-method=OBJC_METHOD include OBJC_METHOD-M OBJC_METHOD, --exclude-objc-method=OBJC_METHOD exclude OBJC_METHOD-s DEBUG_SYMBOL, --include-debug-symbol=DEBUG_SYMBOL include DEBUG_SYMBOL-q, --quiet do not format output messages-d, --decorate Add module name to generated onEnter log statement-o OUTPUT, --output=OUTPUT dump messages to file

基礎(chǔ)使用

frida-trace [options] packagename

啟動(dòng)模式

默認(rèn)使用 attach 模式, 可以指定 -f packageName 使用 spawn 模式啟動(dòng)

frida-trace -U -i strcmp -f com.gdufs.xman

文件輸出

frida-trace -U -i "strcmp" -f com.gdufs.xman -o xman.json

-o filepath 指定輸出的文件路徑, 方便內(nèi)容過(guò)多時(shí)進(jìn)行查看

trace 任意 function

frida-trace -U -i "strcmp" com.example.demoso1

trace 任意 module

frida-trace -U -I "libnative-lib.so" com.example.demoso1

根據(jù)地址進(jìn)行 trace

frida-trace -U -a "libnative-lib.so!0x9281" com.example.demoso1

批量 trace

源碼地址: https://github.com/Pr0214/trace_natives

ps: 需要切換到 frida14 版本

  • 1.將traceNatives.py丟進(jìn)IDA plugins目錄中

在ida 的python console中運(yùn)行如下命令即可找到plugins目錄:os.path.join(idaapi.get_user_idadir(), "plugins")

  • 2.IDA中,Edit-Plugins-traceNatives –> IDA輸出窗口就會(huì)顯示如下字眼:使用方法如下: frida-trace -UF -O C:\Users\Lenovo\Desktop\2021\mt\libmtguard.txt

15.frida-hook-libart

下載地址: https://github.com/lasting-yang/frida_hook_libart

hook art

frida -U --no-pause -f package_name -l hook_art.js

hook_RegisterNatives

frida -U --no-pause -f package_name -l hook_RegisterNatives.js

hook_artmethod

init libext first time

adb push lib/libext64.so /data/local/tmp/libext64.so adb push lib/libext.so /data/local/tmp/libext.so adb shell su -c "cp /data/local/tmp/libext64.so /data/app/libext64.so" adb shell su -c "cp /data/local/tmp/libext.so /data/app/libext.so" adb shell su -c "chown 1000.1000 /data/app/libext*.so" adb shell su -c "chmod 777 /data/app/libext*.so" adb shell su -c "ls -al /data/app/libext*"

use hook_artmethod.js

frida -U --no-pause -f package_name -l hook_artmethod.js # or frida -U --no-pause -f package_name -l hook_artmethod.js > hook_artmethod.log

frida-fart-hook

  • 首先拷貝fart.so和fart64.so到/data/app目錄下,并使用chmod 777 設(shè)置好權(quán)限,然后就可以使用了。

  • 如果目標(biāo) app 沒(méi)有 sdcard 權(quán)限則需要手動(dòng)添加; 或者可以修改 frida_fart_hook.js 中的源碼, 將 savepath 改為 /data/data/應(yīng)用包名/;

  • 該frida版fart是使用hook的方式實(shí)現(xiàn)的函數(shù)粒度的脫殼,僅僅是對(duì)類中的所有函數(shù)進(jìn)行了加載,但依然可以解決絕大多數(shù)的抽取保護(hù)

  • 需要以spawn方式啟動(dòng)app,等待app進(jìn)入Activity界面后,執(zhí)行fart()函數(shù)即可。如app包名為com.example.test,則frida -U -f com.example.test -l frida_fart_hook.js --no-pause ,然后等待app進(jìn)入主界面,執(zhí)行fart()

  • 高級(jí)用法:如果發(fā)現(xiàn)某個(gè)類中的函數(shù)的CodeItem沒(méi)有dump下來(lái),可以調(diào)用dump(classname),傳入要處理的類名,完成對(duì)該類下的所有函數(shù)體的dump,dump下來(lái)的函數(shù)體會(huì)追加到bin文件當(dāng)中。

16.frida 文件寫入(frida/hook libc)

frida api 寫入文件

function writeFile(){var file = new File("/sdcard/reg.dat", "w");file.write("content from frida");file.flush();file.close(); }

frida 定義 NativeFunction 寫入文件

function writeFileNative(){var addr_fopen = Module.findExportByName("libc.so", "fopen");var addr_fputs = Module.findExportByName("libc.so", "fputs");var addr_fclose = Module.findExportByName("libc.so", "fclose");// 將 libc 的系統(tǒng)方法注冊(cè)到 js 層var fopen = new NativeFunction(addr_fopen, "pointer", ["pointer", "pointer"]);var fputs = new NativeFunction(addr_fputs, "int", ["pointer", "pointer"]);var fclose = new NativeFunction(addr_fclose, "int", ["pointer"]);// 在 js 層主動(dòng)調(diào)用 libc 的方法// 不能直接將 js 的字符串傳給 libc中的方法, 需要進(jìn)行轉(zhuǎn)換var filename = Memory.allocUtf8String("/sdcard/reg.dat");var open_mode = Memory.allocUtf8String("w");var file = fopen(filename, open_mode);var buffer = Memory.allocUtf8String("content from frida");var result = fputs(buffer, file);console.log("fputs ret: ", result);// 關(guān)閉文件fclose(file);}

17.hook 讀寫 std::string

function readStdString(str){var isTiny = (str.readU8 & 1) === 0;if (isTiny){return str.add(1).readUtf8String();}return str.add(2 * Process.pointerSize).readPointer().readUtf8String(); }function writeStdString(str, content){var isTiny = (str.readU8() & 1) === 0;if (isTiny){str.add(1).writeUtf8String(content);}else{str.add(2 * Process.pointerSize).readPointer().writeUtf8String(content);} }

18.hook so 文件加載后馬上 hook

//第一種方式(針對(duì)較老的系統(tǒng)版本) var dlopen = Module.findExportByName(null, "dlopen"); console.log(dlopen); if(dlopen != null){Interceptor.attach(dlopen,{onEnter: function(args){var soName = args[0].readCString();console.log(soName);if(soName.indexOf("libc.so") != -1){this.hook = true;}},onLeave: function(retval){if(this.hook) { dlopentodo();};}}); }//第二種方式(針對(duì)新系統(tǒng)版本) android 8.1 使用該方法 var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext"); console.log(android_dlopen_ext); if(android_dlopen_ext != null){Interceptor.attach(android_dlopen_ext,{onEnter: function(args){var soName = args[0].readCString();console.log(soName);if(soName.indexOf("libc.so") != -1){this.hook = true;}},onLeave: function(retval){if(this.hook) {dlopentodo();};}}); }function dlopentodo(){//todo ... }

19.hook libc kill

function replaceKILL(){var kill_addr = Module.findExportByName("libc.so","kill");Interceptor.replace(kill_addr, new NativeCallback(function(arg0, arg1){console.log("arg0=> ", arg0);console.log("arg1=> ", arg1);console.log('libc.so!kill called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');},"int",["int","int"])) }

20.hook init_array

//應(yīng)用以32位在64位終端環(huán)境下運(yùn)行 //adb install --abi armeabi-v7a <path to apk>function get_call_function() {var call_function_addr = null;var symbols = Process.getModuleByName("linker").enumerateSymbols();for (var m = 0; m < symbols.length; m++) {if (symbols[m].name == "__dl__ZL13call_functionPKcPFviPPcS2_ES0_") {call_function_addr = symbols[m].address;console.log("found call_function_addr => ", call_function_addr)hook_call_function(call_function_addr)}} }function hook_call_function(_call_function_addr){console.log("hook call function begin!hooking address :=>",_call_function_addr)Interceptor.attach(_call_function_addr,{onEnter:function(args){if(args[2].readCString().indexOf("base.odex")<0){console.log("============================")console.log("function_name =>",args[0].readCString())var soPath = args[2].readCString()console.log("so path : =>",soPath)var soName = soPath.split("/").pop();console.log("function offset =>","0x"+(args[1]-Module.findBaseAddress(soName)).toString(16))console.log("============================")}},onLeave:function(retval){}}) }setImmediate(get_call_function) function hook_constructor() {if (Process.pointerSize == 4) {var linker = Process.findModuleByName("linker");} else {var linker = Process.findModuleByName("linker64");}var addr_call_function =null;var addr_g_ld_debug_verbosity = null;var addr_async_safe_format_log = null;if (linker) {var symbols = linker.enumerateSymbols();for (var i = 0; i < symbols.length; i++) {var name = symbols[i].name;if (name.indexOf("call_function") >= 0){addr_call_function = symbols[i].address;}else if(name.indexOf("g_ld_debug_verbosity") >=0){addr_g_ld_debug_verbosity = symbols[i].address;ptr(addr_g_ld_debug_verbosity).writeInt(2);} else if(name.indexOf("async_safe_format_log") >=0 && name.indexOf('va_list') < 0){addr_async_safe_format_log = symbols[i].address;} }}if(addr_async_safe_format_log){Interceptor.attach(addr_async_safe_format_log,{onEnter: function(args){this.log_level = args[0];this.tag = ptr(args[1]).readCString()this.fmt = ptr(args[2]).readCString()if(this.fmt.indexOf("c-tor") >= 0 && this.fmt.indexOf('Done') < 0){this.function_type = ptr(args[3]).readCString(), // func_typethis.so_path = ptr(args[5]).readCString();var strs = new Array(); //定義一數(shù)組 strs = this.so_path.split("/"); //字符分割this.so_name = strs.pop();this.func_offset = ptr(args[4]).sub(Module.findBaseAddress(this.so_name)) console.log("func_type:", this.function_type,'\nso_name:',this.so_name,'\nso_path:',this.so_path,'\nfunc_offset:',this.func_offset );}},onLeave: function(retval){}})} } function main() {hook_constructor(); } setImmediate(main);

21.frida dump

document: https://github.com/lasting-yang/frida_dump

21.1 frida dump so

function dump_so(so_name) {Java.perform(function () {var currentApplication = Java.use("android.app.ActivityThread").currentApplication();var dir = currentApplication.getApplicationContext().getFilesDir().getPath();var libso = Process.getModuleByName(so_name);console.log("[name]:", libso.name);console.log("[base]:", libso.base);console.log("[size]:", ptr(libso.size));console.log("[path]:", libso.path);var file_path = dir + "/" + libso.name + "_" + libso.base + "_" + ptr(libso.size) + ".so";var file_handle = new File(file_path, "wb");if (file_handle && file_handle != null) {Memory.protect(ptr(libso.base), libso.size, 'rwx');var libso_buffer = ptr(libso.base).readByteArray(libso.size);file_handle.write(libso_buffer);file_handle.flush();file_handle.close();console.log("[dump]:", file_path);}}); }

21.2 frida dump dex

function get_self_process_name() {var openPtr = Module.getExportByName('libc.so', 'open');var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);var readPtr = Module.getExportByName("libc.so", "read");var read = new NativeFunction(readPtr, "int", ["int", "pointer", "int"]);var closePtr = Module.getExportByName('libc.so', 'close');var close = new NativeFunction(closePtr, 'int', ['int']);var path = Memory.allocUtf8String("/proc/self/cmdline");var fd = open(path, 0);if (fd != -1) {var buffer = Memory.alloc(0x1000);var result = read(fd, buffer, 0x1000);close(fd);result = ptr(buffer).readCString();return result;}return "-1"; }function mkdir(path) {var mkdirPtr = Module.getExportByName('libc.so', 'mkdir');var mkdir = new NativeFunction(mkdirPtr, 'int', ['pointer', 'int']);var opendirPtr = Module.getExportByName('libc.so', 'opendir');var opendir = new NativeFunction(opendirPtr, 'pointer', ['pointer']);var closedirPtr = Module.getExportByName('libc.so', 'closedir');var closedir = new NativeFunction(closedirPtr, 'int', ['pointer']);var cPath = Memory.allocUtf8String(path);var dir = opendir(cPath);if (dir != 0) {closedir(dir);return 0;}mkdir(cPath, 755);chmod(path); }function chmod(path) {var chmodPtr = Module.getExportByName('libc.so', 'chmod');var chmod = new NativeFunction(chmodPtr, 'int', ['pointer', 'int']);var cPath = Memory.allocUtf8String(path);chmod(cPath, 755); }function dump_dex() {var libart = Process.findModuleByName("libart.so");var addr_DefineClass = null;var symbols = libart.enumerateSymbols();for (var index = 0; index < symbols.length; index++) {var symbol = symbols[index];var symbol_name = symbol.name;//這個(gè)DefineClass的函數(shù)簽名是Android9的//_ZN3art11ClassLinker11DefineClassEPNS_6ThreadEPKcmNS_6HandleINS_6mirror11ClassLoaderEEERKNS_7DexFileERKNS9_8ClassDefEif (symbol_name.indexOf("ClassLinker") >= 0 &&symbol_name.indexOf("DefineClass") >= 0 &&symbol_name.indexOf("Thread") >= 0 &&symbol_name.indexOf("DexFile") >= 0) {console.log(symbol_name, symbol.address);addr_DefineClass = symbol.address;}}var dex_maps = {};var dex_count = 1;console.log("[DefineClass:]", addr_DefineClass);if (addr_DefineClass) {Interceptor.attach(addr_DefineClass, {onEnter: function(args) {var dex_file = args[5];//ptr(dex_file).add(Process.pointerSize) is "const uint8_t* const begin_;"//ptr(dex_file).add(Process.pointerSize + Process.pointerSize) is "const size_t size_;"var base = ptr(dex_file).add(Process.pointerSize).readPointer();var size = ptr(dex_file).add(Process.pointerSize + Process.pointerSize).readUInt();if (dex_maps[base] == undefined) {dex_maps[base] = size;var magic = ptr(base).readCString();if (magic.indexOf("dex") == 0) {var process_name = get_self_process_name();if (process_name != "-1") {var dex_dir_path = "/data/data/" + process_name + "/files/dump_dex_" + process_name;mkdir(dex_dir_path);var dex_path = dex_dir_path + "/class" + (dex_count == 1 ? "" : dex_count) + ".dex";console.log("[find dex]:", dex_path);var fd = new File(dex_path, "wb");if (fd && fd != null) {dex_count++;var dex_buffer = ptr(base).readByteArray(size);fd.write(dex_buffer);fd.flush();fd.close();console.log("[dump dex]:", dex_path);}}}}},onLeave: function(retval) {}});} }var is_hook_libart = false;function hook_dlopen() {Interceptor.attach(Module.findExportByName(null, "dlopen"), {onEnter: function(args) {var pathptr = args[0];if (pathptr !== undefined && pathptr != null) {var path = ptr(pathptr).readCString();//console.log("dlopen:", path);if (path.indexOf("libart.so") >= 0) {this.can_hook_libart = true;console.log("[dlopen:]", path);}}},onLeave: function(retval) {if (this.can_hook_libart && !is_hook_libart) {dump_dex();is_hook_libart = true;}}})Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {onEnter: function(args) {var pathptr = args[0];if (pathptr !== undefined && pathptr != null) {var path = ptr(pathptr).readCString();//console.log("android_dlopen_ext:", path);if (path.indexOf("libart.so") >= 0) {this.can_hook_libart = true;console.log("[android_dlopen_ext:]", path);}}},onLeave: function(retval) {if (this.can_hook_libart && !is_hook_libart) {dump_dex();is_hook_libart = true;}}}); }setImmediate(dump_dex);

21.3 frida dump dex class

function get_self_process_name() {var openPtr = Module.getExportByName('libc.so', 'open');var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);var readPtr = Module.getExportByName("libc.so", "read");var read = new NativeFunction(readPtr, "int", ["int", "pointer", "int"]);var closePtr = Module.getExportByName('libc.so', 'close');var close = new NativeFunction(closePtr, 'int', ['int']);var path = Memory.allocUtf8String("/proc/self/cmdline");var fd = open(path, 0);if (fd != -1) {var buffer = Memory.alloc(0x1000);var result = read(fd, buffer, 0x1000);close(fd);result = ptr(buffer).readCString();return result;}return "-1"; }function load_all_class() {if (Java.available) {Java.perform(function () {var DexFileclass = Java.use("dalvik.system.DexFile");var BaseDexClassLoaderclass = Java.use("dalvik.system.BaseDexClassLoader");var DexPathListclass = Java.use("dalvik.system.DexPathList");Java.enumerateClassLoaders({onMatch: function (loader) {try {var basedexclassloaderobj = Java.cast(loader, BaseDexClassLoaderclass);var pathList = basedexclassloaderobj.pathList.value;var pathListobj = Java.cast(pathList, DexPathListclass)var dexElements = pathListobj.dexElements.value;for (var index in dexElements) {var element = dexElements[index];try {var dexfile = element.dexFile.value;var dexfileobj = Java.cast(dexfile, DexFileclass);console.log("dexFile:", dexfileobj);const classNames = [];const enumeratorClassNames = dexfileobj.entries();while (enumeratorClassNames.hasMoreElements()) {var className = enumeratorClassNames.nextElement().toString();classNames.push(className);try {loader.loadClass(className);} catch (error) {console.log("loadClass error:", error);}}} catch (error) {console.log("dexfile error:", error);}}} catch (error) {console.log("loader error:", error);}},onComplete: function () {}})console.log("load_all_class end.");});} } var dex_maps = {};function print_dex_maps() {for (var dex in dex_maps) {console.log(dex, dex_maps[dex]);} }function dump_dex() {load_all_class();for (var base in dex_maps) {var size = dex_maps[base];console.log(base);var magic = ptr(base).readCString();if (magic.indexOf("dex") == 0) {var process_name = get_self_process_name();if (process_name != "-1") {var dex_path = "/data/data/" + process_name + "/files/" + base.toString(16) + "_" + size.toString(16) + ".dex";console.log("[find dex]:", dex_path);var fd = new File(dex_path, "wb");if (fd && fd != null) {var dex_buffer = ptr(base).readByteArray(size);fd.write(dex_buffer);fd.flush();fd.close();console.log("[dump dex]:", dex_path);}}}} }function hook_dex() {var libart = Process.findModuleByName("libart.so");var addr_DefineClass = null;var symbols = libart.enumerateSymbols();for (var index = 0; index < symbols.length; index++) {var symbol = symbols[index];var symbol_name = symbol.name;//這個(gè)DefineClass的函數(shù)簽名是Android9的//_ZN3art11ClassLinker11DefineClassEPNS_6ThreadEPKcmNS_6HandleINS_6mirror11ClassLoaderEEERKNS_7DexFileERKNS9_8ClassDefEif (symbol_name.indexOf("ClassLinker") >= 0 &&symbol_name.indexOf("DefineClass") >= 0 &&symbol_name.indexOf("Thread") >= 0 &&symbol_name.indexOf("DexFile") >= 0) {console.log(symbol_name, symbol.address);addr_DefineClass = symbol.address;}}console.log("[DefineClass:]", addr_DefineClass);if (addr_DefineClass) {Interceptor.attach(addr_DefineClass, {onEnter: function (args) {var dex_file = args[5];//ptr(dex_file).add(Process.pointerSize) is "const uint8_t* const begin_;"//ptr(dex_file).add(Process.pointerSize + Process.pointerSize) is "const size_t size_;"var base = ptr(dex_file).add(Process.pointerSize).readPointer();var size = ptr(dex_file).add(Process.pointerSize + Process.pointerSize).readUInt();if (dex_maps[base] == undefined) {dex_maps[base] = size;console.log("hook_dex:", base, size);}},onLeave: function (retval) {}});}}var is_hook_libart = false;function hook_dlopen() {Interceptor.attach(Module.findExportByName(null, "dlopen"), {onEnter: function (args) {var pathptr = args[0];if (pathptr !== undefined && pathptr != null) {var path = ptr(pathptr).readCString();//console.log("dlopen:", path);if (path.indexOf("libart.so") >= 0) {this.can_hook_libart = true;console.log("[dlopen:]", path);}}},onLeave: function (retval) {if (this.can_hook_libart && !is_hook_libart) {hook_dex();is_hook_libart = true;}}})Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {onEnter: function (args) {var pathptr = args[0];if (pathptr !== undefined && pathptr != null) {var path = ptr(pathptr).readCString();//console.log("android_dlopen_ext:", path);if (path.indexOf("libart.so") >= 0) {this.can_hook_libart = true;console.log("[android_dlopen_ext:]", path);}}},onLeave: function (retval) {if (this.can_hook_libart && !is_hook_libart) {hook_dex();is_hook_libart = true;}}}); }setImmediate(hook_dex);

22.指針運(yùn)算符和讀寫 API


22.1 hook so readPointer()

Java.perform(function () {var libc_addr = Process.findModuleByName("libc.so").base;console.log("libc address is " + libc_addr);// 0x10 轉(zhuǎn)為十進(jìn)制為 16, 讀取console.log(libc_addr.readByteArray(0x10));// readPointer(), 從此內(nèi)存位置讀取 NativePointerconsole.log("pointer size", Process.pointerSize);console.log("readPointer() is " + libc_addr.readPointer());console.log("Memory.readPointer()" + Memory.readPointer(libc_addr.add(Process.pointerSize)));})

22.2 hook so writePointer()

Java.perform(function () {var libc_addr = Process.findModuleByName("libc.so").base;console.log("libc_addr : " + libc_addr);// 分配四個(gè)字節(jié)的空間地址const r = Memory.alloc(4);// 將 libc_addr 指針寫入剛申請(qǐng)的 r 中r.writePointer(libc_addr);// 讀取 r 指針的數(shù)據(jù)var buffer = Memory.readByteArray(r, 4);console.log(buffer);})//libc_addr : 0x7da7fdf000// 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF // 00000000 00 f0 fd a7 ....

22.3 hook so readS32(), readU32()

從指定內(nèi)存地址讀取有符號(hào)或者無(wú)符號(hào) 8/16/21/etc 或浮點(diǎn)數(shù)/雙精度值, 并將其作為數(shù)字返回;

Java.perform(function () {var libc_addr = Process.findModuleByName("libc.so").base;console.log(hexdump(libc_addr));console.log(libc_addr.readS32(), (libc_addr.readS32()).toString(16));console.log(libc_addr.readU32(), (libc_addr.readU32()).toString(16));})

22.4 hook so writeS32(), writeU32()

將有符號(hào)或無(wú)符號(hào)8/16/32/等或浮點(diǎn)數(shù)/雙精度值寫入此內(nèi)存位置

Java.perform(function () {// 開辟四個(gè)字節(jié)的內(nèi)存空間const r = Memory.alloc(4);r.writeS32(0x12345678);console.log(r.readByteArray(0x10));})<!-- 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 00000000 78 56 34 12 7d 00 00 00 98 c0 bb a8 7d 00 00 00 xV4.}.......}...-->

22.5 hook so readByteArray(), writeByteArray()

Java.perform(function () {// 定義一個(gè)需要寫入的字節(jié)數(shù)組var arr = [ 0x72, 0x6F, 0x79, 0x73, 0x75, 0x65];//這里申請(qǐng)以arr大小的內(nèi)存空間var r = Memory.alloc(arr.length);// 將 arr 寫入 r 中r.writeByteArray(arr);// Memory.writeByteArray(r, arr); 同樣可以寫入console.log("memory readbyteArray: ")console.log(r.readByteArray(arr.length));console.log(Memory.readByteArray(r, arr.length));})

22.6 hook so readCString(), writeUtf8String()

Java.perform(function () {// 開辟內(nèi)存空間 存有字符串var r = Memory.allocUtf8String("你好,世界");// 讀取內(nèi)存中的字符串console.log(hexdump(r));console.log(r.readCString());// 往內(nèi)存中寫入新的字符串r.writeUtf8String("Hello,World");console.log(hexdump(r));console.log(r.readCString())})

23.hook 獲取 jni array

// 獲取 jbytesArray 的指針 var arg1Ptr = Java.vm.getEnv().getByteArrayElements(this.arg1, null) // 獲取到指針后可以直接 hexdump 打印 console.log("arg1Ptr",hexdump(arg1Ptr)); // 如果是字符串可以直接轉(zhuǎn) console.log("arg1Ptr",arg1Ptr.readCString());

24.ida 動(dòng)態(tài)調(diào)試

1.將 ida 中的 android-server 推入到手機(jī)中

adb push /Applications/IDA\ Pro\ 7.0/ida.app/Contents/MacOS/dbgsrv/android_server /data/local/tmp/as

android_server 負(fù)責(zé)調(diào)試 32 位的app, android_server64 負(fù)責(zé)調(diào)試 64 位的app, 改名為 as 可以防止部分 android_server 名稱檢測(cè)

2.給 android_server 增加權(quán)限

adb shell su chmod +x /data/local/tmp/as

3.進(jìn)行端口轉(zhuǎn)發(fā) adb forward tcp:11678 tcp:11678
4.啟動(dòng) android_server 并指定端口為 11678

adb shell su /data/local/tmp/as -p11678

5.調(diào)試之前先注入 frida

6.新建一個(gè) ida 界面

7.Debugger - Remote ARMLinux/Android debugger

8.hostname: localhost; Port: 11678; 勾選 Save network settings as default

9.frida 打印出目標(biāo) function 最終的地址, ida 中 g 到目標(biāo) function 地址, 查看是否是

10.thumb 指令集, 如果是 thumb 則 option + g, 將 T 修改為1, 再按 c;
File - Script file - 讀取 ida trace 腳本, 需要更改目標(biāo) so 文件和 function 的起始地址和結(jié)束地址; 讀取之后會(huì)出現(xiàn)斷點(diǎn); 快捷鍵: option F7;

11.frida 主動(dòng)調(diào)用腳本, 檢測(cè)斷點(diǎn)是否觸發(fā)

12.斷點(diǎn)檢測(cè)正常后, ida 中執(zhí)行 starthook()命令, 進(jìn)行 hook 操作; 執(zhí)行suspend_other_thread()掛起其他線程(可選擇)

13.ida 中 Debugger - tracing - tracing options - 設(shè)置 Trace file 路徑 和 取消 Trace over debugger segments 的勾選

14.ida 中 Debugger - tracing - 勾選 instruction tracing

15.frida 主動(dòng)調(diào)用觸發(fā)斷點(diǎn)

16.ida 點(diǎn)擊運(yùn)行按鈕進(jìn)行執(zhí)行, 此時(shí) ida 中黃色部分為已經(jīng)執(zhí)行完的指令, 點(diǎn)擊 Debugger -tracing - tracing window 可以看到當(dāng)前執(zhí)行進(jìn)度;

25.ida 添加自有 python 路徑

修改路徑下的文件 : /Applications/IDA Pro 7.0/ida.app/Contents/MacOS/python/init.py

# Prepare sys.path so loading of the shared objects works lib_dynload = os.path.join(sys.executable,IDAPYTHON_DYNLOAD_BASE,"python", "lib", "python2.7", "lib-dynload")# added by kevin sys.path.insert(0, "/Users/zhangyang/anaconda3/envs/py2/lib/python2.7/site-packages")

26.idapython 腳本調(diào)試

在 pycharm 中開啟調(diào)試

在需要調(diào)試的腳本中添加斷點(diǎn)

import pydevd_pycharmpydevd_pycharm.settrace('localhost', port=12345, stdoutToServer=True, stderrToServer=True)

在 idapython 的__init__.py文件中添加自有的 python 路徑;

先在 pycharm 中打開調(diào)試監(jiān)聽, 在 ida 中運(yùn)行要調(diào)試的腳本即可;

27.jni_helper

  • 進(jìn)入目錄 ~/androidFxxk/idaTools/jni_helper
  • java -jar JadxFindJNI/JadxFindJNI.jar <apk.path> <output.json>
  • ida 中Script File運(yùn)行 jni_help腳本, 路徑 ~/androidFxxk/idaTools/jni_helper/ida/jni_helper.py
  • 導(dǎo)入剛才生成的 output.json 文件即可自動(dòng)識(shí)別

總結(jié)

以上是生活随笔為你收集整理的frida hook so层方法大全的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。