6.3 Communicating With The Device Driver

Now, let's revisit the interaction between the user-mode component and the kernel-mode component. We will get back to our example of the null.sys driver and trigger a write operation to it's device (DeviceNullfrom the user-mode and monitor the IRP sent to the null.sys driver. To monitor the IRP packets sent to the driver, we can use the IrpTracker tool (https://www.osronline.com/article.cfm?article=199). To monitor launch the IrpTracker as an Administrator, click on File | Select Driver and enter the name of the driver (in this case, null), as shown in the following screenshot, and select the OK button:

Now, to trigger the I/O operation, you can open the Command Prompt and type the following command. This will write the string "hello" to the null device. As mentioned earlier, the symbolic link name is what a user-mode application (such as cmd.exe) can use; that is the reason I'm specifying the symbolic link name of the device (NUL) to write the content:

C:>echo "hello" > NUL

A device is treated as a virtual file and before writing to the device, handles to the device will be opened using CreateFile() (an API that's used to create/open a file or device). The CreateFile() API will eventually call NtCreateFile() in ntoskrnl.exe, which sends the request to the I/O manager. The I/O manager finds the driver associated with the device based on the symbolic link name, and calls its dispatch routine corresponding to the IRP_MJ_CREATE major function code. After the handle is opened to the device, the write operation is performed using WriteFile(), which will call NtWriteFile. This request will be dispatched by the I/O manager to the driver's routine that's corresponding to the IRP_MJ_WRITE major function code. The following screenshot shows calls to the driver's dispatch routines that are corresponding to IRP_MJ_CREATE and IRP_MJ_WRITE and their completion status:

At this point, you should have an understanding of how the user-mode code that performs I/O operations communicates with the kernel mode driver. Windows supports another mechanism, which allows the user-mode code to communicate directly with the kernel-mode device driver. This is done using the generic API called DeviceIoControl (exported by kernel32.dll). This API accepts the handle to the device as one of the parameters. Another parameter it accepts is the control code, known as the IOCTL (I/O control) code, which is a 32-bit integer value. Each control code identifies a specific operation to be performed and the type of device on which to perform the operation. A user-mode application can open the handle to the device (using CreateFile), call DeviceIoControl, and pass the standard control codes provided by the Windows operating system to perform direct input and output operations on the device, such as hard disk drive, tape drive, or CD-ROM drive. In addition, a device driver (a rootkit driver) can define its own device-specific control codes, which can be used by the user-mode component of the rootkit to communicate with the driver via the DeviceIoControl API. When a user-mode component calls DeviceIoControl by passing IOCTL code, it calls NtDeviceIoControlFile in ntdll.dll, which transitions the thread to the kernel-mode and calls the system service routine NtDeviceIoControlFile in the Windows executive ntoskrnl.exe. The Windows executive invokes the I/O manager, the I/O manager builds an IRP packet containing the IOCTL code, and then it routes it to the kernel dispatch routine identified by IRP_MJ_DEVICE_CONTROL. The following diagram illustrates this concept of communication between user-mode code and the kernel-mode driver:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.128.129