convenientlymike/android-inline-hook-mapping-trap
GitHub: convenientlymike/android-inline-hook-mapping-trap
一个用于诊断和修复 Android/Linux arm64 上 inline hook 因共享库双重映射而零触发问题的 /proc/maps 地址解析工具。
Stars: 0 | Forks: 0
# 🪤 错误映射陷阱
### 为什么你字节级完美的 Android/Linux inline hook 触发了 **0 次** — 以及 40 行代码的修复方案
[](https://github.com/convenientlymike/android-inline-hook-mapping-trap/actions/workflows/ci.yml)
[](LICENSE)


*你的 inline patch已存在于 `/proc/pid/mem` 中。安装程序提示 OK。进程也没有崩溃。但它触发了
**零**次 —— 而基于 ptrace 的工具 hook 了“相同”的地址却运行正常。这个仓库解释了其中的原因,并
解析出 CPU **实际执行**的地址。*
## 原因
你编写了一个原生的 inline hook。你逐字节地验证了已修补的字节确实存在于内存中。`mprotect` 成功了。
进程存活且健康。但你的 hook 主体从未运行。
陷阱在于:**一个共享库通常会被多次映射到一个进程中** —— 既包含原始文件的 `mmap`,*也*包含
动态链接器的 ELF `LOAD` 镜像。每个人都会写的那种简易解析器 —
```
module_base = lowest_mapping_of(lib); // ← wrong
target = module_base + rva;
```
— 选中的是**原始文件 mmap**,因此你的 patch 落在了一份 **CPU 永远不会执行的**代码副本上。ptrace 工具
(如 gdb,或 frida 风格的 server)之所以有效,是因为其 ELF 解析器针对的是*真正的* `LOAD` 段。相同的 RVA,不同的
mapping,截然相反的结果。为了弄清楚这一点,足足耗费了一整场调试时间(驳回了五个关于“缓存一致性”的假设)。
## ▶️ 复现问题
```
$ python mapping_trap.py 4123 libapp.so 0x2000000
resolving 'libapp.so' @ rva 0x2000000:
mapping groups for lib : 2 ⚠️ TWICE-MAPPED — the trap is live
.text (largest r-xp) : 0x7e0000001000-0x7e0006001000 (96.0 MB) r-xp
ELF load base (off==0) : 0x7e0000000000
✅ executed address : 0x7e0002000000 (load_base + 0x2000000)
❌ naive lowest+rva : 0x700002000000 ← WRONG (this is where a 0-fires hook lands)
```
一个是实际触发的地址。另一个则是你浪费生命的地方。
## 修复方案
对 `/proc/pid/maps` 进行两次遍历,与具体库无关:
1. **找到真正的 `.text`** —— 该库*最大的连续 `r-xp`* 段。这就是区分
ELF `LOAD`(一个大的可执行段)和原始文件 mmap(稀疏、部分可执行的页面)的关键 —— 即使原始
mmap 包含一个诱饵的可执行页面。
2. **将该组中 `off==0` 的 mapping 作为 ELF 加载基址**,而实际执行的地址即为 `load_base + rva`
(其中 `rva` 是 dumper 的*虚拟地址*偏移量,**而不是**文件偏移量)。这在字节级别上等同于 ptrace 工具的
`module.base + rva`。
```
from mapping_trap import resolve_executed_addr
res = resolve_executed_addr(open(f"/proc/{pid}/maps").read(), "libapp.so", 0x2000000)
print(hex(res.address)) # the executed address — patch HERE
print(res.mapping_groups) # > 1 ⇒ the trap is live
print(hex(res.naive_address)) # where "lowest mapping + rva" would have (wrongly) landed
```
## 快速开始
```
git clone https://github.com/convenientlymike/android-inline-hook-mapping-trap
cd android-inline-hook-mapping-trap
python -m pytest -q # 5 tests, ~0.01s
python mapping_trap.py 提炼自一场真实的调试马拉松。如果它能为你省下我为此耗费的一小时,那它的使命就完成了。
标签:逆向工具