API/Code Hooking 


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:

SYSTEM_WIDE_9X: Generally the hook takes effect only in the current process, except if you signal this flag. However, as the name already implies, this flag works in win9x only and even there only for system APIs. If you're interested in this topic, please read also this one.

ACCEPT_UNKNOWN_TARGETS_9X: This flag is only valid in combination with SYSTEM_WIDE_9X. It means that installation of the hook shall succeed even if your callback function contains unknown call/jmp targets. See the documentation of CopyFunction for more information.

NO_SAFE_UNHOOKING: By default madCodeHook counts how many times any thread is currently running inside of your callback function. This way unhooking can be safely synchronized with that counter. Sometimes you don't need/want this counting to happen, though, e.g. if you don't plan to ever unhook, anyway. Or if the counting performance drop is too high for your taste. Or if you want to unhook from inside the hook callback function. In those cases you can set the flag "NO_SAFE_UNHOOKING".

NO_IMPROVED_SAFE_UNHOOKING: With madCodeHook version 2.1f the "safe unhooking" functionality (see above) was improved. Most probably there's no problem with the improvement, but to be sure you can disable it. The improved safe unhooking is currently only available in the NT family.

SAFE_HOOKING: Optionally madCodeHook can use a special technique to make sure that hooking in multi threaded situations won't result in crashing threads. This technique is not tested too well right now, so it's optional for now. You can turn this feature on by setting the flag "SAFE_HOOKING". Without this technique crashes can happen, if a thread is calling the API which we want to hook in exactly the moment when the hook is installed. Safe hooking is currently only available in the NT family.

MIXTURE_MODE: madCodeHook implements two different API hooking methods. The "mixture mode" is the second best method, it's only used if the main hooking method doesn't work for whatever reason (e.g. because of a "bad" API code structure). Normally madCodeHook chooses automatically which mode to use. You can force the use of the mixture mode by specifying this flag. Normally there's no need to do so, though.

NO_MIXTURE_MODE: If you don't want the mixture mode to be used, then simply tell madCodeHook so by using this flag. If the main API hooking method can't be used, this results in a failed hook attempt, though.

NO_AUTO_UNHOOKING: By default madCodeHook will auto unhook everything in finalization. You can disable that - do that on your own risk!

ALLOW_WINSOCK2_MIXTURE_MODE: WinSock2 normally doesn't like the mixture mode. This flag activates a special mode which forces WinSock2 into accepting mixture mode hooks. This is a somewhat experimental feature, though, so it's deactivated by default.

FOLLOW_JMP: By default, if the target API was already hooked by other hook library, madCodeHook switches to mixture mode (if possible). If the other hook library used code overwriting with a simple JMP, using this flag will instead make madCodeHook hook the callback function of the other hook library. This should work just fine. However, your hook will stop working in this case in the moment when the other hook library uninstalls its hook.

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) : bool; stdcall;
function HookAPI  (module, api  : pchar;
                   callbackFunc : pointer;
                   out nextHook : pointer;
                   flags        : dword = 0) : bool; stdcall;

// Example:
var ExitProcessNext : procedure (exitCode: dword); stdcall;

procedure ExitProcessCallback(exitCode: dword); stdcall;
  // okay, this doesn't make much sense, but who cares...  :-)
  ExitProcessNext(exitCode + 1);

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;

// Example:

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;

Sometimes when hooking a lot of APIs with the "mixture mode" in win9x, the installation of all the hooks can take some time. To speed things up a bit, you can put your HookAPI calls into a "CollectHooks".."FlushHooks" frame:

procedure CollectHooks;
procedure   FlushHooks;

// Example:
procedure InstallTextOutHooks;
  HookAPI('gdi32.dll',    'TextOutA',    @TextOutACallbackProc,    @TextOutANextHook);
  HookAPI('gdi32.dll',    'TextOutW',    @TextOutWCallbackProc,    @TextOutWNextHook);
  HookAPI('gdi32.dll', 'ExtTextOutA', @ExtTextOutACallbackProc, @ExtTextOutANextHook);
  HookAPI('gdi32.dll', 'ExtTextOutW', @ExtTextOutWCallbackProc, @ExtTextOutWNextHook);

In case you've not read enough yet, you can also have a look at the "ProcessFunc" Example or at the "ProcessAPI" Example.