2.4 Software Keyboard Spies
159
Schemes: Filter driver in combination with a managing application that performs
installation, loading, and setting of the driver. The driver transfers information about
the keys pressed to the managing application that processes and protocols the received
data;
– Fully autonomous driver records events independently. In this case, it is only
necessary to perform primary installation of the driver in the system, after which
the application that installed the driver can self-destruct;
– Solutions without an installator are also possible—in this case, the driver is
installed with the help of an INF file.
During loading, the driver needs to connect to the keyboard driver stack by means
of functions IoCreateDevice and IoAttachDevice. In most known implementation
scenarios, the filter connects to the device stack \\Device\\KeyboardClass0, which
is a class driver implementing common functionality for keyboards of various types
(Fig. 2.14).
The keylogger will only be interested in interruptions of type IRP_MJ_READ,
since their analysis can help acquire key codes. These IRP requests are sent by
the process csrss.exe, or, to be precise, the raw input stream (RawInputThread) of
this process. The interception sent by this thread first enters the driver filter of the
keylogger (step 1), which installs its completion handler using the function IoSetCompletionRoutine and sends IPR to the driver Kbdclass (step 2). The driver, in turn,
marks IRP as expecting completion and places it in the queue. When a keyboard even
occurs, Kbdclass extracts the waiting IRP from the queue, inserts information about
the button pressed into its buffer, and completes the IPR. Since the IPR contains
the set address of the completion handler, this handler will be called (step 3). The
handler can process the contents of the buffer and transfer information stored in it
Fig. 2.14 Examples of connection of a driver to the keyboard stack
159
Schemes: Filter driver in combination with a managing application that performs
installation, loading, and setting of the driver. The driver transfers information about
the keys pressed to the managing application that processes and protocols the received
data;
– Fully autonomous driver records events independently. In this case, it is only
necessary to perform primary installation of the driver in the system, after which
the application that installed the driver can self-destruct;
– Solutions without an installator are also possible—in this case, the driver is
installed with the help of an INF file.
During loading, the driver needs to connect to the keyboard driver stack by means
of functions IoCreateDevice and IoAttachDevice. In most known implementation
scenarios, the filter connects to the device stack \\Device\\KeyboardClass0, which
is a class driver implementing common functionality for keyboards of various types
(Fig. 2.14).
The keylogger will only be interested in interruptions of type IRP_MJ_READ,
since their analysis can help acquire key codes. These IRP requests are sent by
the process csrss.exe, or, to be precise, the raw input stream (RawInputThread) of
this process. The interception sent by this thread first enters the driver filter of the
keylogger (step 1), which installs its completion handler using the function IoSetCompletionRoutine and sends IPR to the driver Kbdclass (step 2). The driver, in turn,
marks IRP as expecting completion and places it in the queue. When a keyboard even
occurs, Kbdclass extracts the waiting IRP from the queue, inserts information about
the button pressed into its buffer, and completes the IPR. Since the IPR contains
the set address of the completion handler, this handler will be called (step 3). The
handler can process the contents of the buffer and transfer information stored in it
Fig. 2.14 Examples of connection of a driver to the keyboard stack
