hook initarray
如果init、initarray的函数是反调试函数的话,我们需要把这些函数给hook掉
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
| void* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo, const void* caller_addr) {
ProtectedDataGuard guard; soinfo* si = find_library(ns, translated_name, flags, extinfo, caller); loading_trace.End();
if (si != nullptr) { void* handle = si->to_handle(); LD_LOG(kLogDlopen, "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p", si->get_realpath(), si->get_soname(), handle); si->call_constructors(); failure_guard.Disable(); LD_LOG(kLogDlopen, "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p", si->get_realpath(), si->get_soname(), handle); return handle; }
return nullptr; }
|
由于Android系统是64位,逆向分析/system/bin/linker64
可执行文件
在符号表里搜索到call_constructorsEv
函数,在call_constructorsEv
函数onEnter
的时候去hook掉init
和initarray
代码逻辑就是要先通过hook dlopen
来判断是否是我们要hook的so文件,因为其他的so文件也会调用call_constructorsEv
,没有这个判断的话会影响其他so文件加载,然后通过Interceptor.replace
替换到initarray
函数,注意只能替换一次,所以要加上判断
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| function main() { function hook_dlopen(addr, soName, callback) { Interceptor.attach(addr, { onEnter: function (args) { var soPath = args[0].readCString(); if(soPath.indexOf(soName) != -1) hook_call_constructors(); }, onLeave: function (retval) { } }); } var dlopen = Module.findExportByName("libdl.so", "dlopen"); var android_dlopen_ext = Module.findExportByName("libdl.so", "android_dlopen_ext"); hook_dlopen(dlopen, "libxiaojianbang.so", inlineHook); hook_dlopen(android_dlopen_ext, "libxiaojianbang.so", inlineHook);
var isHooked = false; function hook_call_constructors() { var symbols = Process.getModuleByName("linker64").enumerateSymbols(); var call_constructors_addr = null; for (let i = 0; i < symbols.length; i++) { var symbol = symbols[i]; if(symbol.name.indexOf("__dl__ZN6soinfo17call_constructorsEv") != -1){ call_constructors_addr = symbol.address; } } console.log("call_constructors_addr: ", call_constructors_addr); Interceptor.attach(call_constructors_addr, { onEnter: function (args) { if(!isHooked) { hook_initarray(); isHooked = true; } }, onLeave: function (retval) { } }); }
function hook_initarray(){ var xiaojianbangAddr = Module.findBaseAddress("libxiaojianbang.so"); var func1_addr = xiaojianbangAddr.add(0x1C54); var func2_addr = xiaojianbangAddr.add(0x1C7C); var func3_addr = xiaojianbangAddr.add(0x1C2C); Interceptor.replace(func1_addr, new NativeCallback(function () { console.log("func1 is replaced!!!"); }, 'void', []));
Interceptor.replace(func2_addr, new NativeCallback(function () { console.log("func2 is replaced!!!"); }, 'void', []));
Interceptor.replace(func3_addr, new NativeCallback(function () { console.log("func3 is replaced!!!"); }, 'void', [])); } } main();
|
hook JNI_OnLoad
hook时机,在dlopen
onleave的时候去hook,此时JNI_OnLoad
还未执行,必须以no-pause
启动hook,不然so文件完全加载完成之后也来不及hook了,而以no-pause
启动的时候,此时js代码加载了而so文件未加载,如果不hook dlopen
的话,也是找不到so的基址的
其实和hook普通so层函数没有区别,也是获取so文件加载基址(因为dlopen
已经执行完毕,可以定位到so的基址,init
和initarray
可以理解为在dlopen
内部执行,所以相对复杂一点)
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
| function hook_dlopen(addr, soName, callback) { Interceptor.attach(addr, { onEnter: function (args) { var soPath = args[0].readCString(); if(soPath.indexOf(soName) != -1) this.hook = true; }, onLeave: function (retval) { if(this.hook) callback(); } }); }
var dlopen = Module.findExportByName("libdl.so", "dlopen"); var android_dlopen_ext = Module.findExportByName("libdl.so", "android_dlopen_ext"); hook_dlopen(dlopen, "libxiaojianbang.so", hook_JNIOnload); hook_dlopen(android_dlopen_ext, "libxiaojianbang.so", hook_JNIOnload);
function hook_JNIOnload() { var xiaojianbangAddr = Module.findBaseAddress("libxiaojianbang.so"); var funcAddr = xiaojianbangAddr.add(0x1CCC); Interceptor.replace(funcAddr, new NativeCallback(function () { console.log("this func is replaced !"); }, 'void', [])); }
|
hook pthread_create
一些检测函数需要实时运行,那么就有可能用pthread
开启一个子线程
hook它来查看开启了哪些子线程,把和检测相关的子线程hook掉
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function hook_pthread_create(){ var pthread_create_addr = Module.findExportByName("libc.so", "pthread_create"); console.log("pthread_create_addr: ", pthread_create_addr); Interceptor.attach(pthread_create_addr,{ onEnter:function(args){ console.log(args[0], args[1], args[2], args[3]); var Module = Process.findModuleByAddress(args[2]); if(Module != null) console.log(Module.name, args[2].sub(Module.base)); },onLeave:function(retval){ } }) } hook_pthread_create();
|