【PAPER.0x05】论文笔记:HyperDbg: Reinventing Hardware-Assisted Debugging

本文最后更新于:2025年3月13日 凌晨

猫猫帮你调试程序,猫好,人类奴役猫猫,人坏

0x00. 一切开始之前

笔者最近依然在做虚拟化相关的工作(因为这个工作一直做一直摸鱼所以一直没做完喵),所以还是再简单看点相关的论文继续划划水这样子

这一次看的是一个架构比较复杂但是挺有名的开源项目——HyperDbg 的论文:)

Abstract

现在的调试平台都由于各种限制无法提供透明、高效、高性能的 low-level 调试器,这篇论文给出了一个使用虚拟化技术辅助的调试器,其基于一个自定义的虚拟机(笔者:怎么都这么喜欢自己写虚拟机),并通过 EPT 进行基于硬件的指令级模拟与系统级 API 劫持,同时通过部署一个与 VMX 兼容的脚本引擎消除了不必要的上下文切换,实验结果表明 hyperdbg 的隐秘性使其比 WinDbg 和 x64dbg 能调试更多的软件样本,且调试速度比 WinDbg 快得多

CCS Concepts

• Security and privacy → Software reverse engineering; Virtualization and security; Software security engineering; • Software and its engineering → Compilers.

Keywords

Hypervisor, Debugging, Kernel-debugger, Fuzzing, Malware-analysis

0x01. INTRODUCTION

调试器(debugger)是辅助软件开发、软件逆向工程与恶意软件分析中的一个重要工具,但现代软件都有着反虚拟化、反模拟、指纹检测等技术(如调用特定的 OS APIs)来对抗调试,而现有的调试工具都缺乏相应的对抗能力,与此同时一份对 4百万恶意软件的调查显示其中 88% 都装备了反逆向技术、81%装备了反调试或反虚拟化技术,OS APIs 或是 ring-0 的选项使得高权限的恶意软件可以检测到调试器的存在

笔者注:例如最常见的一个检测方式就是指令执行时间,例如 cpuid 指令在模拟执行下的总时长在虚拟机中会比物理机上高不少

因此研究人员将目光放到硬件上,裸金属、hypervisor-level、系统管理模式(System Management Mode)甚至是 Intel 内存管理引擎(Memory Management Engine)都被用来增加调试器的透明度,但也造成了较高的性能损耗,此前提出的子内核调试器虽强但也未能提供丰富的调试功能,且大都停止更新或仅为学术目的而开发,此外社区也要求这类工具提供源码

本文给出 HYPERDBG :基于 VMM & Intel VT-x 的 debugger,其避免使用任何 OS API 或软件调试机制,而是广泛使用处理器功能(如 EPT)来监视程序执行,从而提高了执行透明性,并使得 HyperDbg 可以使用 SOTA 技术(如 hidden hook,与 inline hook 一样快),以及支持硬件调试断点以在对特定位置的读写下断;作者在 13 个打包器与保护器上进行了测试,没有一个检测到了 HYPERDBG,超越现有的其他调试器;作者在 10853 个恶意软件上展示了透明调试的适用性,成功分析的恶意样本数量分别超过 WinDbg 22%、 x64dbg 26%;作者还描述了使用 HYPERDBG 对一个 Windows kernel 0 day 的重新发现

对于高性能调试,HYPERDBG 使用与 VMX-root 兼容的脚本引擎来在内核模式执行整个复杂的调试功能,其脚本消除了用户到内核的交互且提供了巨大的调试性能,作者在单步执行、条件中断、系统调用记录中评估了 HYPERDBG,与 WinDbg 相比分别快了 2.98、1319、2018 倍

作者展示了 HYPERDBG 的设计很 🐮🍺,简而言之本文贡献如下:

  • 作者展示了 HYPERDBG,一个为深度软件分析、逆向工程、隐秘 fuzzing 而特化的 hypervisor 辅助的调试器
  • 作者引入了 VMX-root 兼容的脚本引擎,比 SOTA 调试器快几个数量级
  • 作者在 10853 恶意软件中证明了 HYPERDBG 的透明调试,比 SOTA 调试器能多分析 22%~26% 的样本
  • 作者描述了 HYPERDBG 的多种应用,如大规模与快速恶意软件分析(包括 Windows 0-day 分析)、fuzzing 中的代码覆盖率、IO 设备调试、软件性能测量

作者的代码开源于 https://github.com/HyperDbg/HyperDbg

0x02. TECHNICAL BACKGROUND

本节介绍所需的技术背景知识

2.1 Modern Debuggers

调试(debugging)用于检查与分析软件程序过程,逐步执行、内存观测与修改、断点等都是调试器的重要特性,调试器可被分为用户模式(如 x64dbg、Ollydbg)与内核模式(如 WinDbg、GDB)两类,随着恶意软件技术进步,研究人员开始对能提供更透明环境的虚拟化、硬件辅助方法感兴趣

2.2 Instruction Set Architecture (ISA) Extensions

本节主要介绍 Intel 相关扩展,HYPERDBG 暂时也只支持 Intel 处理器

  • Intel Virtualization Technology(VT-x):Intel 的硬件辅助虚拟化技术,旨在简化虚拟化过程并提高 VMM 性能,其允许一个核心被当作多个核心运行
  • Intel Extended Page Table (EPT):Intel VT-x 中的硬件辅助的 MMU,其通过 EPT 提供了 GPA 到 HPA 的转换以消除软件管理的影子页表的开销,每个 Intel 核心都有一个 EPT 表,以允许多个不同独立系统并行访问
  • Intel Transactional Synchronization Extensions(TSX):TSX 为 x86 的一组指令集扩展,包括 Restricted Transactional Memory,这允许对硬件事务性的支持(如事务操作失败则回滚),本文中的 Intel TSX 特指 RTM

2.3 Terminology

作者的实现基于 Intel 处理器,目标 OS 为 Microsoft Windows

  • Hypervisor:通过虚拟共享资源实现虚拟化的软件,通过抽象硬件资源以运行虚拟机
  • Interrupt Request Level (IRQL):Windows 独立于硬件的中断与代码优先级排序机制,高 IRQL 的进程会抢占低 IRQL 的线程或中断,不同的 IRQL 用于不同目的

0x03. HIGH-LEVEL OVERVIEW

本节简单介绍 HYPERDBG 的设计

3.1 High-level Debugging Flow

HYPERDBG 的子系统与执行流如图 1 所示,Host 与 Guest 之间通过如串口等进行通信,Host 侧提供 CLI 与用户交互,部署了汇编器/反汇编器,并部署了多个使用了硬件特性如 EPT 的调试子系统;如图 1 所示:

  • 调试命令在 1️⃣ 中被汇编/反汇编并传递给 Guest
  • 脚本引擎后端在 Guest 的 hypervisor-level 解释执行,通过如 4️⃣ 所示定位用户或内核被调试者的执行流
  • 2️⃣ 中各子系统基于事件触发执行命令与功能序列(如 3.2 所示)
  • 子系统利用硬件特性(如 EPT)执行 3️⃣ 中操作

Host 与 Guest 间需双向通信,但 HYPERDBG 可在必要时将通信限制在 guest 内核模式中的自动化例程

3.2 Event-Triggered Interface

方便起见,作者使用“事件”(Event)这一抽象概念控制底层函数与构建块的使用,随后定义用于调试的子系统中的“条件”(Conditions)与“操作”(Actions)

3.2.1 Event

调试器所感兴趣的事件,包括设定要监视的系统调用、内存访问等,HYPERDBG 可在事件上执行任意已定义操作

3.2.2 Actions

事件被触发后 HYPERDBG 可以执行称为“操作”的三类功能:下断(暂停执行)、脚本(观测与修改寄存器/内存、创建日志等)、自定义代码(任意客制化汇编代码)

3.2.3 Conditions

用户定义的对事件的约束,从而只在条件满足时触发事件

3.3 Operating Modes

HYPERDBG 有两种操作模式

3.3.1 VMI Mode

虚拟机自省(Virtual Machine Introspection)模式用于常规的用户程序调试与内核模式本地调试,虽然其提供了传统的调试体验与所有的 HYPERDBG 功能,但内核模式的断点与步入受限;VMI 也允许在本地/远程调试中在用户态/内核态运行脚本与代码

3.3.2 Debugger Mode

调试器模式(Debugger Mode)允许通过串口或虚拟串行设备连接到内核并暂停系统以单步调试用户与内核指令

3.3.3 Transparent Mode

笔者注:经典 X 大有 X + 1 个(

透明模式(Transparent Mode)可以同时使用这两种模式,其通过隐藏 HYPERDBG 在时间与微架构级别的存在来提供隐身调试,第 6 节描述了使用的透明技术,第 7.1 皆进行了评估

0x04. BACK-END ARCHITECTURE

本节在子系统级探索 HYPERDBG 的架构设计

4.1 Stepping Subsystem

本节研究传统调试器的步入机制的缺点,并讨论 HYPERDBG 作为 VMX-root 模式调试器的解决方案

4.1.1 Step-in

步入(Step-in)通过设置 RFLAGS trap 标志位让系统在执行单条指令后停止,以让调试器读取/修改寄存器与内存

Challenge. 传统步入机制无法确保逐行步入过程,因为可能转移到其他 CPU 核心执行,中断可能彻底改变执行流

图 2a 是一个步入执行流被 #DB 异常中断打乱的例子,一个简单的解决方案是清除 RFLAGS 的中断标志位来屏蔽外部中断,但很容易破坏操作系统语义;HYPERDBG 引入了 插桩步入 (Instrumental Step-in)来确保调试中的步入机制

Approach. HYPERDBG 通过使用 Monitor Trap Flag (对 Guest 透明,类似 RFLAGS::TF )引入插桩步入机制,非可屏蔽中断(Non-Maskable Interrupts,NMIs)用来确保操作在一个核心上执行、其他核心挂起

4.1.2 Instrumentation Step-in

HYPERDBG 是据作者所知第一个提供了确保步入方法的调试器,如图 2c 所示,在 Guest 执行目标指令后会触发 VM-exit(设置了 MTF),HYPERDBG 仅在该核心上继续执行且禁止中断(设置 VMCS)以提供细粒度的步入,这提供了其他调试器(如 WinDbg)所没有的特性,例如在用户模式执行 SYSCALL 指令时 HYPERDBG 允许直接执行接下来进入内核的指令(SYSCALL handler),或类似的缺页异常 handler,或 SYSRETIRET 指令

4.1.3 Step-over

步过(step-over)机制中调试器会把 call 指令的长度发给被调试者(而非设置 Trap 标志位),设置硬件调试寄存器以在 call 完成后触发并通知调试器下一条指令;由于其他线程/核心也可能触发硬件调试寄存器,HYPERDBG 忽视来自其他线程/进程 ID 的 #DBs,并重置调试寄存器直到到正确的执行上下文与目标线程,图 2b 展示了 HYPERDBG 的单步跳过机制,在检查调用指令后,下一条指令将会抛出断点异常(Breakpoint Exception,#DB)

4.2 Hooking Subsystem

Hooking 即拦截任意事件、运行任意指令、将执行流返回到事件入口点的行为

Challenge. 现有调试器的 hooking 系统使用可以被检测的直接内存访问,且 硬件调试寄存器 (Hardware Debug Registers)的数量与大小是固定的,这限制了 Hooking 的性能

4.2.1 SYSCALL and SYSRET Hooks

HYPERDBG 通过清除扩展特性启用寄存器(Extended Feature Enable Register,即 IA32_EFER )的 SCE 位触发未定义操作异常(undefined opcode exception,#UD)并检查异常源头以实现 hooking 功能,用户可以执行任意脚本并为任意系统调用进入(SYSCALL)或返回(SYSRET)设置 hooks ,调试器可以在实际执行指令前监视/执行/修改系统上下文

Approach. HYPERDBG 通过两种 EPT hooking 机制透明地监视与操纵内存访问,并模拟调试寄存器以超越此前的限制

4.2.2 EPT Hidden Hook

作者提出了对用户/内核不可见的 EPT-level hooking ,在 HYPERDBG 中第一种是在目标机器内存中注入 #BP(0xcc)的传统 EPT hook,第二种利用了 Detours 风格的 Hook,通过跳转到修补后的指令并在回调后返回到常规执行流以改变执行路径,后者虽然存在灵活性限制但避免了昂贵的 VM-exit

4.2.3 Limitless Simulating of Debug Register (monitor)

EPT hooking 也允许通过触发事件触发器(event trigger)来模拟硬件调试寄存器以监视对任意地址范围的任意读写,并消除 HDR 的数量与长度限制

4.3 Memory Access in VMX-root Mode

安全内存访问是设计 hypervisor-level debugger 的一个挑战,因为许多场景都能导致系统挂起或异常(如在 VMX-root 访问用户地址空间),且无法通过现成的指令(如 mov )解决

Challenge. VMX-level 的安全内存访问极其复杂,通常的由 OS 处理会导致性能开销,但对很多场景而言安全且高效的内存访问是必要的

Approach. 作者提出了一系列策略来解决 VMX 内存管理的复杂性

4.3.1 Discover Page-table Entries

检查目标地址页面合法性的传统方法是检查页表中是否有合法的 PTE(并设置了 present 位),作者使用无需在用户态与内核态间切换便能抑制异常的 Intel TSX 进行替代,通过检查包含目标地址的事务的成功执行来检查页面合法性,这仅需要如 Listing 1 所示的简短代码;HYPERDBG 对不支持 TSX 的处理器会在需要时回退到前一种方法;作者的实验证明在用户态能快三个数量级,但在内核态会由于 RTM routine 而减慢 40%

4.3.2 Retrieving a Page by Injecting Page Fault (#PF)

HYPERDBG 在缺页时向被调试者注入缺页异常(通过修改 CR2 为目标虚拟地址)以请求 VMX non-root 从硬盘上带回该页

4.3.3 VMX-root Mode Compatible Message Tracing

VMX-root 与 VMX-non-root 间的消息传递面临巨大挑战,VMX-root 模式下访问分页池有诸多限制,绝大部分 NT 函数也不兼容任何 IRQL;HYPERDBG 使用对 VMX-root 可见的非分页池部署特制的消息追踪机制,细节在 https://rayanfam.com/topics/hypervisor-from-scratch-part-8/ 中进行了彻底讨论

4.3.4 Reading and Writing Memory

出于多方面考虑,HYPERDBG 并不直接访问内存,但使用虚拟寻址方法保留 PTE 并映射对应物理内存到内核虚拟地址以安全地读写

4.3.5 Pre-allocated Pools

HYPERDBG 使用预分配池以解决传统上 VMX root 下无法分配内存的问题,其(4KB 粒度时)提供了 EPT hooks 所需的资源,HYPERDBG 的内存管理器会记录 VMX root 中所需的内存池中释放/替换,并在 VMX non-root 中执行

0x05. FRONT-END ARCHITECTURE

本节讨论连接后端的中间件与 UI

5.1 Communicating and Task Appliance

用网络传输数据的 Windows API 由于中断在 VMX-root 下不可用而不切实际,且由于 IRQL 而需要额外的实现,因此 HYPERDBG 利用串口进行数据传输(如图 3 所示),其简化了设计并允许使用轮询,此外 HYPERDBG 可以使用 KDNet 进行通信

image.png

5.1.1 Sending Data over Serial

HYPERDBG 支持最多四个串口,可以通过串行设备中断挂起被调试方而无需严格轮询,此后使用 VMCALL 返回 VMX-root 等待调试器后续命令

5.1.2 Communication between Cores

HYPERDBG 在 VMX-root 模式通过 NMIs 挂起其他核心,或是不通知其他核而直接执行代码/脚本

5.2 Kernel-level Script Engine

现代调试器缺乏高性能与高可定制的脚本框架,因此作者从零开始设计了一个 VMX-enabled 的脚本引擎,据悉是仅有的可在 VMX-root 模式下提供高级特性如 OS 自旋锁、内存检查、辅助函数(如 printf)等的脚本引擎解决方案;脚本引擎的架构如图 4a 所示,其由一个后端(使用 LL(1)LALR(1) 解析器以追求最大效率)与一个使用 MASM 风格与 C 关键字(如 if/else/for )以及易定制的语法的前端组成

用户输入的脚本被传递给 host 前端,由 lexer 扫描入,并被翻译为中间表示(Intermediate Representation),之后通过串口传输到 guest 的 kernel VMX-root 的一个缓冲区以供执行,之后一个缓冲区逐渐被用执行结果填充并传输回 host;这种方法与用在商业调试器(命令与脚本被逐行发送与解析)中的通过发送整个脚本到 VMX-root mode 并通过单向流响应回用户模式的传统的双向方法相比提供了较大的性能提升

0x06. TRANSPARENCY ANALYSIS

本节用恶意软件分析 HYPERDBG 的透明性

6.1 Hypervisor Detection Methods and Mitigations

检测子操作系统第三方程序(如 hypervisor)通过查询一组指示性的指纹,如注册表项、系统调用(例如查找运行的进程与加载的驱动)、指令(如 CPUID/IDT/LDT ),HYPERDBG 拦截并强制 VM-exit,模拟对应的非虚拟化环境的正常值来对抗,表 1 提供了此类方法的综合预览;更复杂的 VM 检测方法利用时间侧信道,核心思想是特定指令(如 CPUID/GETSEC/INVD/XSETB )会造成 VM-exit 而执行时间更长,列表 2 展示了此类攻击的示例,接下来我们将描述 HYPERDBG 如何对抗此类检测方法

Table 1: Anti-Debugging and Anti-VM exercises and mitigation in HyperDbg

6.2 Timing Transparency in HYPERDBG

HYPERDBG 的透明模式为隐藏虚拟化时间泄漏提供了一种通过识别检测 VM 的序列并将时间值替换为非虚拟化系统的解决方案,据作者所知 HYPERDBG 是第一个提供了修改分析软件用以检测虚拟化环境的时间指纹的实用手段的调试器,通过使用执行时间的统计模型,广泛时间分析被在 VMM 模块启动前执行,以尽可能接近 Guest OS 的正常运行条件的时间戳

作者使用二项高斯分布(two-term Gaussian Distribution)作为回归函数(regressor function),因为实验表明其非常适合对此类执行时间进行建模,图 5 显示了在启用与不启用 HyperDbg 的情况下运行列表 2 中序列的 10k 次执行的测量结果的概率分布函数(Probability Distribution Function),这些值可以被导出且统计参数可以被记录用于模拟目的

Listing 2: The timing measurement code by forcing VM-exit

Figure 5: PDF distribution of timing measurement for deactivated HyperDbg (a), with activated HyperDbg (b)

HyperDbg 目前允许通过两种方法 cover 掉 VM 的时间泄漏:

  • 1)调整跟踪 CPU 时间的 MSR 寄存器(称为 IA32_TIME_STAMP_COUNTER),无需 VM-Exit 但会增加系统不稳定性
  • 2)模拟 RDTSCRDTSCP 指令的结果,需要 VM-Exit 因此引入额外复杂度

时序指令的全局模拟会干扰系统的主要功能(作者在屏幕驱动与音频输出上进行了实验证明)

6.3 Alternative Timing Attack Methods

HyperDbg 还有一些方法能阻碍恶意软件用各种类型的计时攻击探测时间,如在 HyperDbg 中有对 shared ticks 与硬件性能监视计数器(RDPMC)的内置支持

0x07. EVALUATION

7.1 Transparency Evaluation

作者在提供了反调试压力测试的工具 pafishal-khaser 上评估了 HyperDbg 的透明模式,如作者所料,第一种方法(更新 IA32_TIME_STAMP_COUNTER) 会干扰系统主要功能,而第二种方法(模拟)则成功通过这些工具,作者还在常见反调方法与商用软件上评估了 HyperDbg

7.1.1 Evaluation Configuration

作者在不同类别的 10853 个恶意软件样本上分析,分别在 HyperDbg 的普通模式与透明模式进行测试,并与 x64dbg 与 WinDbg 对比,系统为 Windows 20H1;作者使用 C/S 模式分发样本,并使用两种方法恢复系统:基于 Barebox 的无需重启的方法与基于 Windows 系统还原的方法

**Barebox-based Approach **:作者首先使用基于 Barebox 的方法

7.1.2 Evaluation by Anti-Debugging, -VM, and -Hypervisor


【PAPER.0x05】论文笔记:HyperDbg: Reinventing Hardware-Assisted Debugging
https://arttnba3.github.io/2024/08/31/PAPER-0X08-HYPERDBG/
作者
arttnba3
发布于
2024年8月31日
许可协议