Come modificare l’implementazione (deviazione) di una funzione dichiarata esternamente

Ho una funzione di terze parti

function DataCompare(const S1, S2: string; APartial: Boolean): Boolean; begin ... end; 

È utilizzato in un’altra unità di terze parti.

Desidero sostituire il corpo della funzione in fase di esecuzione con un’altra nuova implementazione.

È ansible? Immagino che ci sarà bisogno di alcuni hack (ala VirtualMemoryUnprotect). Una soluzione non assemblata è molto gradita.

Sì, puoi farlo utilizzando le funzioni ReadProcessMemory e WriteProcessMemory per applicare la patch al codice del processo corrente. Fondamentalmente, si ottiene l’indirizzo della procedura o della funzione da correggere e quindi si inserisce un’istruzione Jump all’indirizzo della nuova procedura.

Controlla questo codice

 Uses uThirdParty; //this is the unit where the original DataCompare function is declarated type //strctures to hold the address and instructions to patch TJumpOfs = Integer; PPointer = ^Pointer; PXRedirCode = ^TXRedirCode; TXRedirCode = packed record Jump: Byte; Offset: TJumpOfs; end; PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp; TAbsoluteIndirectJmp = packed record OpCode: Word; Addr: PPointer; end; var DataCompareBackup: TXRedirCode; //Store the original address of the function to patch //this is the implementation of the new function function DataCompareHack(const S1, S2: string; APartial: Boolean): Boolean; begin //here write your own code end; //get the address of a procedure or method of a function function GetActualAddr(Proc: Pointer): Pointer; begin if Proc <> nil then begin if (Win32Platform = VER_PLATFORM_WIN32_NT) and (PAbsoluteIndirectJmp(Proc).OpCode = $25FF) then Result := PAbsoluteIndirectJmp(Proc).Addr^ else Result := Proc; end else Result := nil; end; //patch the original function or procedure procedure HookProc(Proc, Dest: Pointer; var BackupCode: TXRedirCode); var n: {$IFDEF VER230}NativeUInt{$ELSE}DWORD{$ENDIF}; Code: TXRedirCode; begin Proc := GetActualAddr(Proc); Assert(Proc <> nil); //store the address of the original procedure to patch if ReadProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n) then begin Code.Jump := $E9; Code.Offset := PAnsiChar(Dest) - PAnsiChar(Proc) - SizeOf(Code); //replace the target procedure address with the new one. WriteProcessMemory(GetCurrentProcess, Proc, @Code, SizeOf(Code), n); end; end; //restore the original address of the hooked function or procedure procedure UnhookProc(Proc: Pointer; var BackupCode: TXRedirCode); var n: {$IFDEF VER230}NativeUInt{$ELSE}Cardinal{$ENDIF}; begin if (BackupCode.Jump <> 0) and (Proc <> nil) then begin Proc := GetActualAddr(Proc); Assert(Proc <> nil); WriteProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n); BackupCode.Jump := 0; end; end; //Patch the original procedure or function procedure HookDataCompare; begin //look how is passed the address of the original procedure (including the unit name) HookProc(@uThirdParty.DataCompare, @DataCompareHack, DataCompareBackup); end; //restore the address of the original procedure or function procedure UnHookDataCompare; begin UnhookProc(@uThirdParty.DataCompare, DataCompareBackup); end; initialization HookDataCompare; finalization UnHookDataCompare; end. 

Ora ogni volta che si esegue l’app e si effettua una chiamata alla funzione DataCompare , DataCompare eseguita l’istruzione di salto (al nuovo indirizzo), che a sua DataCompareHack verrà chiamata la funzione DataCompareHack .

Penso che JCL abbia alcuni programmi di utilità per questo genere di cose … Non l’ho usato da solo ma ho avuto un rapido sguardo e gli articoli seguenti sembrano promettenti:

 jclSysUtils.WriteProtectedMemory() jclPeImage.TJclPeMapImgHooks.ReplaceImport() 

Penso che il jclHookExcept.JclHookExceptions() dimostri come usarli.