Developing Kernel mode security package

Understanding the registration of Microsoft packages
KSecRegisterSecurityProvider from DriverEntry
KSecRegisterSecurityProvider called from DriverEntry
Registration of a classic package

Registration is performed in ksecpkg!KsecExRegisterOneExtension. The work is done by ksecdd!KsecRegisterExtension (called from KsecInstallBuiltinPackages) via IOCTL 0x390038 (CTL_CODE(FILE_DEVICE_KSEC, 0xE, FILE_ANY_ACCESS, METHOD_BUFFERED)) to \device\ksecdd.

Parameter size is 0x10, consisting of two 8-byte values:

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

Each structure contains two pointers:

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

The array is terminated by a zeroed structure. The negotiate package is loaded directly in ksecdd.

Initialization of a classic package

Initialization happens when LSA is initialized:

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
Registration of a new SSP

Call KSecRegisterSecurityProvider() directly from the DriverEntry function of a legacy driver. This is an export of ksecdd.sys.

Critical timing requirement: the driver must be loaded with SERVICE_BOOT_START — after ksecpkg.sys and before lsass.exe. This means a system reboot is required after driver installation.
KSecRegisterSecurityProvider signature
KSecRegisterSecurityProvider function signature

If called after lsass.exe, the package can be used but NegoEx will failLocatePackageById returns NULL because the name-to-ID translation is done at LSA initialization.

Miscellaneous
Debug output

Enable verbose debug output with:

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