作者论坛账号:CIBao
前言[toc]
对于自动化hookIl2cpp的模块来说,dlopen的hook相当于一个大门,没有该大门口,一切都是纸上谈兵
在armabi-v7a上hookdlopen,轻松的不要不要的,甚至借用一下virtual系列app的va++核心提供的hook_dlopen函数的接口都行
可是到了aarch64这里,找了一圈,能用的hook构件也就一枚And64InlineHook,而且源项目好像还得自己手动修一下才能使用....(可惜whale不支持安卓10,原hookzz的Dobby也木大)
好了有hook构件了,但是我看了一圈主流的VirtualApp商业授权做出来的虚拟多开系列软件,基本上都没实现aarch64的hook_dlopen,有的实现了却没有给调用,自己去调用的话就会卡死(还想借鉴一下方案,逃个课先)
环境预习测试平台机型:红米K30-4G,已Root系统:miui11,android-10
看雪上看到的一篇文章:Android9.0hookdlopen问题虽然半年前就看到这篇文章,但是基本上在看天书,现在拿出来看了一圈,关键实现就是这里虽然我看不懂什么LR寄存器什么的,但是唯独看懂这第三个参数强制赋值为dlerror函数的函数地址,以达到越过系统的限制
而关于那所谓的系统限制,就是在安卓7开始,系统就禁止用户APP打开/读取部分系统库文件,所以直接dlopenlinker会直接失败,具体可以使用dlerror()函数查看原因(懒不贴图了)
初步尝试Hook反汇编libdl.so貌似安卓9开始,dlopen就由libdl.so库进行导入,反汇编看看
看了一下导出函数,也就只有两个函数涉及到dlopen
让我康康这个dlopen长什么样!
中间的.__loader_dlopen是个跳板
最终指向的是got表的导出变量__loader_dlopen
康康__loader_dlopen步骤很简单
加载libdl.so
使用dlsym()获取__loader_dlopen
打印该值,顺便看看该内存所在maps的何处
LOGE("pid:%d",getpid());void*libdl_handle=dlopen("libdl.so",RTLD_NOW);LOGE("libdl_handle:%p",libdl_handle);void*__loader_dlopen_addr=dlsym(libdl_handle,"__loader_dlopen");LOGE("__loader_dlopenat:%p",__loader_dlopen_addr);
先查看logcat输出__loader_dlopen的值为0xf11c
使用adbshell去查看对应的内存区段
adbshellsu#升级为root用户cat/proc/目标pid/maps
跑到linker64里去了,把文件提取出来反汇编,顺便先把这__loader_dlopen的偏移值算出来0xf11c-0x=0xC
反汇编linker64利用刚刚算出来的偏移,转跳后发现指向的是linker64里的__loader_dlopen函数
淦ta直接一套组合拳打在__loader_dlopen函数上!
//定义原型void*(*orig___loader_dlopen)(constchar*,int,constvoid*)=nullptr;void*new___loader_dlopen(constchar*filename,intflags,constvoid*caller_addr){void*handle=orig___loader_dlopen(filename,flags,caller_addr);LOGE("LoadedLib:{%s}:%p",filename,handle);returnhandle;}//执行hookLOGE("pid:%d",getpid());void*libdl_handle=dlopen("libdl.so",RTLD_NOW);LOGE("libdl_handle:%p",libdl_handle);void*__loader_dlopen_addr=dlsym(libdl_handle,"__loader_dlopen");LOGE("__loader_dlopenat:%p",__loader_dlopen_addr);A64HookFunction(__loader_dlopen_addr,(void*)new___loader_dlopen,(void**)orig___loader_dlopen);
然后TM就蹦了!
骚操作Hook各种骚操作(木大)一开始以为是hook构件出问题,各种log查看后来试试whale,但这玩意不支持安卓10(淦)然后试试直接dlopen直接加载libil2cpp.so,也木大尝试直接加载linker64再去hook,但这玩意直接被限制,读取都做不到一天下来,都要放弃了,突然想到一个骚主意,再试试吧
解析转跳指令__loader_dlopen函数中实际上进行dlopen的是该函数
不过由于没法进行加载linker64文件,正常手段根本获取不到这玩意(virtualApp的解析用上了open函数,但是linker64文件无法被加载...木大)
不过好在我有解析过Bxx指令的经验相关文章:B与BL跳转指令目标地址计算方法(aarch64无需再+8)
关键逻辑就是(手动计算时,注意大小端转换!人话就是,字节倒序才是内存中实际的样子!)
指令进行左移8位(2字节)去掉转跳指令
右移8位,高位空缺填补回去
左移2位,获得实际的转跳偏移
合并到一起就变成了
//提取B指令的偏移!!指令为4字节,一定要用对应的数据类型#defineExtract(symbol)(*(int32_t*)(symbol)86)测试看看
计算目标指令的偏移(目标指令地址-函数头地址=偏移)0x-0xC=0x44
上代码!
//提取B指令的偏移#defineExtract(symbol)(ulong)(*(int32_t*)(symbol)86)//内存偏移templateclassTinlineTMemoryOff(void*addr,ulongoff){return(T)((char*)addr+off);}//修正B指令转跳templatetypenameTinlineTAmend_Bxx(Tsymbol){returnMemoryOffT((void*)symbol,Extract(symbol));}//打印autob_do_dlopen=MemoryOffvoid*(__loader_dlopen_addr,0x44);LOGE("hex:%x",*(int32_t*)b_do_dlopen);autodo_dlopen=Amend_Bxx(b_do_dlopen);LOGE("do_dlopen:%p",do_dlopen);
让我康康!
指令是没错了,解析也正常,看看打印出来的地址是否正确0xc4-0x=0x3C2C4
完美!!
进行Hook直接提着地址进行hook!
//源函数声明void*(*_DlopenV26)(constchar*,int,int,int)=nullptr;void*DlopenV26(constchar*name,intflag1,intflag2,intflag3){void*handle=_DlopenV26(name,flag1,flag2,flag3);if(handle!=nullptr)LOGE("LoadedLib:{%s}:%p",name,handle);returnhandle;}//hookA64HookFunction(do_dlopen,(void*)DlopenV26,(void**)_DlopenV26);
终于成功!!
关于Bxx指令偏移目前只反编译过红米K30-4G,红米K20Pro的linker64文件偏移均为0x44,其他机型的linker64文件建议自行反编译看看因为用的是骚操作,能用就已经算不错了T_T
总结本方法算是笨方法,不过总算有个门能让我踏进aarch64的世界了有点诡异的是,不知为何hook__loader_dlopen函数会奔溃理论上Bxx指令的偏移都是0x44,源码的实现都应该一样的至于其他安卓版本....手头上就只有安卓10啊,有心无力...
--官方论坛