尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
AMD-V Hook 驱动开发实战:从 SVM 初始化到 MSR 拦截的完整指南
简介这是一份面向Windows内核驱动开发者与虚拟化技术研究者的实战项目源码聚焦AMD-V硬件虚拟化从零构建基于SVM指令集的内核驱动实现硬件级Hook并支持嵌套虚拟化。适合具备操作系统架构、内核编程接口与硬件指令集基础的中高级开发者用于服务器虚拟化、云平台及虚拟机监控等场景的深入学习与实验验证。资源包共108个文件约3.91MB以85个C头文件与6个C源文件为主体辅以汇编、静态库、工程配置及说明文档覆盖SVM指令处理、页表管理、Hook实现与功能测试等核心模块目录结构完整、自主性强。目前已有220人学习下载。通过该源码读者可掌握从零搭建驱动框架的完整思路理解硬件级Hook与嵌套虚拟化的实现细节并借助附带的开发文档与示例代码快速配置测试环境、评估驱动功能与性能是虚拟化方向难得的实践参考。1. 从零构建 AMD-V Hook 驱动为什么有人宁愿写内核代码也不碰 API在 Windows 上做行为监控、沙箱分析或反作弊对抗常规做法是挂 API Hook、写过滤驱动、或者用 ETW 做事件订阅。但只要目标程序稍微有点自我保护意识这些用户态或半内核态的拦截点就会被逐一绕过。于是有一部分人把目光投向了 CPU 本身——利用 AMD 的 SVMSecure Virtual Machine指令集在硬件层面把整个操作系统装进一个轻量级 Hypervisor 里所有敏感操作在到达内核之前就已经被截获。这就是 AMD-V Hook 驱动要解决的问题不是去改内核的代码路径而是让 CPU 在指令执行层面就把控制权交出来。这个方向适合谁适合已经能写基础 WDM 驱动、理解 IRQL 和分页机制、并且愿意花时间啃 AMD 官方 APM 第二卷的工程师。它不适合刚接触内核开发的新手因为一个错误的 VM_HSAVE_PA 设置就能让整台机器直接蓝屏而且这种蓝屏往往没有 dump 可看。但如果你确实需要一种不依赖内核补丁、不修改目标进程内存的监控手段SVM 嵌套虚拟化是目前在 AMD 平台上最干净的一条路。接下来我会按实际落地顺序从环境确认、SVM 初始化、嵌套分页、到 Hook 点的选择与调试把这条路上能踩的坑尽量提前标出来。2. 动手前的环境确认与 SVM 能力探测2.1 为什么第一步不是写代码而是查 CPU 标志很多人拿到项目标题就开始翻 WRK 或者 ReactOS 的源码结果编译出来的驱动在目标机器上加载即蓝屏。血泪经验是AMD-V 不是所有 AMD CPU 都默认开启的而且 BIOS 里可能被关掉。你需要在写第一行驱动代码之前确认三件事CPU 支持 SVM、BIOS 没有禁用、Windows 没有用 Hyper-V 把 SVM 独占。最直接的确认方式是在目标机上跑一条 CPUID 指令。CPUID 的 0x80000001 叶子返回的 ECX 寄存器第 2 位就是 SVM 支持标志。如果这一位是 0后面所有工作都不用做了。如果这一位是 1 但驱动加载后 VM_RUN 返回错误那大概率是 BIOS 里的 SVM Mode 被关了或者 Hyper-V 已经先占用了。#include intrin.h typedef struct _CPUID_RESULT { int eax; int ebx; int ecx; int edx; } CPUID_RESULT; BOOLEAN CheckSvmSupport(VOID) { CPUID_RESULT result {0}; __cpuid((int*)result, 0x80000001); // ECX bit 2 SVM support if (!(result.ecx (1 2))) { DbgPrint(SVM not supported by CPU\n); return FALSE; } // 检查是否被 Hyper-V 占用CPUID 0x40000000 返回 Microsoft Hv CPUID_RESULT hv {0}; __cpuid((int*)hv, 0x40000000); if (hv.ebx 0x7263694D hv.ecx 0x666F736F hv.edx 0x76482074) { DbgPrint(Hyper-V is running, SVM may be unavailable\n); return FALSE; } return TRUE; }这段代码做了两层检查。第一层是 CPUID 0x80000001 的 ECX bit 2这是 AMD 官方 APM 里定义的 SVM 存在位。第二层是读 CPUID 0x40000000 的厂商字符串如果返回 Microsoft Hv说明 Hyper-V 已经在 root 模式运行此时 SVM 指令虽然 CPU 支持但会被 Hyper-V 的 hypervisor 拦截你的驱动拿不到真正的控制权。参数说明__cpuid是 MSVC 提供的内联函数第二个参数是叶子号。0x80000001 是扩展功能叶子0x40000000 是 hypervisor 厂商叶子。注意在驱动里调用__cpuid是安全的它不涉及内存访问IRQL 要求也不高。2.2 用 WinDbg 确认 SVM 是否真的可用即使 CPUID 检查通过也不代表你的驱动能成功执行 VMRUN。常见情况是 BIOS 里 SVM 被禁用但 CPUID 仍然报告支持。这时候需要看 MSR。AMD 的 VM_CRVM Control RegisterMSR 地址是 0xC0010114其中 bit 4 是 SVMDISSVM Disable。如果这一位是 1说明 SVM 被锁了。#define MSR_VM_CR 0xC0010114 ULONG64 ReadVmCr(VOID) { return __readmsr(MSR_VM_CR); } BOOLEAN IsSvmDisabledByBios(VOID) { ULONG64 vmcr ReadVmCr(); // bit 4 SVMDIS if (vmcr (1ULL 4)) { DbgPrint(SVM disabled by BIOS, VM_CR 0x%llX\n, vmcr); return TRUE; } return FALSE; }__readmsr是内核态读 MSR 的标准方式但注意它只能在 IRQL DISPATCH_LEVEL 时调用。如果你在 DriverEntry 里调用IRQL 是 PASSIVE_LEVEL没问题。如果 SVMDIS 被置位你无法通过软件清除它——这是 BIOS 的硬锁只能进 BIOS 设置里打开 SVM Mode。提示有些主板把 SVM 选项藏在 Advanced CPU Configuration 或 Overclocking 菜单下不同厂商命名不一样。如果找不到直接搜主板手册里的 SVM 或 Virtualization。2.3 驱动签名与测试模式的实际取舍Windows 10 1607 之后内核驱动必须要有微软的 WHQL 签名或者 EV 签名才能加载。对于 AMD-V Hook 这种驱动你不可能拿去送签。实际做法有两种一是开启测试模式bcdedit /set testsigning on二是用虚拟机做开发调试。测试模式会在桌面右下角显示水印但功能不受影响。# 以管理员身份运行 bcdedit /set testsigning on bcdedit /set nointegritychecks on # 重启后生效 shutdown /r /t 0这两条命令的作用testsigning on允许加载测试签名的驱动nointegritychecks on关闭完整性检查。重启后你可以用makecert生成自签名证书然后用signtool给驱动签名。但注意从 Windows 10 1607 开始即使测试模式也需要驱动有签名只是不要求 WHQL。自签名证书需要导入到 受信任的根证书颁发机构 和 受信任的发布者 两个存储区。如果不想折腾签名最省事的方案是在 VMware 或 Hyper-V 里装一个 Windows 虚拟机在虚拟机里开嵌套虚拟化。VMware Workstation 支持暴露 SVM 给 guest但需要在 VM 设置里勾选 Virtualize Intel VT-x/EPT or AMD-V/RVI。这样你的驱动在 guest 里跑蓝屏了也不影响宿主机。3. SVM 初始化从 EFER 到 VMCB 的完整配置3.1 EFER.SVME 是总开关但别急着打开AMD 的 SVM 架构里EFERExtended Feature Enable Register的 SVME 位bit 12是 SVM 的总开关。只有这一位置 1VMRUN 指令才被允许执行。但这里有一个顺序问题如果你在设置 VMCB 之前就打开 SVME然后执行了 VMRUNCPU 会直接关机不是蓝屏是物理关机。所以正确的顺序是先分配 VMCB 和 Host Save Area再设置 EFER.SVME最后才执行 VMRUN。#define MSR_EFER 0xC0000080 #define EFER_SVME (1ULL 12) VOID EnableSvm(VOID) { ULONG64 efer __readmsr(MSR_EFER); efer | EFER_SVME; __writemsr(MSR_EFER, efer); } VOID DisableSvm(VOID) { ULONG64 efer __readmsr(MSR_EFER); efer ~EFER_SVME; __writemsr(MSR_EFER, efer); }__writemsr同样是内核态写 MSR 的标准函数。注意 EFER 是一个全局寄存器打开 SVME 后当前 CPU 上所有核心都会受影响。如果你是多核系统需要在每个核心上都执行一次。通常做法是在 DriverEntry 里用KeSetSystemAffinityThread把线程绑到每个核心然后逐个初始化。3.2 VMCB 的结构与必须手动填的字段VMCBVirtual Machine Control Block是 SVM 里最核心的数据结构大小是 4KB必须 4KB 对齐。它分为两个区域控制区和状态保存区。控制区里你需要手动填的字段包括字段偏移作用常见值intercept_cr_read0x000拦截 CR 读取0xFFFFFFFF全拦intercept_cr_write0x004拦截 CR 写入0xFFFFFFFFintercept_dr_read0x008拦截 DR 读取0xFFFFFFFFintercept_dr_write0x00C拦截 DR 写入0xFFFFFFFFintercept_exceptions0x010拦截异常0xFFFFFFFFintercept_instruction10x014拦截 INTR/IRET 等按需intercept_instruction20x018拦截 VMRUN/VMMCALL 等0xFFFFFFFFintercept_msr0x01CMSR 拦截位图地址指向 2KB 位图guest_asid0x058ASID 编号1tlb_control0x05CTLB 刷新控制1每次刷新n_cr30x0B0嵌套页表基址物理地址vmcb_clean0x0C0干净位图0nrip0x0C8下一条指令地址0这些字段里最容易翻车的是intercept_msr。它不是一个简单的位掩码而是一个指向 2KB MSR 拦截位图的物理地址。位图的每一位对应一个 MSR 地址如果某位是 1访问对应的 MSR 就会触发 #VMEXIT。如果你把intercept_msr设成 0xFFFFFFFFCPU 会尝试从物理地址 0xFFFFFFFF 读位图结果就是直接重启。typedef struct _VMCB { UCHAR intercept_cr_read[2]; UCHAR intercept_cr_write[2]; UCHAR intercept_dr_read[2]; UCHAR intercept_dr_write[2]; ULONG intercept_exceptions; ULONG intercept_instruction1; ULONG intercept_instruction2; ULONG intercept_instruction3; ULONG reserved1; ULONG intercept_msr; // ... 省略中间字段 UCHAR reserved2[0x3C0]; UCHAR guest_area[0x400]; } VMCB, *PVMCB; PVMCB AllocateVmcb(VOID) { PVMCB vmcb ExAllocatePoolWithTag(NonPagedPool, 4096, bcmV); if (!vmcb) return NULL; RtlZeroMemory(vmcb, 4096); // 必须 4KB 对齐 if ((ULONG_PTR)vmcb 0xFFF) { ExFreePoolWithTag(vmcb, bcmV); return NULL; } return vmcb; }ExAllocatePoolWithTag分配的内存不保证 4KB 对齐所以实际项目中通常用MmAllocateContiguousMemorySpecifyCache来分配物理连续且对齐的内存。VMCB 的物理地址要填到 VMCB 的n_cr3字段里所以你必须知道它的物理地址而不是虚拟地址。3.3 Host Save Area 与 VMRUN 的最小执行路径Host Save Area 是一块 4KB 对齐的内存VMRUN 执行时会把当前 Host 的 CPU 状态保存到这里。它的物理地址要写到 MSR 0xC0010117VM_HSAVE_PA里。这个 MSR 必须在打开 EFER.SVME 之前设置好。#define MSR_VM_HSAVE_PA 0xC0010117 PHYSICAL_ADDRESS AllocateHostSaveArea(VOID) { PHYSICAL_ADDRESS low, high, skip; low.QuadPart 0; high.QuadPart 0xFFFFFFFF; skip.QuadPart 0; PVOID va MmAllocateContiguousMemorySpecifyCache( 4096, low, high, skip, MmCached); if (!va) return (PHYSICAL_ADDRESS){0}; RtlZeroMemory(va, 4096); PHYSICAL_ADDRESS pa MmGetPhysicalAddress(va); __writemsr(MSR_VM_HSAVE_PA, pa.QuadPart); return pa; }MmAllocateContiguousMemorySpecifyCache分配的是物理连续内存适合做 VMCB 和 Host Save Area。MmGetPhysicalAddress返回物理地址。注意这个函数只能在非分页内存上调用而且返回的物理地址在启用 PAE 的情况下是 64 位的。VMRUN 指令本身很简单__vmrun(pa_vmcb)。但执行之前你必须确保 VMCB 里的guest_asid不为 0n_cr3指向有效的嵌套页表否则 CPU 会触发 #VMEXIT 并返回错误码。第一次跑的时候建议先把所有拦截位关掉只留一个intercept_instruction2的 VMRUN 位这样 guest 里执行 VMRUN 会触发 #VMEXIT你能确认整个流程是通的。4. 嵌套分页与 Hook 点的选择把控制权放在哪一层4.1 NPT 是必须的但你可以先不启用AMD 的嵌套页表NPTNested Page Table相当于 Intel 的 EPT。它让 guest 的物理地址经过两层转换guest 虚拟地址 - guest 物理地址 - host 物理地址。如果不启用 NPTguest 的物理地址就是 host 的物理地址这意味着 guest 能直接访问 host 的内存你的 Hook 驱动本身也会暴露在 guest 面前。但在开发初期我建议先不启用 NPT。原因很简单NPT 的页表构造比 VMCB 复杂得多而且一旦配错guest 里的 Windows 会以各种奇怪的方式崩溃你很难判断是 NPT 的问题还是 VMCB 的问题。先让 guest 在无 NPT 模式下跑起来确认 VMRUN 和 #VMEXIT 的处理逻辑没问题再回头加 NPT。// 在 VMCB 里关闭 NPT vmcb-n_cr3 0; // 同时在 intercept_instruction2 里打开 VMRUN 拦截 vmcb-intercept_instruction2 | (1 0); // VMRUN关闭 NPT 后guest 的 CR3 直接指向 host 的页表。这时候 guest 和 host 共享同一套页表你的驱动代码在 guest 里也能看到。这显然不是最终方案但作为调试阶段的最小可行路径它能帮你快速定位问题。4.2 MSR 拦截位图Hook 读写 MSR 的精确控制MSR 拦截是 SVM 里最实用的 Hook 点之一。很多内核级操作比如切换内核栈、修改系统调用入口都会涉及 MSR 读写。通过拦截MSR_LSTAR0xC0000082系统调用入口的写入你可以在 guest 修改系统调用处理函数之前拿到控制权。MSR 拦截位图是一块 2KB 的内存每一位对应一个 MSR 地址。MSR 地址范围是 0x00000000 到 0x00001FFF 和 0xC0000000 到 0xC0001FFF。位图的 bit 0 对应 MSR 0x0bit 1 对应 MSR 0x1以此类推。对于 0xC0000000 以上的 MSR位图偏移是(msr - 0xC0000000) / 8。#define MSR_BITMAP_SIZE 2048 PUCHAR AllocateMsrBitmap(VOID) { PUCHAR bitmap ExAllocatePoolWithTag(NonPagedPool, MSR_BITMAP_SIZE, rtbM); if (!bitmap) return NULL; RtlZeroMemory(bitmap, MSR_BITMAP_SIZE); return bitmap; } VOID SetMsrIntercept(PUCHAR bitmap, ULONG msr, BOOLEAN intercept) { ULONG index; if (msr 0xC0000000) { index (msr - 0xC0000000) / 8; } else { index msr / 8; } if (index MSR_BITMAP_SIZE) return; UCHAR bit 1 (msr % 8); if (intercept) { bitmap[index] | bit; } else { bitmap[index] ~bit; } }这段代码里SetMsrIntercept把 MSR 地址映射到位图的字节和位。注意 MSR 地址不是连续的0x00000000-0x00001FFF 和 0xC0000000-0xC0001FFF 是两个独立的区间。位图的前 1KB 对应低地址区间后 1KB 对应高地址区间。如果你把MSR_LSTAR0xC0000082的拦截位设上guest 每次写这个 MSR 都会触发 #VMEXIT你在处理函数里就能看到是谁在改、改成了什么值。4.3 用 #VMEXIT 处理函数实现 Hook 逻辑#VMEXIT 是 SVM 里所有拦截事件的统一入口。当 guest 触发了被拦截的操作CPU 会保存 guest 状态到 VMCB然后跳转到 host 的 #VMEXIT 处理函数。这个处理函数的地址由 Host Save Area 里的RIP字段决定你在初始化 Host Save Area 时就要填好。typedef struct _VMCB_CONTROL { ULONG exit_code; ULONG exit_info_1; ULONG exit_info_2; ULONG exit_int_info; ULONG64 exit_int_info_err; ULONG64 nrip; // ... } VMCB_CONTROL; VOID VmExitHandler(PVMCB vmcb) { ULONG exit_code vmcb-control.exit_code; switch (exit_code) { case 0x7B: // MSR read HandleMsrRead(vmcb); break; case 0x7C: // MSR write HandleMsrWrite(vmcb); break; case 0x81: // VMRUN // guest 里有人执行 VMRUN说明有嵌套虚拟化 DbgPrint(Nested VMRUN detected\n); vmcb-control.nrip 3; // 跳过 VMRUN 指令 break; default: DbgPrint(Unhandled VMEXIT: 0x%X\n, exit_code); break; } }exit_code是 #VMEXIT 的原因码。0x7B 是 MSR 读0x7C 是 MSR 写0x81 是 VMRUN。处理完拦截事件后你必须更新nripNext RIP告诉 CPU 下一条要执行的指令在哪里。如果不更新guest 会一直卡在同一条指令上表现为系统无响应。nrip的更新规则取决于拦截的指令长度。比如 VMRUN 是 3 字节指令所以nrip 3。MSR 读写通常是 2 字节rdmsr或wrmsr但如果是rdmsr带前缀可能是 3 字节。最稳妥的做法是用一个轻量级反汇编器解析当前指令长度但开发初期可以先用固定值遇到问题再调。5. 避坑与排查那些让机器直接重启的瞬间5.1 VMRUN 返回后直接重启没有蓝屏现象驱动加载成功EFER.SVME 也打开了但第一次执行 VMRUN 后机器直接断电重启Windows 事件日志里没有任何记录。原因VMCB 的guest_asid为 0或者n_cr3指向了无效的物理地址。AMD 的 SVM 规范里ASID 0 是保留给 host 的guest 必须使用非零 ASID。如果 ASID 为 0CPU 会触发 SHUTDOWN而不是 #VMEXIT。解决在 VMCB 初始化时把guest_asid设为 1。同时检查n_cr3是否指向有效的页表物理地址。如果暂时不用 NPT把n_cr3设为 0 并关闭 NPT 使能位。5.2 #VMEXIT 处理函数里访问 VMCB 导致二次异常现象guest 触发了 MSR 拦截进入 #VMEXIT 处理函数但在读取vmcb-control.exit_code时又触发了一个异常机器蓝屏错误码是IRQL_NOT_LESS_OR_EQUAL。原因VMCB 分配在分页内存里而 #VMEXIT 处理函数运行在 IRQL HIGH_LEVEL此时分页内存不可访问。如果你用ExAllocatePoolWithTag分配 VMCB它可能在分页池里。解决VMCB 和 Host Save Area 必须用MmAllocateContiguousMemorySpecifyCache分配这是非分页内存。同时在 #VMEXIT 处理函数里不要调用任何可能触发分页的函数包括DbgPrint在某些情况下也会有问题。调试阶段可以用DbgPrint但生产环境应该用KeBugCheckEx或者直接写端口。5.3 嵌套虚拟化下 VMRUN 被 Hyper-V 拦截现象在开启了 Hyper-V 的 Windows 上加载驱动CPUID 检查通过但 VMRUN 执行后返回错误码 0xFFFFFFFFguest 无法启动。原因Hyper-V 运行在 root 模式它把 SVM 指令拦截了。你的驱动实际上是在 Hyper-V 的 guest 里运行无法直接访问硬件 SVM。解决关闭 Hyper-V。用bcdedit /set hypervisorlaunchtype off然后重启。如果必须用 Hyper-V那这个方案就不适合你因为 Hyper-V 不会把 SVM 控制权交给 guest。5.4 MSR 拦截位图地址填错导致物理内存越界现象设置了intercept_msr字段但填的是虚拟地址而不是物理地址VMRUN 执行后机器重启。原因VMCB 里的所有地址字段都是物理地址。intercept_msr指向的位图必须是物理地址而且必须是 2KB 对齐。解决用MmGetPhysicalAddress获取位图的物理地址并确保分配时 2KB 对齐。如果位图是分页内存还要用MmProbeAndLockPages锁定它。5.5 guest 里 Windows 启动到一半卡死现象VMRUN 成功进入 guestWindows 开始启动但加载到某个驱动时卡死没有蓝屏就是不动了。原因某个被拦截的 MSR 或指令没有正确处理guest 在等待一个永远不会到来的响应。常见的是MSR_IA32_SYSENTER_CS或MSR_STAR被拦截后处理函数没有正确模拟读写。解决在 #VMEXIT 处理函数里对于 MSR 读要把 guest 期望的值写到vmcb-guest_area.rax和rdx里对于 MSR 写要更新你维护的影子 MSR 表。如果暂时不想处理就把对应的拦截位关掉让 guest 直接访问硬件 MSR。6. 进阶技巧用 VMCB 的 clean 位减少 #VMEXIT 开销6.1 为什么每次 VMRUN 都刷新 TLB 会让性能掉一半SVM 的tlb_control字段控制 VMRUN 时是否刷新 TLB。如果你每次都设成 1刷新全部guest 里的每个内存访问都会因为 TLB miss 而变慢。实测在 Windows 启动阶段全刷新 TLB 会让启动时间从 10 秒变成 40 秒以上。优化方法是利用 VMCB 的clean位图。clean字段是一个 32 位的位图每一位对应 VMCB 里的一个区域。如果某一位是 1表示该区域自上次 VMRUN 以来没有被修改过CPU 可以跳过加载。你可以把clean设为 0xFFFFFFFF然后只在你修改了 VMCB 字段时才清除对应的位。#define VMCB_CLEAN_INTERCEPT (1 0) #define VMCB_CLEAN_ASID (1 1) #define VMCB_CLEAN_TLB (1 2) #define VMCB_CLEAN_NCR3 (1 3) VOID UpdateVmcbField(PVMCB vmcb, ULONG field) { // 修改字段前清除 clean 位 vmcb-control.vmcb_clean ~field; // 修改字段 // ... // 下次 VMRUN 时 CPU 会重新加载这个区域 }vmcb_clean的位定义在 AMD APM 第二卷里有详细说明。实际使用中最值得优化的是intercept_msr位图和n_cr3。这两个字段不常变设上 clean 位后能显著减少 VMRUN 的开销。6.2 用 ASID 区分不同 guest 进程ASIDAddress Space Identifier是 SVM 里用来区分不同 guest 地址空间的编号。如果你只跑一个 guestASID 固定为 1 就行。但如果你想同时监控多个进程每个进程一个 ASID就能避免每次切换进程时刷新 TLB。#define MAX_ASID 64 ULONG AllocateAsid(VOID) { static ULONG next_asid 1; ULONG asid InterlockedIncrement(next_asid); if (asid MAX_ASID) { InterlockedExchange(next_asid, 1); asid 1; } return asid; }ASID 的范围是 1 到 0xFFFFFFFF但实际硬件可能只支持较小的位数。你可以通过 CPUID 0x8000000A 的 EBX 寄存器查支持的最大 ASID 数。如果超过硬件限制CPU 会触发 #VMEXIT 并返回错误。6.3 一个可复现的验证方法拦截 MSR_LSTAR 并记录调用者要验证你的 Hook 是否真的生效最直接的方法是拦截MSR_LSTAR0xC0000082的写入然后记录是谁在写、写入了什么值。MSR_LSTAR是系统调用入口Windows 在初始化时会写一次之后一般不变。如果有第三方驱动试图修改它你就能抓到。#define MSR_LSTAR 0xC0000082 VOID HandleMsrWrite(PVMCB vmcb) { ULONG msr (ULONG)vmcb-control.exit_info_1; ULONG64 value ((ULONG64)vmcb-guest_area.rdx 32) | vmcb-guest_area.rax; if (msr MSR_LSTAR) { DbgPrint(MSR_LSTAR write: 0x%llX, RIP: 0x%llX\n, value, vmcb-control.nrip); // 可以选择放行或拦截 // 放行直接更新影子 MSR然后跳过 wrmsr 指令 vmcb-control.nrip 2; // wrmsr 是 2 字节 return; } // 其他 MSR 直接放行 __writemsr(msr, value); vmcb-control.nrip 2; }这段代码里exit_info_1是触发 #VMEXIT 的 MSR 地址guest_area.rax和rdx组合成写入的 64 位值。nrip是触发wrmsr指令的地址你可以用它来定位调用者。如果放行直接执行__writemsr然后跳过指令如果拦截就不执行__writemsr只更新你自己的影子表。我自己的习惯是每次改完 VMCB 的拦截位先用一个最简单的 guest比如一个只执行rdmsr的裸机程序验证 #VMEXIT 能正常触发再逐步加复杂度。直接拿完整 Windows 做 guest一旦卡死你很难判断是哪个拦截位的问题。这个方案值得做但前提是你愿意花时间在调试上而不是指望一次编译就能跑通。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

基于Python Django的DES算法企业用户数据安全软件实现与避坑

基于Python Django的DES算法企业用户数据安全软件实现与避坑

简介:这套基于Python语言、Django框架与HTML前端、以DES算法保障企业用户数据安全的Web应用源码包,面向信息安全方向学习者、Django开发者以及需要轻量级数据加密方案的企业内部系统。项目完整展示了从后端逻辑、前端页面到MySQL数据库表设计的开发全流程…

📅 2026/10/7 20:08:43
实战:GPT-6 + Gemma 4 端云混合 AI 调用架构设计——TaoToken 统一 Key 接入与路由验证

实战:GPT-6 + Gemma 4 端云混合 AI 调用架构设计——TaoToken 统一 Key 接入与路由验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/7 20:08:43
树莓派CM4与CM5选型指南:SKU矩阵、底板设计与兼容性分析

树莓派CM4与CM5选型指南:SKU矩阵、底板设计与兼容性分析

1. 从一堆型号里理出头绪:为什么CM4和CM5值得单独拎出来说树莓派这条产品线走到今天,型号已经多到让新人头皮发麻。从最早的Model B、Model A,到后来的Zero系列、3B、3B、4B,再到现在的5和Compute Module家族,官网产品…

📅 2026/10/7 20:08:43
MORE NEWS

更多资讯

📰

嵌入式软件架构规范之 - 分层设计

一、规范的核心思想:驱动文件的“独立性”与“复用性” 该规范的本质是通过分层隔离,实现驱动代码的高复用性、低耦合性,确保驱动模块仅关注“硬件操作逻辑”,不依赖上层业务或下层硬件接口的具体实现细节。其核心要求包括: 二、关键要点解析 1. 驱动文件不能包含应用层…

📰

如何只用10分钟语音,训出一个能上直播的AI变声模型:RVC完整上手指南

如何只用10分钟语音&#xff0c;训出一个能上直播的AI变声模型&#xff1a;RVC完整上手指南 【免费下载链接】Retrieval-based-Voice-Conversion-WebUI Easily train a good VC model with voice data < 10 mins! 项目地址: https://gitcode.com/GitHub_Trending/re/Retri…

📰

G-Helper 完全指南:华硕笔记本如何免费设置风扇曲线、功耗限制与显卡切换

G-Helper 完全指南&#xff1a;华硕笔记本如何免费设置风扇曲线、功耗限制与显卡切换 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Viv…

📰

Buzz 语音转文字:离线 Whisper 转写的完整本地方案

Buzz 语音转文字&#xff1a;离线 Whisper 转写的完整本地方案 【免费下载链接】buzz Buzz transcribes and translates audio offline on your personal computer. Powered by OpenAIs Whisper. 项目地址: https://gitcode.com/GitHub_Trending/buz/buzz 两小时的会议录…

📰

《大模型基础》教材完整 PDF 获取指南:3 个判断定路线 + 文件位置速查表

《大模型基础》教材完整 PDF 获取指南&#xff1a;3 个判断定路线 文件位置速查表 【免费下载链接】Foundations-of-LLMs A book for Learning the Foundations of LLMs 项目地址: https://gitcode.com/GitHub_Trending/fo/Foundations-of-LLMs ZJU-LLMs 团队的开源仓库…

📰

Nangate 45nm开源工艺库+FreePDK45:从RTL到门级仿真的完整数字IC流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬