## 引用 ##
>这篇文章的目的是介绍基于Windows Hyper-V虚拟机平台Hypervisor Platform API实现的魔改版Unicorn Engine模拟器和调试引擎开发心得
[toc]
## 简介 ##
跨平台模拟器unicorn框架基于Qemu的TCG模式(Tiny Code Generator),以无硬件虚拟化支持方式实现全系统的虚拟化,支持跨平台和架构的CPU指令模拟,本文讨论是一款笔者的实验性项目采用Windows Hypervisor Platform虚拟机模式提供了另一种CPU指令的模拟方式,在保持原有unicorn导出接口不变的情况下,采用Hyper-V支持带硬件虚拟化支持的Windows Hypervisor Platform API接口扩展了底层CPU模拟环境实现,支持X86指令集的二进制程序模拟平台和调试器.
## unicorn框架qemu之Hyper-v模式比较 ##
Windows Hypervisor Platform是微软在Hyper-V平台提供一种新的API库,用于允许第三方开发者创建和管理EXO分区.EXO分区是一种与Hyper-V兼容并可以同时运行的虚拟机分区,用于支持第三方开发者的虚拟化解决方案,如VirtualBox、Qemu、VMware等,采用虚拟机容器的方式模拟客户机整个操作系统虚拟环境.
跨平台模拟执行unicorn框架和上层qiling框架都是基于qemu的TCG模式(Tiny Code Generator),支持无硬件虚拟化支持方式在源ISA(处理器架构)和目标ISA不同的情况下CPU指令模拟,类似一个jit解释器,一个循环中不断的读入源ISA程序指令,QEMU先转换成源ISA的IR,反汇编并用代码在目标ISA编译后的IR在模拟TranslationBlock指令中执行,当然这些指令也是转换后的汇编模式比起直接调用c函数模拟可以优化效率,qemu对TranslationBlock在分支执行返回后切换到Qemu上下文保存虚拟环境状态继续下个分支执行,转换过程采用内联汇编的方式支持hook断点与内存监视trace等功能.如果切换成Windows Hypervisor Platform(以下简称Hyper-v虚拟机)模式就省去了模拟cpu指令的环节,真实的物理cpu被虚拟化成vcpu,这个逻辑封装成由Hypervisor API创建虚拟机的调度者调度和物理机共享cpu资源,API底层实现又由Hyper-v自己的调度器(Hypervisor)的Hvix64.exe模块实现,源ISA的指令运行在vcpu上,看起来就像在物理cpu一样.每个hyper-v分区实例是一个相对于其他分区隔离的虚拟环境,由WHvCreatePartition函数创建分区,这个分区通过VID.sys(Virtualization Infrastructure Driver)驱动向管理者也就是是被创建分区的父分区hv(Hypervisor)模块通信抽象成上层api交给调用者调度,hv模块同样也有自己的分区与其他分区隔离,如果要调试hv模块可以通过bcdedit /set hypervisordebug on方式(具体见引用节)启用2个windbg实例调试内核和hv.如果是在物理机上,物理机的操作系统运行在由根分区hv管理创建的虚拟机容器中,嵌套的子分区由它的父分区hv模块管理,所有的虚拟机陷入陷出都首先交给根分区的hv处理,再分发给父分区hv处理完成后回到子分区继续执行,即使被调度的是一段shellcode,整个虚拟环境也具备一个完整的操作系统拥有x86体系虚拟化资源.一个分区允许创建多个可以同时执行调度的vcpu通过WHvCreateVirtualProcessor,每个vcpu都可以设置自己的寄存器上下文,而内存对象被整个分区共享,进入WHvRunVirtualProcessor开始调度,整个调度过程中对外面的Hypervisor是不透明的,直到遇到一个退出条件比如说断点,内存违规访问,vmcall指令等函数会返回,可以从vmexit的上下文中获取退出原因,Hypervisor可以执行对应的操作继续vcpu运行.qemu无硬件虚拟化采用纯模拟的方式实现缺点是速度较慢.Hyper-v模式主要是陷入陷出调度器需要处理时间,源ISA指令执行速度与真实cpu相当,这种方式速度较快.
## 内存管理分析 ##
qemu采用MemoryRegion结构体管理所有分配的gva(客户机虚拟内存地址)到hva(宿主机虚拟内存地址)的映射,内部是一个双向链表结构包含了起始,结束gva和映射hva地址,支持先指定gva再分配hva模式,查询链表通过二叉树方式实现,如果新分配的地址位于已分配区域返回UC_ERR_MAP错误需要重新指定gva,对于读取和写入内存则是先通过gva找到hva,直接操作hva相对偏移量数据,这种方式一般仅限于模拟应用层程序的内存管理,对于所有内存操作只是处理所有已经映射的gva,遇到了未被映射的内存直接抛出UC_ERR_WRITE_UNMAPPED错误结束程序.由于对于内核态程序存在虚拟机地址和物理地址映射关系,这种直接的转换映射处理并不适用于这种情况.而Hyper-v模式多出了一个gpa(客户机物理内存地址)的概念,映射宿主机虚拟内存并不能直接通过hva -> gva的方式映射,而是通过WHvMapGpaRange函数先映射gpa再根据当前vcpu的cr3寄存器pde,pte转换到gva,这种模式也就是我们真实x86体系操作系统的内存映射模式,同时适用于用户态和内核态程序.至于cr3寄存器如映何射gva虚拟内存可以参考看雪其他相关文章这里不在赘述,笔者项目沿用了qemu内存管理框架结构体,实现参考WinHvShellcodeEmulator项目,下面这段代码展示了在虚拟机映射gva和方式.
```
HRESULT WhSeMapHostToGuestVirtualMemory(whpx_state *Partition, uintptr_t HostVa,
uintptr_t *GuestVa, size_t Size,
WHSE_MEMORY_ACCESS_FLAGS Flags)
{
auto size = ALIGN_UP(Size);
PWHSE_ALLOCATION_NODE existingNode = nullptr;
auto hresult =
WhSeFindAllocationNodeByGva(Partition, *GuestVa, &existingNode);
uintptr_t suggestedGva = 0;
if (*GuestVa == 0 || existingNode != nullptr) {
auto hresult = WhSiSuggestVirtualAddress(
Partition, size, &suggestedGva, Partition->VirtualProcessor.Mode);
} else
suggestedGva = ALIGN(*GuestVa);
existingNode = nullptr;
hresult = WhSeFindAllocationNodeByGva(Partition, suggestedGva, &existingNode);
auto startingGva = ALIGN(suggestedGva);
auto endingGva = ALIGN_UP(startingGva + size);
uintptr_t suggestedGpa = 0;
hresult = WhSiSuggestPhysicalAddress(Partition, size, &suggestedGpa);
WHSE_ALLOCATION_NODE node{.BlockType =
MEMORY_BLOCK_TYPE::MemoryBlockVirtual,
.HostVirtualAddress = HostVa,
.GuestPhysicalAddress = suggestedGpa,
.GuestVirtualAddress = startingGva,
.Size = size};
hresult = WhSeInsertAllocationTrackingNode(Partition, node);
// Setup matching PTEs
for (auto gva = startingGva, page = suggestedGpa; gva < endingGva;
gva += PAGE_SIZE, page += PAGE_SIZE) {
hresult = WhSiInsertPageTableEntry(Partition, gva, page);
hresult = ::WHvMapGpaRange(
Partition->partition, reinterpret_cast<PVOID>(HostVa),
static_cast<WHV_GUEST_PHYSICAL_ADDRESS>(suggestedGpa), size, Flags);
*GuestVa = startingGva;
return hresult;
}
HRESULT WhSiInsertPageTableEntry(whpx_state *Partition,
uintptr_t VirtualAddress,
uintptr_t PhysicalAddress)
{
// "Explode" the VA into translation indexes
uint16_t pml4Idx;
uint16_t pdpIdx;
uint16_t pdIdx;
uint16_t ptIdx;
uint16_t phyOffset;
auto hresult = WhSiDecomposeVirtualAddress(
VirtualAddress, &pml4Idx, &pdpIdx, &pdIdx, &ptIdx, &phyOffset);
// Search entry in PML4
auto pml4e = reinterpret_cast<PMMPTE_HARDWARE>(
Partition->MemoryLayout.Pml4HostVa)[pml4Idx];
if (pml4e.Valid == FALSE) {
// Shouldn't happen as we initialized all PLM4 entries upfront
return HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
}
// Search entry in Page Directory Pointers
uintptr_t pdpHva = 0;
h
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
跨平台模拟执行unicorn框架基于Qemu的TCG模式(Tiny_Code_Generator),_unicorn-whpx.zip (31个子文件)
unicorn-whpx-main
unicorn-whpx-core
x86_64_whpx.h 109KB
target
WinHvDefs.hpp 7KB
WinHvMemory.hpp 2KB
DoubleLinkedList.cpp 7KB
DoubleLinkedList.hpp 2KB
WinHvMemoryInternal.hpp 3KB
unicorn-whpx.h 822B
WinHvMemoryPrivate.hpp 798B
WinHvHelpers.hpp 574B
WinHvMemoryPrivate.cpp 4KB
WinHvMemoryInternal.cpp 29KB
unicorn-whpx.c 171KB
whpx-internal.h 6KB
WinHvHelpers.cpp 14KB
WinHvMemory.cpp 21KB
WinHvAllocationTracker.hpp 3KB
WinHvAllocationTracker.cpp 7KB
softmmuwhpx
vl.c 2KB
exec-vary.c 2KB
ioport.c 5KB
cpus.c 22KB
memory_mapping.c 5KB
exec.c 64KB
memory.c 41KB
qiling
utils.py 3KB
gdb.py 33KB
unicorn
unicorn_const.py 3KB
unicorn.py 43KB
2.7z 2.55MB
img
unifix.gif 8.26MB
README.md 21KB
共 31 条
- 1
资源评论
普通网友
- 粉丝: 0
- 资源: 510
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功