KernelHook 是一个面向 Android ARM64/GKI 内核的可加载内核模块(LKM)Hook 框架,源自B佬的KernelPatch 项目。该框架提供了完整的内核函数拦截与修改能力,支持多种 Hook 模式,可用于内核研究、安全分析、系统定制等场景。
接触到kpm不久后就移植了kp的hook和kpm加载框架,中途一直有涂涂改改,但没上什么应用场景测试,索性就开源,欢迎佬们进行应用测试,最终反哺回kp。当前代码框架基本与kp一致,底层稍微动了一下,但不影响kpm的转换
Inline Hook 通过直接修改目标函数入口的指令来实现拦截:
工作流程:
Wrap 模式允许在原函数执行前后插入多个回调:
执行顺序:
针对函数指针表的 Hook,适用于:
框架自动生成支持 0-12 个参数的回调类型:
Inline Hook 覆盖目标函数入口后,需要确保原函数能继续正确执行。ARM64 大量使用 PC-relative 指令,必须重写这些指令的目标地址。
支持的指令类型:
重定位策略:
模块加载时分配一段可执行内存区域用于存储 Hook 元数据和 trampoline 代码:
内存布局:
生命周期管理:
安全的代码修补后端,支持两种路径:
高版本 Android 内核启用 KCFI(Kernel Control Flow Integrity)后,间接调用会检查函数类型。本框架通过 Hook CFI 检查函数来实现绕过:
绕过逻辑:
提供了对系统调用的便捷 Hook 支持:
封装策略:
Rust 编写的模块加载器,简化设备端部署:
功能:
快速使用:
推荐测试组合:
一些小说明
项目链接 658K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6F1K9i4q4A6N6i4q4A6N6i4S2Q4x3V1k6S2M7X3@1$3y4q4)9#2k6X3E0W2M7X3&6W2L8q4)9#2k6X3S2G2L8$3D9`.
| 指令类型 |
说明 |
重定位长度 |
B, BL |
相对跳转 |
6-8 条 |
B.cond |
条件分支 |
8 条 |
ADR, ADRP |
地址加载 |
4 条 |
LDR literal |
常量池加载 |
6 条 |
CBZ/CBNZ |
条件比较跳转 |
6 条 |
TBZ/TBNZ |
位测试跳转 |
6 条 |
| 其他 |
原样复制 |
2 条 |
| 参数 |
默认值 |
说明 |
enable_selftests |
0 |
运行时执行本地自测 |
enable_inline_selftests |
0 |
执行 inline hook/wrap 自测 |
enable_fp_selftests |
0 |
执行函数指针 hook/wrap 自测 |
enable_syscall_selftests |
0 |
执行 syscall hook 自测 |
enable_vfs_demo |
1 |
安装 vfs_open demo hook |
arm64_kernel_hook/
├── lkm.c
├── hook.h
├── hook_types.h
│
├── hook_chain.c
├── fp_hook.c
├── hook_reloc.c
├── hook_chain_ops.h
│
├── hotpatch.c
├── hmem.c
├── pgtable.c
├── cache.h
│
├── secpass.c
├── kallsyms_name.c
├── syscall.c
│
├── log.h
├── hook_utils.h
│
├── hook_runtime.h
├── hook_transit_ops.h
│
└── loader/
├── src/main.rs
├── Cargo.toml
└── .cargo/config.toml
原始函数入口: 备份并重定位的 trampoline:
LDR X17,
RET X17 -> [原始指令2] NOP
-> JUMP BACK
hook_wrap(func, argno, before, after, udata);
before A
before B
origin_func() // 原始函数
after B
after A
fp_hook(fp_addr, replace_func, &backup);
fp_hook_wrap(fp_addr, argno, before, after, udata);
typedef void (*hook_chainN_callback)(hook_fargsN_t *fargs, void *udata);
hook_wrap2(func, my_before, my_after, NULL);
fp_hook_wrap4(fp_addr, before, after, udata);
text = hook_alloc(PAGE_SIZE * 10);
hook_mem_add((uint64_t)text, size);
stop_machine()
↓
fixmap 映射目标页
↓
copy_to_kernel_nofault()写入
↓
caches_clean_inval_pou()
↓
其他 CPU isb()完成
report_cfi_failure
__cfi_slowpath_diag
__cfi_slowpath
__cfi_check
__cfi_check_fail
syscall_init();
hook_syscalln(nr, narg, before, after, udata);
unhook_syscalln(nr, before, after);
cargo run -- --adb-run \
--device-loader target/aarch64-linux-android/release/hook-loader \
--name hook_module \
../hook_module.ko \
enable_selftests=0 enable_vfs_demo=1
enable_selftests=1 enable_inline_selftests=0 enable_fp_selftests=1 enable_syscall_selftests=0 enable_vfs_demo=0
enable_selftests=1 enable_inline_selftests=1 enable_fp_selftests=1 enable_syscall_selftests=1 enable_vfs_demo=0
enable_selftests=0 enable_inline_selftests=0 enable_fp_selftests=0 enable_syscall_selftests=0 enable_vfs_demo=1
推荐使用ddk进行构建,ci中也构建好了demo,可在action下载测试
cd loader
cargo check
cargo build --target aarch64-linux-android --release
hook_err_t hook(void *func, void *replace, void **backup);
void unhook(void *func);
hook_err_t hook_wrap(void *func, int32_t argno, void *before, void *after, void *udata);
void hook_unwrap(void *func, void *before, void *after);
hook_wrap0() ~ hook_wrap12()
int fp_hook(uintptr_t fp_addr, void *replace, void **backup);
int fp_unhook(uintptr_t fp_addr, void *backup);
hook_err_t fp_hook_wrap(uintptr_t fp_addr, int32_t argno, void *before, void *after, void *udata);
void fp_hook_unwrap(uintptr_t fp_addr, void *before, void *after);
fp_hook_wrap0() ~ fp_hook_wrap12()
void my_before(hook_fargs4_t *fargs, void *udata) {
fargs->arg0 += 1;
}
void my_after(hook_fargs4_t *fargs, void *udata) {
fargs->ret += 100;
}
hook_wrap4(some_func, my_before, my_after, NULL);
接触到kpm不久后就移植了kp的hook和kpm加载框架,中途一直有涂涂改改,但没上什么应用场景测试,索性就开源,欢迎佬们进行应用测试,最终反哺回kp。当前代码框架基本与kp一致,底层稍微动了一下,但不影响kpm的转换
| 指令类型 |
说明 |
重定位长度 |
B, BL |
相对跳转 |
6-8 条 |
B.cond |
条件分支 |
8 条 |
ADR, ADRP |
地址加载 |
4 条 |
LDR literal |
常量池加载 |
6 条 |
CBZ/CBNZ |
条件比较跳转 |
6 条 |
TBZ/TBNZ |
位测试跳转 |
6 条 |
| 其他 |
原样复制 |
2 条 |
| 参数 |
默认值 |
说明 |
enable_selftests |
0 |
运行时执行本地自测 |
enable_inline_selftests |
0 |
执行 inline hook/wrap 自测 |
enable_fp_selftests |
0 |
执行函数指针 hook/wrap 自测 |
enable_syscall_selftests |
0 |
执行 syscall hook 自测 |
enable_vfs_demo |
1 |
安装 vfs_open demo hook |
- Inline Hook:直接修改目标函数入口指令,实现函数拦截
- Inline Wrap:支持在函数调用前后插入多个回调,形成链式拦截
- Function Pointer Hook:修改函数指针表(如 syscall table、ops 结构)
- Function Pointer Wrap:函数指针的链式包装与回调
- ARM64 指令重定位:自动处理 PC-relative 指令的重定位
- KCFI 绕过:兼容高版本内核的 CFI 安全机制
- 热补丁支持:使用 fixmap + stop_machine 实现安全的代码修补
before 回调可以修改参数(fargs->arg0 等)
after 回调可以修改返回值(fargs->ret)
- 设置
skip_origin = 1 可跳过原函数
- Syscall Table(
sys_call_table[nr])
- VFS operations(
file_operations、inode_operations)
- 其他函数指针数组
- 将分配区域划分为多个
hook_mem_warp_t 槽位
- 每个槽位可存储
hook_t、hook_chain_t 或 fp_hook_chain_t
- 使用位图快速查找空闲槽位
- 支持引用计数,防止提前释放
hook_mem_zalloc(): 分配 Hook 内存
hook_mem_get(): 增加引用计数
hook_mem_put(): 减少引用计数
hook_mem_retire(): 标记为已释放但不复用(防止野指针)
- 临时修改页表权限为可写
- 直接内存写入
- flush I-cache
- 恢复页表权限
- 检查目标地址是否在本模块 Hook 内存范围内
- 如果是,直接返回/忽略,允许执行
- 模块卸载时恢复所有修改
- 如果能获取
sys_call_table,使用函数指针 hook
- 否则通过符号名解析,使用 inline hook
- 自动检测是否使用 syscall wrapper
TRAMPOLINE_MAX_NUM = 6
RELOCATE_INST_NUM = 56
HOOK_CHAIN_NUM = 16
FP_HOOK_CHAIN_NUM = 32
- 1.有的地方函数并没有适配的很好,因为默认测试6.1和6.6的设备,一些有问题的地方可以发issue
- 2.在hook_alloc和hook_module_prepare_text这个地方有需要的可以去改改
- 3.可以将hook函数gpl导出,安装hook模块后,编写新的模块直接用(后面有空会规范一下代码推上去,都测试好了的
- 备份目标函数入口前 4-5 条指令
- 生成跳转指令写入函数入口,跳转到替换函数
- 将备份指令搬迁到可执行内存区域并重定位
- 卸载时恢复原始指令
- 解码指令,提取目标地址
- 如果目标在 trampoline 区域,映射到重定位后的新地址
- 生成等价的绝对跳转序列
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!