My colleagues and I recently analyzed TDL4—a variant of the well-known TDSS malware family. TDSS, as you may already know, is an advanced malware that evades detection by going back to where we stopped looking long ago—in the boot sector. Back in the 16-bit DOS days, boot viruses spread from disk to disk, wreaking havoc on systems until 32-bit Windows came along and made them obsolete. However, the boot sector as a malware container is making a comeback, with bootkits like TDSS at the forefront.
Malware writers have figured out that the boot sector is a good way to circumvent detection—a lot of antivirus software no longer perform rigorous checks on this as in the past. As such, using it is a good way to circumvent Microsoft’s security settings.
So how does TDL4 work?
After getting a handle to the disk through ZwOpenFile, it then uses ZwDeviceIoControlFile to directly access it. This allows ZwDeviceIoControlFile to directly access an object (in this case, the disk), instead of looking for its name.
.text:00401780 push 48h ; OutputBufferLength
.text:00401782 mov eax, edx
.text:00401784 shr eax, 8
.text:00401787 mov [ebp-2Dh], al
.text:0040178A lea eax, [ebp-50h]
.text:0040178D push eax ; OutputBuffer
.text:0040178E push 48h ; InputBufferLength
.text:00401790 push eax ; InputBuffer
.text:00401791 push IOCTL_SCSI_PASS_THROUGH_DIRECT ; IoControlCode
.text:00401796 lea eax, [ebp-8]
.text:00401799 push eax ; IoStatusBlock
.text:0040179A xor eax, eax
.text:0040179C push eax ; ApcContext
.text:0040179D push eax ; ApcRoutine
.text:0040179E push eax ; Event
.text:0040179F push FileHandle ; FileHandle
.text:004017A2 mov [ebp-50h], cx
.text:004017A6 mov byte ptr [ebp-4Ah], 0Ah
.text:004017AA mov byte ptr [ebp-49h], 12h
.text:004017AE mov dword ptr [ebp-40h], 1388h
.text:004017B5 mov [ebp-2Fh], bl
.text:004017B8 mov [ebp-2Ch], dl
.text:004017BB call ds:ZwDeviceIoControlFile
However, using ZwDeviceIoControlFile is not an easy task, as it needs to set up a lot of structures before being able to directly access the disk. Notice here that aside from pushing arguments into the stack, it also fills in values to a structure that is needed for the operation, which explains the push statements interspersed with mov [ebp+location], register statements.