Uninformed: Informative Information for the Uninformed

Vol 5» 2006.Sep

Implementing the Decoder

The implementation of the decoder involves taking the encoded form and converting it back into the raw form. This must all be done using assembly instructions that will execute natively on the target machine after an exploit has succeeded and it must also use only those instructions that fall within the valid character set. To accomplish this, it makes sense to figure out what instructions are available out of the valid character set. To do that, it's as simple as generating all of the permutations of the valid characters in both the first and second byte positions. This provides a pretty good idea of what's available. The end-result of such a process is a list of about 105 unique instructions (independent of operand types). Of those instructions the most interesting are listed below:


Some very useful instructions are available, such as add, xor, push, pop, and a few jcc's. While there's an obvious lack of the traditional mov instruction, it can be made up for through a series of push and pop instructions, if needed. With the set of valid instructions identified, it's possible to begin implementing the decoder. Most decoders will involve three implementation phases. The first phase is used to determine the base address of the decoder stub using a geteip technique. Following that, the encoded data must be transformed from its character-safe form to the form that it will actually execute from. Finally, the decoder must transfer control into the decoded data so that the actual payload can begin executing. These three steps will be described in the following sections.

In order to better understand the following sections, it's important to describe the general approach that is going to be taken to implement the decoder. Figure [*] describes the general structure of the decoder. The stub header is used to prepare the necessary state for the decode transforms. The transforms themselves take the encoded data, as a series of four byte blocks, and translate it using the process described in section [*]. Finally, execution falls through to the decoded data that is stored in place of the encoded data.

Figure: Structure of the Decoder
Image transform1