A low level file system driver was bundled with the latest version of Backdoor.Proxybox named "rxsupply". The malicious driver was designed to deny access to the files used by the malware in order to improve persistence on compromised computers. The driver functionality and methods used for hooking kernel file system access are described below.
Figure 1. File system device stack with malicious file system filter
The malicious driver is loaded by Windows as a service at system startup. The entry point of the driver performs the following steps to act as a file system filter:
Sets up its own IRP filter functions.
Figure 2. Driver entry: IRP handler setup
Attaches itself to the file system driver device stack.
Figure 3. Driver entry: Creating a device from a malicious driver to attach to the file system stack
Figure 4. Driver entry: Attaching a malicious device to the file system device stack
Builds a trampoline/hook into the existing file system device IRP function for IRP_MJ_READ
Figure 5. Driver entry: Hook file system device IRP_MJ_READ handler
Driver IRP filter functions
Every driver in the Windows kernel has a set of functions used to handle requests as a means of communication. In the malicious driver, all of these IRPs are handled by one function that filters out and deals with only four of them.
Figure 6. Malicious driver’s IRP handler functions
The IRPs dealt with by the IRP filter function at 0xf5b5b950 are related to file access:
- IRP_MJ_CREATE
- IRP_MJ_READ
- IRP_MJ_WRITE
- IRP_MJ_SET_INFORMATION
The driver checks which file is being accessed and which process is requesting access and will drop the IRP if the file is in the driver's list of protected files. After these malicious IRP handlers are setup, the next step for the driver is to insert itself into the device stack for the file system in order to intercept IRPs sent to the real file system device.
Figure 7. Driver IRP handler
File system stack
Windows employs file system drivers to handle access to the physical disk device in order to abstract reading from physical sectors to reading a directory path and file name. Windows also enables other drivers to interact with this driver through a construct called a device stack. The device stack is a chain of devices each acting sequentially on IRPs. The malicious driver's goal is to receive each IRP before the file system device does and to check to see whether or not to pass it down the chain.
Figure 8. Windbg list of file system devices associated with driver object “NTFS”
Figure 9. Windbg list of devices attached to the NTFS device stack
In order to do this, the malicious driver makes a call to IoAttachDeviceToDeviceStackSafe with a reference to the target file system device. This Windows kernel function will insert the malicious driver device into the stack of devices receiving IRP requests for file system actions. At this point the malicious driver will receive each IRP before the file system device. It can then decide not to pass it to the real file system device based on criteria, such as the file accessed or which process is trying to access the file.
File system IRP_MJ_READ hook
At this point, you might ask yourself why the driver needs to hook IRP_MJ_READ in the real file system device. After all, it has already installed itself into the device stack and is intercepting IRPs before the file system. The answer lies in the implementation of the malicious driver's IRP handlers.
As the IRP travels down through the kernel device stack towards the file system device, each intermediary device has a chance to operate on it. When the IRP gets to the file system device at the bottom of the stack, in the case of an IRP_MJ_READ, the IRP buffer is filled with the file contents and then the CompletionRoutines are called up from the bottom of the stack for each device in the stack that wanted access to the file. These completion routines are set by each device in the stack in its IRP handler function.
The file system IRP_MJ_READ hook from the malicious driver checks to see if a trusted process is accessing a protected file, in which case it should grant access to the file. If so, the hook function adds an entry in the completion routine chain and it will be the first completion routine to run after the file system driver fills the IRP buffer with the file contents. This routine obfuscates the IRP buffer by moving the original buffer into new allocated memory and replacing it with four magic values and a pointer to the allocated memory.
Figure 10. NTFS file system driver IRP_MJ_READ hook
The malicious driver also implements a completion routine from the top of the file system device stack, in its own IRP handler. This completion routine is the last to run since the malicious driver sits on the top of the stack. It checks the magic values of the obfuscated buffer and reconstructs the original buffer containing the contents of the file. This method of dual access points in the file system stack makes it more difficult for intermediate drivers to acquire the contents of protected files.
Figure 11. Malicious driver completion routine, checking magic values
Figure 12. Windbg: Obfuscated IRP buffer and pointer to real file contents buffer
If the lowest level implementation of an antivirus solution is in the file system stack, it is unlikely it will be able to detect this type of malicious file system filter driver or its protected payload. Symantec antivirus products are able to remove this family of back doors, detected as Backdoor.Proxybox.