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 регистр общего назначения, то как можно обращаться кнему как к регистру ввода вывода?
ОтветитьУдалить