by Mike Saunders, Principal Security Consultant
This blog is the thirteenth in a series of blogs on obfuscation techniques for hiding shellcode. You can find the rest of the series here. If you’d like to try these techniques out on your own, you can find the code we’ll be using on the Red Siege GitHub.
When I was discussing writing this series with Senior Security Consultant Corey Overstreet, he proposed an interesting idea of obfuscation shellcode by calculating and storing byte offsets rather than storing shellcode directly. You can find Corey’s blog about this technique here. Let’s take a look at how his technique works.
By calculating offsets, I mean calculating the numerical difference between one byte of shellcode and another. We’ll use the Python code below to generate our offsets. We start out by reading in our raw shellcode and calculating the length of that shellcode.
Now we’ll define a few variables. First, we create an empty list to store our calculated offsets. We’ll store the first byte of our shellcode in previous_byte
. We’ll use this variable to keep track of the last byte we operated on through our loop. remaining_idx
is an index variable used for iterating through our shellcode. We start at index 1 as there’s no delta to calculate for the first byte of shellcode.
Throughout this series, we’ve been using Metasploit Meterpreter reverse_http
shellcode. The shellcode started out with the following bytes: 0xfc, 0x48, 0x83, 0xe4
. Now it’s time to start calculating offsets. When we enter the loop, we’re starting at the second byte of shellcode – 0x48
. We calculate the delta by subtracting previous_byte
(0xfc
) from our current position in the shellcode. We then test to see if the result is negative. If we subtract 0xfc
from 0x48
, the result will be negative, so we add 256 to get the corresponding positive value, which would be 0x4c
.
Now that we have the delta, we append that value to our offset array. Finally, we’ll set previous_byte
to 0x48
, increment our index, and start the loop over again.
def get_offsets(input_file): # read in our raw shellcode and get the length raw_sc = get_raw_sc(input_file) sc_len = len(raw_sc) offset_arr = [] # stores the calculated offsets previous_byte = raw_sc[0] # Store previous byte we processed. remaining_idx = 1 # starts at 1 - second byte of shellcode # Loop through remaining bytes of shellcode while remaining_idx < sc_len: # Subtract previous byte from current byte to get the offset current_byte = raw_sc[remaining_idx] - previous_byte # Add 256 if value is negative to wrap around. if current_byte < 0: current_byte = current_byte + 256 # Add current byte of offset array offset_arr.append(current_byte) # Update previous byte to current shellcode byte previous_byte = raw_sc[remaining_idx] remaining_idx += 1
Using this logic, our offset array will start out with 0x4c, 0x3b, 0x61
. The C Code will look like the code below. We have a variable to store our first byte of shellcode, first_byte
. Next, we have an unsigned char array, delta
. This array contains our calculated offsets. We use an unsigned char array versus a signed as the only possible values are 0 to 255. This will make our lives easier when we’re reconstructing our shellcode. If the value is greater than 255, it will automatically wrap around without having to subtract 256. Finally, we’ll create an empty array to store the reconstructed shellcode.
unsigned char first_byte = 0xfc; unsigned char delta[597] = { 0x4c, 0x3b, 0x61, 0xc ... }; unsigned char shellcode[598] = { 0x00 };
We’ll declare an integer to store the size of our delta array:
int cap = sizeof(delta) / sizeof(delta[0]);
Now, we’ll populate the first byte of the shellcode array with the value of first_byte
.
shellcode[0] = first_byte;
We’ll declare two index variables. These will be used to keep track of where we’re at in the shellcode and delta arrays.
unsigned int delta_idx, shellcode_idx;
Finally, it’s time to rebuild our shellcode with a simple for loop. Inside the loop, we set the shellcode index to delta_idx + 1
. The first time we enter the loop, shellcode_idx
will be 1. We need to start at index 1, because we previously wrote the first byte of shellcode into the array.
The first time we enter the loop, delta_idx
will be 0. To calculate the next byte of shellcode, we’ll read the value at shellcode[0]
, which is 0xfc
, and add the first value from the delta
array – 0x4c
. Because we’re using unsigned characters, this becomes 0x48
instead of 0x148
. Only the right-most two bits are saved.
for (delta_idx = 0; delta_idx < cap; delta_idx++) { shellcode_idx = delta_idx + 1; shellcode[shellcode_idx] = shellcode[delta_idx] + delta[delta_idx]; }
And that’s it. The for loop will reconstruct our shellcode back to the original values. How does this technique fare on VT? Incredibly well! Only two engines alerted on this payload at the time this blog was written. This technique is tied with using XOR with a multibyte key for the best score in the series.
Offset Technique VT Score
You can find the example code for this article as well as the other articles in this series at the Red Siege GitHub.
This blog is part of a larger series on obfuscation techniques. Stay tuned for our next installment!
About Principal Security Consultant Mike Saunders
Mike Saunders is Red Siege Information Security’s Principal Consultant. Mike has over 25 years of IT and security expertise, having worked in the ISP, banking, insurance, and agriculture businesses. Mike gained knowledge in a range of roles throughout his career, including system and network administration, development, and security architecture. Mike is a highly regarded and experienced international speaker with notable cybersecurity talks at conferences such as DerbyCon, Circle City Con, SANS Enterprise Summit, and NorthSec, in addition to having more than a decade of experience as a penetration tester. You can find Mike’s in-depth technical blogs and tool releases online and learn from his several offensive and defensive-focused SiegeCasts. He has been a member of the NCCCDC Red Team on several occasions and is the Lead Red Team Operator for Red Siege Information Security.
Certifications:
GCIH, GPEN, GWAPT, GMOB, CISSP, and OSCP
By Red Siege | February 2, 2025
The Red Siege train is heading to Denver, Colorado, for the first-ever Wild West Hackin’ Fest @ Mile High from February 5-7, 2025! If you’re a cybersecurity professional who loves […]
Learn More
Red Siege at Wild West Hackin’ Fest Mile High 2025 – What to Expect!
By Red Siege | January 31, 2025
Ever wondered if your organization is truly secure or if your teams are just crossing items off a checklist? A Security Posture Review (SPR) is a solid way to answer […]
Learn More
By Red Siege | January 28, 2025
The Security Posture Review (SPR) is the newest addition to our suite of security offerings at Red Siege. We’ve combined our collective experiences in red team, blue team, and security […]
Learn More