#delphi #ассемблер
unit BSOD; interface uses WinAPI.Windows; procedure Crash; function RtlSetProcessIsCritical(unu: Cardinal; proc: Pointer; doi: Cardinal): Integer; stdcall; external 'ntdll.dll'; function RtlAdjustPrivilege(Privilege: Cardinal; Enable: Boolean; CurrentThread: Boolean; out OldPrivilege: Boolean): Cardinal; stdcall; external 'ntdll'; implementation procedure Crash; asm lea eax, dword[esp+12] //invoke RtlAdjustPrivilege, 20, 1, 0, eax push eax push 0 push 1 push 20 call RtlAdjustPrivilege //invoke RtlSetProcessIsCritical, 1, 0, 0 push 0 push 0 push 1 call RtlSetProcessIsCritical call ExitProcess end; end. В 32-битном приложении, если вызвать Crash, то винда крашится. Как заставить этот код работать в 64-битном приложении?
Ответы
Ответ 1
Если не знаете, как написать код на ассемблере, то пишите вначале код на Delphi, смотрите, какой код генерирует компилятор (ставите брекпоинт в функции и когда дойдёте до него, открывайте окно дизассемблера Ctrl+Alt+D), берёте его за основу и улучшаете. Вот для такого Delphi кода: procedure Crash; var VOldPrivilege: Boolean; begin RtlAdjustPrivilege(20, True, False, VOldPrivilege); RtlSetProcessIsCritical(1, nil, 0); ExitProcess(1); end; при компиляции в 64-битном режиме, генерируется вот такой ассемблерный код: push rbp sub rsp,$30 mov rbp,rsp mov ecx,$00000014 mov dl,$01 xor r8,r8 lea r9,[rbp+$2f] call RtlAdjustPrivilege mov ecx,$00000001 xor edx,edx xor r8,r8 call RtlSetProcessIsCritical mov ecx,$00000001 call ExitProcess lea rsp,[rbp+$30] pop rbp ret А вот такой код для 32-битного режима, можете сравнить со своим: push ebp mov ebp,esp push ecx lea eax,[ebp-$01] push eax push $00 push $01 push $14 call RtlAdjustPrivilege push $00 push $00 push $01 call RtlSetProcessIsCritical push $01 call ExitProcess pop ecx pop ebp ret Отличие кода для разных платформ в том, что для x32 используется соглашение вызовов stdcall (параметры передаются через стек), а в x64 - fastcall (первые 4 параметра передаются через регистры, остальные через стек). При разработке соглашений по вызовам (calling conventions) для архитектуры x86-64 решили положить конец существованию различных вариантов вызова функций. В Win32 существовал целый ряд соглашений о вызове: stdcall, cdecl, fastcall, thiscall и так далее. В Win64 только одно «родное» соглашение по вызовам. Модификаторы подобные __cdecl компилятором игнорируются. Думаю, что все согласятся в благородстве такого резкого сокращение числа соглашений. Соглашение по вызовам на платформе x86-64 похоже на соглашение fastcall, существующее в x86. В x64-соглашении первые четыре целочисленных аргумента (слева направо) передаются в 64-битных регистрах, выбранных специально для этой цели: RCX: 1-й целочисленный аргумент RDX: 2-й целочисленный аргумент R8: 3-й целочисленный аргумент R9: 4-й целочисленный аргумент Остальные целочисленные аргументы передаются через стек. Указатель «this» считается целочисленным аргументом, поэтому он всегда помещается в регистр RCX. Если передаются значения с плавающей точкой, то первые четыре из них передаются в регистрах XMM0-XMM3, а последующие — через стек. Цитата отсюда: https://habrahabr.ru/company/intel/blog/94340/Ответ 2
Приведенный выше код - это код, главная задача которого сделать BSOD. Если кратко - если процесс помечен как критический функцией RtlSetProcessIsCritical и он завершился (все равно как), то винда также делать себе харакири (например, через bsod). По хорошему нужно вызвать RtlSetProcessIsCritical но с тремя нулями, что бы снять с себя этот флажок. UPD Вышеуказанная функция хочет прав админа. Иначе сделать процесс "критическим" нельзя. И это правильно. Если хочется именно бсода (я правда не понимаю, зачем оно нужно нормальному человеку), то можно написать свой драйвер, главной задачей которого будет вызвать его по желанию. Но если хочется бсод, что бы напугать пользователя, прав админа не хватает - можно использовать скринсейвер от MS - https://technet.microsoft.com/en-us/sysinternals/bluescreen.aspx
Комментариев нет:
Отправить комментарий