在delphi中调用例程调用

时间:2012-01-23 20:34:51

标签: delphi monkeypatching

我想修补一个例程调用,以便能够自己处理它并进行一些修改。 我正在写一个资源加载器。我想修补Delphi的LoadResourceModule和 InitInheritedComponent例程与我的例程。我已经在MadExcept.pas单元中检查了PatchAPI调用,但如果我可以将其用于我的项目,则无法弄明白。

我想要像

这样的东西
  

我的exe在运行时调用 - > LoadResourceModule - >跳到 - > MyCustomResourceModule ...

任何关于此的指示都会非常有用。

3 个答案:

答案 0 :(得分:16)

我使用以下代码:

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
  OldProtect: DWORD;
begin
  if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then 
  begin
    Move(NewCode, Address^, Size);
    FlushInstructionCache(GetCurrentProcess, Address, Size);
    VirtualProtect(Address, Size, OldProtect, @OldProtect);
  end;
end;

type
  PInstruction = ^TInstruction;
  TInstruction = packed record
    Opcode: Byte;
    Offset: Integer;
  end;

procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
  NewCode: TInstruction;
begin
  NewCode.Opcode := $E9;//jump relative
  NewCode.Offset := NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
  PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;

您可以通过调用RedirectProcedure

来实现您的hook / patch /绕行
RedirectProcedure(@LoadResourceModule, @MyLoadResourceModule);

这适用于32位代码。它也适用于64位代码,只要旧函数和新函数都驻留在同一个可执行模块中。否则跳转距离可能超过32位整数的范围。

如果有人可以提供适用于64位地址空间的替代方案,无论这两个地址有多远,我都会非常感兴趣。

答案 1 :(得分:7)

此处已有Delphi detours library

  

Delphi Detours Library是一个允许你钩住delphi的库   和Windows API函数。它提供了一种简单的插入方式和   删除钩子。

     

功能:

     
      
  • 支持x86和x64架构。
  •   
  • 允许通过Trampoline功能调用原始功能。
  •   
  • 支持Multi Hook。
  •   
  • COM / Interfaces / win32api支持。
  •   
  • 支持COM vtable修补。
  •   
  • 完全线程安全的代码挂钩和取消挂钩。
  •   
  • 支持挂钩对象方法。
  •   
  • 支持Delphi 7 / 2005-2010 / XE-XE7。
  •   
  • 支持Lazarus / FPC。
  •   
  • 支持64位地址。
  •   
  • 该库不使用任何外部库。
  •   
  • 库可以随时插入和删除钩子。
  •   
  • 该库包含InstDecode库,允许您解码asm指令(x86& x64)。
  •   

答案 2 :(得分:3)

我修改了David Heffernan的代码以获得64位支持和间接跳转到BPL中的方法。在以下帮助下: http://chee-yang.blogspot.com.tr/2008/11/hack-into-delphi-class.html

type
  PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp;
  TAbsoluteIndirectJmp = packed record
    OpCode: Word;  // $FF25(Jmp, FF /4) 
    Addr: DWORD;  // 32-bit address
                  // in 32-bit mode: it is a direct jmp address to target method
                  // in 64-bit mode: it is a relative pointer to a 64-bit address used to jmp to target method
  end;

  PInstruction = ^TInstruction;
  TInstruction = packed record
    Opcode: Byte;
    Offset: Integer;
  end;


function GetActualAddr(Proc: Pointer): Pointer;
begin
  Result := Proc;
  if Result <> nil then
    if PAbsoluteIndirectJmp(Result)^.OpCode = $25FF then  // we need to understand if it is proc entry or a jmp following an address
{$ifdef CPUX64}
      Result := PPointer( NativeInt(Result) + PAbsoluteIndirectJmp(Result)^.Addr + SizeOf(TAbsoluteIndirectJmp))^;
      // in 64-bit mode target address is a 64-bit address (jmp qword ptr [32-bit relative address] FF 25 XX XX XX XX)
      // The address is in a loaction pointed by ( Addr + Current EIP = XX XX XX XX + EIP)
      // We also need to add (instruction + operand) size (SizeOf(TAbsoluteIndirectJmp)) to calculate relative address
      // XX XX XX XX + Current EIP + SizeOf(TAbsoluteIndirectJmp)
{$else}
      Result := PPointer(PAbsoluteIndirectJmp(Result)^.Addr)^;
      // in 32-bit it is a direct address to method
{$endif}
end;

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
  OldProtect: DWORD;
begin
  if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then //FM: remove the write protect on Code Segment
  begin
    Move(NewCode, Address^, Size);
    FlushInstructionCache(GetCurrentProcess, Address, Size);
    VirtualProtect(Address, Size, OldProtect, @OldProtect); // restore write protection
  end;
end;

procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
  NewCode: TInstruction;
begin
  OldAddress := GetActualAddr(OldAddress); 

  NewCode.Opcode := $E9;//jump relative
  NewCode.Offset := NativeInt(NewAddress) - NativeInt(OldAddress) - SizeOf(NewCode);

  PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;