陌小杨の小站
首页项目归档照片墙音乐灵境说说杂谈友链关于
封面

Driver Reverse Engineering 101 - Part II: Unpacking a VMProtected Kernel Driver

写作时间:2025-11-21
# 逆向工程
# Windows
# 驱动
# VMProtect
# 脱壳

为什么需要脱壳?

在 IDA 中打开驱动后,发现没有导入函数,所有调用都是间接调用,引用的是未初始化的内存——这是 VMProtect 的 IAT 保护机制。

驱动运行时才会解密并恢复 IAT,因此需要让驱动执行起来后将其内存转储出来。幸运的是,该驱动未被虚拟化,因此只需处理 IAT 加密。


脱壳步骤

1. 安装驱动服务(作为启动驱动)

sc.exe create ksophon_x64 binPath= "C:\Windows\system32\drivers\ksophon_x64.sys" start= boot type= kernel

2. WinDbg 内核调试设置

在调试机上设置 "Break on connection",重启目标虚拟机,WinDbg 在启动时中断。

3. 设置断点

  • sxe ld:ksophon_x64.sys — 在驱动加载时中断
  • 使用 !dh 获取入口点地址,然后设置断点 bp <module>+<entry_offset>
  • 在 DriverEntry 返回地址处再设一个断点,此时 VMProtect 和驱动的所有初始化代码已执行完毕,IAT 已解密

4. 内存转储

使用以下命令将驱动镜像从内存中导出:

.writemem C:\temp\dumped.sys START START+SIZE

记录 ntoskrnl.exe 的基地址(lm k),因为 IAT 中的偏移与此相关。


修复 PE 文件

转储后的文件是内存映射布局,需要使用 PeBear 等工具将各节的 RAW_ADDR 设置为对应的 VIRTUAL_ADDR,使 IDA 能正确解析节区。


恢复导入地址表(IAT)

转储后的 IAT 中存在两类条目:

直接引用

直接指向 ntoskrnl 中的函数地址,无需额外处理。

跳板函数

指向驱动 .text 段中的小段代码,通过计算得到实际函数地址。

跳板函数示例:

  • 加载一个立即数
  • 减去某个值得到驱动内指针地址
  • 加上该指针指向的值
  • 最终结果指向 PsGetCurrentProcess

使用 Unicorn 模拟跳板函数

由于跳板函数是位置无关代码,可以编写 Unicorn Python 脚本自动化模拟所有跳板函数:

  1. 加载转储后的驱动
  2. 遍历 .rdata 节,识别指向 .text 段的条目
  3. 模拟执行直到遇到 xchg rcx, [rsp+imm] 指令(计算结果在 rcx 中)
  4. 根据 ntoskrnl 基地址计算偏移并输出

最终效果

  • 使用 WinDbg 的 ln 命令或 PDB 解析库,将计算出的地址解析为函数名
  • IDA 中 IAT 恢复后,代码从混乱的间接调用变为可读的函数调用,可以正常进行静态分析

关键工具

工具 用途
WinDbg 内核调试、断点设置、内存转储
PeBear PE 文件修复(对齐节区)
Unicorn Engine 模拟跳板函数执行以解析 IAT
IDA Pro 静态分析

总结

  • 对于未虚拟化的 VMProtect 保护驱动,脱壳只需在正确的时机(IAT 解密后)进行内存转储
  • IAT 恢复的关键在于区分直接引用和跳板函数,并利用模拟执行自动解析跳板函数的目标地址
  • 整个过程需要内核调试环境的搭建和基本的 PE 文件结构知识
avatar

陌小杨

热爱折腾代码的开发者,记录学习与生活的点点滴滴。

RECOMMENDED

(Anti-)Anti-Rootkit Techniques - Part I: UnKovering Mapped Rootkits

2024-03-23

(Anti-)Anti-Rootkit Techniques - Part II: Stomped Drivers and Hidden Threads

2024-09-19

(Anti-)Anti-Rootkit Techniques - Part III: Hijacking Pointers

2025-02-16

Table of Contents