2012-02-13 4 views
4

この投稿は、questionの投稿のフォローアップで、投稿された投稿はRanです。メソッドをコールバックとしてWindows API呼び出しに渡す方法(フォローアップ)

accepted answerは、普通の普通の関数を使用しています。

この抜粋は、特に私の注意をキャッチ:

インスタンスメソッドは、 インスタンスの参照を含む余分な、暗黙の、パラメータ、すなわち自己を持っています。 、私は終わる(uneeded自己暗黙的な参照を取り除く言い直すと準拠適応コールバック関数へのポインタを提供するために)「パラメータ」アダプタの種類を使用する方法があるべきことをしっかりと確信して

これを見つけること article コールバッククラスによって Peter Morris

合計すると、彼はアダルトトリックとしてサンク技術を使用します。 (免責事項:私はコードをテストしたことはありません)。

解決策としてはそれほどクリーンではありませんが、想定されるすべての利点を備えたオブジェクト指向設計が可能です。

私の質問:

TCallbackThunkは、コールバック関数のシグネチャに基づいていることを知って、ピーター・モリスが移動するための方法で行ったようにそれをやっている場合、上記参照さポストの答えがどうなりますか?

+0

私は、いくつかのAPIコールバックがlParamの回避策を許可しているものを追加しますが、いくつかはそうではありません(例:図のWinNLS)。また、これはStdcallThunkなどと呼ばれるべきです。 – OnTheFly

+0

生成されたコードが実行可能ページに存在しないため、これは機能しません。あなたはその問題を解決することができます。しかし、あなたはx86上でしか動作できず、x64で失敗するコードを持っています。 –

+0

@David Heffernan:ありがとう。私のボックスはx86で、Delphi 5,7、2007で動作するコードはすべてXEで動作します。私は投稿を編集する必要があります。 – menjaraz

答えて

3

EnumWindows(参照された質問の関数)は、データパラメータを提供するので、実際にすべての作業を行う必要はありません。答えに示されているオブジェクト参照など、必要な値を置くことができます。 Morrisの手法は、汎用データパラメータを提供しないコールバック関数に適しています。

モリスのコードを使用するように回答するには、まずコールバックメソッドのシグネチャがAPIのコールバック関数のシグネチャと一致することを確認する必要があります。 EnumWindowsを呼び出しているので、Boolを返す2つの引数の関数が必要です。コーリング規約は標準である必要があります(Morrisのコードはそれを前提としており、他の呼び出し規約を犠牲にするのは困難です)。

function TAutoClickOKThread.cbEnumWindowsClickOK(
    Wnd: HWnd; Param: LParam): Bool; stdcall; 
begin 
    // ... 
end; 

次に、我々は、すべてのマシンコードにTCallbackThunkデータ構造を設定し、ジャンプが意図したコールバックメソッドを参照するオフセット。

しかし、私たちはMorrisの記述方法を使用していません。彼のコードはデータ構造をスタックに置きます。つまり、実行可能コードスタックに入れています。現代のプロセッサとオペレーティングシステムはこれをもう許しません - 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命令が何であるかわかりません。

+0

+1:非常に有益!私が答えを受け入れる前に、Morrisのコードが高齢化していることを考えると、2つのことを確かめたいだけです。 1)ポインタ調整は有効です(VMT/TObjectはバージョン間で変更されます)。2)ハードコードされたASM命令と同じです。私はASMとBASMの知識がほとんどないことを告白する必要があります。ありがとうございました。 – menjaraz

+0

コードインジェクションがセキュリティを脅かす原因となるのはなぜか分かります。 – menjaraz

+0

ポインタ調整は、JMP命令のサイズを補正することです。 JMP命令のオフセットは、* next *命令との相対的なものです(アドレス計算が行われる前にEIPが進められているため)。 VMTのサイズやオブジェクトとは関係ありません。 X86命令は変更されていません。 –

関連する問題