function ReadVMWareFlags: Cardinal; assembler; asm // сохранили регистры, которые мы сейчас будем использовать // (eax, edx и ecx сохранять не нужно, // поскольку соглашение вызова позволяет их менять) push ebx // задаём параметры чтения ("волшебные" значения) xor ebx, ebx mov eax, 'VMXh' // $564D5868 mov ecx, 0Ah mov dx, 'VX' // $5856 // читаем из I/O порта in eax, dx // результат - в Result mov eax, ebx // восстановили сохранённые регистры pop ebx end; function IsRunningVMWare: Boolean; const CVMWARE_FLAG = $564D5868; begin try Result := (ReadVMWareFlags = CVMWARE_FLAG); except Result := False; end; end;Этот код предназначен для определения запущены ли мы под виртуальной машиной VMWare или нет. Для этого код читает из некоего порта ввода-вывода процессора x86 некое значение (с помощью команды x86
in
). Если прочитанное значение равно сигнатуре VMWare - мы запущены под ней.Если же мы не запущены под VMWare, то попытка прочитать что-то из порта ввода-вывода процессора возбудит исключение
EXCEPTION_PRIV_INSTRUCTION
($C0000096 - "Privileged Instruction"), поскольку такая операция доступна только режиму ядра, но никак не прикладной программе режима пользователя. В этом случае мы ловим исключение в блоке try/except.
Предположим, что код корректно определяет VMWare. Вопрос: есть ли здесь баг или всё в порядке? Вопрос именно про самый натуральный баг, не про "здесь можно улучшить".
В интернете полно вариантов этого кода. В том числе аналогичные алгоритмы для определения других виртуальных машин.
P.S. Задачка исключительно на знание справки Delphi. Не надо выдумывать что-то сверхсложное.
Ответ.
Может, не баг, но для гарантии я бы добавил
ОтветитьУдалитьconst
CVMWARE_FLAG: cardinal = $564D5868;
А для assembler-функций компилятор сделает корректный SEH-кадр?
ОтветитьУдалитьЭто вопрос или ответ? :))
УдалитьВообще-то вопрос. Я не знаю, как там с этим делом у Delpi, а в C++ нет определять исключительно ассемблерные функции, можно только либо использовать вставки внутри "нормальных" функций, либо подлинковывать такие функции извне. И в обоих случаях ebx при броске останется не восстановленным. Подозреваю даже, что и при корректном SEH никто его не восстановит, но в Delphi могут быть свои правила.
УдалитьЧтобы компилятор сгенерировал информацию о раскрутке стэка, в начале функции нужны магические инструкции:
Удалитьpush ebp
mov ebp, esp
Chaa прав.
ОтветитьУдалитьБолее того это даже написано в документации http://docwiki.embarcadero.com/RADStudio/Seattle/en/PC-Mapped_Exceptions#Unwinding_Assembly_Routines
Если в двух словах, работаете с исключениями в asm - значит должны гарантировать stack frames. А в ReadVMWareFlags ими и не пахнет.
И после возникшего `Privileged instruction` регистры восстановятся не правильно.
не глядя в ответ, меня смущает импользование команды mov вместо mvi, если eax регистр общего назначения, то как можно обращаться кнему как к регистру ввода вывода?
ОтветитьУдалить