fuqiuluo’s blog

记录美好生活

技术分享

安卓 - 基于异常的无痕Hook

#系统调用#作弊#内核#内核模块#Linux#安全
type
Post
status
Published
date
May 3, 2026
slug
summary
tags
系统调用
作弊
内核
内核模块
Linux
安全
category
技术分享
icon
password

核心原理

ARM64 页表项有一个 UXN(Unprivileged eXecute Never)位。将目标代码页的 PTE 设置 UXN=1 后,用户态执行该页任何指令都会触发 Instruction Abort(EC=0x20, DFSC=Permission Fault),陷入 EL1。
内核侧通过 inline hook do_mem_abort() 注册自定义 handler,在异常到达信号投递之前拦截。handler 检查 fault 地址是否属于已注册的断点页,是则修改 pt_regs->pc 重定向到预编译的 recomp(重编译)页,返回用户态后 CPU 从recomp 页继续执行。整个过程对用户态透明:没有 ptrace、没有 BRK 指令、没有信号投递。

重编译引擎

对目标页的全部 1024 条指令(4KB / 4 = 1024)做静态重编译:

两趟扫描

  • 布局计算:遍历每条指令,分类并计算 expansion 大小,构建 offset_map[insn_idx] → output_offset 映射表
  • 代码生成:根据分类结果 emit 重编译指令到 output buffer

指令分类与改写规则

指令类型
页内 (inpage)
页外 (outpage)
普通指令
1:1直通
B (无条件跳转)
重算 offset
nearby: 直接 B /far: 压栈 + 跳回原页触发 fault
BL (带链接跳转)
LR = 原始下一条,B 页内
LR = 原始下一条,B/BR 外部目标
B.cond / CBZ / TBZ
重算 imm
条件跳 + 8, B skip, far redirect
ADRP / ADR
LDR Xd, [PC, #8]; B skip; .quad addr
LDR literal
用 X17 做中转加载原始数据地址
关键设计:所有 PC-relative 指令都被改写为绝对寻址,保证在 recomp 页新位置上语义不变。
recomp 页以 VM_READ | VM_EXEC | VM_MIXEDMAP | VM_DONTDUMP 映射到目标进程用户空间,由 insert_vm_struct() 直接插入 VMA。

三种断点模式

BP_MODE_DBI(轻量断点,12 slot prefix)

BP_MODE_INSTRUMENT(全上下文,89 slot prefix)

BP_MODE_INLINE_HOOK(函数替换,4 slot prefix)

不保存 LR,handler 看到原始调用者的 LR。适合函数级替换。

Fault Handler 调度逻辑

Nearby vs Far 模式

recomp 页分配时用 get_unmapped_area(hint=原始页地址) 尝试就近分配:
  • Nearby(±120MB 内):outpage 分支直接用 B imm26(±128MB 范围),零寄存器污染
  • Far(超出范围):压 32 字节栈帧(saved X17 + magic + target PC),跳回原始 UXN 页触发 fault,fault handler 从栈帧取出真实目标地址
BP_FLAG_NO_NEARBY 可强制 far 模式.
Loading...