mirror of
https://github.com/CloudDelphi/Virtual-File-System
synced 2025-12-19 09:53:54 +01:00
129 lines
3.7 KiB
ObjectPascal
129 lines
3.7 KiB
ObjectPascal
unit VfsPatching;
|
|
(*
|
|
Description: Code patching facilities, based on PatchForge library.
|
|
All hooks are thread-safe.
|
|
*)
|
|
|
|
|
|
(***) interface (***)
|
|
|
|
uses
|
|
Windows, SysUtils, Utils, PatchForge;
|
|
|
|
|
|
(* Replaces original STDCALL function with the new one with the same prototype and one extra argument.
|
|
The argument is callable pointer, used to execute original function. The pointer is passed as THE FIRST
|
|
argument before other arguments. *)
|
|
function SpliceWinApi (OrigFunc, HandlerFunc: pointer): pointer;
|
|
|
|
|
|
(***) implementation (***)
|
|
|
|
|
|
type
|
|
(* Import *)
|
|
TPatchMaker = PatchForge.TPatchMaker;
|
|
TPatchHelper = PatchForge.TPatchHelper;
|
|
|
|
|
|
(* Writes arbitrary data to any write-protected section *)
|
|
function WriteAtCode (NumBytes: integer; {n} Src, {n} Dst: pointer): boolean;
|
|
var
|
|
OldPageProtect: integer;
|
|
|
|
begin
|
|
{!} Assert(Utils.IsValidBuf(Src, NumBytes));
|
|
{!} Assert(Utils.IsValidBuf(Dst, NumBytes));
|
|
result := NumBytes = 0;
|
|
|
|
if not result then begin
|
|
try
|
|
result := Windows.VirtualProtect(Dst, NumBytes, Windows.PAGE_EXECUTE_READWRITE, @OldPageProtect);
|
|
|
|
if result then begin
|
|
Utils.CopyMem(NumBytes, Src, Dst);
|
|
Windows.VirtualProtect(Dst, NumBytes, OldPageProtect, @OldPageProtect);
|
|
end;
|
|
except
|
|
result := false;
|
|
end;
|
|
end; // .if
|
|
end; // .function WriteAtCode
|
|
|
|
(* Writes patch to any write-protected section *)
|
|
function WritePatchAtCode (PatchMaker: TPatchMaker; {n} Dst: pointer): boolean;
|
|
var
|
|
Buf: Utils.TArrayOfByte;
|
|
|
|
begin
|
|
{!} Assert(PatchMaker <> nil);
|
|
{!} Assert((Dst <> nil) or (PatchMaker.Size = 0));
|
|
// * * * * * //
|
|
result := true;
|
|
|
|
if PatchMaker.Size > 0 then begin
|
|
SetLength(Buf, PatchMaker.Size);
|
|
PatchMaker.ApplyPatch(pointer(Buf), Dst);
|
|
result := WriteAtCode(Length(Buf), pointer(Buf), Dst);
|
|
end;
|
|
end; // .function WritePatchAtCode
|
|
|
|
function SpliceWinApi (OrigFunc, HandlerFunc: pointer): pointer;
|
|
const
|
|
CODE_ADDR_ALIGNMENT = 8;
|
|
|
|
var
|
|
{O} p: PatchForge.TPatchHelper;
|
|
{OI} SpliceBridge: pbyte; // Memory is never freed
|
|
OrigFuncBridgeLabel: string;
|
|
OrigCodeBridgeStartPos: integer;
|
|
OverwrittenCodeSize: integer;
|
|
|
|
begin
|
|
{!} Assert(OrigFunc <> nil);
|
|
{!} Assert(HandlerFunc <> nil);
|
|
p := TPatchHelper.Wrap(TPatchMaker.Create);
|
|
SpliceBridge := nil;
|
|
result := nil;
|
|
// * * * * * //
|
|
|
|
// === BEGIN generating SpliceBridge ===
|
|
// Add pointer to original function bridge as the first argument
|
|
p.WriteTribyte(PatchForge.INSTR_PUSH_PTR_ESP);
|
|
p.WriteInt(PatchForge.INSTR_MOV_ESP_PLUS_4_CONST32);
|
|
p.ExecActionOnApply(PatchForge.TAddLabelRealAddrAction.Create(p.NewAutoLabel(OrigFuncBridgeLabel)));
|
|
p.WriteInt(0);
|
|
|
|
// Jump to new handler
|
|
p.Jump(PatchForge.JMP, HandlerFunc);
|
|
|
|
// Ensure original code bridge is aligned
|
|
p.Nop(p.Pos mod CODE_ADDR_ALIGNMENT);
|
|
|
|
// Set result to offset from splice bridge start to original function bridge
|
|
result := pointer(p.Pos);
|
|
|
|
// Write original function bridge
|
|
p.PutLabel(OrigFuncBridgeLabel);
|
|
OrigCodeBridgeStartPos := p.Pos;
|
|
p.WriteCode(OrigFunc, PatchForge.TMinCodeSizeDetector.Create(sizeof(PatchForge.TJumpCall32Rec)));
|
|
OverwrittenCodeSize := p.Pos - OrigCodeBridgeStartPos;
|
|
p.Jump(PatchForge.JMP, Utils.PtrOfs(OrigFunc, OverwrittenCodeSize));
|
|
// === END generating SpliceBridge ===
|
|
|
|
// Persist splice bridge
|
|
GetMem(SpliceBridge, p.Size);
|
|
WritePatchAtCode(p.PatchMaker, SpliceBridge);
|
|
|
|
// Turn result from offset to absolute address
|
|
result := Ptr(integer(SpliceBridge) + integer(result));
|
|
|
|
// Create and apply hook at target function start
|
|
p.Clear();
|
|
p.Jump(PatchForge.JMP, SpliceBridge);
|
|
WritePatchAtCode(p.PatchMaker, OrigFunc);
|
|
// * * * * * //
|
|
p.Release;
|
|
end;
|
|
|
|
end. |