delphi - tornillo - Cómo cambiar la implementación(desvío) de una función declarada externamente
resultante de una causa (2)
Creo que JCL tiene algunos utils para este tipo de cosas ... No lo he usado yo mismo, pero he echado un vistazo rápido y los siguientes elementos parecen prometedores:
jclSysUtils.WriteProtectedMemory()
jclPeImage.TJclPeMapImgHooks.ReplaceImport()
Creo que jclHookExcept.JclHookExceptions()
demuestra cómo usarlos.
Tengo una función de terceros
function DataCompare(const S1, S2: string; APartial: Boolean): Boolean;
begin
...
end;
Se usa en otra unidad de terceros.
Deseo reemplazar el cuerpo de la función en tiempo de ejecución con otra implementación nueva.
es posible? Supongo que habrá necesidad de algún truco (ala VirtualMemoryUnprotect). Una solución no ensamblable es muy bienvenida.
Sí, puede hacerlo utilizando las funciones ReadProcessMemory
y WriteProcessMemory
para parchear el código del proceso actual. Básicamente, se obtiene la dirección del procedimiento o función para parchar y luego se inserta una instrucción Jump en la dirección del nuevo procedimiento.
Verifique este código
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.
Ahora, cada vez que ejecuta su aplicación y se realiza una llamada a la función DataCompare
se ejecutará la instrucción de salto (a la nueva dirección), lo que provocará que se DataCompareHack
función DataCompareHack
.