9

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

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

提前致谢。

4

2 回答 2

4

乔安娜的旧红药丸可能有用:invisiblethings.org 博客的随机备份页面

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

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

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

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

于 2012-04-11T01:22:09.893 回答
0

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

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

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

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

于 2015-05-22T03:43:03.613 回答