Jak zmienić implementację (objazd) funkcji deklarowanej zewnętrznie

I have a third party function

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

Jest używany w innej jednostce trzeciej.

Chcę zastąpić ciało funkcji w czasie wykonywania inną nową implementacją.

Czy to możliwe? Myślę, że będzie potrzeba jakiegoś hack (Ala VirtualMemoryUnprotect). Nie-assembler rozwiązanie jest bardzo mile widziane.
Author: Ivelin Nikolaev, 2011-08-02

2 answers

Yes you can do that, using the ReadProcessMemory Oraz WriteProcessMemory Funkcje łatania kodu bieżącego procesu. Zasadniczo dostajesz adres procedury lub funkcji do poprawki, a następnie wstawiasz instrukcję skoku na adres nowej procedury.

Sprawdź ten kod

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.

Teraz po każdym uruchomieniu aplikacji i wywołaniu funkcji DataCompare zostanie wykonana Instrukcja skoku (na nowy adres), co spowoduje, że funkcja DataCompareHack będzie zadzwoniłem zamiast tego.

 35
Author: RRUZ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-24 07:50:22

Myślę, że JCL ma jakieś utile do tego typu rzeczy... Nie używałem go sam, ale szybko spojrzałem i następujące przedmioty wyglądają obiecująco:

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

Myślę, że jclHookExcept.JclHookExceptions() pokazuje, jak ich używać.

 2
Author: ain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-01 23:12:30