【问题标题】:64-bit windows VMware detection64位windows VMware检测
【发布时间】:2012-04-10 12:03:39
【问题描述】:

我正在尝试开发一个应用程序来检测程序是否在虚拟机中运行。

对于 32 位 Windows,以下链接中已经有方法说明: http://www.codeproject.com/Articles/9823/Detect-if-your-program-is-running-inside-a-Virtual

我正在尝试在 64 位 Windows 操作系统中调整有关 Virtual PC 和 VMware 检测的代码。对于 VMware,该代码可以在 Windows XP 64 位操作系统中成功检测。但是当我在本机系统(Windows 7 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;
}

提前致谢。

【问题讨论】:

  • 嗯,是的,尝试访问硬件端口,这是一项特权操作,会陷入用户代码中。您需要使用 SEH 捕获异常。看起来您正在尝试,但您没有显示 (1) 编译器选项或 (2) 调试器跟踪。

标签: visual-c++ assembly 64-bit vmware detection


【解决方案1】:

来自Joanna 的旧红色药丸可能会起作用:random backup page of invisiblethings.org blog

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

 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;
 }

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

因为IDTR寄存器只有一个,但至少有两个OS同时运行(即宿主机和客户机操作系统),VMM需要把客户机的IDTR重新定位到一个安全的地方,这样才不会和一个主人的一个。不幸的是,VMM 无法知道来宾操作系统中运行的进程是否(以及何时)执行 SIDT 指令,因为它没有特权(并且它不会产生异常)。这样进程就得到了IDT表的重定位地址。据观察,在 VMWare 上,IDT 的重定位地址为地址 0xffXXXXXX,而在 Virtual PC 上为 0xe8XXXXXX。这是在 VMWare Workstation 4 和 Virtual PC 2004 上测试的,两者都在 Windows XP 主机操作系统上运行。

注意:我自己没有测试过,但看起来它使用了非特权方法。如果它一开始不适用于 x64,则进行一些调整可能会有所帮助。

另外,刚刚发现了一个内容可能对您有帮助的问题:Detecting VMM on linux

【讨论】:

    【解决方案2】:

    我的猜测是你的函数损坏了寄存器。

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

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

    正确的代码可能应该在 try/except 块之外而不是内部执行 PUSH/POP。

    【讨论】:

    • 或许setjmplongjmp可以用来强制保存寄存器和栈指针(可以使用全局变量让结果在longjmp中存活)
    • 也许您可以使用 SetUnhandledExceptionFilter 来捕获错误,使用 PEXCEPTION_POINTERS 调整“继续”地址,然后返回 EXCEPTION_CONTINUE_EXECUTION。
    猜你喜欢
    • 2011-10-24
    • 1970-01-01
    • 2017-08-04
    • 1970-01-01
    • 2011-12-15
    • 2010-10-10
    • 2010-09-25
    • 2011-01-13
    相关资源
    最近更新 更多