Skip to content

Developing a kernel-mode security package

How the Microsoft packages register
KSecRegisterSecurityProvider from DriverEntry
KSecRegisterSecurityProvider called from DriverEntry
Registering a built-in package

Registration happens in ksecpkg!KsecExRegisterOneExtension. ksecdd!KsecRegisterExtension (called from KsecInstallBuiltinPackages) does the work, through IOCTL 0x390038 (CTL_CODE(FILE_DEVICE_KSEC, 0xE, FILE_ANY_ACCESS, METHOD_BUFFERED)) to \device\ksecdd.

The input buffer is 0x10 bytes, two 8-byte values:

  • First: 0x2 (the code)
  • Second: a pointer to an array of structures

Each structure holds two pointers:

  • A pointer to SECPKG_KERNEL_FUNCTION_TABLE (see ntsecpkg.h)
  • A pointer to a UNICODE_STRING

A zeroed structure ends the array. The Negotiate package lives in ksecdd itself.

Initializing a built-in package

ksecdd initializes the packages when LSA starts:

ksecpkg!NtLmInitKernelPackage
ksecdd!InitializePackages+0x327
ksecdd!CreateClient+0xfe
ksecdd!IsOkayToExec+0x1c
ksecdd!InitSecurityInterfaceW+0xb
ksecdd! ?? ::NNGAKEGL::`string'+0x48c
ksecdd!KsecDispatch+0x9a
nt!IopXxxControlFile+0x607
nt!NtDeviceIoControlFile+0x56
nt!KiSystemServiceCopyEnd+0x13
ntdll!ZwDeviceIoControlFile+0xa
lsass!LsapOpenKsec+0xec
lsass!main+0x14f
lsass!MIDL_user_free+0x1b5
kernel32!BaseThreadInitThunk+0xd
ntdll!RtlUserThreadStart+0x1d
Registering a new SSP

Call KSecRegisterSecurityProvider() from the DriverEntry of a legacy driver. ksecdd.sys exports it.

Load order: the driver must start as SERVICE_BOOT_START, after ksecpkg.sys and before lsass.exe. Installing it takes a reboot.
KSecRegisterSecurityProvider signature
KSecRegisterSecurityProvider function signature

Registered after lsass.exe starts, the package works on its own but NegoEx fails: LocatePackageById returns NULL, because LSA maps package names to IDs only at startup. Load a kernel-mode security package without a reboot shows how to skip the reboot, and the crash this lookup failure can cause.

Debugging
Debug output

Turn on verbose debug output:

ed nt!Kd_KSECDD_Mask 0xFFFFFFFF
e ksecpkg!KsecInfoLevel 6

Sample output from a checked build:

0xe100b30.0xe302060> KSec:  Calling TlsDecryptMessage()
0xe100b30.0xe302060> KSec:  Calling SslDecryptPacket()
0xe100b30.0xe302060> KSec:  SslDecryptPacket: returned 0x0
0xe100b30.0xe302060> KSec:  TlsDecryptMessage returned 0x0
0xe100b30.0xe302060> KSec:      Read Sequence [IN]: 2
0xe100b30.0xe302060> KSec:  Header (plaintext): cbBuffer:0x5, pvBuffer:0x02a52d70
0xe100b30.0xe302060> KSec:  Data (plaintext): cbBuffer:0x121, pvBuffer:0x02a52d75
0xe100b30.0xe302060> KSec:  Trailer (plaintext): cbBuffer:0x1f, pvBuffer:0x02a52e96
(...)
0xcd1f740.0xe5117b0> KSec:  NegoExtsQueryContextAttributes returned 0
0xcd1f740.0xe5117b0> KSec:  NegoExtsGetContextToken called