使用注入的Delphi dll启用__fastcall挂钩在MSVC ++上创建的应用程序

时间:2012-12-04 12:48:59

标签: visual-studio-2010 delphi assembly hook delphi-2010

我试图在使用微软Visual Studio 2010编译的应用程序中挂钩一个函数,并从delphi 2010 dll启用__fastcall,但我不知道如何绕道以下问题:

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的前两个参数(从左到右评估)。剩余的参数从右到左被压入堆栈。”

     

Borland fastcall   从左到右评估参数,它通过EAX,EDX,ECX传递三个参数。剩下的参数被推到堆栈上,也是从左到右。[6]   它是Embarcadero Delphi的32位编译器的默认调用约定,其中>它被称为寄存器。

取自: http://en.wikipedia.org/wiki/X86_calling_conventions

这就是问题,borland fastcall和microsoft __fastcall是不同的。

所以我认为我需要在Hook函数中使用一段汇编代码来对齐寄存器或其他东西,但我还是无法解决这个问题。

任何帮助都将不胜感激。

EDIT1: David Heffernan答案部分工作。 (它只能在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.

2 个答案:

答案 0 :(得分:3)

C ++函数正在ECXEDX传递参数。所以你只需将它们复制到Delphi期望的寄存器:EAXEDX。由于第二个参数已经在正确的寄存器中,所以您需要的是:

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

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

我在两个函数中完成了这个,这样我就可以编写一个纯asm函数来执行寄存器交换。我们希望纯asm避免所有序言。所以,onTextMessageWrapper是你的钩子函数。

另请注意,由于您使用的是Unicode Delphi,因此您需要PAnsiCharchar*匹配。

我对调用约定的最佳参考是Agner Fog。你会在那里找到所有血腥的细节。重要的一点是,在Windows x86上,EAX,ECX和EDX寄存器是易失性或临时寄存器。这意味着被调用者可以修改这些寄存器而无需恢复它们。这就是为什么我修改上面的EAX并且不打算把它放回去。

答案 1 :(得分:-1)

另一种尝试是更改此功能签名,如下所示

From:procedure onTextMessageWrapper(Modo:Integer; Msg:PAnsiChar);寄存器; To:procedure onTextMessageWrapper;寄存器;