Linux内核函数运行时Hook异常:无效或系统崩溃原因排查
内核函数Hook问题排查:部分函数无响应或系统冻结
背景
我尝试通过LKM在运行时Hook任意Linux内核函数,提取传递给它们的参数。
用户态编排逻辑步骤
- 调用LKM获取待Hook函数的地址
hooked_addr; - 反汇编
hooked_addr处内容,找到总长度≥13字节的连续指令序列(13字节对应movabs r10,imm+jmp r10的长度); - 将该连续指令序列保存到
replaced_insns,用于在shim返回原函数前执行; - 调用LKM分配可执行内存,保存地址到
exec_addr; - 调用LKM获取用于提取参数的拦截函数“shim”的地址
shim_addr; - 构造
movabs r10,${exec_addr}; jmp r10;的机器码,补nop至指令总长度后保存到hook_insns; - 计算
jmp_back_addr=hooked_addr+ 提取的连续指令总长度; - 构造
movabs r10,${jmp_back_addr}; jmp r10的机器码保存到jmp_back_insns; - 构造
movabs r10,${shim_addr}; call r10的机器码保存到shim_insns; - 将
exec_addr、hooked_addr、hook_insns、replaced_insns、jmp_back_insns、shim_insns发送至LKM。
LKM处理逻辑步骤
- 将
hook_insns写入hooked_addr; - 将
shim_insns写入exec_addr; - 将
replaced_insns写入exec_addr; - 将
jmp_back_insns写入exec_addr。
最终Hook流程
- 被Hook的内核函数的序言部分被替换为跳转到LKM分配的地址;
- LKM分配的可执行空间先调用拦截函数,再执行原函数被替换的序言,最后跳转回原函数。
当前问题
Hookvmalloc时shim能被调用并输出内容,但Hooknetif_rx时无任何反应;Hook其他内核函数时,要么无反应,要么系统直接冻结需重启。请问哪里出错了?为何多数情况下系统会冻结?
问题排查与解决方案
1. 指令拆分逻辑错误
你当前的指令边界查找逻辑(“超过13字节的首个指令边界”)存在致命问题:若拆分时截断了多字节指令,会导致原函数执行非法指令,直接触发内核panic或系统冻结。
- 修复:反汇编时逐指令累加长度,直到总长度≥13字节,确保提取的
replaced_insns是完整的指令集合,绝对不能截断任何一条指令。
2. 内存修改的原子性与缓存一致性缺失
直接修改内核代码段和可执行内存时,未处理以下关键问题:
- 内核代码段默认只读,修改前需临时修改页表属性为
可写+可执行,修改后恢复原属性; - x86架构下,修改代码后必须执行
clflush指令刷新CPU缓存,避免执行旧的缓存指令; - 多CPU场景下,需用
smp_call_function同步所有CPU的指令缓存,否则其他CPU可能执行旧代码,引发竞态或崩溃。
3. netif_rx无响应的特殊原因
netif_rx属于网络栈核心函数,失效可能源于:
- 内联优化:内核编译开启内联后,
netif_rx的地址可能不是实际执行的代码地址,导致Hook失效; - 上下文冲突:
netif_rx可能在中断上下文执行,若shim函数使用了睡眠相关操作(如某些场景下的printk),会触发中断上下文非法睡眠,直接导致系统无响应或崩溃。
4. 寄存器状态破坏
你的shim调用逻辑未处理寄存器保存与恢复:
- x86-64调用约定中,
r10是易失性寄存器,movabs r10,shim_addr; call r10会破坏其值,而原函数可能依赖该寄存器的初始状态; - 调用shim前必须保存所有非易失性寄存器(
rbx, rbp, r12-r15),调用后恢复,否则会导致原函数执行时寄存器状态错误,引发不可预测的崩溃。
5. 可执行内存权限问题
LKM分配可执行内存时,需确保内存页权限为可执行+可读+可写(修改阶段),且分配区域符合内核SMAP/SMEP等安全机制的要求。若权限设置错误,会触发页错误,导致系统崩溃。
内容的提问来源于stack exchange,提问作者jafarlihi
相关产品推荐
相关产品推荐

