如何更改外部声明函数的实现(绕行) [英] How to change the implementation (detour) of an externally declared function

查看:140
本文介绍了如何更改外部声明函数的实现(绕行)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有第三方功能

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆