KSE_SHIM

The KSE_SHIM structure provides input to and receives some output from the KseRegisterShim and KseRegisterShimEx functions. It is the top-level description of a driver shim. A shim provider calls these functions to register the shim with the Kernel Shim Engine (KSE) for eventual application to one or more drivers.

Documentation Status

The KSE_SHIM structure is not documented. Microsoft’s name for it is known from symbol files for a driver (NDIS.SYS) that registers a shim and uses C++ for instantiating its KSE_SHIM 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.

Layout

The KSE_SHIM is 0x1C and 0x38 bytes in 32-bit and 64-bit Windows 10, respectively.

Offset (x86) Offset (x64) Size Description
0x00 0x00 dword ignored;
observed to be size of structure
0x04 0x08 pointer address of non-optional identifier for shim, as GUID structure
0x08 0x10 pointer ignored;
observed to be address of friendly name for shim as null-terminated Unicode string 
0x0C 0x18 pointer after successful registration:
address of callback-routines structure in kernel
0x10 0x20 pointer address of optional routine for notification when shim is removed from a driver
0x14 0x28 pointer address of optional routine for notification when shim is applied to driver
0x18 0x30 pointer address of non-optional KSE_COLLECTION array

Each shim is assumed to have its own GUID. The KSE does not permit concurrent registration of two shims that have the same GUID. The first dword of the GUID is used to identify the shim in logs.

Each shim must have a KSE_COLLECTION array. If instead the pointer is NULL, the shim cannot be registered.

Callbacks To The Kernel

When a shim is registered, the KSE edits the KSE_SHIM so that the registrant has access to helper routines. If only for now, the structure whose address is entered into the KSE_SHIM provides for two routines and both are specifically for hooks of I/O requests and related driver routines. Microsoft’s names for the structure and its members are not known. However, there’s just the one implementation and the members are pointers to kernel routines that are named in symbol files. These are the names given below:

Offset (x86) Offset (x64) Definition
0x00 0x00
VF_DRIVER_IO_CALLBACKS * 
(*KseGetIoCallbacks) (
    PDRIVER_OBJECT);
0x04 0x08
NTSTATUS 
(*KseSetCompletionHook) (
    PDEVICE_OBJECT, 
    PIRP, 
    PIO_COMPLETION_ROUTINE, 
    PVOID);

A shim provider that hooks a driver’s handling of I/O requests will typically need to forward the dispatch phase of a request to wherever it would have gone in that driver if not hooked. These original addresses for the handling are collected into a structure that the KSE associates with the shimmed driver’s DRIVER_OBJECT. The linkage works through the KseCallbacks member of the DRIVER_EXTENSION but shim providers are not meant to know that, let alone depend on it. Instead, they use KseGetIoCallbacks.

The collection of addresses that a shim provider gets from KseGetIoCallbacks is named above as VF_DRIVER_IO_CALLBACKS. This is Microsoft’s name for an undocumented structure that is used by the Driver Verifier for so similar a purpose that its members have one-to-one correspondence with those of whatever structure the KSE uses. Perhaps this is the Driver Verifier’s structure taken as ready-made. Perhaps it’s renamed to something like KSE_DRIVER_IO_CALLBACKS. Who knows. Whatever it’s named, shim providers must know the layout:

Offset (x86) Offset (x64) Definition
0x00 0x00
PDRIVER_INITIALIZE DriverInit;
0x04 0x08
PDRIVER_STARTIO DriverStartIo;
0x08 0x10
PDRIVER_UNLOAD DriverUnload;
0x0C 0x18
PDRIVER_ADD_DEVICE AddDevice;
0x10 0x20
PDRIVER_DISPATCH MajorFunction [IRP_MJ_MAXIMUM_FUNCTION + 1];

A shim provider that hooks a driver’s handling of I/O requests will often also want to learn of a request’s completion. While handling the request on its way to the shimmed driver, the shim provider may call KseSetCompletionHook to prepare the request’s current I/O stack location so that the shim provider will be notified of completion after any notification is handled by the shimmed driver. No matter whether the request completes as successful or failed, or is cancelled, the shim provider’s completion routine is called with the device object and context that were given to KseSetCompletionHook.

Callbacks From The Kernel

A KSE_SHIM may also provide the addresses of routines for the KSE to call whenever the shim that is described by the KSE_SHIM is applied to a driver or removed from a driver. Microsoft’s two built-in shim providers that supply these routines give them names that end in HookDriverTargeted and HookDriverUntargeted, respectively. Taking these as plausibly Microsoft’s names for the members, the following would be their definitions:

VOID 
(*HookDriverUntargeted) (
    PVOID);

VOID 
(*HookDriverTargeted) (
    PUNICODE_STRING, 
    PVOID, 
    ULONG, 
    ULONG, 
    ULONG);

The UNICODE_STRING is for the driver’s so-called base name. The PVOID for each callback is the base address of the driver’s image in memory. The three ULONG arguments are respectively the size of the image, and the TimeDateStamp and CheckSum from the driver’s IMAGE_NT_HEADERS.