///////////////////////////////////////////////////////////////////////////////
// ShellcodeHarness.cpp : Console application to load raw shellcode from
//                        a file on disk, and run it. With a debugger
//                        attached to this process, you can easily step 
//                        through a shellcode payload (e.g., MetaSploit's).
//
// Security disclaimer: obviously the point of this executable is to
// execute arbitrary other executable code specified on its command line,
// which is functionality that could be used by an attacker. ShellcodeHarness 
// is for testing purposes only.
//
// Feature wishlist:
//  - incorporate a disassembly-to-stdout option
//  - attach a debugger or otherwise issue a debug break as shellcode begins

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;

// Chosen to avoid out-of-memory errors. You can go bigger, or use 0 if you 
// want an unlimited buffer (just don't try to load a 2GB shellcode).
#define BUF_SIZE 0

// Assume shellcode is like a function that takes no arguments and
// returns no results:
typedef void (*shellcodeFunc)();

// Instructs user how to run ShellcodeHarness.
void PrintUsage()
{
	wcout << "PrintUsage: ShellcodeHarness.exe path/to/rawShellcodeFile" << endl;
}

// Utility function for getting Windows' system error message strings
void PrintError(_TCHAR* attemptedAction)
{
	LPVOID lpMsgBuf;
	DWORD dw = GetLastError();

	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		dw,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR)&lpMsgBuf,
		0, NULL);

	wcout << attemptedAction << " Error: " << (LPTSTR)lpMsgBuf << endl;

	LocalFree(lpMsgBuf);
}

// Attempts to open the file specified as the command line argument, memory-
// map it as executable pages of memory, and execute it. 
int ShellcodeExec(_TCHAR* shellcodeFile)
{
	shellcodeFunc shellcode;
	
	// Open the file (get a handle to the file):
	HANDLE hFile = CreateFile(shellcodeFile,
							  GENERIC_READ | GENERIC_EXECUTE,	// desired access
							  NULL,				// share mode (none)
							  NULL,				// security (default, non-inheritable)
							  OPEN_EXISTING,	// fail if not there
							  0,				// flags & attributes (ignored)
							  NULL);			// template file (none)
	if(hFile == INVALID_HANDLE_VALUE)
	{
		PrintError(L"Could not open shellcode file.");
		return 1;
	}

	// The POSIX way to memory map a file is mmap(). Windows doesn't have that,
	// so unless you're writing in Java/Ruby/Python/Perl/.NET etc., you must
	// call the Windows APIs: CreateFileMapping(), MapViewOfFile().
	HANDLE hMapFile;
	hMapFile = CreateFileMapping(hFile,					// existing open file
								 NULL,					// default security
								 PAGE_EXECUTE_READ,		// execute & read access
								 0,						// max object size (hi DWORD)
								 BUF_SIZE,				// max object size (lo DWORD)
								 NULL);					// name of mapping object
	if(hMapFile == INVALID_HANDLE_VALUE)
	{
		PrintError(L"Could not create file mapping object.");
		return 1;
	}

	shellcode = (shellcodeFunc) MapViewOfFile(hMapFile, 
											  FILE_MAP_EXECUTE | FILE_MAP_READ,
											  0, 0, BUF_SIZE);
	if(shellcode == NULL)
	{
		PrintError(L"Could not map shellcode file into memory.");
		return 1;
	}

	// Try to execute the shellcode:
	__try
	{
		shellcode();  // Visual Studio tip: breakpoint here, switch to disassembly view, then step-into. 
	}
	__except(GetExceptionCode()==EXCEPTION_IN_PAGE_ERROR ?
			EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
	{
		wcout << "Failed to execute shellcode." << endl;
	}

	// Clean up (but you'll probably never reach here because shellcode will 
	// exit and terminate the thread):
	UnmapViewOfFile(shellcode);
	CloseHandle(hMapFile);
	CloseHandle(hFile);

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	if(argc != 2)
	{
		PrintUsage();
		return -1;
	}

	// Load the interference DLL from the local directory. It exports a symbol
	// which should hash to the same value as "WinExec", and will deceive the
	// hashing-based search for kernel32!WinExec.
	HMODULE hInterferenceDll = LoadLibrary(L".\\kernel32.dll");
	if (hInterferenceDll == NULL)
		wcout << "[ShellcodeHarness:main] Failed to find the interference DLL." << endl;

	return ShellcodeExec(argv[1]);
}