9

Вопрос по 64bit, assembly, visual-c++ – 64-битное обнаружение Windows VMware

Я пытаюсь разработать приложение, которое определяет, работает ли программа внутри виртуальной машины.

Для 32-битной Windows уже есть методы, описанные в следующей ссылке: http://www.codeproject.com/Articles/9823/Detect-if-your-program-is-running-inside-a-Virtual

Я пытаюсь адаптировать код, касающийся обнаружения виртуальных ПК и VMware, в 64-битной операционной системе Windows. Для VMware код может успешно обнаруживаться в 64-разрядной ОС Windows XP. Но программа вылетает, когда я запускаю ее в собственной системе (64-разрядная ОС Windows 7).

Я помещаю код в файл .asm и определяю пользовательский шаг сборки с помощью файла ml64.exe. ASM-код для 64-битной Windows:

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) трассировку отладчика.

Apr 10, 2012, 2:03 PMот

2ответа

4

Старыйred pill отДжоанна может работать:случайная резервная страница блога invisiblethings.org:

Swallowing the Red Pill is more or less equivalent to the following code (returns non zero when in 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;
 }

The heart of this code is actually the SIDT instruction (encoded as 0F010D[addr]), which stores the contents of the interrupt descriptor table register (IDTR) in the destination operand, which is actually a memory location. What is special and interesting about SIDT instruction is that, it can be executed in non privileged mode (ring3) but it returns the contents of the sensitive register, used internally by operating system.

Because there is only one IDTR register, but there are at least two OS running concurrently (i.e. the host and the guest OS), VMM needs to relocate the guest's IDTR in a safe place, so that it will not conflict with a host's one. Unfortunately, VMM cannot know if (and when) the process running in guest OS executes SIDT instruction, since it is not privileged (and it doesn't generate exception). Thus the process gets the relocated address of IDT table. It was observed that on VMWare, the relocated address of IDT is at address 0xffXXXXXX, whereas on Virtual PC it is 0xe8XXXXXX. This was tested on VMWare Workstation 4 and Virtual PC 2004, both running on Windows XP host OS.

Примечание. Я сам не проверял его, но, похоже, он использует непривилегированный подход. Если сначала он не работает для x64, может помочь некоторая настройка.

Также только что обнаружил вопрос с контентом, который может вам помочь:Обнаружение VMM в Linux

0

Я предполагаю, что ваша функция портит регистры.

Работа на реальном оборудовании (не в виртуальной машине), вероятно, должна вызывать исключение в "rax, dx". Если это происходит, то управление передается вашему обработчику исключений, который устанавливает результат, но не восстанавливает регистры. Такое поведение будет полностью неожиданным для звонящего. Например, он может что-то сохранить в регистр EBX / RBX, а затем вызвать ваш ассемблерный код, ваш ассемблерный код «mov RBX, 0», он выполняет, перехватывает исключение, устанавливает результат, возвращает, а затем вызывающий абонент вдруг понимает, что его сохраненный данных больше нет в EBX / RBX! Если в EBX / RBX был сохранен какой-то указатель - вы сильно упадете. Все может случиться.

Конечно, ваш ассемблерный код сохраняет / восстанавливает регистры, но это происходит только тогда, когда не возникает исключение. То есть если ваш код работает на ВМ. Затем ваш код выполняет свой обычный путь выполнения, исключений не возникает, регистры будут восстановлены нормально. Но если есть исключение - ваши POP будут пропущены, потому что выполнение будет передано обработчику исключений.

Правильный код, вероятно, должен выполнять PUSH / POP вне блока try / кроме, а не внутри.

RelatedQuestions