Out of Order Code Execution
What is it?
Out of Order Execution occurs when an in-line assembler interprets the instructions as if they are right next to each other when in fact the instructions may never be executed to begin with.
This concept cannot be described in assembly, however only in machine code. There are several ways to preform OOE, however this article contains an eight-byte solution that will not only jump through breakpoints laid within a debugger but also detect if breakpoints were present.
8 bytes was the smallest that this code would function inside, if readers can get it even shorter then please do so and let us know |
Shellcode
For this article, our shellcode will be:
\xeb\x01\x68\x6a\x58\x58 \x34\x58 |
|
In those 8 bytes we have jumped past the \x68, or the push instruction, into our actual code. Our actual code is the data for the push instruction, not the push instruction itself. By jumping past the push instruction into 0x04, we are able to execute these four [bytes], which is a DWORD. And as it so happens, the \x58 at the end is used in an xor, not to pop eax. However, apon review in a debugger, you will find the code looks like :
jmp 0x01 push 0x3458586a pop eax |
if one didn't know any better wouldn't it seem that the code made eax equal to 0x3458586a ?
Its a neat obfuscation technique, however it can also be used as an Anti-heuristics. When putting breakpoints over the push or pop instructions, of course since the breakpoints are around other bytes that we're not executing we're not going to stop execution for the breakpoints. And for some reason, these breakpoints cause the low 8 bits of eax to hang during the xor.
In other words:
cmp eax, 0 |
Detecting Breakpoints
We can detect if there were breakpoints during execution, or not. Now we can erase ourselves if we want to be intelligent, or we can attempt a debugger exploit. A better way to cmp eax, 0 would be to cmp al with 0x00, only two more bytes: \x3c\x00
So lets turn it up one more notch in stead of just leaving it at that. Say we want to wrap our code so that it looks entirely like another set of instructions and the code will continue to execute out-of-order. We want to compare eax to 0, if eax is not zero, we want to jump 9 bytes forward - for whatever reason. The purpose of this is to learn out-of-order code execution, not debugger exploitation. So what instructions are needed?
We will need push DWORD; pop eax; xor al, [byte]; cmp eax, and jne. So, we'll construct our code like so, with the fake execution stack so that the wrapped code can be seen:
|
So in a debugger, the code will display as:
Assembly | Machine Code |
---|---|
jmp 0x00000004 push 0x3458686a push 0x0975003c |
\xeb\x01 \x68\x6a\x68\x58\x34 \x68\x3c\x00\x75\x09 |
But what is actually being executed is:
Assembly | Machine Code |
---|---|
push 0x68 pop eax xor al, 0x68 cmp eax, 0x00 jne 0x09 |
\x6a\x68 \x58 \x34\x68 \x3c\x00 \x75\x09 |
Notice the machine code being executed is the same machine code following the first push DWORD or \x68 instruction. The jump to 0x04 and the push DWORD are simply \xeb\x01\x68, and the instructions following that are multiwrapped. Now, the value that xor al or \x34 takes at address 0x00000008 must also be an instruction that supports a DWORD parameter. For one last example, we'll show off one more type of out-of-order Byte wrapping. But keep in mind, in 12 bytes you have now not only obfuscated your code but detected if breakpoints were present, and done a conditional jump 9 bytes ahead if there in fact WERE any breakpoints around. So for our last example of obfuscation, we'll use code that does the exact same thing, however looks different on the inside of a debugger:
Assembly | Machine Code |
---|---|
jmp 0x00000004 xor eax, 0x3458356a xor eax, 0x0975003c |
\xeb\x01 \x35\x6a\x35\x58\x34 \x35\x3c\x00\x75\x09 |
Not too much different than the last set of code, now is it? Obviously, some instructions have changed, however this code will do the same thing:
|
This time we have hidden our instructions behind xor instructions in stead of the push DWORD instruction. The code we actually execute :
Assembly | Machine Code |
---|---|
push 0x35 pop eax xor al, 0x35 cmp eax, 0x00 jne 0x09 |
\x6a\x35 \x58 \x34\x35 \x3c\x00 \x75\x09 |
Notice that this time 0x35 is pushed instead of 0x68, then xor al with 0x35 instead of 0x68. That is because 0x68 represents the push DWORD instruction, while 0x35 represents the xor eax, DWORD instruction. Play around with that a bit, push your knowledge further! After all, its still only 12 bytes