Use "HookCode/HookAPI" to hook any function or API. Both your callback
function and the next hook variable must have exactly the same definition
(parameters + calling convention). Please use "HookAPI" as much as you can.
"HookCode" is only meant for situations where "HookAPI" can't be used.
Normally when calling HookCode/API you don't need to put anything into the
"flags" parameter. However, in some specific situations the flags may be
useful. So here's what they mean:
One thing you should know is that madCodeHook API hooks can be successfully
installed even if the DLL which exports the to-be-hooked API is not loaded
yet in the current process. For each API hook madCodeHook watches over
DLL loading/unloading and installs/uninstalls its API hooks automatically at
the right time. Can you have it any more comfortable?
|
function HookCode (code : pointer;
callbackFunc : pointer;
out nextHook : pointer;
flags : dword = 0;
numStackParams : dword = 32) : bool; stdcall;
function HookAPI (module, api : PAnsiChar;
callbackFunc : pointer;
out nextHook : pointer;
flags : dword = 0;
numStackParams : dword = 32) : bool; stdcall;
var ExitProcessNext : procedure (exitCode: dword); stdcall;
procedure ExitProcessCallback(exitCode: dword); stdcall;
begin
ExitProcessNext(exitCode + 1);
end;
HookAPI('kernel32.dll', 'ExitProcess', @ExitProcessCallback, @ExitProcessNext);
|
|
If you're done with hooking, you can uninstall the hooks again. Process
wide hooks are uninstalled automatically, when your DLL is unloaded or when
your process exits. System wide hooks (only available in win9x) keep
installed, if you don't manually uninstall them. Uninstalling is normally
(if you didn't specify DONT_COUNT when hooking) delayed until the
hook callback function is not in use by any thread anymore. This avoids
crashes when a hook DLL is being uninjected.
|
function UnhookCode (var nextHook: pointer) : boolean;
function UnhookAPI (var nextHook: pointer) : boolean;
UnhookAPI(@ExitProcessNext);
|
|
Here is an explanation of the flags you can use in your HookAPI/HookCode calls:
|
const
NO_SAFE_UNHOOKING = $00000001;
SAFE_HOOKING = $00000020;
MIXTURE_MODE = $00000002;
NO_MIXTURE_MODE = $00000010;
ALLOW_WINSOCK2_MIXTURE_MODE = $00000080;
FOLLOW_JMP = $00000200;
STORE_THREAD_STATE = $00000400;
USE_ABSOLUTE_JMP = $00000800;
|
|
When calling HookAPI with the "STORE_THREAD_STATE" flag, madCodeHook will
store the thread state, every time the hooked API is called. You can call
"GetStoredThreadState" to get access to the thread state from within your
hook callback function.
|
type
TPThreadState = ^TThreadState;
TThreadState = record
rflags : NativeUInt;
r15 : NativeUInt;
r14 : NativeUInt;
r13 : NativeUInt;
r12 : NativeUInt;
r11 : NativeUInt;
r10 : NativeUInt;
r9 : NativeUInt;
r8 : NativeUInt;
rdi : NativeUInt;
rsi : NativeUInt;
rbp : NativeUInt;
rbx : NativeUInt;
rdx : NativeUInt;
rcx : NativeUInt;
rax : NativeUInt;
rsp : NativeUInt;
rflags : NativeUInt;
edi : NativeUInt;
esi : NativeUInt;
ebp : NativeUInt;
esp : NativeUInt;
ebx : NativeUInt;
edx : NativeUInt;
ecx : NativeUInt;
eax : NativeUInt;
end;
function GetStoredThreadState (var threadState: TPThreadState) : bool; stdcall;
|
|
Some firewall/antivirus programs install API hooks, too. Sometimes they
uninstall your hooks. So if you hook often hooked APIs like CreateProcess,
you might want to call RenewHook inside of your hook callback function
(after you called the next hook), to make sure that your hook is still
installed. Don't have fear, it rarely happens that another program is
uninstalling your hooks. And if it happens, it only happens for such APIs,
which are hooked very often. So normally you don't need to care. RenewHook
is only there just in case...
|
function RenewHook (var nextHook: pointer) : bool; stdcall;
|
|
When unhooking an API madCodeHook (normally) waits until the hook is not in
use anymore. Only then the API is unhooked. This is what I call "safe
unhooking". It makes sure that there are no access violations when a hook
dll gets unloaded. However, if safe unhooking constantly thinks that an API
hook is still in use, this will freeze the unhooking and thus also the
unloading of the hook dll. In order to be able to debug such situations you
can call "IsHookInUse" to ask whether safe unhooking thinks that the hook
is still in use or not. The returned number indicates how often the hook is
still in use. "0" means the hook is not in use anymore.
|
function IsHookInUse (var nextHook: pointer) : integer; stdcall;
|
|
Putting all your HookAPI calls into a "CollectHooks".."FlushHooks" frame
can eventually speed up the installation of the hooks.
|
procedure CollectHooks;
procedure FlushHooks;
procedure InstallTextOutHooks;
begin
CollectHooks;
HookAPI('gdi32.dll', 'TextOutA', @TextOutACallbackProc, @TextOutANextHook);
HookAPI('gdi32.dll', 'TextOutW', @TextOutWCallbackProc, @TextOutWNextHook);
HookAPI('gdi32.dll', 'ExtTextOutA', @ExtTextOutACallbackProc, @ExtTextOutANextHook);
HookAPI('gdi32.dll', 'ExtTextOutW', @ExtTextOutWCallbackProc, @ExtTextOutWNextHook);
FlushHooks;
end;
|
|
In case you've not read enough yet, you can also have a look at the
"ProcessFunc" Example or at the "ProcessAPI" Example.