指针扫描开发避坑记录
代码状态
ptrscan 相关代码已从 master 回滚。计划在支线分支重新开发。
踩过的坑
1. UE4 全局对象在堆上,不在 .data
- libUE4.so 的 rw- 段只有 84KB(0x15000)
- GEngine/GWorld/GUObjectArray 等全局对象通过 .data 里的指针间接引用
- 从 target 反向 BFS 8 层到不了 .data → 0 条有用链
- 教训: UE4 指针链深度 > 10 层,CE 默认 depth=7 不够
2. 代码段指令被误认为指针
- ARM64
bl指令编码0x94000071xxxxxxxxuntag 后落在堆地址范围 find_module_bsearch匹配了 r-x 代码段 → 垃圾 chain- 修复: 只认 rw- 段为 static base
3. base_offset 解算混乱
- 最初存 file-relative offset → _parse_address 匹配不上 segment
- 改成 segment-relative offset → 客户端不知道是哪个 segment
- 改成绝对地址 → 重启后失效
- 正确方案: 存 (module_name, segment_file_offset, offset_within_segment)
- 或者更简单:存绝对地址 + module name 用于显示,重启后重新扫描
4. BFS 内存爆炸
- 20M pairs × 16B × 2 (pairs + pairs_tmp) = 640MB → OOM 杀 server
- pairs_tmp 从未使用(radix sort 没实现,用的 qsort)→ 白分配 320MB
- BFS level 2 产生 1.7M hits 但 inner loop 不 break → 百万次无用迭代
- 教训: server 端 malloc 总量必须 < 200MB
- 修复: 删 pairs_tmp,inner loop break when nxt_level full
5. VMA bitmap vs 5M cap 截断
- 4.6GB 可读内存 → 48M 候选指针 → 5M cap 只覆盖 10%
- 提到 10M 后覆盖 ~20%,够找到 level 0 hits
- 教训: cap 按进程内存大小动态调整
6. QTimer.singleShot 从子线程静默失败
- worker thread 里用 QTimer.singleShot(0, lambda) 回调主线程 → 永远不执行
- UI 永远停在 “scanning…”
- 修复: 用 pyqtSignal.emit(线程安全的跨线程通信)
7. VMA iterator use-after-free(滑动窗口方案)
- drop mmap_read_lock → copy_to_user → reacquire 后,VMA_ITERATOR 的 maple tree cursor 指向已释放内存
- 修复: 放弃滑动窗口,改用 vmalloc 一整块(do_scan 模式)
8. untagged_addr 硬编码 39-bit
- SM8750 可能用 48-bit VA
- 硬编码
& 0x7FFFFFFFFF会截断有效指针 - 修复: 用内核
untagged_addr()宏
9. offset 顺序争议
- a4 reviewer 说需要 reverse,a5 说不需要
- 亲自 trace 确认:不需要 reverse
- BFS 输出
[closest_to_target, ..., closest_to_base] _resolve_pointer走range(len-1, -1, -1)先 deref 再加 offset → 正确
实测数据
| 指标 | 值 |
|---|---|
| FPS2 进程内存 | 4.6GB 可读,4096 VMAs |
| 模块数 | 1024 |
| libUE4.so 段数 | 4(r-x 5C5C000 + r-x 4936000 + r— 7F5000 + rw- 15000) |
| 10M pairs 收集 | ~1s |
| qsort 10M | ~0.5s |
| BFS 8 levels | ~0.5s |
| target 到对象头 offset | 0x1440(寄存器 x20 验证) |
| 访问代码 | libUE4.so+0x6D84C4C (LR) |
三个可行方向
方案 A: 内核态 BFS(最省内存)
- 不预收集 pair,每层直接 kmap 扫内存
- 内存 O(4MB),时间 O(depth × 2s)
- 最适合大游戏
方案 B: 正向追踪
- 从 .data 段已知全局指针出发,正向遍历对象树
- 需要 UE4 对象布局知识
方案 C: 断点辅助(已验证可行)
- 对 target 设 read 断点 → 寄存器反推对象指针
- x20 = 对象基址,offset = 0x1440
- 递归断点上层对象
- 手动但精确
Last updated on