3-28 指针扫描DFS重写 + FPS2弹药链修正
成果
稳定弹药指针链(已验证,死亡重生后依然有效)
GEngine (libUE4.so+0xB034CD8, 在BSS段)
→ +0x780 GameViewportClient
→ +0x78 GameInstance
→ +0x38 LocalPlayers TArray.Data
→ [0] deref
→ +0x30 PlayerController
→ +0x260 Character
→ +0x750 Actor Weapon ← BP_LPSP_PCH_C层,非C++层
→ +0x1440 Ammo (int32)GEngine运行时地址 = libUE4.so rw-段基址 + 0x2ADCD8(rw-段file_offset=0xAD87000,GEngine file_offset=0xB034CD8)
关键修正:+0x120 → +0x750
- 旧链 Char+0x120:C++层ALPSPCharacter的字段,死亡后不更新,指向已销毁的旧武器对象
- 新链 Char+0x750:Blueprint层BP_LPSP_PCH_C的
Actor Weapon字段,死亡重生后正确指向新武器 - 根因:游戏实际玩家类是
BP_LPSP_PCH_C → ABP_PlayerBase_C → ALPSPCharacter,SDK dump中BP_BaseCharacter_C是另一个独立继承链,offset完全不同
DFS指针扫描重写
将shadow_ce.ko的指针扫描从BFS改为DFS(参考mypower项目):
- 算法:递归DFS + result_max剪枝(DFS_BRANCH_MAX=2048)
- 原理:每层扫全部RW内存找指向当前target的指针,超过阈值则剪枝跳过
- 结果:226秒找到10条depth 8-9的链到达libUE4.so静态段
- 内存:~200KB(vs BFS的128MB),不会OOM
过程中踩的坑
BFS失败记录
- 节点爆炸:offset=8192时depth 3就500K+ hits,撞4M节点上限,到不了depth 8
- per-node=3太狠:学CE设max_per_node=3,整棵树被掐死,10层才625个节点
- per-layer cap:100K/层还是不够,depth 3仍然爆
DFS调参
- DFS_BRANCH_MAX=512:depth 1有513个hit,差1个被全剪。提到2048解决
- 找到的链不稳定:DFS找到的10条链,靠近静态端的前3跳经过堆临时对象,GC后断裂
- 结论:反向指针扫描对UE4本质上很难,正向SDK offset才是正确方向
SDK offset踩坑
- BP_BaseCharacter_C vs BP_LPSP_PCH_C:两个不同继承链,offset完全不同
BP_BaseCharacter_C+0x510= CurrentWeaponBP_LPSP_PCH_C+0x510= PlayerTagWidget(是Widget不是武器!)
- *Character+0x508 (Magazine)**:C++层ALPSPCharacter字段,死亡后指向被释放的对象
- execInstanceVariable:UE4 Blueprint变量访问器,offset不硬编码,从UProperty元数据运行时读取
新增/修改文件
shadow_ce.c
do_ptrscan:BFS → DFS重写dfs_scan_one:扫描所有RW页找指向target的指针dfs_frame/dfs_hit:DFS栈帧结构- ART文件过滤:.vdex/.odex/.art/.dex/.oat不作为静态基址
chain_read.c(新增)
- 简单的指针链追踪工具
- 用法:
chain_read <pid> <addr> [+off1 +off2 ...] - 通过/dev/shadow_ce ioctl读内存
参考
- mypower :userspace DFS指针扫描,result_max=512剪枝,offset_max=512,process_vm_readv
- CE默认max_per_node=3,对UE4不适用(堆对象引用太密集)
下一步
- 把链写入shadow_ce客户端作为pointer chain follow功能
- 找HP(HealthComponent+0x4F8附近)和备用弹药
- 验证链跨游戏重启(杀进程重开)是否稳定
Last updated on