На самом деле вам не нужно проходить всю эту работу, поскольку EnumWindows
(функция в указанном вопросе) предоставляет параметр данных.Вы можете поместить туда любое значение, например, ссылку на объект, указанную в ответе.Техника Морриса лучше подходит для функций обратного вызова, которые не предоставляют какого-либо параметра данных общего назначения.
Чтобы адаптировать ответ для использования кода Морриса, сначала необходимо убедиться, что сигнатура метода обратного вызова совпадаетподпись функции обратного вызова API.Поскольку мы вызываем EnumWindows
, нам нужна функция с двумя аргументами, возвращающая Bool.Соглашение о вызовах должно быть stdcall (потому что код Морриса предполагает это, и трудно согласовать любое другое соглашение о вызовах).
function TAutoClickOKThread.cbEnumWindowsClickOK(
Wnd: HWnd; Param: LParam): Bool; stdcall;
begin
// ...
end;
Далее мы настраиваем структуру данных TCallbackThunk
со всем машинным кодоми смещение перехода, относящееся к предполагаемому методу обратного вызова.
Однако мы не используем способ, описанный Моррисом.Его код помещает структуру данных в стек.Это означает, что мы помещаем исполняемый код в стек .Современные процессоры и операционные системы не позволяют этого больше - ОС остановит вашу программу.Мы могли бы обойти это, вызвав VirtualProtect
, чтобы изменить разрешения текущей страницы стека, разрешив ее выполнение, но это делает всю страницу исполняемой, и мы не хотим оставлять программу открытой для атаки.Вместо этого мы выделим блок памяти специально для thunk-записи отдельно от стека.
procedure TAutoClickOKThread.Execute;
var
Callback: PCallbackThunk;
begin
Callback := VirtualAlloc(nil, SizeOf(Callback^),
Mem_Commit, Page_Execute_ReadWrite);
try
Callback.POPEDX := $5A;
Callback.MOVEAX := $B8;
Callback.SelfPtr := Self;
Callback.PUSHEAX := $50;
Callback.PUSHEDX := $52;
Callback.JMP := $E9;
Callback.JmpOffset := Integer(@TAutoClickOKThread.cbEnumWindowsClickOK)
- Integer(@Callback.JMP) - 5;
EnumWindows(Callback, 0);
finally
VirtualFree(Callback);
end;
end;
Обратите внимание, что это 32-битные инструкции x86 в этой записи.Я понятия не имею, какими будут соответствующие инструкции x86_64.