Kernel-mode callbacks routines are used by various drivers, they are commonly used by malwares or third party products because they make possible to “hijack” critical functions without having to patch the SSDT (System Service Dispatch Table) which is protected by PatchGuard on x64 version of Windows. Moreover, it avoids to patch the prolog code of the target function.
This article is a short introduction to what functions are registering callback and where they are stored. Windows Kernel is storing callback functions using different methods, some of them can be retrieved in a table like notify routines, or via a linked list like Bug check callback functions.
The most infected callback table is the “Load Image” (PspLoadImageNotifyRoutine) callback table, which is infected by TLD4 Rootkit as highlighted by Frank Boldewin.
PspLoadImageNotifyRoutine, PspCreateProcessNotifyRoutine, PspCreateThreadNotifyRoutine are part of the Process Manager and entries can be registered using PsSetImageLoadNotifyRoutine(), PsSetCreateProcessNotifyRoutine[Ex](), and PsSetCreateThreadNotifyRoutine() functions.
PspNotifyEnableMask is updated when a table is used, each lower bit correspond to a callback table of the process manager.
Create process notify routines are called two times, one time during the creation of the first/main thread in PspInsertThread(), and a second time during the destruction of the process in PspExitProcess().
Create thread notify routines are called each time PspInsertThread() is invoked by the creation new thread and also each time PspExitThread() is invoked during the destruction of a thread.
And finally, load image notify routines are invoked by the Memory Manager each time an executable image is loaded in memory.
Configuration Manager (Registry) call back functions are managed by the double link list called CallbackListHead on Windows Vista+ and by the callback table CmpCallBackVector in NT 5 and below. These callbacks are registry by CmRegisterCallback() function. As highlighted by Scott Noone on his personal blog.
Bug checks (B.S.O.D.) have three linked list dedicated to callbacks: KeBugCheckCallbackListHead, KeBugCheckReasonCallbackListHead, and KeBugCheckAddPagesCallbackListHead introduced in Vista+. These callbacks functions are sometimes patched by rootkit such as Rustock.C to remove “sanitize” the physical memory before the generation of a Microsoft crash dump during the B.S.O.D. as highlighted by Frank Boldewin in his Hack.lu presentation in 2008. Please notice that these callback functions are not called during the generation of a Microsoft crash dump using MoonSols WinDD utility.
Entries in KeBugCheckCallbackListHead are inserted by KeRegisterBugCheckCallback() function and entries in KeBugCheckReasonCallbackListHead are inserted by KeRegisterBugCheckReasonCallback() functions.
NMI (Non-maskable interrupt) callbacks are managed by the double link list called KiNmiCallbackListHead and registrable by KeNmiRegisterCallback() – These callbacks are invoked each time KiHandleNmi() function is invoked, and this function is called every time the hardware interruption 2 occurs (INT2, nt!KiNmiInterruptStart()).
AlpcpLogCallbackListHead is managed by Windows ALPC (Advanced Local Procedure Call) Manager. In theory only the internal kernel function AlpcRegisterLogRoutine() can insert an entry in this link-list, and this ALPC callbacks are invoked every time an ALPC log message is sent.
EmpCallbackListHead is a linked list managed by Errata Manager, only the Windows Kernel can have access to it to register entries.
Some of these callback tables, linked-list are only available from Windows Vista symbols (e.g. AlpcpLogCallbackListHead, KiNmiCallbackListHead).
The Windows Debugger script is available below, to run it use the following command:
This WinDbg script is working with every version of Windows from XP to 7, and for X86, x64 and IA64 architectures. Example of output can be found here.