是否可以修补/重定向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
是我的主要问题。
如何从该记录全局打补丁?
谢谢你,奈夫顿。
2条答案
按热度按时间knpiaxh11#
首先,要修补的代码如下:
但是你的
TryCastFixed
实现被破坏了,会导致堆栈溢出甚至更糟。重定向的方式简单地将一条jmp指令写入TryCast
可执行代码的前5个字节。这意味着无论你何时调用或跳转到原始方法,它都会跳转到你的方法。如果你的方法跳转回来,你就有了一个来回跳转的无限循环。你的jmp指令也会出现在编译器创建的方法的开始部分已经执行的代码之后。这意味着寄存器中的值可能不再相同,你不能在这里简单地使用jmp指令。如果你想继续使用原来的方法,那么你需要使用像DDetours或madCodeHook这样的库(我假设还有其他的库)。
否则,我建议您简单地将代码从RTL TryCast复制到您的例程中,并添加修复程序,这样您就可以摆脱重定向,因为您不再需要原始方法了。
8fsztsew2#
您尝试过https://github.com/MahdiSafsafi/DDetours吗?这是一个专门为挂钩 Delphi 函数而设计的库。免责声明:我确实知道它是否能截获记录帮助器方法。