如何更改外部声明函数的实现(绕行) [英] 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屋!