How To Use madCodeHook 

www.madshi.net

On this page we'll work out together how to write a project which hooks an API system wide in both win9x and winNT families. Which API shall we hook? Hmmmm... Let's take a very system API, "TerminateProcess". We'll install a hook which protects our process from being terminated.

Before beginning with the work, let me say it loud and clear: I don't want madCodeHook to be used for illegal purposes! If you want to write a virus or a backdoor or whatever, please use something else. madCodeHook is used by several people for serious work and I don't want their work to be impacted negatively in any way. If you spread viruses which uses madCodeHook, some anti virus programs will condemn every single product, which uses madCodeHook. I don't want that to happen, so please use it only for serious and legal purpose. Thank you!

Okay, let's begin with the API hooking code. When hooking an API, we need to write some kind of hook callback function, which will later get called everytime someone tries to call the to-be-hooked API. Then we may need some way to call the original API from within our hook callback function. The most simple way to do so is to use a function variable. So let's have a look at a first easy chunk of code:

var OriginalTerminateProcess : function (processHandle, exitCode: dword) : bool; stdcall;

function TerminateProcessCallback(processHandle, exitCode: dword) : bool; stdcall;
begin
  result := OriginalTerminateProcess(processHandle, exitCode);
end;

Does that look alright to you? The "TerminateProcessCallback" function shall be our hook callback function. Inside the first version of our callback, we do nothing but call the original API. In order to enable us to handle all parameters as well as the result of the API correctly, we must use *exactly* the same function definition everywhere, which is also used by the original API - including the calling convention.

Now that we have a callback function and a "OriginalAPI" function variable, all we need to do is to install the hook. We do so by calling madCodeHook's HookAPI. But before doing that let's slightly rename our function variable. madCodeHook automatically builds up a full hooking queue. So in fact what we thought would be the original API function might just be another hook callback function. So let's rename "OriginalTerminateProcess" to "TerminateProcessNext".

var TerminateProcessNext : function (processHandle, exitCode: dword) : bool; stdcall;

function TerminateProcessCallback(processHandle, exitCode: dword) : bool; stdcall;
begin
  result := TerminateProcessNext(processHandle, exitCode);
end;

initialization
  HookAPI('kernel32.dll', 'TerminateProcess', @TerminateProcessCallback, @TerminateProcessNext);
end.

Okay, that should already work. Now let's fill our callback function, so that it actually does something. We want our own process to be protected from being terminated. So the first thing we have to do in our callback function is to check out which process is about to be terminated. Hmmmmm, the parameters give us a process handle. But which process hides behind that handle? Fortunately, madCodeHook exports two useful functions. With ProcessHandleToId we can convert the process handle to an ID, and with ProcessIdToFileName we can get the process' file name. If the file name is identical to our application's file name, we have to prevent the TerminateProcess call! Otherwise we let it pass:

function ThisIsOurProcess(processHandle: dword) : boolean;
var pid   : dword;
    arrCh : array [0..MAX_PATH] of char;
begin
  pid := ProcessHandleToId(processHandle);
  result := (pid <> 0) and ProcessIdToFileNameA(pid, arrCh, MAX_PATH) and
            (PosText('OurApplication.exe', arrCh) > 0);
end;

function TerminateProcessCallback(processHandle, exitCode: dword) : bool; stdcall;
begin
  if (integer(processHandle) > 0) and ThisIsOurProcess(processHandle) then begin
    result := false;
    SetLastError(ERROR_ACCESS_DENIED);
  end else
    result := TerminateProcessNext(processHandle, exitCode);
end;

This should actually work quite nicely. However, madCodeHook API hooks normally show effect only in the current process. That means, if another process calls TerminateProcess, we're lost. But the solution is quite easy. First, let's put all of our code into a little DLL like this:

library TPHook;

uses Windows, madRemote, madCodeHook, madStrings;

var TerminateProcessNext : function (processHandle, exitCode: dword) : bool; stdcall;

function ThisIsOurProcess(processHandle: dword) : boolean;
var pid   : dword;
    arrCh : array [0..MAX_PATH] of char;
begin
  pid := ProcessHandleToId(processHandle);
  result := (pid <> 0) and ProcessIdToFileNameA(pid, arrCh, MAX_PATH) and
            (PosText('OurApplication.exe', arrCh) > 0);
end;

function TerminateProcessCallback(processHandle, exitCode: dword) : bool; stdcall;
begin
  if (integer(processHandle) > 0) and ThisIsOurProcess(processHandle) then begin
    result := false;
    SetLastError(ERROR_ACCESS_DENIED);
  end else
    result := TerminateProcessNext(processHandle, exitCode);
end;

begin
  HookAPI('kernel32.dll', 'TerminateProcess', @TerminateProcessCallback, @TerminateProcessNext);
end.

And now in our application let's just inject this DLL into all processes system wide. That's very easy by using madCodeHook again.

After you have built the hook dll, you need to configure and then sign the drivers to make them work. More information about the injection drivers can be found here.

program OurApplication;

uses Windows, madCodeHook;

begin
  // load injection driver for 32bit and 64bit OSs
  LoadInjectionDriver('TPDemoDriver', 'tpdemo32.sys', 'tpdemo64.sys');
  // inject dll into all running processes
  InjectLibrary('TPDemoDriver', 'TPHook.dll', ALL_SESSIONS, true);

  MessageBox(0, 'You can''t call TerminateProcess on me!', 'Boasting...', MB_ICONINFORMATION);

  // uninject dll from all running processes
  UninjectLibrary('TPDemoDriver', 'TPHook.dll', ALL_SESSIONS, true);
  // stop injection driver (this completely removes the driver)
  StopInjectionDriver('TPDemoDriver');
end.