Android逆向10-Frida_Native 来自吾爱破解-正己
https://www.52pojie.cn/thread-1701353-1-1.html
Process、Module、Memory Process
对象代表当前被Hook的进程,能获取进程的信息,枚举模块,枚举范围等
API
含义
Process.id
返回附加目标进程的 PID
Process.isDebuggerAttached()
检测当前是否对目标程序已经附加
Process.enumerateModules()
枚举当前加载的模块,返回模块对象的数组
Process.enumerateThreads()
枚举当前所有的线程,返回包含 id
, state
, context
等属性的对象数组
Module
对象代表一个加载到进程的模块(例如,在 Windows 上的 DLL,或在 Linux/Android 上的 .so 文件),能查询模块的信息,如模块的基址、名称、导入/导出的函数等
API
含义
Module.load()
加载指定so文件,返回一个Module对象
enumerateImports()
枚举所有Import库函数,返回Module数组对象
enumerateExports()
枚举所有Export库函数,返回Module数组对象
enumerateSymbols()
枚举所有Symbol库函数,返回Module数组对象
Module.findExportByName(exportName)、Module.getExportByName(exportName)
寻找指定so中export库中的函数地址
Module.findBaseAddress(name)、Module.getBaseAddress(name)
返回so的基地址
Memory
是一个工具对象,提供直接读取和修改进程内存的功能,能够读取特定地址的值、写入数据、分配内存等
方法
功能
Memory.copy()
复制内存
Memory.scan()
搜索内存中特定模式的数据
Memory.scanSync()
同上,但返回多个匹配的数据
Memory.alloc()
在目标进程的堆上申请指定大小的内存,返回一个NativePointer
Memory.writeByteArray()
将字节数组写入一个指定内存
Memory.readByteArray
读取内存
枚举导入导出表
导出表(Export Table) :列出了库中可以被其他程序或库访问的所有公开函数和符号的名称。
导入表(Import Table) :列出了库需要从其他库中调用的函数和符号的名称。
简而言之,导出表告诉其他程序:“这些是我提供的功能。”,而导入表则表示:“这些是我需要的功能。”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function hookTest1 ( ){ Java .perform (function ( ){ let SecurityUtil = Java .use ("com.zj.wuaipojie.util.SecurityUtil" ); SecurityUtil ["checkVip" ].implementation = function ( ){ console .log ('checkvip is called' ); let ret = this .checkVip (); console .log ('checkvip ret value is ' + ret); return ret; }; }) } function main ( ){ Java .perform (function ( ){ hookTest1 (); }); } setImmediate (main);
获取so地址
1 2 3 var moduleAddr1 = Process .findModuleByName ("lib52pojie.so" ).base ; var moduleAddr2 = Process .getModuleByName ("lib52pojie.so" ).base ; var moduleAddr3 = Module .findBaseAddress ("lib52pojie.so" );
改成return true即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function hookTest1 ( ){ Java .perform (function ( ){ var imports = Module .enumerateImports ("lib52pojie.so" ); for (var i =0 ; i < imports.length ;i++){ if (imports[i].name == "vip" ){ console .log (JSON .stringify (imports[i])); console .log (imports[i].address ); } } var exports = Module .enumerateExports ("lib52pojie.so" ); for (var i =0 ; i < exports .length ;i++){ console .log (JSON .stringify (exports [i])); } }) }
Native函数的Hook 整数型、布尔值类型、char类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function hookTest2 ( ){ Java .perform (function ( ){ var helloAddr = Module .findExportByName ("lib52pojie.so" ,"Java_com_zj_wuaipojie_util_SecurityUtil_checkVip" ); console .log (helloAddr); if (helloAddr != null ){ Interceptor .attach (helloAddr,{ onEnter : function (args ){ }, onLeave : function (retval ){ console .log (retval); retval.replace (1 ); } }) } }) }
字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 function hookTest2 ( ){ Java .perform (function ( ){ var helloAddr = Module .findExportByName ("lib52pojie.so" ,"Java_com_zj_wuaipojie_util_SecurityUtil_vipLevel" ); if (helloAddr != null ){ Interceptor .attach (helloAddr,{ onEnter : function (args ){ var jString = Java .cast (args[2 ], Java .use ('java.lang.String' )); console .log ("参数:" , jString.toString ()); var JNIEnv = Java .vm .getEnv (); var originalStrPtr = JNIEnv .getStringUtfChars (args[2 ], null ).readCString (); console .log ("参数:" , originalStrPtr); }, onLeave : function (retval ){ var returnedJString = Java .cast (retval, Java .use ('java.lang.String' )); console .log ("返回值:" , returnedJString.toString ()); } }) } }) }
this.content.x1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function hookTest3 ( ){Java .perform (function ( ){ var helloAddr = Module .findExportByName ("lib52pojie.so" ,"Java_com_zj_wuaipojie_util_SecurityUtil_checkVip" ); console .log (helloAddr); if (helloAddr != null ){ Interceptor .attach (helloAddr,{ onEnter : function (args ){ args[0 ] = ptr (1000 ); console .log (args[0 ]); }, onLeave : function (retval ){ retval.replace (20000 ); console .log ("retval" ,retval.toInt32 ()); } }) } }) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function hookTest2 ( ){Java .perform (function ( ){ var helloAddr = Module .findExportByName ("lib52pojie.so" ,"Java_com_zj_wuaipojie_util_SecurityUtil_vipLevel" ); if (helloAddr != null ){ Interceptor .attach (helloAddr,{ onEnter : function (args ){ var JNIEnv = Java .vm .getEnv (); var originalStrPtr = JNIEnv .getStringUtfChars (args[2 ], null ).readCString (); console .log ("参数:" , originalStrPtr); var modifiedContent = "至尊" ; var newJString = JNIEnv .newStringUtf (modifiedContent); args[2 ] = newJString; }, onLeave : function (retval ){ var returnedJString = Java .cast (retval, Java .use ('java.lang.String' )); console .log ("返回值:" , returnedJString.toString ()); var JNIEnv = Java .vm .getEnv (); var modifiedContent = "无敌" ; var newJString = JNIEnv .newStringUtf (modifiedContent); retval.replace (newJString); } }) } }) }
Hook未导出函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function hookTest6 ( ){ Java .perform (function ( ){ var soAddr = Module .findBaseAddress ("lib52pojie.so" ); console .log (soAddr); var funcaddr = soAddr.add (0x1071C ); console .log (funcaddr); if (funcaddr != null ){ Interceptor .attach (funcaddr,{ onEnter : function (args ){ }, onLeave : function (retval ){ console .log (retval.toInt32 ()); } }) } }) }
函数地址计算
安卓里一般32 位的 so 中都是thumb
指令,64 位的 so 中都是arm
指令
通过IDA里的opcode bytes来判断,arm 指令为 4 个字节(options -> general -> Number of opcode bytes (non-graph) 输入4)
thumb 指令,函数地址计算方式: so 基址 + 函数在 so 中的偏移 + 1 arm 指令,函数地址计算方式: so 基址 + 函数在 so 中的偏移
Hook_dlopen dlopen源码
android_dlopen_ext源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function hook_dlopen ( ) { var dlopen = Module .findExportByName (null , "dlopen" ); Interceptor .attach (dlopen, { onEnter : function (args ) { var so_name = args[0 ].readCString (); if (so_name.indexOf ("lib52pojie.so" ) >= 0 ) this .call_hook = true ; }, onLeave : function (retval ) { if (this .call_hook ) hookTest2 (); } }); var android_dlopen_ext = Module .findExportByName (null , "android_dlopen_ext" ); Interceptor .attach (android_dlopen_ext, { onEnter : function (args ) { var so_name = args[0 ].readCString (); if (so_name.indexOf ("lib52pojie.so" ) >= 0 ) this .call_hook = true ; }, onLeave : function (retval ) { if (this .call_hook ) hookTest2 (); } }); }
IDA脚本一键式hook 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 (function ( ) { function print_arg (addr ) { try { var module = Process .findRangeByAddress (addr); if (module != null ) return "\n" +hexdump (addr) + "\n" ; return ptr (addr) + "\n" ; } catch (e) { return addr + "\n" ; } } function hook_native_addr (funcPtr, paramsNum ) { var module = Process .findModuleByAddress (funcPtr); try { Interceptor .attach (funcPtr, { onEnter : function (args ) { this .logs = "" ; this .params = []; this .logs =this .logs .concat ("So: " + module .name + " Method: Java_com_zj_wuaipojie_util_SecurityUtil_checkVip offset: " + ptr (funcPtr).sub (module .base ) + "\n" ); for (let i = 0 ; i < paramsNum; i++) { this .params .push (args[i]); this .logs =this .logs .concat ("this.args" + i + " onEnter: " + print_arg (args[i])); } }, onLeave : function (retval ) { for (let i = 0 ; i < paramsNum; i++) { this .logs =this .logs .concat ("this.args" + i + " onLeave: " + print_arg (this .params [i])); } this .logs =this .logs .concat ("retval onLeave: " + print_arg (retval) + "\n" ); console .log (this .logs ); } }); } catch (e) { console .log (e); } } hook_native_addr (Module .findBaseAddress ("lib52pojie.so" ).add (0x10544 ), 0x0 ); })();