首页
论坛
专栏
课程

[系统底层] [原创]Windows 10 (14393) VT虚拟化与CPU时间计数器

2016-9-16 21:55 11247

[系统底层] [原创]Windows 10 (14393) VT虚拟化与CPU时间计数器

2016-9-16 21:55
11247

声明:本文及代码仅供学习交流,转载请保留原作者信息。
首先要感谢下坛友的支持,以及各路大牛对小弟我的指导。
第一次在看雪发文章,有疏漏错误之处还望指出。

大家应该知道巨硬对Windows 10 的架构做了极大的更新。同时也增加了一些新的汇编指令。

那CPU时间计数器和VT加载有何关系呢?
这要从我前几天准备在Win10上加载VT开始。

Win10下自带Hyper-V,先把它关掉。


本来抱着直接把MiniVT重新用WDK 10编译就好的心态运行虚拟机,然后加载。
结果是,蓝屏。

这份VT代码在Win7 x64上跑得好好的,怎么到Win10就不行了?
于是我在VMM(EXIT事件接口函数下断点),一切正常,没有出现什么寄存器被篡改、事件没处理等问题。
奇怪?难不成Win10不允许第三方加载VT?

后面我查看了下蓝屏信息(虚拟机和真实机都是同一个蓝屏代码):CRITICAL_PROCESS_DIED
它的意思是:系统关键进程终止(DIED)。


奇怪,难道是System进程出问题了?
后面我在Windbg里看到,不是System进程出问题,是services.exe和svhosts.exe进程出了问题。

 *** Unhandled exception 0xc000001d, hit in C:\Windows\system32\svchost.exe -k netsvcs:

 *** enter .exr 0000001C05B7E670 for the exception record
 ***  enter .cxr 0000001C05B7E180 for the context
 *** then kb to get the faulting stack

Break instruction exception - code 80000003 (first chance)
0033:00007ff9`2cf1212a cc  

这个是应用层异常,因为是svhosts.exe进程,牵连了内核层一起崩溃了。
异常代号是0xc000001d,居然是个非法指令异常。

kd> .exr 0000001C05B7E670
ExceptionAddress: 00007ff92cec4a3a
   ExceptionCode: c000001d [B]([U]Illegal instruction[/U][/B])
  ExceptionFlags: 00000000
NumberParameters: 0


继续查看异常发生地址,是这个"RDTSCP"指令出现了非法指令异常。
kd> u 00007ff92cec4a3a
00007ff9`2cec4a3a 0f01f9          rdtscp
00007ff9`2cec4a3d 33c0            xor     eax,eax
00007ff9`2cec4a3f 8ac1            mov     al,cl
00007ff9`2cec4a41 c3              ret
00007ff9`2cec4a42 b853000000      mov     eax,53h
00007ff9`2cec4a47 0f03c0          lsl     eax,eax
00007ff9`2cec4a4a 7504            jne     00007ff9`2cec4a50
00007ff9`2cec4a4c c1e80e          shr     eax,0Eh

嗯哼?Windbg都能识别出是RDTSCP指令,为什么还会非法指令异常?
于是我搜索了下RDTSCP这个指令的用途,它是RDTSC的升级版,在一些比较新的处理器中用于获得CPU时间计数器。
到这里我就没头绪了,RDTSCP这个指令怎么和VT相冲突了?
然后,我又查看了Intel手册关于RDTSCP的处理。

在Intel手册附录C我找到了这个RDTSCP指令的VMEXIT处理。

51 当客户机软件运行 RDTSCP 并且 "enable RDTSCP" 、 "RDTSC exiting" 标识位在虚拟机运行控制域中置为1时触发。

按照注释说的,应该是开启了这两个标识位才会产生这个exit事件才对啊。
不管了,为了验证必须处理RDTSCP指令EXIT事件,我参考了newbluepill开启了那两个标识并且在exithandler里模拟执行了RDTSCP(注意:开启了RDTSCP指令的监视后,还必须要处理RDTSC指令的EXIT事件)。
模拟执行RDTSCP,只要像处理RDTSC一样就可以了,即调用RDTSC汇编指令后,把edx:eax赋值给客户机即可完成处理。

果然,处理了这个事件后,VT开启成功了。的确是我们缺少了必要的处理,导致了系统关键进程发生非法指令异常,关键进程异常退出,并最终导致系统蓝屏。

附上最终效果(多核+真实机)
(注:TestVT是通过调用CPUID指令来检查VT是否开启成功的。成功则修改ebx,ecx,edx为指定的数值)

总结:
Windows 7为了兼容一些老的处理器,并没有使用Intel给出的一些新指令。所以,在Win7下开启VT,并不需要对RDTSC和RDTSCP做出必要处理。当然,并不排除某些CPU计时软件会用到这些指令。
因为Windows 10 新增了这些指令,所以要求开发者进行单独处理。

其实,你如果做出一个完整VT系统,可以完全忽略以上问题。

不管怎么样,我们在Win10加载VT(最小化),还是成功了的。于是,我们现在可以在Win10下干点......


附上对RDTSC和RDTSCP的处理代码(部分)
exithandler.h
void HandleRDTSC()
{
  ULONG uCPUID;
  uCPUID = KeGetCurrentProcessorNumber();
  Asm_Rdtsc(&g_GuestRegs[uCPUID].rax, &g_GuestRegs[uCPUID].rdx);
}

// Work for Windows 10
void HandleRDTSCP()
{
  ULONG uCPUID;
  uCPUID = KeGetCurrentProcessorNumber();
  g_GuestRegs[uCPUID].rax = (Asm_GetTSC() & 0xFFFFFFFF);
  g_GuestRegs[uCPUID].rdx = (Asm_GetTSC() >> 32);
}

extern "C" void VMMEntryPoint()
{
  ULONG64 ExitReason;
  ULONG64 ExitInstructionLength;
  ULONG64 GuestResumeEIP;
  ULONG64 uCPUID;
  uCPUID = KeGetCurrentProcessorNumber();
  ExitReason = Vmx_VmRead(VM_EXIT_REASON);
  ExitInstructionLength = Vmx_VmRead(VM_EXIT_INSTRUCTION_LEN);

  g_GuestRegs[uCPUID].rsp = Vmx_VmRead(GUEST_RSP);
  g_GuestRegs[uCPUID].rip = Vmx_VmRead(GUEST_RIP);
  g_GuestRegs[uCPUID].cr3 = Vmx_VmRead(GUEST_CR3);
  switch(ExitReason)
  {
  case EXIT_REASON_CPUID:
    {
      HandleCPUID();
      break;
    }
  case EXIT_REASON_INVD:
    {
      HandleInvd();
      break;
    }
  case EXIT_REASON_VMCALL:
    {
      HandleVmCall();
      break;
    }
  case EXIT_REASON_MSR_READ:
    {
      HandleMsrRead();
      break;
    }
  case EXIT_REASON_MSR_WRITE:
    {
      HandleMsrWrite();
      break;
    }
  case EXIT_REASON_CR_ACCESS:
    {
      HandleCrAccess();
      break;
    }
    case EXIT_REASON_RDTSC:  // 16
    {
      HandleRDTSC();
      break;
    }
    case EXIT_REASON_RDTSCP: // 51
    {
      HandleRDTSCP();
      break;
    }
  default:
    break;
  }

  GuestResumeEIP = g_GuestRegs[uCPUID].rip+ExitInstructionLength;
  Vmx_VmWrite(GUEST_RIP,GuestResumeEIP);
  Vmx_VmWrite(GUEST_RSP,g_GuestRegs[uCPUID].rsp);
}

vtasm.asm
Asm_Rdtsc Proc
  mov rbx,rcx
  mov rsi,rdx

  xor rax,rax
  xor rdx,rdx

  rdtsc
  mov [rbx],rax
  mov [rsi],rdx
  ret
Asm_Rdtsc Endp

Asm_GetTSC PROC
;Copy from newbluepill
  rdtsc
  shl    rdx, 32
  or    rax, rdx
  ret
Asm_GetTSC ENDP

vtsystem.cpp
extern "C" void SetupVMCS()
{
     // ...... 
     // 下面的代码开启RDTSC事件
        uCPUBase = VmxAdjustControls(0,MSR_IA32_VMX_PROCBASED_CTLS);
  uCPUBase |= CPU_BASED_RDTSC_EXITING;
  uCPUBase |= CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
       Vmx_VmWrite(CPU_BASED_VM_EXEC_CONTROL,uCPUBase);

  uTemp64 = 0;
  uTemp64 |= SECONDARY_EXEC_RDTSCP;  // enable RDTSCP
  Vmx_VmWrite(SECONDARY_VM_EXEC_CONTROL, uTemp64);
     // ......
}

驱动文件,Win10 x64(测试签名)
MiniVT_Win10.rar

[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

上传的附件:
最新回复 (18)
小宝来了 1 2016-9-16 21:56
2
0
沙发自己坐啦
黑洛 1 2016-9-16 22:00
3
0
mobai
Elias恩子 2016-9-16 22:01
4
0
顶一下小宝。。。。。。
fengyunabc 1 2016-9-16 22:01
5
0
顶!!!
夜雾 2016-9-16 22:06
6
0
希望小宝能出更多关于VT技术的好文章和好视频
hzqst 3 2016-9-16 22:42
7
0
当我没说。。。
myqqi 1 2016-9-17 08:19
8
0
虽然不懂,但绝对是好文章,以后留着用
FadeTrack 1 2016-9-17 14:32
9
0
mark 一下 有空再看
ugvjewxf 2016-9-17 16:21
10
0
难得有人讲解细节原理'顶下
killpy 2 2016-9-17 17:03
11
0
小宝牛逼 学习了 希望多出一些这方面的文章
wanc 2016-9-19 19:09
12
0
看不懂的样子
rozbo 2016-9-20 14:43
13
0
直接用Hyper-V不就好了。。至于自己弄VT吗
coolboyme 2 2016-11-29 16:46
14
0
额,SECONDARY_EXEC_RDTSCP这个宏没给定义~
mudbee 2017-5-28 16:34
15
0
求直接放代码,我不是伸手党,但是这次伸手了。
yy虫子yy 2017-5-28 17:28
16
0
路过mark一下
kingswb 2017-5-28 18:01
17
0
学习下的
mudbee 2017-5-30 15:25
18
0
已经移植到win10x64  虚拟机上  多核下  一切ok。但是真机下卡死。。。
gdleave 2019-4-21 11:45
19
0
感谢分享经验,学习下
游客
登录 | 注册 方可回帖
返回