3

Delphi 2010 dll から __fastcall を有効にして、Microsoft Visual Studio 2010 でコンパイルされたアプリケーション内で関数をフックしようとしていますが、次の問題を回避する方法を理解するスキルがありません。

C++ 関数は次のとおりです。

     void __fastcall function(int arg1; char* arg2);

私はそのようなことを試みていました(uallHookを使用):

    var FTextMessage : procedure(Modo: integer; Msg: pchar); register;
    procedure onTextMessage(Modo: integer; Msg: pchar); register;
    begin
      ShowMessage(inttostr(Modo) + ' - ' + string(Msg));
      FTextMessage(Modo, Msg);
    end;
    begin
    HookCode(Ptr($574210), @onTextMessage, @FTextMessage);
    end.

これにより、デバッグ/クラッシュが発生します。

だから、私はそれを見つけました:

「Microsoft または GCC[4] __fastcall[5] 規則 (別名 __msfastcall) は、ECX および EDX に適合する最初の 2 つの引数 (左から右に評価) を渡します。残りの引数は右から左にスタックにプッシュされます。」

Borland fastcall 引数を左から右に評価し、EAX、EDX、ECX を介して 3 つの引数を渡します。残りの引数も左から右にスタックにプッシュされます。[6] これは、Embarcadero Delphi の 32 ビット コンパイラのデフォルトの呼び出し規約であり、レジスタとして知られています。

出典: http://en.wikipedia.org/wiki/X86_calling_conventions

これが問題です。borland fastcall と microsoft __fastcall は異なります。

そのため、フック関数内でアセンブリ コードを使用してレジスタなどを整列させる必要があると考えていますが、まだこれを理解することはできません。

どんな助けでも大歓迎です。

Edit1: David Heffernan Answer は部分的に機能します。(showmessage までしか機能しません)

     var FTextMessage : procedure(Modo: integer;Msg: PAnsiChar); register;

     procedure onTextMessage(Modo: integer;Msg: PAnsiChar); register;
     begin
       ShowMessage(inttostr(Modo) + ' - ' + string(Msg));
       asm
         MOV ECX,Modo
         MOV EDX,Msg
         JMP FTextMessage
       end;  // I got a crash trying or without trying to restore the registers before executing the JMP FTextMessage
     //  FTextMessage(Modo,Msg); // < Also this method doesnt work either, if I call the Original function from here (without executing asm code above) i got a crash too. (this is what i was meaning with "to correct the registers")
     end;

     procedure onTextMessageWrapper(Modo: Integer;Msg: PAnsiChar); register;
     asm
       MOV EDX,ECX  // < Moving ECX to EDX, I'm able to Access Modo and Msg correctly in onTextMessage procedure.
       JMP onTextMessage
     end;

     begin
       HookCode(Ptr($574210), @onTextMessageWrapper, @FTextMessage);
     end.
4

2 に答える 2

3

C ++関数は、とにパラメータを渡しECXますEDX。したがって、Delphiが期待しているレジスタにそれらをコピーする必要があります:EAXEDXそれぞれ。2番目のパラメーターはすでに正しいレジスターにあるので、必要なのはこれだけです。

procedure onTextMessage(Modo: Integer; Msg: PAnsiChar); register;
begin
  ...
end;

procedure onTextMessageWrapper(Modo: Integer; Msg: PAnsiChar); register;
asm
  MOV EAX,ECX
  JMP onTextMessage
end;

これを2つの関数で実行したのでasm、レジスタスワッピングを実行する純粋な関数のみを記述できます。asmすべての前文を避けるために純粋にしたいと思います。だから、onTextMessageWrapperあなたのフック関数です。

PAnsiCharUnicode Delphiを使用しているため、と一致させる必要があることにも注意してくださいchar*

規約を呼び出すために私が知っている最良のリファレンスは、AgnerFogによるものです。あなたはそこにすべての厄介な詳細を見つけるでしょう。重要な点の1つは、Windows x86では、EAX、ECX、およびEDXレジスタが揮発性またはスクラッチレジスタであるということです。つまり、呼び出し先は、これらのレジスタを復元せずに変更できます。そのため、上記のEAXを変更し、わざわざ元に戻す必要はありません。

于 2012-12-04T13:01:48.963 に答える
-1

別の試みは、この関数シグネチャを以下のように変更することです

From: procedure onTextMessageWrapper(Modo: Integer; Msg: PAnsiChar); 登録; To: プロシージャ onTextMessageWrapper; 登録;

于 2012-12-04T21:06:54.957 に答える