If you’ve look at any of the major bootkits such as TDL4 and Rovnix, you’ve probably noticed they employ certain self defense features to prevent removal; specifically, intercepting read/write requests to the boot sectors. While these defense mechanisms can fool some software, they may, in some cases, make infections even easier to spot.
Rovnix is probably the less stealthy of the two: It intercepts read/write requests to the boot disk by hooking the miniport driver, on read attempts it fills the buffer with zeros, resulting in the boot sectors appearing completely empty, on write requests it simply returns ACCESS_DENIED. Although this does prevent reading & writing the sectors, it’s usually a sure sign of an infection when the boot sector is blank but your system boots, or you can’t write the boot sector even with SYSTEM privileges.
On the other had we have TDL4, which goes a step further: Instead of filling the buffer with zeros during read attempts, it instead replaces the read data with the original, non-infected master boot record (MBR). As a result of TDL4’s clever trickery, any tools attempting to read the MBR will just see the original windows MBR and assume nothing is wrong; however, TDL4 also opted for a similar method to Rovnix by just denies writes to the boot sector, but with the slightly more inconspicuous error: STATUS_INVALID_DEVICE_REQUEST.
Obviously straight up denying write requests to the boot sector is going to raise some questions, so what if we improved upon TDL4’s method and also allowed writing to the spoofed, non-infected MBR, instead of the real one on disk.
Intercepting Disk I/O
|2 identical device stacks for different disks|
The device “DeviceHardDisk0DR0” is almost always the boot disk and is the NT device name for “.PhysicalDrive0”. The device directly below the disk device is the Miniport and usually belongs to atapi.sys, scsiport.sys, iastor.sys (or in the case of vmware, lsi_sas.sys), this is the driver we want to hook. We can get the device object of the Miniport by opening “DeviceHardDisk0DR0” then calling “IoGetLowerDeviceObject” with it, all we then need to do is replace the IRP_MJ_SCSI pointer in the driver’s object with a pointer to our filter routine, which will intercept all I/O for that disk device.
Filtering Miniport Requests
Srb = SCSI_REQUEST_BLOCK
- Set up a completion routine to be called after the hard disk has processed the read request.
- When the completion routine is called, map the caller’s buffer (Irp->MdlAddress) into system memory and replace the infected mbr with the clean one in it.
- Allow the request to complete.
- Map the caller’s buffer (Srb->DataBuffer) into system memory and read the first 512 bytes (1 sector) into the clean MBR buffer.
- Increment the caller’s buffer (Srb->DataBuffer) by 512 bytes.
- Decrement the transfer length (Srb->DataTransferLength) by 512 bytes.
- Add 1 to the Logical Block Address (Stored in Cdb).
- Subtract 1 from the Number of blocks to transfer (Stored in Cdb).
- Pass the request to the real Miniport (this will write all the sectors the caller wanted, except the MBR).
- Replace the original Srb->DataBuffer (Just to be safe).
- If the call succeeded, add 512 to Srb->DataTransferLength (This is the number of bytes actually written to disk, because we skipped them MBR we need to make it seem like we didn’t).
- Allow the request to complete.
Proof of Concept
Is this the real code?
Is this just spoofed for me?
bots trying to hide.
Not sure of the legality.
The system will be able to read/write to this fake MBR without modifying the real one, when the driver is unloaded or the system rebooted, the original MBR will still be intact and the face one will be gone. For some reason the driver will crash the system if loaded then unloaded many times in a row without reboot, but it’s not a huge issue and I’m too lazy to debug.
GitHub of code: https://github.com/MalwareTech/FakeMBR/