用 Delphi 64位检测虚拟化环境?

6ljaweal  于 2023-02-04  发布在  其他
关注(0)|答案(2)|浏览(116)
// VMware detection as described by Elias Bachaalany
function IsInsideVMware: Boolean;
begin
  Result := True;

  try
    asm
      push edx;
      push ecx;
      push ebx;

      mov eax, 'VMXh';
      mov ebx, 0;
      mov ecx, 10;
      mov edx, 'VX';

      in eax, dx;

      cmp ebx, 'VMXh';
      setz [Result];

      pop ebx;
      pop ecx;
      pop edx;
    end;
  except
    Result := False;
  end;
end;

function IsRunningUnderHyperV: BOOL; stdcall;
var
  VMBranding: array[0..12] of AnsiChar;
begin
  asm
    mov eax, $40000000;
    cpuid;
        mov dword ptr [VMBranding+0], ebx;  // Get the VM branding string
        mov dword ptr [VMBranding+4], ecx;
        mov dword ptr [VMBranding+8], edx;
  end;
  VMBranding[12] := #0;
  Result := CompareText(String(VMBranding), 'Microsoft Hv') = 0;
end;

对于64位 Delphi 应用程序,如何做到这一点?
如果我尝试将其编译为64位,则会收到消息“不支持的语言功能:ASM”和“操作数大小不匹配”。我知道你需要把asm代码和pascal代码分开,寄存器也不一样,但是不知道怎么做?

wtlkbnrh

wtlkbnrh1#

最后,我已经使用这个解决方案为32/64位.

var
  LFlag: Cardinal;

//================================= VMWare =====================================

procedure TryVMWare;
{$IFDEF CPUX86}
  asm
    push eax
    push ebx
    push ecx
    push edx
    mov eax, 'VMXh'
    mov ecx, 0Ah
    mov dx, 'VX'
    in eax, dx
    mov LFlag, ebx
    pop edx
    pop ecx
    pop ebx
    pop eax
  end;
{$ENDIF CPUX86}
{$IFDEF CPUX64}
  asm
    push rax
    push rbx
    push rcx
    push rdx
    mov eax, 'VMXh'
    mov ecx, 0Ah
    mov dx, 'VX'
    in eax, dx
    mov LFlag, ebx
    pop rdx
    pop rcx
    pop rbx
    pop rax
  end;
{$ENDIF CPUX64}

function IsInsideVMware: Boolean;
begin
  LFlag := 0;
  try
    TryVMWare;
  except
  end;
  Result := LFlag = $564D5868;
end;

至于检测64位中的其他VM品牌,我使用了以下代码:
https://github.com/JBontes/FastCode/blob/master/FastcodeCPUID.pas
代码已更新,可作为x64位运行和编译,并可检测虚拟机品牌。

ajsxfq5m

ajsxfq5m2#

JEDI JclSysInfo.GetCpuInfo()函数可以获取您想要了解的关于CPU的所有信息,并返回物理设备的特征,无论您是在VM中还是在根操作系统上。检测大多数VM的最简单方法是获取CPUID字符串:

function GetVMBranding: String;
var
  VMBranding: array[0..12] of AnsiChar;
begin
  asm
    mov eax, $40000000;
    cpuid;
    mov dword ptr [VMBranding+0], ebx;  // Get the VM branding string
    mov dword ptr [VMBranding+4], ecx;
    mov dword ptr [VMBranding+8], edx;
  end;
  VMBranding[12] := #0;
  Result := String(VMBranding);
end;

然后将其与已知字符串进行比较(可以在https://en.wikipedia.org/wiki/CPUID #:~:text= In%20the%20x86%20architecture%2C%20the,and%20SL%2Denhanced%20486%20processors上找到一个列表)。但是,有两个重要的警告:
1.如果安装了Hyper-V,CPUID查询将返回Hyper-V签名,无论您是在根操作系统上还是在虚拟机中运行。这是因为一旦安装了Hyper-V,其虚拟机管理程序将管理线程,甚至是根操作系统的线程。我还没有找到检测在Hyper-V虚拟机中实际运行的方法。

  1. VirtualBox和WINE需要不同的检测方法。WINE向NTDLL.DLL添加了一些函数,因此查找这些函数是检测WINE的可靠方法。对于VirtualBox,您必须在运行进程列表中查找其服务。
function CheckWine: Boolean;
var
  hnd: THandle;
  wine_get_version: function : pchar; {$IFDEF Win32} stdcall; {$ENDIF}
  wine_unix2fn: procedure (p1:pointer; p2:pointer); {$IFDEF Win32} stdcall; {$ENDIF}
begin
  Result := False;
  hnd := LoadLibrary('ntdll.dll');
  if hnd > 32 then begin
    wine_get_version := GetProcAddress(hnd, 'wine_get_version');
    wine_unix2fn := GetProcAddress(hnd, 'wine_nt_to_unix_file_name');
    if assigned(wine_get_version) or assigned(wine_unix2fn) then
       Result := True;
    FreeLibrary(hnd);
  end;
end;

//uses WinApi.TlHelp32
function CheckVirtualBox: Boolean;
var
  handle: THandle;
  procinfo: ProcessEntry32;
begin
  Result   := False;
  handle   := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  procinfo.dwSize := sizeof(PROCESSENTRY32);
  while(Process32Next(handle, procinfo)) do begin
    if (POS('VBoxService.exe', procinfo.szExeFile) > 0) then begin
      Result := True;
      Break;
    end;
  end;
  CloseHandle(handle);
end;

相关问题