bytedance / bhook

:fire: ByteHook is an Android PLT hook library which supports armeabi-v7a, arm64-v8a, x86 and x86_64.
https://github.com/bytedance/bhook/tree/main/doc#readme
MIT License
2.05k stars 315 forks source link

Android 9部分设备上hook 失败 #94

Closed Gangbadei closed 6 months ago

Gangbadei commented 6 months ago

bytehook Version

1.0.10

Android OS Version

9.0

Android ABIs

arm64-v8a

Device Manufacturers and Models

vivo y5s, oppo A8

Describe the Bug

现象:hook 失败,在dladdr 之后打印dl_info 的数据,和目标符号不匹配

调试过程:

  1. hook 的时候发现没有打印 hook chain: verify OK,在bh_hook_manager_verify_got_value 失败的代码里加了日志打印。 hook 失败的设备上打印了新增的日志

  2. 在bh_hook_manager_verify_got_value中的 dladdr 之后添加了dl_info 的日志,发现hook 失败时打印出的符号和hook的目标符号对不上 图2

    正常hook的日志 ---- bytehook_tag: check for normal export func: _Z9FindEntryPvRK9ZipStringP8ZipEntry

hook失败的日志 ---- bytehook_tag: check for normal export func: _Z12EndIterationPv

  1. 代码里把 bh_hook_manager_verify_got_value 校验跳过之后,目标符号 hook 正常

异常设备的so: libandroidfw.so.zip 正常设备的so: libandroidfw_normal.so.zip

调用代码: hacker.c.zip

Gangbadei commented 6 months ago

bh_hook_manager_verify_got_value失败的日志打印: image

dladdr 之后的dl_info 打印: image

caikelun commented 6 months ago

看了下 android 9 OPPO A8 的 ARM64 libziparchive.so:

$ llvm-readelf -sW ./libziparchive.so
......
85: 000000000000a274     8 FUNC    GLOBAL DEFAULT    12 _Z12EndIterationPv
98: 000000000000a278     4 FUNC    GLOBAL DEFAULT    12 _Z9FindEntryPvRK9ZipStringP8ZipEntry
......

可以看到这两个函数是紧挨着的,结合 _Z12EndIterationPv 的汇编分析,它的体积应该是 4 字节才对,现在错误的记录为了 8 字节,导致和 _Z9FindEntryPvRK9ZipStringP8ZipEntry 的地址范围重叠了

bh_hook_manager_verify_got_value 调用 dladdr 获取地址对应的符号名,最终 dladdr 会走到如下函数:

static bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
  return sym->st_shndx != SHN_UNDEF &&
      soaddr >= sym->st_value &&
      soaddr < sym->st_value + sym->st_size;
}

在这个函数中,会发现 _Z12EndIterationPv 的地址范围已经 match,于是就直接返回了,dladdr 只会返回第一个 match 的函数信息。

这问题的根本原因是设备上的 libziparchive.so 的符号表中信息有错误。

可以先注释掉对 bh_hook_manager_verify_got_value 的调用,一般来说没什么问题。这个检测的目的是:如果在 bytehook hook 某个函数之前,已经有其他 hook 逻辑替换了当前 GOT 中的函数地址值(已经被hook了),那么 bytehook 再替换的话,就影响了之前的hook效果,bytehook的初衷是为了在 app 中统一集中管理所有的 PLT hook,因此遇到这种情况的话,就返回失败了,后续再通过 errno 来手动解决冲突问题。

Gangbadei commented 6 months ago

收到 多谢解答。