Before introducing the complexities of kernel-level multi-threading and thread synchronization, I should first discuss the reason why these mechanisms are required for keyboard logging. The rootkit developed in this book is implemented as a kernel device driver, and device drivers are run at various processing levels that constrain their functionality. The following list details the device driver processing levels and the driver routines called at those levels.
Driver routines called: DriverEntry, AddDevice, Reinitialize, Unload routines, most dispatch routines, driver-created threads, and worker-thread callbacks. No interrupts are masked off at this processing level.
Driver routines called: Some dispatch routines are called at this processing level. APC_LEVEL interrupts are masked off at this processing level.
Driver routines called: StartIo, AdapterControl, AdapterListControl, ControllerControl, IoTimer, Cancel (while holding the cancel spin lock), DpcForIsr, CustomTimerDpc, and CustomDpc routines. DISPATCH_ LEVEL and APC_LEVEL interrupts are masked off. Device, clock, and power failure interrupts can occur at this processing level.
Driver routines called: InterruptService and SynchCritSection routines. All interrupts at IRQL<= DIRQL of the driver’s interrupt object are masked off at this processing level. Device interrupts with a higher DIRQL value can occur, along with clock and power failure interrupts.
Because the key data from the keyboard is collected at IRQL = DISPATCH_LEVEL and file I/O requires IRQL = PASSIVE_LEVEL, a thread running at the passive processing level must be created to perform the actual logging of key data to disk.