Visual c++ 64位windows VMware检测

Visual c++ 64位windows VMware检测,visual-c++,assembly,64-bit,vmware,detection,Visual C++,Assembly,64 Bit,Vmware,Detection,我试图开发一个应用程序,检测程序是否在虚拟机中运行 对于32位窗口,以下链接中已经介绍了一些方法: 我正在尝试在64位Windows操作系统中修改有关虚拟PC和VMware检测的代码。对于VMware,该代码可以在Windows XP 64位操作系统中成功检测。但当我在本机系统(Windows7 64位操作系统)中运行该程序时,它会崩溃 我将代码放在一个.asm文件中,并使用ml64.exe文件定义自定义构建步骤。64位Windows的asm代码为: IsInsideVM proc

我试图开发一个应用程序,检测程序是否在虚拟机中运行

对于32位窗口,以下链接中已经介绍了一些方法:

我正在尝试在64位Windows操作系统中修改有关虚拟PC和VMware检测的代码。对于VMware,该代码可以在Windows XP 64位操作系统中成功检测。但当我在本机系统(Windows7 64位操作系统)中运行该程序时,它会崩溃

我将代码放在一个.asm文件中,并使用ml64.exe文件定义自定义构建步骤。64位Windows的asm代码为:

IsInsideVM proc

      push   rdx
      push   rcx
      push   rbx

      mov    rax, 'VMXh'
      mov    rbx, 0     ; any value but not the MAGIC VALUE
      mov    rcx, 10    ; get VMWare version
      mov    rdx, 'VX'  ; port number

      in     rax, dx    ; read port
                        ; on return EAX returns the VERSION
      cmp    rbx, 'VMXh'; is it a reply from VMWare?
      setz   al         ; set return value
      movzx rax,al

      pop    rbx
      pop    rcx
      pop    rdx

      ret
IsInsideVM endp
我在cpp文件中称此部分为:

__try
{
returnValue = IsInsideVM();
}
__except(1)
{
    returnValue = false;
}
提前感谢。

五月工作日的老红色药丸:

吞下红色药丸或多或少等同于以下代码(在矩阵中返回非零):

这段代码的核心实际上是SIDT指令(编码为0F010D[addr]),它将中断描述符表寄存器(IDTR)的内容存储在目标操作数中,目标操作数实际上是一个内存位置。SIDT指令的特殊和有趣之处在于,它可以在非特权模式(ring3)下执行,但它返回操作系统内部使用的敏感寄存器的内容

因为只有一个IDTR寄存器,但至少有两个操作系统同时运行(即主机和来宾操作系统),VMM需要将来宾的IDTR重新定位到安全的位置,以便它不会与主机的IDTR冲突。不幸的是,VMM无法知道在来宾操作系统中运行的进程是否(以及何时)执行SIDT指令,因为它没有特权(并且不会生成异常)。因此,该进程获得IDT表的重新定位地址。据观察,在VMWare上,IDT的重新定位地址位于地址0xffXXXXXX,而在虚拟PC上是0xE8XXXXX。这已在VMWare Workstation 4和Virtual PC 2004上进行了测试,这两个版本都运行在Windows XP主机操作系统上

注意:我没有亲自测试过它,但看起来它使用了一种非特权的方法。如果一开始对x64不起作用,一些调整可能会有所帮助


另外,我刚刚发现了一个可能对您有所帮助的问题:

我猜您的函数会更正寄存器

在真实硬件(非虚拟机)上运行可能会在“in-rax,dx”处触发异常。若发生这种情况,控制权将传递给异常处理程序,异常处理程序设置结果,但不恢复寄存器。调用者完全无法预料这种行为。例如,它可以将某些内容保存到EBX/RBX寄存器中,然后调用您的asm代码,您的asm代码执行“mov RBX,0”,它执行、捕获异常、设置结果、返回-然后调用方突然意识到其保存的数据不再在EBX/RBX中!如果EBX/RBX中存储了一些指针,那么您将很难崩溃。任何事情都有可能发生

当然,asm代码会保存/恢复寄存器,但只有在未引发异常时才会发生这种情况。例如,如果您的代码正在VM上运行。然后代码执行其正常执行路径,不会引发异常,寄存器将正常恢复。但如果出现异常,您的POP将被跳过,因为执行将传递给异常处理程序


正确的代码可能会在try/except块之外执行PUSH/POPs操作,而不是在内部。

是的,尝试访问硬件端口(这是一种特权操作)将捕获用户代码。您需要使用SEH捕获异常。看起来您正在尝试,但您尚未显示(1)编译器选项或(2)调试器跟踪。可能可以使用
setjmp
longjmp
强制保留寄存器和堆栈指针(可以使用全局变量使结果在longjmp之后仍然有效)也许您可以使用SetUnhandledExceptionFilter来捕获错误,摆弄PEXCEPTION_指针来调整“continue”地址,然后返回EXCEPTION_continue_执行。
 int swallow_redpill () {
   unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3";
   *((unsigned*)&rpill[3]) = (unsigned)m;
   ((void(*)())&rpill)();
   return (m[5]>0xd0) ? 1 : 0;
 }