Geoff Chappell, Software Analyst
An array of KSE_HOOK structures provides the third level in the description of a driver shim. The second level of the description is an array of KSE_HOOK_COLLECTION structures. The top top level is a KSE_SHIM structure.
Microsoft’s name for this structure is known from symbol files for a driver (NDIS.SYS) that registers a shim and uses C++ for instantiating its KSE_HOOK array as statically allocated data: the C++ decoration names the type. Microsoft’s names and types are not known for members, there being no type information in the symbol file.
The KSE_HOOK is 0x10 and 0x20 bytes in 32-bit and 64-bit Windows 10, respectively.
Offset (x86) | Offset (x64) | Size | Description |
---|---|---|---|
0x00 | 0x00 | dword | type of hook: 0 to hook function in shimmed driver’s Import Address Table; 1 to hook shimmed driver’s receipt of I/O requests and related notifications; 2 for last KSE_HOOK in array |
0x04 | 0x08 | pointer | for type 0 only: address of name of exported function to hook, as null-terminated ANSI string |
dword | for type 1 only: I/O callback code | ||
0x08 | 0x10 | pointer | address of hook routine |
0x0C | 0x18 | pointer | initially NULL; for type 0 only: receives forwarding address |
For the last hook in the array, i.e., for type 2, all other members are ignored.
Each KSE_HOOK must specify a hook routine to which a shimmed driver’s execution is to be diverted. If instead the pointer is NULL, then the shim that contains this KSE_HOOK cannot be registered.
When a registered shim is applied to some driver, the Kernel Shim Engine (KSE) edits each KSE_HOOK.
The type 0 hooks are applied after the driver is loaded, of course, but before it executes any of its code, even for initialisation. This ensures that all the driver’s code is subject to the redirection of functions that the driver imports. The type 1 hooks are applied later, because it is only during the driver’s initialisation that the driver sets into various members of the given DRIVER_OBJECT the addresses at which it wants to be called for such things as I/O requests. The codes for these I/O callbacks are:
Code | Interpretation |
---|---|
1 | to hook what the driver puts in the DriverInit member |
2 | to hook what the driver puts in the DriverStartIo member |
3 | to hook what the driver puts in the DriverUnload member |
4 | to hook what the driver puts in the AddDevice member (of the DRIVER_EXTENSION) |
100 + mj | to hook what the driver puts in the MajorFunction member for the IRP major function mj |
It is not clear what Microsoft intends by changing the DriverInit member. Having loaded a driver and expecting to initialise it, the kernel sets DriverInit to the driver’s entry point for initialisation and then calls that entry point. To hook the member after the initialisation is too late if the goal is to affect the driver’s initialisation. More study is evidently needed.