Is it possible to patch/redirect any method of a record defined in RTL? If it is, how to do it?
I'm trying to patch TValue.TryCast
function, i want to redirect this function to my function definition from where i jump to orinal function and after that i check for additional stuff and exit.
To put some light on this topic, here is what i'm doing now and it did not work.
I declare:
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;
and then there is a patching stuff:
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;
As can be seen, code is completed from bits and pieces from internet, and PatchTValueHelper_TryCast
is my main problem.
How to patch function from this record globally?
Thanks, NevTon.
Did you try https://github.com/MahdiSafsafi/DDetours? This is a library specifically designed for hooking Delphi functions. Disclaimer: I do know know if it can intercept record helper methods.