## KME-32
Kewl Mutation Engine (TM)
release 1.xx
User's Manual

[Русский] [English]

### Contents

- Decryptor structure
- Decryptor length/Compression
- Features
- How to link/include
- How to call
- Passing control from decryptor to virus

### Decryptor structure

There is no "polymorphic decryptor" and "encrypted data" as different objects, it is all decryptor, whose task is just to push some data to the stack in reversed order and then pass control to that data using instructions equivalent to JMP ESP.

Source data: (virus) | Encrypted data:
--- | ---
    ...
    nop
    db 22
    db 33
    db 44
    db 55
    db 66
    db 77
    db 88
    ...
    ...
    XOR     EAX, EBX
    ADD     EAX, (88776655h - curr_eax)
    ROR     EBX, 4
    XOR     EBX, (44332290h xor curr_ebx)
    ...
    PUSH    EAX
    ...
    PUSH    EBX
    ...

Instead of standard polymorphic engines which produces data of length DECRYPTOR_LENGTH + SOURCE_DATA_LENGTH, KME produces data of length SOURCE_DATA_LENGTH * k, where k is some data expansion coefficient, which depends upon many parameters.

### Decryptor length/Compression

When all features are enabled, produced data is 2-3 times more than source data. But there exists an interesting effect: when all "logic" is disabled (i.e. there is no register encryption, see FLAG_NOCMD) and data to encrypt is a repeating byte/word/dword, then produced decryptor will be shorter than source data. Maximal compression for single polimorphic layer is 4 times, but it can be greater when using multilayer technique.

How decryptor length depends on number of layers

layer# | --- | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13
| --- | 5000 | 11k | 34k | 101k | 300k | 893k | 2.66M | 7.9M
| FLAG_NOCMD | 5000 | 1280 | 380 | 200 | 225 | 342 | 531 | 813 | 1.2k | 1.8k | 3k | 4k | 6k | 10k

To create these pictures i was encrypting 5k NOP-buffer. Red color -- "logic" enabled, blue color -- logic disabled (FLAG_NOCMD). As you can see, on third layer achieved 25-times compression.

### Features

You can use KME everywhere -- ring3 and ring0, NT and win9X at least. Flat memory model, no segment registers used. There is no system calls inside of the engine, only register/memory manipulation. All parameters are passed on the stack. Engine's local variables are located in the stack too. Engine's code as well as produced decryptor's code is non-sensitive to offset displacement, 'coz there is no data used.

You can specify the following parameters:
- registers usage (min 1, max 7),
- commands usage,
- presence and parameters of JMPs (when pieces of code has random location in the decryptor and are linked with jmps),
and some other parameters.

Also you can specify RandSeed -- number to initialize random number generator. As a result all the produced decryptor depends on parameters you pass to engine, RandSeed and source data.

Decryptor is produced in a single pass, and no extra memory used to do it. As a result length of source data/decryptor is unlimited. So you can create decryptor of 100MB-length and start virus from such file every boot. It is also possible to create multilayer decryptors by multiple calls to KME. (see examples)

### How to link/include

KME exists in three forms:

1. Compiled OBJ-file (KME32.OBJ and KME32.INT)

YOURMAKE.BAT | YOURSRC.ASM:
--- | ---
    tasm  YOURSRC.ASM
    tlink YOURSRC.OBJ KME32.OBJ
    include KME32.INT
    extrn kme_main:PROC

2. Sources (KME32.INC and KME32.INT)

YOURSRC.ASM
    include KME32.INT
    include KME32.INC

3. As "binary include" file (KME32BIN.INC и KME32.INT)

YOURSRC.ASM
    include KME32.INT
    include KME32BIN.INC

### How to call

KME has only one PUBLIC near-procedure, called kme_main. It has pascal-convention call, i.e. it ends with "RET xxxx" command. All 13 parameters are of DWORD-type.

       push    Flags        ; flags, FLAG_XXX
       push    CommandMask  ; command set, CMD_XXX
       push    RegMask      ; register set, REG_XXX
       push    RandSeed     ; random number generator initializer
       push    JmpProb      ; (1/probability) of jmps. JMP if rnd(JmpProb)==0
                              used only if FLAG_NOJMPS is not specified
       push    OutEntryPtr  ; pointer to DWORD, where decryptor entrypoint
                              will be stored. if FLAG_EIP0, 0 will be stored.
       push    OutSizePtr   ; pointer to DWORD with produced decryptor size
                              w/o jmps -- ~InputSize*k here will be stored
                              with jmps -- OutMaxSize will be stored
       push    OutFiller    ; character to initialize decryptor buffer with
       push    OutMaxSize   ; maximal decryptor buffer size
       push    OutPtr       ; pointer to decryptor buffer
       push    InputEntry   ; virus entry point (where to pass control to)
       push    InputSize    ; source data (virus) size
       push    InputPtr     ; source buffer
       call    kme_main

       jc      error

Return values:

Registers unchanged, DF=0 (CLD)

CF=0 if all ok
CF=1 if error (no free space in output buffer)

Comments:

All constants are defined in KME32.INT.

Flags (first parameter)

FLAG_DEBUG | insert INT3 (0CCh) to decryptor start/end
FLAG_NOLOGIC | disable "logic" (register encryption)
FLAG_NOJMPS | disable jmps
FLAG_EIP0 | disable random decryptor entrypoint selection (if FLAG_NOJMPS)
FLAG_NOSHORT | disable short-instructions for EAX

CommandMask (second parameter)

Define command set which may be used in the decryptor.

CMD_xxx | see KME32.INT
CMD_ALL | use all commands

All commands of type CMD_xxx (not CMD2_xxx) may be globally disabled by FLAG_NOLOGIC in the Flags parameter.

If CMD2_ADD, CMD2_SUB and CMD2_XOR are all disabled at the same time, CMD2_XOR will be used.

Of course, some commands will be used anyway:

- MOV to load initial register values
- PUSH and XOR to modify&push data
- ADD and JMPreg to return from decryptor

RegMask (third parameter)

Define set of registers which may be used in the decryptor. Totally 7 registers may be used (all 32-bit regs except ESP)

REG_xxx | see KME32.INT
REG_ALL | use all possible registers (EAX/EBX/ECX/EDX/ESI/EDI/EBP)

If no registers defined, EAX will be used.

Entry points (InputEntry and OutputEntryPtr)

All entry points are relative to their buffers.

### Passing control from decryptor to virus

After data is decrypted, JMP (ESP+InputEntry) is executed.

At this time all registers from RegMask set are destructed, and virus with N-1 layers (assuming there were N layers) are pushed on the stack Size of all this shit can be calculated as sum of lengths of virus and all decryptors except first, but each length is dword-aligned ((InputSize+3) and (not 3)).

(c) 1999 Z0MBiE, z0mbie.cjb.net

[Top] [Contents] [Русский]