如何更改外部声明函数的实现(绕道) [英] How to change the implementation (detour) of an externally declared function
问题描述
我有第三方功能
function DataCompare(const S1, S2: string; APartial: Boolean): Boolean;
begin
...
end;
它用于另一个第三方单元.
It is used in another third party unit.
我希望在运行时用另一个新实现替换函数体.
I wish to replace the body of the function at runtime with another new implementation.
这可能吗?我想需要一些黑客(ala VirtualMemoryUnprotect).非常欢迎非汇编程序解决方案.
Is this possible? I guess there will be a need of some hack (ala VirtualMemoryUnprotect). A non-assembler solution is very welcome.
推荐答案
是的,您可以使用 ReadProcessMemory
和 WriteProcessMemory
函数用于修补当前进程的代码.基本上,您获取要修补的过程或函数的地址,然后向新过程的地址插入一条跳转指令.
Yes you can do that, using the ReadProcessMemory
and WriteProcessMemory
functions to patch the code of the current process. Basically, you get the address of the procedure or function to patch and then insert a Jump instruction to the address of the new procedure.
检查此代码
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.
现在每次执行应用程序并调用 DataCompare
函数时,都会执行跳转指令(到新地址),从而导致 DataCompareHack
函数将被调用.
Now every time you execute your app and a call to the DataCompare
function was made, the jump instruction (to he new address) will be executed causing which the DataCompareHack
function will be called instead.
这篇关于如何更改外部声明函数的实现(绕道)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!