EnumWindows
(参照されている質問の関数)はデータパラメーターを提供するため、実際にすべての作業を行う必要はありません。回答に示されているオブジェクト参照など、必要な値をそこに置くことができます。Morrisの手法は、汎用データパラメーターを提供しないコールバック関数に適しています。
Morrisのコードを使用するように回答を調整するには、最初に、コールバックメソッドのシグネチャがAPIのコールバック関数のシグネチャと一致することを確認する必要があります。を呼び出しているEnumWindows
ので、Boolを返す2つの引数の関数が必要です。呼び出し規約はstdcallである必要があります(Morrisのコードはそれを想定しており、他の呼び出し規約をサンクするのは難しいため)。
function TAutoClickOKThread.cbEnumWindowsClickOK(
Wnd: HWnd; Param: LParam): Bool; stdcall;
begin
// ...
end;
TCallbackThunk
次に、目的のコールバックメソッドを参照するすべてのマシンコードとジャンプオフセットを使用してデータ構造を設定します。
ただし、モリスが説明した方法は使用しません。彼のコードはデータ構造をスタックに置きます。これは、実行可能コードをスタックに配置していることを意味します。最近のプロセッサとオペレーティングシステムはそれをもう許可していません—OSはあなたのプログラムを停止します。現在のスタックページのパーミッションを変更して実行できるようにすることでこれを回避できますがVirtualProtect
、ページ全体が実行可能になり、プログラムを攻撃のために開いたままにしたくありません。代わりに、スタックとは別に、特にサンクレコードにメモリのブロックを割り当てます。
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命令がどうなるかわかりません。