Kapimon : Kernel API Monitor ( Version 2.0 )
KAPIMON can be used to hook kernel and device drivers APIs for trouble-shooting purposes. It also offers a special option that automatically hooks ExAllocatePoolWithTag, ExFreePoolWithTag to trace kernel pool allocations.
KAPIMON has two components : KAPIMON.EXE a user mode program that interacts with the user and TRACE.SYS, a kernel mode driver which is installed and loaded as a standard Windows NT service.
To install KAPIMON, copy kapimo.exe and trace.sys files on a local drive's subdirectory and create a symbol subdirectory and copy the symbol files for the Windows NT and service pack installed on your system.
KAPIMON works with symbol files that are provided with the standard Windows NT builds. It uses IMAGEHLP.DLL to load symbolic information for kernel, HAL and device drivers. This is very similar to the use of symbolic information by Windows NT kernel debugger.
You can define "_NT_SYMBOL_PATH" as an environment variable pointing to the location of symbol files for the current build/service pack running on your system. This could also be done by using the –p [symbol path] option from the command line. If neither of these two options are used, KAPIMON will prompt you for the symbol path. The minimum symbol file required is the NTOKRNL.DBG file.
HOOKING an API
KAPMON is used to hook kernel mode APIs. The –h option from the command line activates this feature. Optionally –hr can be used to allow hooking functions at the function entry and on the function return, making the function return value available. When working with symbolic info, Kapimon uses the Fpo info to decide wheather a symbol could be an API or a global variable. This information could be wrong for a function that does not have any Fpo info. The -hrf option makes it possible to hook all symbols available for the system's components.
Once an API is hooked, the trace driver’s hook routine will take control when the API gets called. The hook routine will then log the call ( the call parameters and the stack back trace), and returns control to the function being called.
A very simple mechanism to hook functions. The function prolog is replaced by a jump to the hook routine dedicated for this purpose. The hook routine saves the call context, logs the call , restores the context and returns to the function being called. The control from the called function to the hook routine and back is transfered by using the "jump" instruction.
As an example lets take ExAllocatePoolWithTag function. This function has the following function prolog :
KAPIMON will change the code as follows :
When ExAllocatePoolWithTag gets called, the jump instruction reroutes control to the TRACE hook routine that is something similar to the following :
It is very important to keep in mind the above mechanism. Only those APIs that have a similar function prolog allow the use of this mechanism and can be hooked safely. Attempting to hook functions that do not use a standard function prolog might make the system crash.
KAPIMON, in this version, does very little verification on function prologs. The user has to make sure that this assumption applies to the functions being hooked. Moreover, not much filtering is done on the symbols that are loaded for kernel modules. These symbols could be functions, global variables or strings. Attempting to hook global variables could also make the system crash ( the variable value will be overwritten by the jump instruction).
HOOKING an API with Return Value
When hooking an API with return value, TRACE gains control at the function entry and at the function return. The EAX register value is considered to be the function’s return value and is logged in the trace buffer. The return value has a meaning only if the function uses EAX for it's return value.
Tracking Pool allocations
Selecting "Hook->Trace Kernel pool allocations" hooks ExAllocatePoolWithTag, and it’s counterpart and ExFreePoolWithTag. This option will trace kernel drivers’ calls to memory allocation/free functions. When this option is used, the user interface tries to match memory allocations with their free counterparts and keep trak of memory that has been allocated and not freed.
Two Capture buffers are used : Kernel and user.
The kernel capture buffer is allocated by the trace.sys form non-paged pool. This buffer can be resized from the "options menu -> Capture Buffer ( Non Paged)".
User mode capture buffer is allocated by KAPIMON.EXE. The current size is hard coded to 15000 entries. When the buffer is full, KAPIMON simply resets it by disregarding the buffer's content.
Filtering can be used to filter calls from the capture buffer.
The Filter Dialog box has two parts : the kernel mode filters and the user mode filters.
Kernel mode filters can be used to filter calls coming from selected modules ( checked ) in the filter list. Trace.sys simply disregards calls containing a selected module in the stack back trace.
User mode filtering is applied by the user mode interface, after the kernel buffer is transferred to the user mode buffer.
Two types of user mode filtering are available : Filtering on Modules and filtering on Tags.
Filtering on modules can be used to include modules that are selected. KAPIMON will rescan the stack back trace and will keep those entries that have an API from the selected modules in the call path.
Tag Filtering, is only useful when tracing memory allocations. Tags are the third parameter of ExAllocatePoolWithTag. When the tag filtering options is selected, the tag filter value is matched with the third parameter to the call.
The "tag" value in the filter dialog, can be up to four characters. Blank is considered to be a wildcard. Example : the tag "T" will match to any tag starting with T. I.e : Tcpt,Thre,...
KAPIMON has the following command line options :