Written by:
Sergey Podobriy,
Development Coordinator of Driver Development Team, Apriorit Inc.
http://www.apriorit.com
Contents
1.1. What is API hooking?
1.2. Local and global hooks
2. AppInit_DLLs infrastructure
3. Mhook library
4. Writing the code
4.1.Original function
4.2.Hooked function
4.3.Setting the hook
4.4.Unhooking
5.Running a sample
6.Limitations
7.Useful references
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.dllB (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_MACHINESOFTWAREMicrosoftWindows NT CurrentVersionWindows 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 |
Space – or comma -separated list of DLLs to load. The complete path to the DLL should be specified using short file names. | C:PROGRA~1TestTest.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:
BOOL Mhook_SetHook(PVOID *ppSystemFunction, PVOID pHookFunction); BOOL Mhook_Unhook(PVOID *ppHookedFunction);
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:
///////////////////////////////////////////////////////////////////////// // Defines and typedefs #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) typedef struct _MY_SYSTEM_PROCESS_INFORMATION { ULONG NextEntryOffset; ULONG NumberOfThreads; LARGE_INTEGER Reserved[3]; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ImageName; ULONG BasePriority; HANDLE ProcessId; HANDLE InheritedFromProcessId; } MY_SYSTEM_PROCESS_INFORMATION, *PMY_SYSTEM_PROCESS_INFORMATION; typedef NTSTATUS (WINAPI *PNT_QUERY_SYSTEM_INFORMATION)( __in SYSTEM_INFORMATION_CLASS SystemInformationClass, __inout PVOID SystemInformation, __in ULONG SystemInformationLength, __out_opt PULONG ReturnLength );
To store original function address create a global variable and initialize it:
////////////////////////////////////////////////////////////////////////// // Original function PNT_QUERY_SYSTEM_INFORMATION OriginalNtQuerySystemInformation = (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(::GetModuleHandle(L"ntdll"), "NtQuerySystemInformation");