首页
社区
课程
招聘
[原创]峰会落选议题 基于HyperV的软件保护编译器
发表于: 13小时前 444

[原创]峰会落选议题 基于HyperV的软件保护编译器

13小时前
444

  本文章本是今年2026年看雪峰会的投稿议题之一,但是不符合AI主题导致落选,所以我在此公布研究,希望能够帮助到大家。

我于2025年12月左右创建这个系统,我称之为太虚幻境,GhostVeil Protect System,太虚的本质是一套编译器工具链,并且作为我的本科毕业设计存在,所以有些部分的核心代码不会公布,因为我还没有毕业,另外原定于议题中公布的Windows Boot漏洞将不会公布,本系统依赖于Winodws boot loader中的一个隐秘漏洞,用于创建一个系统不可见的内存区域,话不多说开始正题。


  太虚(GhostVeil)是一套基于 Intel VT-x 硬件虚拟化技术的新一代软件保护系统,运行于 Ring -1 特权层。以 Hypervisor 层的 Host 作为被保护软件的执行调度器,将被保护目标自动分解为基本块(Basic Block),通过对执行流的精密调度,在硬件层面实现对软件控制流的完整掌控。

借助 Intel EPT Execute-Only 技术,代码页对外不可读、不可写,软件断点、内存转储、调试器注入等传统攻击手段悉数失效。

  在这之前我们需要了解一些前置知识

    Intel VT-x(Virtualization Technology for IA-32/64)是Intel处理器提供的硬件虚拟化扩展技术,允许在同一物理硬件上同时运行多个相互隔离的操作系统实例。VT-x引入了两种处理器运行模式:VMX Root模式(Host)和VMX Non-Root模式(Guest)。Hypervisor运行于VMX Root模式,享有对硬件的完全控制权;被保护的客户操作系统及应用程序运行于VMX Non-Root模式,其特权指令的执行受到Hypervisor的监控与拦截。

VT-x通过虚拟机控制结构(VMCS,Virtual Machine Control Structure)管理Host与Guest之间的状态切换。VMCS是一块内存区域,记录了Guest的寄存器状态、控制字段及退出原因等信息。当Guest执行特定敏感指令时,处理器自动触发VM Exit,将控制权交还给Hypervisor;Hypervisor处理完毕后通过VMRESUME指令恢复Guest执行,此过程称为VM Entry。

VT-x的核心操作流程如下:首先由Hypervisor执行VMXON指令进入VMX操作模式,随后通过VMLAUNCH启动Guest虚拟机。Guest运行期间,凡触发VM Exit条件的指令(如CPUID、RDMSR、I/O操作等)均会陷入Hypervisor进行处理。本文所设计的GreatVoid系统正是利用CPUID指令必然触发VM Exit这一特性,将其作为控制流调度的同步点,实现对被保护程序每个基本块执行流的精密控制。




扩展页表(EPT,Extended Page Tables)是Intel VT-x提供的第二级地址转换机制。在启用EPT的虚拟化环境中,Guest物理地址(GPA)到宿主机物理地址(HPA)的转换由EPT页表完成,而非直接映射,从而实现了对Guest内存访问权限的精细控制。

EPT页表项中包含三个独立的访问控制位:可读位(R)、可写位(W)和可执行位(X)。通过对这三个权限位的组合配置,Hypervisor可以对Guest的每一个内存页设置不同的访问策略。其中,Execute-Only模式是指将内存页配置为仅设置可执行位(X=1),同时清除可读位和可写位(R=0,W=0)。在此模式下,Guest可以正常执行该页中的代码,但任何读取或写入该页内容的操作都将触发EPT Violation,从而陷入Hypervisor进行处理。

GreatVoid系统利用EPT Execute-Only特性对被保护程序的代码页进行保护。被保护代码所在的内存页被配置为Execute-Only,使得攻击者无法通过内存读取指令获取代码内容,从根本上封堵了内存转储(Memory Dump)攻击手段。同时,由于代码页不可写,软件断点(INT 3指令写入)也无法生效,传统调试手段因此失效。结合CPUID触发VM Exit的控制流调度机制,GreatVoid在硬件层面实现了对被保护程序的完整执行流掌控。此外,GreatVoid的运行时组件以Bootkit形式实现。系统在Boot阶段由Bootkit读取TFR表并将其加载至内存,随后通过对Windows启动加载器(WinLoad.efi)的特定机制进行利用,将运行时组件注入至系统启动流程中,在操作系统内核初始化之前完成Hypervisor的部署与激活。值得注意的是,Bootkit在Boot阶段所申请的内存区域对操作系统内核不可见,该内存不会出现在操作系统的物理内存管理结构中,因此无法被内核及用户态程序感知或枚举。GhostVeil运行时通过私有的寻址机制对该内存区域进行访问,从而保证TFR表及运行时数据在系统运行期间不会暴露于操作系统的内存视图之内。出于安全考虑,本文对所利用的具体技术细节不作公开披露。

    太虚是一个穿越Ring-1到Ring3的保护系统所以开销较大,需要搭配ShellCode编译器将核心的算法代码提取为ShellCode之后进行保护,这里进行说明 ShellCode编译器将会作为一个组件存在于编译链中,同时太虚在编译过程中将会通过热点分析分析出热点的嵌套执行块降低 执行块的 混淆膨胀体积 以提升性能。

传统Pass开发(IR层)

 

LLVM的Pass机制是对IR进行分析和变换的标准手段。开发者通过继承FunctionPass或ModulePass实现自定义Pass,在IR层面对程序进行修改。IR Pass操作的对象是虚拟寄存器和SSA形式的指令,与具体物理寄存器无关,适合进行结构性变换。本文的GVShellcodeCompiler即以ModulePass形式实现,在IR层完成全局变量下沉、调用链收集及外部符号哈希化等变换。IR Pass可通过opt工具以插件形式加载,无需修改LLVM源码树。

 

MachineFunctionPass(MC层)

 

MachineFunctionPass运行于寄存器分配完成之后、机器码输出之前,操作对象为真实的物理寄存器和机器指令。与IR Pass相比,MachineFunctionPass能够直接获取RAX、RBX等物理寄存器的活跃信息,精确识别序言指令边界,并对基本块进行机器级切割。由于MachineFunctionPass不支持插件式加载,必须集成进LLVM源码树并通过addPreEmitPass注册。

GreatVoid的GVAntiDbg模块(GVA)以MachineFunctionPass形式实现,在机器码输出前向被保护函数的基本块中插入反调试检测stub。选择MC层而非IR层的原因在于:反调试指令的插入需要精确控制物理寄存器的使用,避免与寄存器分配结果冲突,而这一信息只有在MC层才能准确获取。


Basic Block与CFG

    基本块(Basic Block)是程序控制流分析的基本单位,由一组顺序执行的线性指令序列构成。每个基本块有且仅有一个入口点(第一条指令)和一个出口点(终结指令)。终结指令要么跳转到另一个基本块,要么从函数返回。在基本块执行过程中,控制流不会从中间进入,也不会从中间跳出,这一性质使得基本块成为编译器分析与变换的原子单位。

    控制流图(CFG,Control Flow Graph)是以基本块为节点、以基本块之间的跳转关系为有向边所构成的图结构。一个函数对应一张CFG,其中有且仅有一个入口块,可能存在多个出口块。CFG完整描述了程序在运行时所有可能的执行路径,是编译器进行优化、混淆及静态分析的核心数据结构。

在LLVM IR中,基本块以BasicBlock类表示,函数以Function类表示,二者均继承自Value基类。通过对Function的迭代器遍历可以获取函数内所有基本块,进而对每个基本块的指令序列进行分析与变换。

GreatVoid的GVRC模块以基本块为核心处理单元,在MachineFunctionPass阶段对每个基本块进行切割,并在其末尾插入CPUID指令作为控制流调度的同步点。TFR表以基本块为粒度记录控制流信息,GVRuntime在运行时依据TFR表对每个基本块的后继执行目标进行动态调度。


支配树(Dominator Tree)

 

    在控制流图中,若从程序入口到达基本块B的所有路径都必须经过基本块A,则称A支配B(A dominates B)。基于支配关系可以构建支配树(Dominator Tree),树中每个节点的父节点即为其直接支配节点(Immediate Dominator)。支配树是编译器进行循环分析、代码优化及静态分析的核心数据结构。

 

回边与自然循环

 

    在控制流图中,若存在一条边从基本块A指向基本块B,且B支配A,则该边称为回边(Back Edge)。每一条回边对应一个自然循环,其中B为循环头(Loop Header),循环体由所有能够不经过B而到达A的基本块构成。GreatVoid通过逆后序遍历(RPO)结合支配关系识别所有回边,进而收集自然循环体内的基本块集合。

 

算法实现

 

    本文实现了CLoopAnalysis类完成上述分析,其核心流程分为四个步骤。第一步遍历RPO序列,对每个基本块的后继节点检查是否满足回边条件,即后继节点的RPO编号不大于当前节点且后继节点支配当前节点,将满足条件的边记录为回边。第二步对每条回边从tail节点出发沿前驱方向进行反向BFS,收集直到header为止的所有基本块,构成自然循环体。第三步遍历所有循环,对每个循环体内的基本块累加嵌套深度计数,并记录其最内层循环头。第四步将计算结果写回每个基本块的m_nestDepth字段,供后续模块查询。

 

嵌套深度与热点识别

 

    对每个基本块计算其循环嵌套深度(Nest Depth),位于多层嵌套循环内部的基本块具有更高的执行频率,被识别为热点代码(Heat Code)。这一方法本质上是静态分析中抽象程序点技术的工程应用——在不实际运行程序的前提下,通过对CFG结构的静态推导,以程序点的抽象状态近似估计运行时的执行频率分布,属于典型的May Analysis范畴。

GreatVoid的GVRC模块利用热点代码识别结果,对循环内部的基本块采取整体打包策略,避免在循环体内部插入CPUID调度点,从而防止因频繁VM Exit导致的性能损耗。

我们将详细讲述VT分发器的设计这是太虚的核心。

GVRuntime运行于Ring -1特权层,是GreatVoid系统的核心运行时组件。其主要职责是在被保护程序执行过程中,拦截由CPUID指令触发的VM Exit事件,查询TFR表获取当前基本块的控制流信息,计算下一基本块的执行地址并写入跳转寄存器,最后通过VMRESUME恢复Guest执行。

VT分发器的核心dispatch逻辑根据TFR表中的FlowType字段进行分支处理,共处理以下五种控制流类型。

1.     对于Ret类型,分发器从Guest栈顶读取返回地址,将rsp加8模拟ret语义,并将读取到的地址写入跳转寄存器。

2.     对于Single和RetStub类型,分发器直接将succs[0]中记录的后继地址写入跳转寄存器。

3.     对于Cond类型,分发器读取VMCS中的RFLAGS寄存器,根据TFR表记录的condCode字段索引条件判断handler表,根据判断结果选择succs[0](fall-through)或succs[1](taken)写入跳转寄存器。

4.     对于Call类型,分发器将succs[1]中记录的return stub地址压入Guest栈,再将succs[0]中记录的callee入口地址写入跳转寄存器。

5.     对于ExternCall类型,外部调用通过GVSCC的resolve_api机制处理,硬件直接执行call与ret,不经VT调度。

此外,GreatVoid的运行时组件以Bootkit形式部署。系统在Boot阶段由Bootkit读取TFR表并加载至内存,通过对Windows启动加载器WinLoad.efi的特定机制进行利用,在操作系统内核初始化之前完成Hypervisor的部署与激活。Bootkit在Boot阶段申请的内存区域对操作系统内核不可见,不出现在操作系统的物理内存管理结构中,GVRuntime通过私有寻址机制访问该区域,保证TFR表及运行时数据在系统运行期间不暴露于操作系统的内存视图之内。出于安全考虑,本文对所利用的具体技术细节不作公开披露。

下面给出TFR表的结构

多分支TFR

TFR表以基本块为粒度,每个基本块对应一条TraceFlowRecord记录,包含以下字段:FlowType字段标识该基本块的控制流类型,共分为Ret、Single、Cond、Call、RetStub、ExternCall六种;condCode字段在FlowType为Cond时有效,存储条件跳转的条件码,与x86 0F8x系列opcode低nibble对应;succs字段为两个SuccInfo结构,分别存储后继基本块的序号与回填后的地址偏移;freeIn与freeOut字段分别记录该基本块入口与出口处的空闲物理寄存器掩码,供GVRC选择跳转寄存器时使用。

六种FlowType的语义如下表所示:

FlowType

后继数

succs含义

GVR处理方式

Ret

动态

无

读Guest栈顶,rsp加8,写跳转寄存器

Single

1

succs[0]为目标


冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
点赞 ・11
打赏
分享
最新回复 (6)
雪    币: 2473
活跃值: (1925)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
2 楼
66
12小时前
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3 楼
666
12小时前
0
雪    币: 906
活跃值: (2311)
能力值: ( LV8,RANK:125 )
在线值:
发帖
回帖
粉丝
4 楼
学习
11小时前
0
雪    币: 234
活跃值: (3260)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5 楼
1
11小时前
0
雪    币: 7542
活跃值: (7061)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
6 楼
666
10小时前
0
雪    币: 742
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7 楼
学习学习
7小时前
0
游客
登录 | 注册 方可回帖
返回