1. Introduction

This article describes an easy way to set up system-wide global API hooks. It uses AppInit_DLLs registry key for DLL injection and Mhook library for API hooking. To illustrate this technique we will show how to easily hide calc.exe from the list of running processes.

1.1 What is API hooking?

API hooking means intercepting some API function calls. By means of it you can alter the behavior of any software. Hooks are widely used by antiviruses, security applications, system utilities, programming tools etc.

1.2 Local and global hooks

There are two types of hooks: local and global ones. Local hooks are applied only to the specific application. Global hooks are applied to all processes in the system. The hook technique, which is shown in this article, is global and impacts on all processes in all sessions (in contrast to the SetWindowsHooks way that is bounded to the specific desktop).

2. AppInit_DLLs infrastructure

AppInit_DLLs infrastructure is a mechanism for loading an arbitrary list of DLLs in all user-mode processes which are linked with User32.dll (Actually, there are very few executables that are not linked with it). The DLLs are loaded by User32.dll on its initialization.

The behavior of the AppInit_DLLs infrastructure is configured by a set of values that are stored under the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows key in the registry. These registry values are described in the table:

Value

Description

Sample values

LoadAppInit_DLLs
(REG_DWORD)

Value that globally enables or disables AppInit_DLLs.

0x0 – AppInit_DLLs are disabled.
0x1 – AppInit_DLLs are enabled.

AppInit_DLLs
(REG_SZ)

Space - or comma -separated list of DLLs to load. The complete path to the DLL should be specified using short file names.

C:\PROGRA~1\Test\Test.dll

RequireSignedAppInit_DLLs
(REG_DWORD)

Require code-signed DLLs.

0x0 – Load any DLLs.
0x1 – Load only code-signed DLLs.

Table 1 - AppInit_DLLs Infrastructure registry values.

3. Mhook library

There are several libraries for api hooking. The typical things that they do are:

Overwriting the beginning of the target function with custom code (so-called trampoline). When the function executes it will jump to the hook handler.

Storing overwritten original code of the target function somewhere. It is needed for the correct target function functioning.

Restoring overwritten portion of the target function.

Mhook is a free open source library for api hooking. It supports both x86 and x64 platforms and it is very easy in use. Mhook interface is simple and quite self describing:

For more info on library usage see the code sample shown in the next paragraph or visit Mhook home page.

4. Writing the code

We aregoing to write a user-mode DLL. First you should download the latest Mhook sources and add it to the project. If you are using precompiled headers turn it off for Mhook files.

As I’ve mentioned above our example will hide the calc.exe from the list of running processes.

4.1 Original function

The list of running processes is queried by calling NTAPI function NtQuerySystemInformation. So, we need to add some NTAPI stuff to our project. Unfortunately winternl.h header doesn’t contain full information and we have to define required data types ourselves:

Hooked function

In the hooked function we call the original function first. Then check SystemInformationClass. If it is SystemProcessInformation we loop through the list of the running processes and find all entries for calc.exe to cut them out from the list. That’s all!

5. Running a sample

Now it’s time to show the described hook in action. Build the project and put the resulting AppInitHook.dll to the root of the disk C.

Figure 1 - The hook DLL is put to the root of the disk C.

Open the registry editor and locate AppInit_DLLs registry key (The key is HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT \CurrentVersion\Windows). Then specify the path to the hook DLL (C:\AppInitHook.dll in our case).

Figure 2 – Modifying the registry.

After the registry has been modified the hook starts working. Let’s run a few instances of calc.exe. Then open Windows Task Manager and look at the processes tab. There is no calc.exe at all!

Figure 3 - Windows Task Manager processes tab.

Let’s see what shows another popular tool written by Mark Russinovich - Process Explorer.

Figure 4 - Process Explorer shows no calc.exe.

All calc.exe instances are hidden successfully. And finally run command line tool tasklist.exe:

Figure 5 - Tasklist.exe listing of the running processes.

The hook is working!

6. Limitations

There are a few limitations of this hook technique you should know about:

As it was mentioned before this hook is applied only to those processes that are linked to User32.dll.

As hooking is performed in DllMain of User32.dll you can call functions only from Kernel32.dll and Ntdll.dll (other libraries are not initialized yet).

Windows7/Windows 2008 R2 introduces the new security feature – AppInit DLLs have to be digitally signed (however there is a registry key that can turn this feature off).

Someone suggested starting a worker thread from the DllMain and wait for the library to load there, but what if this specific library never loads because the process that's being started doesn't contain it?

The hook can be implemented only as dll and runs in a context of the calling process. However you can incorporate an RPC mechanism and communicate with your service application. Be careful, don't do a lot of stuff in the DllMain!

Can Mhook, hook one specific application thread (ie setwindowshookex) or is it system-wide only? For example, if I hooked the createwindow function, isn't that going to hook all processes on the machine and not just one targeted application? It would seem to be simpler to use setwindowshookex in that case unless there are other advantages.

Sure, you can hook only one specific process but hook dll will be loaded to all processes (very similar to setwindowshookex). You just have to get process image name in your hook dll and decide whether to setup hooks or not.

Just to be clear. The approach to using mhook would be just to ignore all other hook methods(injection, setwindowshook) and if need be filter by thread or window calling the dll. So does this approach save in code/memory loaded into any one application and/or the performance degradation is trivial? Basically I'm swapping loading code into every thread I choose by injection(setwindowshook) vs a global check on the thread id/window I really want to run code on (mhook).

For the start only call the original function from your hook. Everything should work fine. Than analyze what else you do in the hook. Also you can log calls to CopyFileExW in the first (only original) and the second (with your logic) cases and look for the difference.

I think you didn't copy the file required for uninstall or copy to the wrong place\name.

You are right.Actually the DebugPrint() or OutputDebugString()changes the LastError value.So either we should not use it as first statement in the hooked Function call or we have to save and restore the LastError value before return, as you rightly pointed out.

How weird!In a XP 32b environment, everything hooked OK with registry method.But after I installed Office 2010, powerpoint and only powerpoint, no matter 2003 or 2010, can NOT be hooked with registry anymore(Remote Hooking is still OK).Any idea?

This way works greatly on windows other than win7 and later.In Windows 7 64bits environment I just cannot let the dlls been hooked by the registry.I've set registry values correctly, codesigned the dll, but still won't hook.I tried a remote hook method which use CreateRemoteThread(), it can hook 32bit processes but not 64bit processes.Please Help.

Yes, this method is OK in Windows 7, my previous problem is due to a silly fault. The LoadAppInit_DLLs Key in Windows 7 MUST be DWORD type. In Vista my .reg script can be LoadAppInit_DLLs="1", but win7 won't accept that.After I changed the data type of LoadAppInit_DLLs, DLLs hook beautifully.Thanks for the reply.

You may hook user32 functions later.I mean you don't/can't hook them in DllMain, instead hook them in other functions afterwards.For example, just create a thread in DllMain, later the thread hooks user32 functions.

1. You have to hook LoadLibrary. You need to hook all function: LoadLibraryA/W and LoadLibraryExA/W. If your dll will never be run under WOW64 then you may hook only LoadLibraryExW.2. After executing the original function call GetModuleHandleEx with the name of the dll you want to hook.3. If GetModuleHandleEx returns a valid handle hook the dll and make it unloadable (don't call FreeLibrary).4. Make sure that operations above are atomic. Use critical section for that.5. Don't hook twice (unless you really want to do that).