首页
社区
课程
招聘
[原创] Android10 aarch64 dlopen Hook
发表于: 2021-5-7 11:22 14100

[原创] Android10 aarch64 dlopen Hook

2021-5-7 11:22
14100

对于自动化hook Il2cpp 的模块来说, dlopen 的hook相当于一个大门, 没有该大门口, 一切都是纸上谈兵

armabi-v7a 上hook dlopen, 轻松的不要不要的, 甚至借用一下 virtual 系列app的 va++ 核心提供的 hook_dlopen 函数的接口都行

可是到了 aarch64 这里, 找了一圈, 能用的 hook构件 也就一枚 And64InlineHook, 而且源项目好像还得自己手动修一下才能使用....

好了有 hook构件 了, 但是我看了一圈主流的 VirtualApp 商业授权做出来的 虚拟多开 系列软件, 基本上都没实现 aarch64hook_dlopen, 有的实现了却没有给调用, 自己去调用的话就会卡死

就你妈离谱

看雪上看到的一篇文章: Android9.0 hook dlopen问题
虽然半年前就看到这篇文章,但是基本上在看天书,现在拿出来看了一圈, 关键实现就是这里

虽然我看不懂什么 LR寄存器 什么的, 但是唯独看懂这第三个参数强制赋值为 dlerror 函数的函数地址, 以达到越过系统的限制

而关于那所谓的系统限制, 就是在安卓7开始, 系统就禁止 用户APP 打开/读取 部分 系统库文件 , 所以直接 dlopen linker 会直接失败, 具体可以使用 dlerror() 函数查看原因

貌似安卓9开始, dlopen就由 libdl.so 库进行导入, 反汇编看看

看了一下导出函数, 也就只有两个函数涉及到dlopen

让我康康这个 dlopen 长什么样!

中间的 .__loader_dlopen 是个跳板

最终指向的是got表的导出变量 __loader_dlopen

步骤很简单

先查看logcat输出

__loader_dlopen 的值为0x700258f11c

使用adb shell去查看对应的内存区段

跑到 linker64 里去了, 把文件提取出来反汇编, 顺便先把这 __loader_dlopen 的偏移值算出来
0x700258f11c - 0x7002557000 = 0x3811C

利用刚刚算出来的偏移,转跳后发现指向的是 linker64 里的 __loader_dlopen 函数

直接一套组合拳打在 __loader_dlopen 函数上!

然后TM就蹦了!

一开始以为是hook构件出问题, 各种log查看
后来试试whale, 但这玩意不支持安卓10
然后试试直接dlopen直接加载 libil2cpp.so, 也木大
尝试直接加载 linker64 再去hook, 但这玩意直接被限制, 读取都做不到
一天下来, 都要放弃了, 突然想到一个骚主意, 再试试吧

__loader_dlopen 函数中实际上进行dlopen的是该函数

不过由于没法进行加载 linker64 文件, 正常手段根本获取不到这玩意
(virtualApp的解析用上了open函数, 但是linker64文件无法被加载...木大)

不过好在我有解析过 Bxx指令 的经验
相关文章: B与BL跳转指令目标地址计算方法 (aarch64无需再+8)

关键逻辑就是 (手动计算时,注意大小端转换! 人话就是,字节倒序才是内存中实际的样子!)

合并到一起就变成了

计算目标指令的偏移(目标指令地址-函数头地址=偏移)
0x38160 - 0x3811C = 0x44

上代码!

让我康康!

指令是没错了, 解析也正常, 看看打印出来的地址是否正确
0x70025932c4 - 0x7002557000 = 0x3C2C4

完美!!

直接提着地址进行hook!

终于成功!!

目前只反编译过 红米K30-4G, 红米K20Prolinker64 文件
偏移均为 0x44, 其他机型的 linker64 文件建议自行反编译看看
因为用的是骚操作, 能用就已经算不错了 T_T

本方法算是笨方法, 不过总算有个门能让我踏进 aarch64 的世界了
有点诡异的是, 不知为何hook __loader_dlopen 函数会奔溃
理论上 Bxx指令 的偏移都是 0x44, 源码的实现都应该一样的
至于其他安卓版本....手头上就只有安卓10啊, 有心无力...


 
 
 
 
测试平台
机型: 红米K30-4G, 已Root
系统: miui11, android-10
测试平台
机型: 红米K30-4G, 已Root
系统: miui11, android-10
 
 
 
 
 
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_dlopen at: %p", __loader_dlopen_addr);
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_dlopen at: %p", __loader_dlopen_addr);
 
adb shell
su #升级为root用户
cat /proc/目标pid/maps
adb shell
su #升级为root用户
cat /proc/目标pid/maps
 
// 定义原型
void *(*orig___loader_dlopen)(const char *, int , const void *) = nullptr;
void *new___loader_dlopen(const char *filename, int flags, const void *caller_addr)
{
    void *handle = orig___loader_dlopen(filename, flags, caller_addr);
    LOGE("LoadedLib: {%s}:%p", filename, handle);
    return handle;
}
 
//执行hook
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_dlopen at: %p", __loader_dlopen_addr);
 
A64HookFunction(__loader_dlopen_addr, (void *)new___loader_dlopen,
                (void **)&orig___loader_dlopen);
// 定义原型
void *(*orig___loader_dlopen)(const char *, int , const void *) = nullptr;
void *new___loader_dlopen(const char *filename, int flags, const void *caller_addr)
{
    void *handle = orig___loader_dlopen(filename, flags, caller_addr);
    LOGE("LoadedLib: {%s}:%p", filename, handle);
    return handle;
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 6
支持
分享
最新回复 (8)
雪    币: 916
活跃值: (3434)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
2
"可是到了 aarch64 这里, 找了一圈, 能用的 hook构件 也就一枚 And64InlineHook"

dobby、frida-gum 哭晕在厕所
2021-5-9 11:18
1
雪    币: 29
活跃值: (5637)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3

hook一下linker内的__dl__ZN19android_namespace_t13is_accessibleERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE,也就是android_namespace_t::is_accessible,让它永远返回true即可解决namespace限制问题

最后于 2021-5-26 13:05 被不吃早饭编辑 ,原因:
2021-5-26 13:05
1
雪    币: 3064
活跃值: (7803)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
葫芦娃 "可是到了 aarch64 这里, 找了一圈, 能用的 hook构件 也就一枚 And64InlineHook" dobby、frida-gum 哭晕在厕所
嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻 活捉葫芦娃一枚
2021-5-26 13:11
0
雪    币: 29
活跃值: (5637)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
文中通过解析opcode得到的那个函数其实是linker的导出函数,手动解析一下linker的导出表(linker其实就是一个特殊的elf文件)即可直接得到该函数的offset
2021-5-26 13:18
0
雪    币: 29
活跃值: (5637)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6

另外linker并不存在无法加载的问题,因为实际上zygote进程启动时内存中装载的第一段内存的就是linker文件的映射。可以通过解析maps来获取内存中加载好的linker的文件路径

最后于 2021-5-26 13:24 被不吃早饭编辑 ,原因:
2021-5-26 13:23
0
雪    币: 3347
活跃值: (13988)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
7
和VA里面代码差不多,VA里面是通过systemcall去查找linker地址,然后进行Hook的
2021-5-26 14:18
0
雪    币: 2089
活跃值: (3933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
恩,楼主绕了太大的弯子,推荐看看我开源的这个:https://github.com/2-young-2-simple/VirtualApp
把仅ARM注释掉,同样支持ARM64的hook,dlopen的钩子实际上不一定要在dlopen上弄,不是会有个回调函数嘛
2021-5-30 08:59
0
雪    币: 59
活跃值: (185)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
dlopen、linker都是开源的。。。。
2021-9-17 10:45
0
游客
登录 | 注册 方可回帖
返回
//