Delphi 2010 -补丁/重定向RTL记录方法

rryofs0p  于 2022-11-04  发布在  其他
关注(0)|答案(2)|浏览(174)

是否可以修补/重定向RTL中定义的记录的任何方法?如果可以,如何进行?
我正在尝试修补TValue.TryCast函数,我想将此函数重定向到我的函数定义,从那里我跳转到orinal函数,然后我检查其他东西并退出。
为了给这个主题提供一些线索,下面是我现在正在做的事情,但它没有起作用。
我宣布:

type
  TValueHelper = record helper for TValue
  public
    function TryCastFixed(ATypeInfo: PTypeInfo; out AResult: TValue): Boolean;
  end;

var
  TValueTryCastOrgAddr: Pointer;

function TValueHelper.TryCastFixed(ATypeInfo: PTypeInfo; out AResult: TValue): Boolean;
begin
  asm
    JMP TValueTryCastOrgAddr
  end;
  // fix for conversion from TValue
  if not Result and (ATypeInfo <> Nil) and (ATypeInfo = System.TypeInfo(TValue)) then begin
    AResult := TValue.From<TValue>(Self);
    Exit(True);
  end;
end;

然后是修补程序:

type
  PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp;
  TAbsoluteIndirectJmp = packed record
    OpCode: Word;   //$FF25(Jmp, FF /4)
    Addr: ^Pointer;
  end;

function WriteProtectedMemory(BaseAddress, Buffer: Pointer; Size: Cardinal; out WrittenBytes: Cardinal): Boolean;
var
  OldProtect, Dummy: Cardinal;
begin
  WrittenBytes := 0;
  if Size > 0 then begin // VirtualProtect for DEP issues
    OldProtect := 0;
    Result := VirtualProtect(BaseAddress, Size, PAGE_EXECUTE_READWRITE, OldProtect);
    if Result then try
      Move(Buffer^, BaseAddress^, Size);
      WrittenBytes := Size;
      if OldProtect in [PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY] then
        FlushInstructionCache(GetCurrentProcess, BaseAddress, Size);
    finally
      Dummy := 0;
      VirtualProtect(BaseAddress, Size, OldProtect, Dummy);
    end;
  end;
  Result := WrittenBytes = Size;
end;

function GetActualAddr(Proc: Pointer): Pointer;
begin
  if Proc <> Nil then begin
    if (PAbsoluteIndirectJmp(Proc).OpCode = $25FF) then
      Result := PAbsoluteIndirectJmp(Proc).Addr^
    else
      Result := Proc;
  end
  else
    Result := Nil;
end;

procedure RedirectFunction(OldP, DestP: Pointer);
type
  TJump = packed record
    Jmp: Byte; // $E9;
    Offset: Integer;
  end;

var
  Jump: TJump;
  WrittenBytes: Cardinal;
begin
  if IsLibrary then
    raise Exception.Create('RedirectFunction: Not allowed in a DLL');
  //
  OldP := GetActualAddr(OldP); 
  TValueTryCastOrgAddr := OldP;
  DestP := GetActualAddr(DestP);
  Jump.Jmp := $E9;
  Jump.Offset := Integer(DestP) - Integer(OldP) - SizeOf(TJump);
  WriteProtectedMemory(OldP, @Jump, SizeOf(TJump), WrittenBytes);
end;

procedure PatchTValueHelper_TryCast;
begin
  RedirectFunction(@@TValue.TryCast, @@TValueHelper.TryCastFixed); // this is not working, 
  // as it can't access undeclared record, how to do it correctly?
end;

可以看出,代码是从互联网上的点点滴滴完成的,PatchTValueHelper_TryCast是我的主要问题。
如何从该记录全局打补丁?
谢谢你,奈夫顿。

knpiaxh1

knpiaxh11#

首先,要修补的代码如下:

RedirectFunction(@TValue.TryCast, @TValue.TryCastFixed);

但是你的TryCastFixed实现被破坏了,会导致堆栈溢出甚至更糟。重定向的方式简单地将一条jmp指令写入TryCast可执行代码的前5个字节。这意味着无论你何时调用或跳转到原始方法,它都会跳转到你的方法。如果你的方法跳转回来,你就有了一个来回跳转的无限循环。你的jmp指令也会出现在编译器创建的方法的开始部分已经执行的代码之后。这意味着寄存器中的值可能不再相同,你不能在这里简单地使用jmp指令。
如果你想继续使用原来的方法,那么你需要使用像DDetours或madCodeHook这样的库(我假设还有其他的库)。
否则,我建议您简单地将代码从RTL TryCast复制到您的例程中,并添加修复程序,这样您就可以摆脱重定向,因为您不再需要原始方法了。

8fsztsew

8fsztsew2#

您尝试过https://github.com/MahdiSafsafi/DDetours吗?这是一个专门为挂钩 Delphi 函数而设计的库。免责声明:我确实知道它是否能截获记录帮助器方法。

相关问题