Click here to Skip to main content
11,634,631 members (68,573 online)
Click here to Skip to main content

Easy way to set up global API hooks

, , 19 Mar 2012 CPOL 171K 6.3K 177
Rate this:
Please Sign up or sign in to vote.
This article describes an easy way to set up system-wide global API hooks.

Contents

1.      Introduction
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. 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:

  1. Overwriting the beginning of the target function with custom code (so-called trampoline). When the function executes it will jump to the hook handler.
  2. Storing overwritten original code of the target function somewhere. It is needed for the correct target function functioning.
  3. 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");

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!

Note: This function must have the same signature as the original one.

//////////////////////////////////////////////////////////////////////////
// Hooked function

NTSTATUS WINAPI HookedNtQuerySystemInformation(
    __in       SYSTEM_INFORMATION_CLASS SystemInformationClass,
    __inout    PVOID                    SystemInformation,
    __in       ULONG                    SystemInformationLength,
    __out_opt  PULONG                   ReturnLength
    )
{
    NTSTATUS status = OriginalNtQuerySystemInformation(SystemInformationClass,
        SystemInformation,
        SystemInformationLength,
        ReturnLength);

    if (SystemProcessInformation == SystemInformationClass && STATUS_SUCCESS == status)
    {
        //
        // Loop through the list of processes
        //

        PMY_SYSTEM_PROCESS_INFORMATION pCurrent = NULL;
        PMY_SYSTEM_PROCESS_INFORMATION pNext    = (PMY_SYSTEM_PROCESS_INFORMATION)SystemInformation;
        
        do
        {
            pCurrent = pNext;
            pNext    = (PMY_SYSTEM_PROCESS_INFORMATION)((PUCHAR)pCurrent + pCurrent->NextEntryOffset);

            if (!wcsncmp(pNext->ImageName.Buffer, L"calc.exe", pNext->ImageName.Length))
            {
                if (0 == pNext->NextEntryOffset)
                {
                    pCurrent->NextEntryOffset = 0;
                }
                else
                {
                    pCurrent->NextEntryOffset += pNext->NextEntryOffset;
                }

                pNext = pCurrent;
            }            
        } 
        while(pCurrent->NextEntryOffset != 0);
    }

    return status;
}
 

4.3 Setting the hook

Setting the hook is pretty easy: call Mhook_SetHook from DllMain when the DLL is loaded to a new process:

//////////////////////////////////////////////////////////////////////////
// Entry point

BOOL WINAPI DllMain(
    __in HINSTANCE  hInstance,
    __in DWORD      Reason,
    __in LPVOID     Reserved
    )
{        
    switch (Reason)
    {
    case DLL_PROCESS_ATTACH:
        Mhook_SetHook((PVOID*)&OriginalNtQuerySystemInformation, HookedNtQuerySystemInformation);
        break;
 

4.4 Unhooking

Unhooking is performed by calling Mhook_Unhook from DllMain when the DLL is unloaded from the process:

//////////////////////////////////////////////////////////////////////////
// Entry point

BOOL WINAPI DllMain(
    __in HINSTANCE  hInstance,
    __in DWORD      Reason,
    __in LPVOID     Reserved
    )
{        
    switch (Reason)
    {
    ...
    case DLL_PROCESS_DETACH:
        Mhook_Unhook((PVOID*)&OriginalNtQuerySystemInformation);
        break;
    }

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.

api-hooks/diskc.PNG

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).

api-hooks/registry.PNG

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!

api-hooks/taskmgr.png

Figure 3 - Windows Task Manager processes tab.

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

api-hooks/procexp.png

Figure 4 - Process Explorer shows no calc.exe.

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

api-hooks/tasklist.png

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:

  1. As it was mentioned before this hook is applied only to those processes that are linked to User32.dll.
  2. 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).
  3. 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).
  4. The file path to AppInit DLL must not contain spaces.

Useful references

  1. Working with the AppInit_DLLs registry value
  2. AppInit DLLs in Windows 7 and Windows Server 2008 R2
  3. API hooking revealed
  4. Mhook, an API hooking library, v2.2
  5. Microsoft Research's Detours
  6. DllMain Callback Function

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Authors

Sergey Podobry
Team Leader ApriorIT
Ukraine Ukraine
No Biography provided

Apriorit Inc
Apriorit Inc.
Hungary Hungary
ApriorIT is a Software Research and Development company that works in advanced knowledge-intensive scopes.

Company offers integrated research&development services for the software projects in such directions as Corporate Security, Remote Control, Mobile Development, Embedded Systems, Virtualization, Drivers and others.

Official site http://www.apriorit.com
Group type: Organisation

32 members


You may also be interested in...

Comments and Discussions

 
AnswerRe: trying to hook socket/WSASocket Pin
Sergey Podobry21-Jan-13 2:27
memberSergey Podobry21-Jan-13 2:27 
GeneralRe: trying to hook socket/WSASocket Pin
Boyracer21-Jan-13 21:13
memberBoyracer21-Jan-13 21:13 
GeneralRe: trying to hook socket/WSASocket Pin
Sergey Podobry21-Jan-13 23:56
memberSergey Podobry21-Jan-13 23:56 
GeneralRe: trying to hook socket/WSASocket Pin
Boyracer22-Jan-13 4:51
memberBoyracer22-Jan-13 4:51 
GeneralRe: trying to hook socket/WSASocket Pin
Boyracer7-Feb-13 5:40
memberBoyracer7-Feb-13 5:40 
QuestionWhat if the API I want to hook to is not from ntdll.dll? Pin
dc_200018-Aug-12 21:28
memberdc_200018-Aug-12 21:28 
AnswerRe: What if the API I want to hook to is not from ntdll.dll? Pin
Sergey Podobry20-Aug-12 3:29
memberSergey Podobry20-Aug-12 3:29 
QuestionUse the hook in the windows service. Pin
Member 777926126-Apr-12 15:41
memberMember 777926126-Apr-12 15:41 
AnswerRe: Use the hook in the windows service. Pin
Sergey Podobry26-Apr-12 22:20
memberSergey Podobry26-Apr-12 22:20 
QuestionQuestion??? Pin
crin9918-Mar-12 23:53
membercrin9918-Mar-12 23:53 
AnswerRe: Question??? Pin
Sergey Podobry19-Mar-12 3:24
memberSergey Podobry19-Mar-12 3:24 
QuestionMhook for specific application thread Pin
Member 157271014-Mar-12 7:30
memberMember 157271014-Mar-12 7:30 
AnswerRe: Mhook for specific application thread Pin
Sergey Podobry14-Mar-12 11:26
memberSergey Podobry14-Mar-12 11:26 
GeneralRe: Mhook for specific application thread Pin
Member 157271016-Mar-12 7:33
memberMember 157271016-Mar-12 7:33 
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).

By way of example is this what you mean?

DLL_PROCESS_ATTACH: Mhook_SetHook(CreateWindow, MyCreateWindow)

MyCreateWindow: if currentThread != threadIWant &&
currentWindow != windowIWant
return CreateWindow
else ..... mycreatewindow code ......


Thanks again!
Questionproblem with copyfileexw Pin
Dinakara K23-Nov-11 2:12
memberDinakara K23-Nov-11 2:12 
SuggestionRe: problem with copyfileexw Pin
Sergey Podobry23-Nov-11 2:28
memberSergey Podobry23-Nov-11 2:28 
GeneralRe: problem with copyfileexw Pin
Dinakara K23-Nov-11 2:52
memberDinakara K23-Nov-11 2:52 
AnswerRe: problem with copyfileexw Pin
Sergey Podobry23-Nov-11 3:22
memberSergey Podobry23-Nov-11 3:22 
GeneralRe: problem with copyfileexw Pin
Dinakara K24-Nov-11 2:12
memberDinakara K24-Nov-11 2:12 
Questionppt problem Pin
john-6553716-Nov-11 16:14
memberjohn-6553716-Nov-11 16:14 
AnswerRe: ppt problem Pin
john-6553716-Nov-11 20:14
memberjohn-6553716-Nov-11 20:14 
Questionwindows 7 problem Pin
john-6553713-Nov-11 19:21
memberjohn-6553713-Nov-11 19:21 
AnswerRe: windows 7 problem Pin
Sergey Podobry13-Nov-11 22:20
memberSergey Podobry13-Nov-11 22:20 
GeneralRe: windows 7 problem Pin
john-6553714-Nov-11 16:28
memberjohn-6553714-Nov-11 16:28 
Questionhooking of user32.dll Pin
job@3deden.com28-Oct-11 6:33
memberjob@3deden.com28-Oct-11 6:33 
AnswerRe: hooking of user32.dll Pin
john-6553716-Nov-11 18:10
memberjohn-6553716-Nov-11 18:10 
AnswerRe: hooking of user32.dll Pin
Sergey Podobry16-Nov-11 23:44
memberSergey Podobry16-Nov-11 23:44 
GeneralRe: hooking of user32.dll Pin
dc_200019-Aug-12 17:36
memberdc_200019-Aug-12 17:36 
AnswerRe: hooking of user32.dll Pin
Sergey Podobry20-Aug-12 3:24
memberSergey Podobry20-Aug-12 3:24 
GeneralRe: hooking of user32.dll Pin
ahmd010-Jun-13 13:29
memberahmd010-Jun-13 13:29 
AnswerRe: hooking of user32.dll Pin
Sergey Podobry11-Jun-13 23:32
memberSergey Podobry11-Jun-13 23:32 
QuestionFreezing issue in PowerPoint 2007 Pin
nick_qi2-Mar-11 17:03
membernick_qi2-Mar-11 17:03 
QuestionRe: Freezing issue in PowerPoint 2007 Pin
Sergey Podobry6-Mar-11 22:29
memberSergey Podobry6-Mar-11 22:29 
AnswerRe: Freezing issue in PowerPoint 2007 Pin
nick_qi8-Mar-11 13:46
membernick_qi8-Mar-11 13:46 
QuestionAny other resource? Pin
Xercoy25-Jan-11 12:21
memberXercoy25-Jan-11 12:21 
AnswerRe: Any other resource? Pin
Sergey Podobry25-Jan-11 22:00
memberSergey Podobry25-Jan-11 22:00 
GeneralRe: Any other resource? Pin
Xercoy26-Jan-11 8:48
memberXercoy26-Jan-11 8:48 
AnswerRe: Any other resource? Pin
Sergey Podobry26-Jan-11 23:18
memberSergey Podobry26-Jan-11 23:18 
GeneralWorks fine on 32 bit machine. Not working in 64 Pin
yarongol13-Jan-11 4:27
memberyarongol13-Jan-11 4:27 
AnswerRe: Works fine on 32 bit machine. Not working in 64 Pin
Sergey Podobry13-Jan-11 5:16
memberSergey Podobry13-Jan-11 5:16 
GeneralRe: Works fine on 32 bit machine. Not working in 64 Pin
Xercoy25-Jan-11 9:24
memberXercoy25-Jan-11 9:24 
GeneralMy vote of 5 Pin
gndnet8-Jan-11 9:11
membergndnet8-Jan-11 9:11 
GeneralMhook SuspendOtherThreads implementation Pin
glizzen b1-Jan-11 21:07
memberglizzen b1-Jan-11 21:07 
AnswerRe: Mhook SuspendOtherThreads implementation Pin
Sergey Podobry3-Jan-11 22:00
memberSergey Podobry3-Jan-11 22:00 
GeneralRe: Mhook SuspendOtherThreads implementation Pin
glizzen b11-Jan-11 20:57
memberglizzen b11-Jan-11 20:57 
AnswerRe: Mhook SuspendOtherThreads implementation Pin
Sergey Podobry11-Jan-11 21:38
memberSergey Podobry11-Jan-11 21:38 
GeneralTerminateProcess hook Pin
NehaMishra286848-Dec-10 0:28
memberNehaMishra286848-Dec-10 0:28 
GeneralRe: TerminateProcess hook Pin
Sergey Podobry8-Dec-10 2:23
memberSergey Podobry8-Dec-10 2:23 
GeneralRe: TerminateProcess hook Pin
NehaMishra2868421-Dec-10 0:53
memberNehaMishra2868421-Dec-10 0:53 
AnswerRe: TerminateProcess hook Pin
Sergey Podobry21-Dec-10 4:09
memberSergey Podobry21-Dec-10 4:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150728.1 | Last Updated 19 Mar 2012
Article Copyright 2009 by Sergey Podobry, Apriorit Inc
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid