Syscall 表 Hook — 拦截系统调用最直接的方式
什么是 Syscall 表 Hook
Linux 内核里有一个全局数组叫 sys_call_table——每个索引对应一个系统调用号,数组元素指向该 syscall 的内核实现函数。syscall-table-hook 就是修改这个数组的某个条目,让它指向你自己的处理函数。
原 sys_call_table:[read_ptr, write_ptr, open_ptr, close_ptr, ...]
syscall-table-hook open 后:[read_ptr, write_ptr, my_open_ptr, close_ptr, ...]
↑ 指向你的函数
当用户态程序执行 open() 系统调用时,CPU 陷入内核态,内核根据 syscall 号查 sys_call_table,找到你装的 hook 函数并执行。
和 Inline-Hook 的区别
| 维度 | Syscall-Table-Hook | Inline-Hook |
|---|---|---|
| 修改位置 | sys_call_table 数组条目 | 目标函数开头的机器指令 |
| 可 hook 的目标 | 只能 hook syscall 处理函数(所有 syscall 都有表项) | 任何内核函数 |
| 实现复杂度 | 简单(替换指针) | 复杂(处理指令重定位、trampoline) |
| 适用场景 | 拦截用户态程序发起的系统调用 | 拦截任意内核路径 |
syscall-table-hook 是用户态 → 内核态 边界上最直接的拦截点。所有 App 操作文件、创建进程、访问网络都走 syscall——在这里做 hook 能覆盖所有 App 的行为。
典型用途
隐藏 Root 文件
最常见的用法:hook openat 或 access syscall。任何 App 尝试 open("/sbin/su") 或 access("/data/adb/..."),syscall-table-hook 直接让它返回"文件不存在"。
修改 syscall 返回值
某些 root 检测 App 会检查 syscall 的 errno 或特定返回值——KPM 可以在 hook 里修改这些值。
记录系统调用
调试用途——hook 所有 syscall 然后记录调用者、参数、返回值到内核日志,用于分析 root 检测逻辑。
KernelPatch 的 API
和 inline-hook 一样,KernelPatch 框架也封装了 syscall-table-hook 的 API:
struct kp_syscall_hook *hook = kp_syscall_hook_create(__NR_openat, my_openat_handler);
kp_syscall_hook_install(hook);
__NR_openat 是 syscall 号(ARM64 上 openat 的号是 56)。hook 处理函数签名和原 syscall 一致。
关于 ptrace 和 seccomp
现代 Android root 检测还可能用 ptrace 或 seccomp 来限制系统调用——syscall-table-hook 在这两类场景下都能生效,因为 hook 点在 ptrace/seccomp 之前。
性能影响
syscall 是用户态程序和内核最频繁的交互——每个文件操作、每次进程调度都涉及 syscall。syscall-table-hook 的单次开销很小(只是多一次指针跳转),但如果 hook 里做了复杂逻辑(比如路径匹配、文件 I/O),会显著拖慢系统性能。
建议:hook 里只做简单的判断,复杂逻辑放到异步处理。
局限性
syscall-table-hook 只覆盖用户态发起的 syscall——内核内部的操作(比如内核自己打开文件)不经过 sys_call_table,所以 hook 不到。这时候就需要 inline-hook 了。