DelphiHookUtils is a Delphi/Pascal inline hook library for Windows. It is inspired by wr960204's delphi-hook-library and replaces BeaEngine with LDE64 to keep the compiled code small. The library supports function pointer hooks, Win32 API export hooks, Delphi COM/interface method hooks, and TObject method hooks on x86, x64, and ARM64EC.
- Inline trampoline hooks for x86, x64, and ARM64EC targets.
HookProcoverloads for a direct function pointer or a loaded module export name.HookInterfacefor COM and Delphi interface methods by MethodIndex.HookProcon Delphi object method pointers such as@TObject.FreeInstance.- Uses embedded LDE64 instruction-length decoding instead of BeaEngine, keeping the unit footprint small.
UnHookProcrestores the original entry point and frees trampoline memory.- Includes DUnit tests and demos for VCL, FMX, Delphi console, Free Pascal, IE, XP, RTL, and BPL scenarios.
- Delphi 7 or later, or Free Pascal with
{$MODE DELPHI} - Windows x86, x64, or ARM64EC
- Two units in
Source/:HookUtils.pasandHookIntfs.pas
- Clone this repository.
- Add the
Sourcedirectory to your Delphi, Lazarus, or Typhon project search path. - Add
HookUtilsand/orHookIntfsto your unitusesclause.
uses
HookUtils, HookIntfs;This repository includes Delphinus metadata:
Delphinus.Info.jsonDelphinus.Install.json
After publishing the repository, it can be indexed by Delphinus as a source-only package. Restart the IDE after installing through Delphinus so the new search path is picked up.
For more runnable examples, see the projects under Demos/.
uses
Windows, HookUtils;
var
MessageBoxNext: function (hWnd: HWND; lpText, lpCaption: PChar;
uType: UINT): Integer; stdcall;
function MessageBoxCallback(hWnd: HWND; lpText, lpCaption: PChar;
uType: UINT): Integer; stdcall;
begin
Result := MessageBoxNext(hWnd, 'Hooked text', lpCaption, uType);
end;
procedure InstallApiHook;
begin
HookProc('user32.dll', 'MessageBoxW', @MessageBoxCallback, @MessageBoxNext);
end;
procedure RemoveApiHook;
begin
UnHookProc(@MessageBoxNext);
end;HookProc with module and export names only works when the target module is already loaded. Call LoadLibrary first if needed.
var
TargetNext: Pointer;
procedure InstallPointerHook;
begin
HookProc(SomeFunction, @ReplacementProc, TargetNext);
end;On x64, trampoline memory must be allocated within ±2 GB of the target entry point. On ARM64EC, native ARM64 and emulated x64 targets are detected automatically.
HookIntfs resolves Delphi COM stubs and hooks the underlying method implementation.
uses
ComObj, ShlObj, HookIntfs;
var
ShellLink: IShellLink;
SetPathNext: function (Self: IShellLink; pszFile: LPTSTR): HResult; stdcall;
function SetPathCallback(Self: IShellLink; pszFile: LPTSTR): HResult; stdcall;
begin
Result := SetPathNext(Self, 'C:\Windows');
end;
procedure InstallInterfaceHook;
begin
ShellLink := CreateComObject(CLSID_ShellLink) as IShellLink;
HookInterface(ShellLink, 20, @SetPathCallback, @SetPathNext);
end;AMethodIndex is the VTable slot index, including methods inherited from parent interfaces. CalcInterfaceMethodAddr can be used to inspect the resolved entry point.
var
FreeInstanceNext: procedure (Self: TObject);
procedure FreeInstanceCallback(Self: TObject);
begin
FreeInstanceNext(Self);
end;
procedure InstallObjectHook;
begin
HookProc(@TObject.FreeInstance, @FreeInstanceCallback, @FreeInstanceNext);
end;HookProc and HookInterface return a trampoline pointer in AOldProc. Call it from your replacement procedure to execute the saved prologue and continue into the original body:
Result := MessageBoxNext(hWnd, lpText, lpCaption, uType);UnHookInterface is equivalent to UnHookProc for interface hooks.
HookProc and HookInterface return False when the target is invalid, memory cannot be allocated, page protection cannot be changed, or LDE64 cannot decode the entry instructions. They do not raise exceptions for those failures. Wrap installation and removal in normal Delphi try/finally blocks and always unhook during unit finalization or application shutdown.
- Source files are kept as UTF-8 with Windows CRLF line endings.
- Install and remove hooks from unit
initialization/finalizationor controlled startup/shutdown code. The library does not suspend other threads while patching code. - Do not hook functions whose entry is smaller than 5 bytes on x86/x64, or smaller than 16 bytes on native ARM64.
- Do not hook targets whose first overwritten bytes contain branch or jump instructions.
- Delphi BPL exports and DLL import thunks are resolved through an internal
FixFuncpass on x86/x64. - On ARM64EC, native ARM64 code uses absolute
LDR/BRtrampolines allocated with EC-marked memory; emulated x64 targets keep the x64 long-jump path. - For design details, platform differences, and review notes, see Doc/Hook.md and Doc/Arm64.md.
Contributions are welcome! Please fork this repository and submit pull requests with your improvements. Behavior changes should include matching DUnit coverage in UnitTest/.
This project is licensed under the Mozilla Public License 2.0. See LICENSE for details.
Thanks to wr960204 for the original delphi-hook-library design and to the LDE64 project for the lightweight instruction-length engine used in this library.