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 Windows API hooking. To illustrate this technique we will show how to easily hide calc.exe from the list of running processes.
Leader of Driver Team
1.1. What is API hooking?
1.2. Local and global API hooks
2. AppInit_DLLs infrastructure
3. Mhook library
4. Writing the code
4.1. Original function
4.2. Hooked function
4.3. Setting the API hook
5. Running the API hooking example
7. Useful references
API hooking means intercepting some API function calls. By means of it you can alter the behavior of any software or system. Hooks are widely used by antiviruses, security applications, system utilities, programming tools, etc.
There are two types of API 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 Windows 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).
AppInit_DLLs infrastructure is a mechanism for loading a custom 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 (and thus injected into corresponding processes).
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 that globally enables or disables AppInit_DLLs.||0x0 – AppInit_DLLs are disabled.|
0x1 – AppInit_DLLs are enabled.
|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|
|Require code-signed DLLs.||0x0 – Load any DLLs.|
0x1 – Load only code-signed DLLs.
Table 1 - AppInit_DLLs Infrastructure registry values.
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 32-bit and 64-bit 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.
We are going to write a user-mode DLL in C++. 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. This will illustrate how to create and inject DLL into a process to set up global API hook.
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:
To store original function address, we create a global variable and initialize it:
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!
Note: This function must have the same signature as the original one.
Setting the hook is pretty easy: call
DllMain when the DLL is loaded to a new process:
Unhooking is performed by calling
DllMain when the DLL is unloaded from the process:
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 DLL hook (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!
There are a few limitations of this hook method you should know about:
- As it was mentioned before this hook is applied only to those processes that are linked to User32.dll.
- As DLL hooking is performed in
DllMainof User32.dll you can call functions only from Kernel32.dll and Ntdll.dll (other libraries are not initialized yet).
- Windows7/Windows 2008 R2 introduce the new security feature – AppInit DLLs have to be digitally signed (however there is a registry key that can turn this feature off).
- The file path to AppInit DLL must not contain spaces.
- Working with the AppInit_DLLs registry value
- AppInit DLLs in Windows 7 and Windows Server 2008 R2
- API hooking revealed
- Mhook, an API hooking library, v2.2
- Microsoft Research's Detours
- DllMain Callback Function