Llamada de rutina de parche en Delphi
monkeypatching (3)
Quiero parchar una llamada de rutina para poder manejarlo yo mismo con algunas modificaciones. Estoy escribiendo un cargador de recursos. Quiero parchear las rutinas LoadResourceModule y InitInheritedComponent de Delphi con las mías. Revisé la llamada de PatchAPI en la unidad MadExcept.pas, pero no pude determinar si puedo usar eso para mi proyecto.
Quiero algo como
mi exe en tiempo de ejecución llama -> LoadResourceModule -> salta a -> MyCustomResourceModule ...
Cualquier sugerencia sobre esto sería muy útil.
Yo uso el siguiente código:
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;
Implementarás tu gancho / parche / desvío llamando a RedirectProcedure
:
RedirectProcedure(@LoadResourceModule, @MyLoadResourceModule);
Esto funcionará para el código de 32 bits. También funcionará para el código de 64 bits siempre que las funciones antiguas y nuevas residan en el mismo módulo ejecutable. De lo contrario, la distancia de salto puede exceder el rango de un entero de 32 bits.
Me interesaría mucho si alguien pudiera proporcionar una alternativa que funcionara para el espacio de direcciones de 64 bits, independientemente de lo lejos que estuvieran las dos direcciones.
Modifiqué el código de David Heffernan para soporte de 64 bits y salto indirecto a métodos en un BPL. Con la ayuda de: 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;
Ya hay una biblioteca de desvíos de Delphi para esto.
La Biblioteca Delphi Detours es una biblioteca que le permite enlazar las funciones delphi y API de Windows. Proporciona una manera fácil de insertar y quitar el gancho.
Caracteristicas :
- Admite la arquitectura x86 y x64.
- Permitir llamar a la función original a través de la función Trampoline.
- Soporte para Multi Hook.
- Compatibilidad con COM / Interfaces / win32api.
- Soporte de parcheo Vtable.
- Codificación y desenganche de código totalmente seguro para subprocesos.
- Soporte de gancho Método de objeto.
- Compatible con Delphi 7 / 2005-2010 / XE-XE7.
- Soporte Lazarus / FPC.
- La dirección de 64 bit es compatible.
- La biblioteca no usa ninguna biblioteca externa.
- La biblioteca puede insertar y quitar el gancho en cualquier momento.
- La biblioteca contiene la biblioteca InstDecode, que le permite decodificar instrucciones asm (x86 y x64).