Патч обычный вызов в delphi
Я хочу исправить обычный вызов, чтобы иметь возможность обрабатывать его сам с некоторыми изменениями.
Я пишу загрузчик ресурсов. Я хочу исправить Delphi LoadResourceModule и
InitInheritedComponent с моим. Я проверил PatchAPI-вызов в блоке MadExcept.pas, но не смог понять, могу ли я использовать его для моего проекта.
Мне нужно что-то вроде
мой exe при вызовах во время выполнения → LoadResourceModule → перейти в → MyCustomResourceModule...
Любые указатели на это будут очень полезны.
Ответы
Ответ 1
Я использую следующий код:
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-битного адресного пространства, независимо от того, насколько далеко друг от друга были два адреса.
Ответ 2
Для этого уже существует Delphi обходная библиотека.
Библиотека Delphi Detours - это библиотека, позволяющая подключать delphi и API окон. Он обеспечивает простой способ вставки и удалите крючок.
Особенности:
- Поддержка архитектуры x86 и x64.
- Разрешить вызов исходной функции через функцию Trampoline.
- Поддержка Multi Hook.
- Поддержка COM/интерфейсов/win32api.
- Поддержка COM vtable patching.
- Полностью потокобезопасный код для подключения и отцепления.
- Поддержка метода привязки объектов.
- Поддерживается Delphi 7/2005-2010/XE-XE7.
- Поддержка Lazarus/FPC.
- Поддерживается 64-разрядный адрес.
- Библиотека не использует внешнюю библиотеку.
- Библиотека может вставлять и удалять крючок в любое время.
- Библиотека содержит библиотеку InstDecode, которая позволяет вам декодировать инструкции asm (x86 и x64).
Ответ 3
Я изменил код Дэвида Хеффернана на 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;