如何轻松编写Rootkit:Linux内核系统调用拦截技术解析

如何轻松编写Rootkit - Trail of Bits技术博客

我们开源了名为KRF的故障注入工具,它利用内核态系统调用拦截技术。您现在就可以使用它来发现程序中的错误假设(及由此产生的漏洞)。快来试试吧!

本文介绍如何通过普通内核模块在Linux内核中拦截系统调用。我们将快速回顾系统调用及其拦截意义,然后演示拦截read(2)系统调用的基础模块实现。

与其他故障注入策略有何不同?

其他故障注入工具主要依赖以下技术:

  1. LD_PRELOAD技巧:拦截libc暴露的系统调用包装函数。存在明显缺陷:

    • 仅适用于动态链接场景(Go等新语言和静态编译趋势使其适用性降低)
    • 包装函数与实际系统调用可能存在显著差异(如open()可能调用openat(2))
  2. 动态插桩框架(如DynamoRIO/Intel PIN):

    • 允许在函数或机器码级别检测系统调用
    • 带来显著的运行时开销

内核态故障注入规避了上述问题:直接重写实际系统调用,且几乎不增加运行时开销。

系统调用基础

系统调用是内核向用户空间暴露资源的接口,涉及:

  • I/O操作(open/close/read/write)
  • 进程管理(fork/kill/wait)
  • 网络通信(send/recv)
  • 特殊操作(ioctl)

与传统函数调用不同,系统调用需要昂贵的上下文切换(x86通过int 80h/sysenter指令触发)。

系统调用表定位技术

Linux内核通过sys_call_table数组管理系统调用,但自2.6版本后不再直接导出该符号。我们使用kallsyms_lookup_name接口可靠获取其地址:

c 复制代码
static unsigned long *sys_call_table;

int init_module(void) {
  sys_call_table = (void *)kallsyms_lookup_name("sys_call_table");
  if (!sys_call_table) {
    printk(KERN_ERR "查找sys_call_table失败\n");
    return -1;
  }
  return 0;
}

系统调用注入实现

基础拦截示例(以read为例):

c 复制代码
asmlinkage long phony_read(int fd, char __user *buf, size_t count) {
  printk(KERN_INFO "拦截到read调用:fd=%d, %lu字节\n", fd, count);
  return orig_read(fd, buf, count);
}

x86架构需处理CR0寄存器的写保护位:

c 复制代码
#define CR0_WRITE_UNLOCK(x) \
  do { \
    unsigned long __cr0; \
    preempt_disable(); \
    __cr0 = read_cr0() & (~X86_CR0_WP); \
    BUG_ON(unlikely(__cr0 & X86_CR0_WP)); \
    write_cr0(__cr0); \
    x; \
    __cr0 = read_cr0() | X86_CR0_WP; \
    BUG_ON(unlikely(!(__cr0 & X86_CR0_WP))); \
    write_cr0(__cr0); \
    preempt_enable(); \
  } while (0)

高级应用场景

  1. 强制故障注入
c 复制代码
asmlinkage long phony_read(int fd, char __user *buf, size_t count) {
  return -ENOSYS;
}
  1. 用户定向故障
c 复制代码
asmlinkage long phony_read(int fd, char __user *buf, size_t count) {
  if (current_uid().val == 1005) return -ENOSYS;
  return orig_read(fd, buf, count);
}
  1. 数据篡改
c 复制代码
asmlinkage long phony_read(int fd, char __user *buf, size_t count) {
  unsigned char kbuf[1024];
  memset(kbuf, 'A', sizeof(kbuf));
  copy_to_user(buf, kbuf, sizeof(kbuf));
  return sizeof(kbuf);
}

KRF工具特性

我们开发的KRF工具具备:

  • 按可执行文件精确拦截能力
  • 支持完整系统调用"配置文件"操作
  • 实时故障注入能力
  • 完全兼容静态链接程序

替代方案对比

  1. syscall_intercept:基于LD_PRELOAD但使用capstone反汇编libc
  2. ptrace(2):用户空间子进程监控方案,存在调试器冲突和性能问题
  3. eBPF/kprobes:仅支持参数记录,无法实现实际拦截

技术说明:本文介绍的CR0写解锁机制源自PaX/grsecurity的"rare write"实现

相关推荐
李昊哲小课2 分钟前
SpringBoot4 云端咖啡站 阶段五:交付与进阶
人工智能·spring boot·大模型·log4j·智能体
阿里云大数据AI技术7 分钟前
一套 Spark SQL,打通多种 Catalog:EMR Serverless Spark 统一数据处理实践
人工智能·sql·spark
BFT白芙堂9 分钟前
Franka & DROID :面向真实场景的机器人操作数据集
人工智能·学习·机器学习·机器人·具身智能·franka·robotiq
深圳讯鹏科技13 分钟前
工业视觉计数落地实践:米厂米袋多目标检测与越线计数的边缘 AI 方案
人工智能·讯鹏科技·ai视觉计数传感器·ai 视觉计数传感器·ai视觉计数系统
邵宇然21 分钟前
编译期安全编程的边界探索:当 Rust 的类型系统还不足以表达我们的意图
人工智能
loopne21 分钟前
AI网文写作实验笔记(十三):系列总结——12 篇实验、8 条核心结论,把“AI 写小说“每一步拆开验证
人工智能·经验分享·笔记·ai写作·智能写作
2601_9670972225 分钟前
白光干涉仪品牌众多怎么筛选靠谱厂家?选购要点及优可测等品牌参考
人工智能
zandy101129 分钟前
claude code用不了?国内外AI 编程工具的演进与三类路径选择
人工智能
武汉海翎光电32 分钟前
从零开始了解数据采集——工业数据采集新趋势:边缘计算与云计算的强强联合
人工智能·云计算·边缘计算
AI产品测评官36 分钟前
AI智能体在招聘场景的工程实践:屏幕语义理解与风控规避
人工智能·求职招聘