逆向工程实战手册 第 27 章

第 27 章 Windows 内核逆向(驱动 / Rootkit)

内核逆向 = 分析 .sys 驱动、内核模块、Rootkit。核心知识点:驱动模型(WDM/KMDF)、IOCTL 通信、Dispatch 例程、Rootkit 技术分类、内核调试。本章以知识架构为主,代码为辅。

📍 知识点地图 | 主题:内核逆向 | 前置:第4章 | 后续:第79章 | 核心概念:WDM/KMDF、IOCTL、Rootkit、WinDbg

27.1 为什么要分析内核

驱动是提权漏洞的重灾区: 内核驱动 ioctl 越权写 → 任意地址写 → SYSTEM
Rootkit 是隐蔽持久化的基础: 内核态可隐藏进程/文件/网络
EDR 与反 EDR 的战场: 现代检测都在内核层

27.2 Windows 驱动模型分类学

模型 特征 分析重点
WDM 老式,手动管理 IRP DriverEntry → 设备创建 → Dispatch 例程
KMDF 现代框架,事件驱动 EvtDriverDeviceAdd → Queue → I/O 回调
Minifilter 文件系统过滤驱动 FltRegisterFilter → Pre/Post 回调
NDIS 网络驱动 网卡/协议栈
恶意驱动 常伪装成合法签名(BYOVD) 看 LolDrivers 已知漏洞驱动库

27.3 WDM 驱动分析流程(架构)

1. 找 DriverEntry(入口)
   → IDA 自动识别,或搜 IoCreateDevice / IoCreateSymbolicLink

2. 找设备名与符号链接
   → \Device\MyDriver(内核名) / \DosDevices\MyDriver(用户态名)
   → 用户态 CreateFile("\\.\MyDriver") 就能打开

3. 找 Dispatch 例程(核心!)
   → DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl
   → 这是 DeviceIoControl 调用的入口

4. 分析 IOCTL 分发
   → switch(IoControlCode) 分发不同功能
   → 每个 case 是一个"功能模块"

5. 找漏洞(安全分析的核心)
   → 用户可控缓冲区未验证长度 → 溢出
   → METHOD_NEITHER 直接用用户指针 → 任意读写
   → 未检查权限 → 非特权用户可调用

27.4 IOCTL 编码原理(必须会解析)

IOCTL code 是 32 位整数,4 段信息编码:

31    16 15  14 13    2 1 0
┌────────┬────┬────────┬──┐
│DeviceType│Acc│ Function│Meth│
└────────┴────┴────────┴──┘

Method: 0=BUFFERED 1=IN_DIRECT 2=OUT_DIRECT 3=NEITHER
Access: 0=ANY 1=READ 2=WRITE 3=READ|WRITE
def decode_ioctl(code):
    device_type = (code >> 16) & 0xFFFF
    access = (code >> 14) & 0x3
    function = (code >> 2) & 0xFFF
    method = code & 0x3
    methods = {0:"BUFFERED",1:"IN_DIRECT",2:"OUT_DIRECT",3:"NEITHER"}
    return (f"DevType=0x{device_type:X} Func=0x{function:X} "
            f"Method={methods[method]} Access=ANY")

decode_ioctl(0x80002034)
# DevType=0x8000 Func=0x80D Method=BUFFERED Access=ANY

安全含义

METHOD_BUFFERED: 系统复制缓冲区 → 漏洞点是长度检查缺失
METHOD_NEITHER: 直接用用户态指针 → 可造成任意读写(高危)
Access=ANY: 任何权限都能调用该 ioctl → 提权入口

27.5 内核 Rootkit 技术分类(检测视角)

技术 实现原理 检测方法
syscall table hook 修改 sys_call_table 条目 对比内存表与磁盘 vmlinux
VFS hook 改 file_operations 函数指针 检查 fops 指针是否越界
Netfilter hook 注册网络过滤回调 遍历 netfilter hook 链表
kprobe/ftrace hook 注册内核回调 检查 ftrace 注册列表
eBPF rootkit 加载恶意 BPF 程序 bpftool prog list
DKOM 直接修改内核对象(进程链表) 遍历 task_struct 对比 /proc
IRP hook 劫持驱动 IRP 分发 检查 MajorFunction 表

Rootkit 逆向重点:找到它 hook 了什么(哪个表/哪个函数)、hook 逻辑是什么(过滤了什么)、怎么恢复。

27.6 Linux 内核模块(LKM)逆向

识别与分析流程

file module.ko    # 注意: relocatable,不是 executable!

# 找入口
readelf -s module.ko | grep -E "init_module|cleanup_module"
modinfo module.ko                      # 元信息

# 找 file_operations(核心!)
# 搜索 register_chrdev / cdev_add / misc_register
# → 找到 fops 结构体 → 定位 ioctl/read/write 处理函数

# 分析 ioctl
# unlocked_ioctl / compat_ioctl → switch(cmd) 分发

# 找 Rootkit 行为
# 修改 sys_call_table / /proc / netfilter / VFS

加载调试

# QEMU + GDB 内核调试
qemu-system-x86_64 -kernel bzImage -s -S ...
gdb vmlinux -ex "target remote :1234"
# 常用: info threads / lx-symbols / lx-dmesg / p init_task

27.7 内核调试环境搭建

Windows(WinDbg)

被调试机:
  bcdedit /debug on
  bcdedit /dbgsettings net hostip:192.168.x.x port:50000
调试机:
  WinDbg → Attach to Kernel → Net → Port:50000

常用命令:
  !analyze -v            # 自动分析崩溃
  lm                     # 已加载模块
  !drvobj \Driver\xxx    # 驱动对象
  dt nt!_DRIVER_OBJECT   # 结构体
  bp module!function     # 下断点

Linux(QEMU + GDB)

qemu-system-x86_64 -kernel bzImage -s -S ...   # -s = gdb 1234, -S = 暂停
gdb vmlinux
(gdb) target remote :1234
(gdb) lx-symbols          # 加载内核符号
(gdb) lx-dmesg            # 内核日志

27.8 驱动漏洞常见模式(安全审计清单)

□ 未验证缓冲区长度 → 栈/堆溢出
□ METHOD_NEITHER 用户指针未校验 → 任意地址读写
□ 无权限检查 → 非特权用户触发
□ 竞争条件(多线程同时 ioctl)→ 双重释放/UAF
□ 整数溢出 → 绕过长度检查
□ 任意地址写 → 改 SSDT/调用门/进程令牌
□ 符号链接劫持 → 与用户态配合

27.9 工具链

工具 用途
IDA + Driver Buddy Reloaded 驱动分析(自动识别 IOCTL/Dispatch)
WinDbg Preview Windows 内核调试
GDB + QEMU Linux 内核调试
Volatility 3 内存取证(找隐藏模块)
crash 内核 dump 分析
LolDrivers 已知漏洞驱动库(BYOVD 查询)
FLIRT/Lumina 识别 WDK 库函数

动手练习

  1. 用 IDA 打开一个 WDM 示例驱动(微软驱动示例),走完 27.3 的五步流程。
  2. 练习 IOCTL 解码:给 5 个 IOCTL code,写出 Method/Access/Function。
  3. 阅读一个 Rootkit 样本分析报告,指出它用了 27.5 表中的哪些技术。
  4. 搭一个 QEMU + GDB 内核调试环境,加载一个测试模块并下断点。

深入阅读

  • 仓库:skills/reverse-engineering/kernel-driver-reverse.md(本仓库内核驱动逆向全量参考)
  • 仓库:skills/reverse-engineering/platforms.md(内核驱动/eBPF 章节)
  • 仓库:skills/reverse-engineering/languages-compiled.md(C++ vtable 恢复)
  • 仓库:skills/pwn-chain/references/kernel-pwn.md(内核漏洞利用)
  • 实战案例:skills/field-journal/seed-016_k8s-container-escape.md