2012-01-23 17 views
17

Quiero parchar una llamada de rutina para poder manejarlo yo mismo con algunas modificaciones. Estoy escribiendo un cargador de recursos. Quiero parchear las rutinas de LoadResourceModule de Delphi y InitInheritedComponent 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.Llamada de rutina de parche en delphi

Quiero algo así como

mi exe en el tiempo de ejecución de llamadas -> LoadResourceModule -> Ir a -> MyCustomResourceModule ...

Cualquier punteros en esto sería muy útil.

+3

Esto se llama 'detour' comprobar esta pregunta [Cómo cambiar la aplicación (desvío) de una función declarada externamente] (http://stackoverflow.com/questions/6905287/ how-to-change-the-implementation-detour-of-an-externally-declarated-function) – RRUZ

+0

Estaba pensando en lo mismo hoy, así que usar esta técnica permitiría, por ejemplo, agregar código en la transmisión de componentes (desde DFM a la aplicación) mecanismo? Entonces, por ejemplo, podría tener un lugar central para registrar las clases de componentes usados, o hacer alguna garantía de calidad ('¡no use clases de BDE! O esa versión anterior del componente X!'). – mjn

+2

@mjn Hay otros puntos de extensión que permiten hacer eso más fácilmente. Por ejemplo 'TReader.OnFindComponentClass'. El código de aplicación siempre debe ser un último recurso cuando nada más puede hacer el trabajo. –

Respuesta

16

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ías su gancho/parche/desvío llamando RedirectProcedure:

RedirectProcedure(@LoadResourceModule, @MyLoadResourceModule); 

Esto funcionará para 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.

+6

Puede ser una buena idea * anular el parche * de la redirección o asegurarse de que no haya interrupción de código al cerrar la aplicación: la llamada redirigida se puede realizar (por ejemplo, mediante RTL u otra unidad cargada antes de la unidad de redirección) y saltar a algún código no inicializado. –

+0

@Arnaud Eso puede ser cierto. En todo mi uso de esto, me redirecciono antes de hacer cualquier llamada, o es una rutina sin efectos secundarios y, por lo tanto, sin parchar no importa –

+0

@DavidHeffernan Solo por un pensamiento, ¿cómo puedo llamar al procedimiento anterior si quiero obtener el valor predeterminado valor y luego trabajar en ese valor. Como en el código anterior, sobrescribimos la dirección de la rutina anterior para saltar al nuevo procedimiento. Algo así como MyLoadResourceModule utiliza internamente LoadResourceModule y hace algo más ... –

7

Ya existe un Delphi detours library para esto.

La Biblioteca Delphi desvíos es una biblioteca que le permite conectar funciones delphi y Windows API .Se proporciona una manera fácil de insertar y quitar gancho.

Características:

  • x86 Soporte y arquitectura x64.
  • Permite llamar a la función original a través de la función Trampoline.
  • Soporte para Multi Hook.
  • Compatibilidad con COM/Interfaces/win32api.
  • Compatibilidad con parches COM vtable.
  • Codificación y desenganche de código totalmente seguro para subprocesos.
  • Soporte de enganche Método del objeto.
  • Compatible Delphi 7/2005-2010/XE-XE7.
  • Soporte Lazarus/FPC.
  • Se admite la dirección de 64 bits.
  • 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 & x64).
3

he modificado el código de David Heffernan para el soporte de 64 bits y el salto indirecto a los métodos en una 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; 
Cuestiones relacionadas