我想修补一个例程调用,以便能够自己处理它并进行一些修改。 我正在写一个资源加载器。我想修补Delphi的LoadResourceModule和 InitInheritedComponent例程与我的例程。我已经在MadExcept.pas单元中检查了PatchAPI调用,但如果我可以将其用于我的项目,则无法弄明白。
我想要像
这样的东西我的exe在运行时调用 - > LoadResourceModule - >跳到 - > MyCustomResourceModule ...
任何关于此的指示都会非常有用。
答案 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
:
RedirectProcedure(@LoadResourceModule, @MyLoadResourceModule);
这适用于32位代码。它也适用于64位代码,只要旧函数和新函数都驻留在同一个可执行模块中。否则跳转距离可能超过32位整数的范围。
如果有人可以提供适用于64位地址空间的替代方案,无论这两个地址有多远,我都会非常感兴趣。
答案 1 :(得分:7)
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;