PayloadRC4UUIDEncryptor/PayloadRC4UUIDEncryptor/EncrObf.c
#include "common.h"

// disable error 4996 (caused by sprint)
#pragma warning (disable:4996)

BOOL Rc4EncryptionViaSystemFunc032(IN PBYTE pPayloadData, IN DWORD dwPayloadSize, IN PBYTE pRc4Key, IN DWORD dwRc4KeySize) {

	HANDLE		hAdvapi32	= NULL; // Handle to DLL
	NTSTATUS	STATUS		= NULL;	// Stores NTSTATUS

	USTRING Data = {
		.Buffer = pPayloadData,
		.Length = dwPayloadSize,
		.MaximumLength = dwPayloadSize
	};

	USTRING	Key = {
		.Buffer = pRc4Key,
		.Length = dwRc4KeySize,
		.MaximumLength = dwRc4KeySize
	};

	// Get handle to advapi32.dll
	hAdvapi32 = LoadLibraryA("advapi32.dll");
	if (!hAdvapi32) {
		errorWin32("LoadLibraryA - Failed to get handle to advapi32.dll");
		return FALSE;
	}

	// Get handles to SystemFunction032 using GetProcAddress
	fnSystemFunction032 pSystemFunction032 = (fnSystemFunction032)GetProcAddress(
		hAdvapi32,
		"SystemFunction032"
	);
	if (!pSystemFunction032) {
		errorWin32("GetProcAddress - Failed to get address to SystemFunction032");
		return FALSE;
	}
	
	// RC4 encrypt the data
	// https://doxygen.reactos.org/df/d13/sysfunc_8c.html#a66d55017b8625d505bd6c5707bdb9725
	STATUS = pSystemFunction032(&Data, &Key);
	if (!NT_SUCCESS(STATUS)) {
		errorNT("SystemFunction032 - Failed", STATUS);
		return FALSE;
	}

	return TRUE;
}

// Print the input buffer as a hex char array (c syntax)
VOID PrintHexData(IN LPCSTR Name, IN PBYTE Data, IN SIZE_T Size) {

	printf("unsigned char %s[] = {", Name);

	for (int i = 0; i < Size; i++) {
		if (i % 16 == 0) {
			printf("\n\t");
		}
		if (i < Size - 1) {
			printf("0x%0.2X, ", Data[i]);
		}
		else {
			printf("0x%0.2X ", Data[i]);
		}
	}

	printf("};\n\n");

}

// Generate random bytes of size "sSize", used for key generation
VOID GenerateRandomBytes(PBYTE pByte, SIZE_T sSize) {

	for (int i = 0; i < sSize; i++) {
		pByte[i] = (BYTE)rand() % 0xFF;
	}

}

BOOL GenerateKeys(IN SIZE_T sKey, OUT PBYTE* pbKey2) {

	PBYTE	pbKey = NULL;	// stores the key

	// Allocate memory for the key
	pbKey = (PBYTE)malloc(sKey);

	// Check if allocation was successfull
	if (!pbKey) {
		error("malloc - Allocation of memory failed.")
		return FALSE;
	}

	// Generate a random seed
	srand(time(NULL));

	// Generate the key
	for (int i = 0; i < sKey; i++) {
		pbKey[i] = (BYTE)rand() % 0xFF;
	}

	// Give back the key
	*pbKey2 = pbKey;

	return TRUE;
}

//BOOL EncryptStringW(IN LPWSTR string, LPSTR name, PBYTE pbRealKey) {
//
//	DWORD	dwStringSize	= NULL; // Stores size of the string
//	PBYTE	pbString		= NULL;	// Stores pointer to the string
//
//	// Calculate the string length in wide characters
//	dwStringSize = (wcslen(string) + 1) * sizeof(wchar_t); // Calc string length in wide chars
//
//	// Allocate enough memory
//	pbString = (PBYTE)malloc(dwStringSize); // Allocate enough memory
//
//	// Copy the wide string content
//	wcscpy_s(pbString, wcslen(string) + 1, string);
//
//	// Encrypt the string
//	Rc4EncryptionViaSystemFunc032(pbString, dwStringSize, pbRealKey, RC4KEYSIZE); // Encrypt it
//
//	// PrintHexData
//	PrintHexData(name, pbString, dwStringSize); // print it
//
//	// Free memory
//	if (pbString) {
//		free(pbString);
//	}
//
//	return TRUE;
//}

BOOL PaddBuffer(IN PBYTE InputBuffer, IN SIZE_T InputBufferSize, OUT PBYTE* OutputPaddedBuffer, OUT SIZE_T* OutputstPaddedSize) {

	PBYTE	PaddedBuffer = NULL;
	SIZE_T	stPaddedSize = NULL;

	// Calc the nearest number of * 16
	stPaddedSize = InputBufferSize + 16 - (InputBufferSize % 16);

	info("Adding %i bytes", (stPaddedSize - InputBufferSize));

	// Allocate memory
	PaddedBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), 0, stPaddedSize);
	if (!PaddedBuffer) {
		return FALSE;
	}

	// Zero the allocated memory
	ZeroMemory(PaddedBuffer, stPaddedSize);

	// Copying old buffer to a new padded buffer
	memcpy(PaddedBuffer, InputBuffer, InputBufferSize);

	// Save results back to main function
	*OutputPaddedBuffer = PaddedBuffer;
	*OutputstPaddedSize = stPaddedSize;

	return TRUE;
}

char* GenerateUUid(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 UUID segment is 32 bytes
	char Output0[32], Output1[32], Output2[32], Output3[32];

	// There are 4 segments in a UUID (32 * 4 = 128)
	char result[128];

	// Generating output0 from the first 4 bytes
	sprintf(Output0, "%0.2X%0.2X%0.2X%0.2X", d, c, b, a); // Litle endian 1x4

	// Generating output1 from the second 4 bytes
	sprintf(Output1, "%0.2X%0.2X-%0.2X%0.2X", f, e, h, g); // Litle endian 2x2

	// Generating output2 from the third 4 bytes
	sprintf(Output2, "%0.2X%0.2X-%0.2X%0.2X", i, j, k, l); // Big endian 1x4

	// Generating output3 from the last 4 bytes
	sprintf(Output3, "%0.2X%0.2X%0.2X%0.2X", m, n, o, p); // Big endian 1x4

	// Combining Output to generate UUID
	sprintf(result, "%s-%s-%s%s", Output0, Output1, Output2, Output3);

	return (char*)result;
}

BOOL GenerateUuidOutput(unsigned char* pShellcode, SIZE_T ShellcodeSize) {
	
	// Check if anything is null or if its not multiple of 16
	if (pShellcode == NULL || ShellcodeSize == NULL || ShellcodeSize % 16 != 0) {
		return FALSE;
	}
	
	// Start printint char array
	printf("char* UuidArray[%d] = { \n\t", (int)(ShellcodeSize / 16));

	// Start at 16, read 1 byte at a time
	int c = 16;
	int counter = 0;
	char* UUID = NULL;

	for (int i = 0; i < ShellcodeSize; i++) {
		if (c == 16) {
			counter++;

			// Generating the UUID string from 16 bytes which begin at i until [i + 15]
			UUID = GenerateUUid(
				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]
			);
			if (i == ShellcodeSize - 16) {

				// Print the last UID string
				printf("\"%s\"", UUID);
				break;
			}
			else {
				// Print a UUID string
				printf("\"%s\", ", UUID);
			}
			c = 1;
			// Beautify output
			if (counter % 3 == 0) {
				printf("\n\t");
			}
		}
		else {
			c++;
		}
	}
	printf("\n};\n\n");
	return TRUE;
}

BOOL EncrObfFunctions(IN const char* FileInput) {

	DWORD	dwPayloadSize		= NULL; // Size of the payload
	PBYTE	pbPayload			= NULL; // Pointer to payload
	PBYTE	pbKey				= NULL; // Pointer to the key

	// Read payload
	info("ReadPayloadFile - Reading payload");
	if (!ReadPayloadFile(FileInput, &dwPayloadSize, &pbPayload)) {
		error("ReadPayloadFile - Failed to read file");
		return FALSE;
	}
	info("ReadPayloadFile - Read %d payload bytes", dwPayloadSize);

	// Generate keys
	info("GenerateKeys - Generating keys");
	GenerateKeys(RC4KEYSIZE, &pbKey);

	// RC4 encrypt the payload
	if (!Rc4EncryptionViaSystemFunc032(pbPayload, dwPayloadSize, pbKey, RC4KEYSIZE)) {
		error("Rc4EncryptionViaSystemFunc032 - Failed");
		return FALSE;
	}

	// UID Obfuscate the payload

	// Padding buffer, if needed
	if (dwPayloadSize % 16 != 0) {
		
		info("Padding required size not dividable by 16, it is %i", dwPayloadSize);
		PBYTE	pbPaddedBuffer = NULL;
		SIZE_T	stPaddedSize = NULL;
		
		PaddBuffer(pbPayload, dwPayloadSize, &pbPaddedBuffer, &stPaddedSize);
		if (!GenerateUuidOutput(pbPaddedBuffer, stPaddedSize)) {
			return EXIT_FAILURE;
		}
	}
	else {
		info("Padding not required size is dividable by 16, it is %i", dwPayloadSize);
		if (!GenerateUuidOutput(pbPayload, dwPayloadSize)) {
			return EXIT_FAILURE;
		}
	}

	// Print the encrypted payload and protected key
	PrintHexData("cKey", pbKey, RC4KEYSIZE);

	// Free memory
	if (pbKey) {
		free(pbKey);
	}

	return TRUE;

}