4.1 Technical Principles & 4.2 keyboard filter framework

Source: Internet
Author: User

4.1 Technical Principles & 4.2 keyboard filter framework

 

4.1 prerequisites

Symbolic Link: a symbolic link is actually an "alias ". A device object (actually) can be represented by a different name. A Symbolic Link can point to any object with a name.

Zwcreatefile is an important function. There are actually two functions with the same name: one in the kernel and the other at the application layer. Therefore, you can call createfile directly in an application to call this function.
It not only opens files, but also opens Device objects (returns a handle similar to a file handle ). Therefore, you will often see that the application calls this function to interact with the kernel. This function eventually calls ntcreatefile.

PDO: phsiycal device object (physical device object ). PDO is the device object at the bottom of the device stack (inaccurate, but real)

NT! Iogetattacheddevice, NT! Obpcreathandle is often used in the windbg debugging tool .! The content before the number indicates the module name, and the subsequent content indicates the function name or variable name. For example, NT! Iogetattacheddevice indicates the iogetattacheddevice function in the module nt.


4.1.2 from the shortcut key to the kernel in Windows

The csrss.exe process can be viewed in the task manager's progress. This process is critical. It has a thread called Win32! Rawinputthread. This thread uses a guid (guid_class_keyboard) to obtain the PDO Symbolic Link name of the keyboard device.

Applications cannot open a device directly based on the device name. Generally, the device is opened by a symbolic link name.

Simply put, win32k! Rawinputthread thread is always nt! Zwreadfile requires reading data, and then waits for the keyboard key to be pressed. When the key on the keyboard is pressed, win32k! Rawinputthread processes nt! The data obtained by zwreadfile is NT! Zwreadfile requires reading data and then waiting for the key on the keyboard to be pressed.

We usually see the PS/2 Keyboard device stack. If you do not have other keyboard filter programs installed, the device stack is like this:
** The top-level device object is the device object generated by the driver kdbclass.
** The device object in the middle layer is the device object generated by the i8042prt driver.
** The underlying device object is the device object generated by the ACPI driver.
Here, you only need to know. Next, you need to find the device object that drives kdbclass.


4.1.3 keyboard hardware principles

A character occurs from the keyboard to the computer screen, and there are many complicated transformations in the middle. You need to know some knowledge here.
** The key is not represented by characters, but a scan code is assigned to each key.
** The interaction between the keyboard and the CPU is the interrupt and read ports. This operation is serial. When an interruption occurs, the keyboard sends a notification to the CPU. This notification can only notify one event: a key is pressed and a key pops up. The CPU can only receive notifications and read the Port Scan code. It never takes the initiative to "View" any key.
** Online Data Query: If the scan code for a key is X, the scan code for the same key is x + 0x80.
** In Windows XP, both the port and the interrupt number are fixed, that is, the interrupt number is 0x93, and the port number is 0x60. For each interrupted sending, the CPU reads the scan code in Port 0x60. Only one byte can be saved in Port 0x60, but the scan code can contain two bytes. At this time, two interruptions occur, the CPU reads two bytes of the scan code successively.

Note: for example, it is impossible to press two keys at the same time. Regardless of how keys are pressed, information is transmitted in a byte serial mode at a time.


4.2 keyboard filter framework
4.2.1 find all keyboard devices

Open the driver object kdbclass and bind all the devices under it.

Find all the objects under the driver:
(1) For deviceobject under driver_object, all Device objects under the driver are in the device chain. You can traverse the device by using the domain nextdevice in the chain node.
(2) Call ioenumeratedeviceobjectlist. This function can enumerate all devices under a drive.

Here, the new function, obreferenceobjectbyname, is used to obtain the pointer of an object through a name.

4.2.2 application device Expansion

When generating a filter device, we can specify a "device extension" of any length for this device. The content in this extension can be filled in as any one, as a custom data structure.

In this way, the pointer of the real device can be saved in the device object, so there is no need to map two arrays, and each time you have to find them.

In keyboard filtering, the author specifically defines a structure as a device extension as follows:

Typedef struct _ c2p_dev_ext {// size of this structure ulong nodesize; // filter the pdevice_object pfilterdeviceobject of the device object; // The protection lock kspin_lock iorequestsspinlock for simultaneous calls; // process kevent ioinprogressevent synchronously between processes; // The bound device object pdevice_object targetdeviceobject; // The underlying device object (real device) pdevice_object lowerdeviceobject before binding;} c2p_dev_ext, * pc2p_dev_ext;

 

To generate a device object with device extension information, the key is to call iocreatedevice, note that the second parameter is filled with the extension length. For example, when a filter device is generated in the previous example, the code used is:

Status = iocreatedevice (in driverobject, in sizeof (c2p_dev_ext), // The extended length is in null, in ptargetdeviceobject-> devicetype, in ptargetdeviceobject-> characteristics, in false, out & pfilterdeviceobject );

 

The function for filling in the extended domain is as follows:

NTSTATUS c2pDevExtInit(     IN PC2P_DEV_EXT devExt,     IN PDEVICE_OBJECT pFilterDeviceObject,     IN PDEVICE_OBJECT pTargetDeviceObject,     IN PDEVICE_OBJECT pLowerDeviceObject ) {     memset(devExt, 0, sizeof(C2P_DEV_EXT));     devExt->NodeSize = sizeof(C2P_DEV_EXT);     devExt->pFilterDeviceObject = pFilterDeviceObject;     KeInitializeSpinLock(&(devExt->IoRequestsSpinLock));     KeInitializeEvent(&(devExt->IoInProgressEvent), NotificationEvent,     FALSE);     devExt->TargetDeviceObject = pTargetDeviceObject;     devExt->LowerDeviceObject = pLowerDeviceObject;     return( STATUS_SUCCESS ); }    

 

4.2.3 DriverEntry of the keyboard filter module
The difference from the serial port is that the removal of the link keyboard is required here.

Ntstatus DriverEntry (in pdriver_object driverobject, in punicode_string registrypath) {ulong I; ntstatus status; kdprint ("c2p. SYS: Entering DriverEntry \ n "); // fill in the pointer of all the distribution functions for (I = 0; I <irp_mj_maximum_function; I ++) {driverobject-> majorfunction [I] = c2pdispatchgeneral;} // enter a read distribution function separately. Because the filtering is to read the key information // others are not important. This distribution function is written separately. Driverobject-> majorfunction [irp_mj_read] = c2pdispatchread; // enter an irp_mj_power function separately. This is because such requests need to call // A pocalldriver and a postartnextpowerirp, which is special. Driverobject-> majorfunction [irp_mj_power] = c2ppower; // We want to know when a device we have bound has been detached (for example, from the machine. // is it unplugged ?) Therefore, write a dedicated PNP (plug-and-play) Distribution Function driverobject-> majorfunction [irp_mj_pnp] = c2ppnp; // uninstall the function. Driverobject-> driverunload = c2punload; gdriverobject = driverobject; // bind all keyboard devices. Status = c2pattachdevices (driverobject, registrypath); Return status ;}

 

4.2.4 dynamic uninstallation of the keyboard filter module

Unlike serial port filtering, the keyboard is always in the "One read request is not completed" status.
A key is pressed on the keyboard to trigger the interruption. The keyboard driver reads the scan code from the port. The data obtained from the keyboard is handed over to the IRP. The IRP is ended. The result is win32k! The rawinputthread thread waits for the end of the read operation -- processing data, and then -- calls nt! Zwreadfile to start a new wait.

Gc2pkeycount is used to prevent pending requests from being completed. Gc2pkeycount is a global variable here. Each time a read request arrives, gc2pkeycount is incremented by 1. When each read request is completed, gc2pkeycount is subtracted by 1. Therefore, the wait will end only after all requests are completed; otherwise, the wait will continue endlessly.

In fact, the uninstall process ends only when a key is pressed. The gc2pkeycount operation is shown in section 4.3 "keyboard filter request processing" below.

# Define Merge (-10) # define merge (Limit * 1000) # define merge (Limit * 1000) void c2punload (in pdriver_object driverobject) {pdevice_object deviceobject; pdevice_object olddeviceobject; pc2p_dev_ext devext; large_integer ldelay; prkthread currentthread; // delay some time ldelay = rtlconvertlongtolargeinteger (100 * delay_one_milli Second); currentthread = kegetcurrentthread (); // set the current thread to a low real-time mode so that its running affects other programs as little as possible. Kesetprioritythread (currentthread, low_realtime_priority); unreferenced_parameter (driverobject); kdprint ("DriverEntry unloading... \ n "); // traverse all devices and unbind them from deviceobject = driverobject-> deviceobject; while (deviceobject) {// unbind and delete all devices c2pdetach (deviceobject); deviceobject = deviceobject-> nextdevice;} assert (null = driverobject-> deviceobject); While (gc2pkeycount) {kedelayexecutionthread (kerne Lmode, false, & ldelay);} kdprint ("DriverEntry unload OK! \ N "); return ;}

 

4.1 Technical Principles & 4.2 keyboard filter framework

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.