2012-01-23 11 views
17

Desidero eseguire il patch di una chiamata di routine per poterlo gestire personalmente con alcune modifiche. Sto scrivendo un caricatore di risorse. Voglio applicare patch alle routine LoadResourceModule di Delphi e alle routine InitInheritedComponent di con quella di mine. Ho controllato la chiamata PatchAPI nell'unità MadExcept.pas, ma non sono riuscita a capirlo se posso utilizzarla per il mio progetto.Patch chiamata di routine in delphi

voglio qualcosa di simile

mio exe a chiamate runtime -> LoadResourceModule -> Vai a -> MyCustomResourceModule ...

Eventuali indicazioni su questo sarebbe molto utile.

+3

Questo si chiama 'detour' controllare questa domanda [Come modificare la realizzazione (deviazione) di una funzione dichiarata esterno] (http://stackoverflow.com/questions/6905287/ come cambiare l'implementazione-deviazione di una funzione dichiarata esternamente) – RRUZ

+0

Oggi stavo pensando allo stesso modo, quindi l'utilizzo di questa tecnica consentirebbe ad esempio di aggiungere codice nello streaming dei componenti (da DFM alla domanda) meccanismo? Così, per esempio, potrei avere un posto centrale per registrare le classi di componenti usate, o fare qualche controllo di qualità ('non usare le classi BDE o quella vecchia versione del componente X!')? – mjn

+2

@mjn Ci sono altri punti di estensione che consentono di farlo più facilmente. Ad esempio 'TReader.OnFindComponentClass'. Il codice di patching dovrebbe essere sempre l'ultima risorsa quando nient'altro può portare a termine il lavoro. –

risposta

16

Io uso il seguente codice:

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; 

si implementa il tuo gancio/patch/deviazione chiamando RedirectProcedure:

RedirectProcedure(@LoadResourceModule, @MyLoadResourceModule); 

questo lavoro per codice a 32 bit. Funzionerà anche per il codice a 64 bit purché sia ​​le vecchie che le nuove funzioni risiedano nello stesso modulo eseguibile. In caso contrario, la distanza di salto potrebbe superare l'intervallo di un numero intero a 32 bit.

Sarei molto interessato se qualcuno potesse fornire un'alternativa che funzionasse per lo spazio di indirizzamento a 64 bit, a prescindere da quanto distanti fossero i due indirizzi.

+6

Può essere una buona idea * sgancio * il reindirizzamento o assicurarsi che non ci sia interruzione di codice alla chiusura dell'applicazione - la chiamata reindirizzata può essere effettuata (ad esempio dall'RTL o un'altra unità caricata prima dell'unità di reindirizzamento) e saltare ad alcuni codici non inizializzati. –

+0

@Arnaud Può essere vero. In tutto il mio uso di questo reindirizzamento prima di effettuare qualsiasi chiamata, o è una routine senza effetti collaterali e quindi l'unpatching non importa –

+0

@DavidHeffernan Solo per un pensiero, come posso chiamare la vecchia procedura se voglio ottenere il default valore e quindi lavorare su quel valore. Poiché nel codice precedente, sovrascriviamo l'indirizzo della vecchia routine per passare alla nuova procedura. Qualcosa come MyLoadResourceModule utilizza internamente LoadResourceModule e fa qualcosa in più .... –

7

C'è già un Delphi detours library per questo.

Il Delphi Detours Library è una libreria che consente di collegare le funzioni di Delphi e API di Windows .It fornisce un modo facile da inserire e rimuovere gancio.

Caratteristiche:

  • supporto x86 e x64. Architettura
  • Consentire di chiamare la funzione originale tramite la funzione Trampolino.
  • Supporto per gancio multiplo.
  • Supporto COM/Interfacce/win32api.
  • Supporto patch vtable COM.
  • Aggancio e sgancio del codice completamente thread-safe.
  • Supporto Oggetto aggancio Metodo.
  • supportato Delphi 7/2005-2010/XE-XE7.
  • Supporto Lazarus/FPC.
  • L'indirizzo a 64 bit è supportato.
  • La libreria non utilizza alcuna libreria esterna.
  • La libreria può inserire e rimuovere il gancio in qualsiasi momento.
  • La libreria contiene la libreria InstDecode, che consente di decodificare le istruzioni asm (x86 & x64).
3

Ho modificato il codice di David Heffernan per il supporto a 64-bit e salto indiretto a metodi in una BPL. Con qualche aiuto da: 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; 
Problemi correlati