Windows 內建 runas.exe 僅支援命令列,參數繁瑣且無法互動選擇桌面。本文實作一套 GUI RunAs 工具,提供直覺介面、桌面隔離、帳號驗證、特權啟用、SYSTEM 啟動等進階功能,適合系統管理員、開發人員與自動化部署腳本使用。
WinSta0 下所有桌面 (Default, Winlogon, ScreenSaver, Disconnect 等),雙擊選擇於隔離桌面啟動。LogonUser 即時驗證憑證正確性。SeIncreaseQuotaPrivilege, SeAssignPrimaryTokenPrivilege, SeChangeNotifyPrivilege, SeTcbPrivilege,註銷重登即生效。System 進程 Token、調整 TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY、DuplicateTokenEx + CreateProcessAsUser。cmd.exe, regedit.exe, mmc.exe 等快捷選項。
std::vector EnumDesktops() {
std::vector result;
HWINSTA hWinSta = OpenWindowStation(L"WinSta0", FALSE, WINSTA_ENUMDESKTOPS);
if (!hWinSta) return result;
wchar_t name[256];
for (DWORD i = 0; EnumDesktops(hWinSta, [](LPTSTR lpszDesktop, LPARAM lParam) {
auto& vec = *reinterpret_cast*>(lParam);
vec.push_back(lpszDesktop);
return TRUE;
}, reinterpret_cast(&result)); ++i) {}
CloseWindowStation(hWinSta);
return result;
}
bool VerifyCredentials(const wchar_t* user, const wchar_t* domain, const wchar_t* pwd) {
HANDLE hToken;
return LogonUser(user, domain, pwd, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken)
&& (CloseHandle(hToken), true);
}
bool EnablePrivilege(LPCTSTR pszPrivilege, bool bEnable = true) {
HANDLE hToken; TOKEN_PRIVILEGES tp = {1, {{0,0, bEnable ? SE_PRIVILEGE_ENABLED : 0}}};
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return false;
LookupPrivilegeValue(nullptr, pszPrivilege, &tp.Privileges[0].Luid);
BOOL ok = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, nullptr, nullptr);
CloseHandle(hToken);
return ok && GetLastError() != ERROR_NOT_ALL_ASSIGNED;
}
bool LaunchAsSystem(LPCWSTR cmdLine, LPCWSTR workDir, HWINSTA hWinSta, HDESK hDesk) {
// 1. 找 SYSTEM 進程 (如 winlogon.exe, services.exe)
DWORD pid = FindSystemProcess(); // ToolHelp32 遍歷
HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
HANDLE hSysToken; OpenProcessToken(hProc, TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_QUERY, &hSysToken);
// 2. 複製 Token 並設為 Primary
HANDLE hPrimary; DuplicateTokenEx(hSysToken, MAXIMUM_ALLOWED, nullptr, SecurityImpersonation, TokenPrimary, &hPrimary);
// 3. 設定啟動資訊
STARTUPINFO si = {sizeof(si)}; si.lpDesktop = (LPWSTR)L"WinSta0\\Default"; // 或傳入選擇的桌面
PROCESS_INFORMATION pi;
// 4. CreateProcessAsUser
BOOL ok = CreateProcessAsUser(hPrimary, nullptr, (LPWSTR)cmdLine, nullptr, nullptr, FALSE,
CREATE_UNICODE_ENVIRONMENT, nullptr, workDir, &si, &pi);
// 清理 handles...
return ok;
}

介面區塊:程式路徑/參數/目錄 → 使用者/密碼/網域 (含選單/驗證按鈕) → 桌面下拉清單 → 常用程式下拉 → 特權啟用按鈕 → 執行/取消。
userenv.h, secpol.h 等)。Default,程式將不顯示於當前使用者畫面,適合背景服務、自動化測試。LsaAddAccountRights 等) 管理特權,比手動編輯註冊表更安全。| 工具 | 介面 | 桌面隔離 | SYSTEM 啟動 | 特權管理 |
|---|---|---|---|---|
| runas.exe | CLI | ✗ | ✗ | ✗ |
| PsExec | CLI | ✗ | ✓ (-s) | ✗ |
| RunAsTool (第三方) | GUI | 部分 | ✓ | 部分 |
| 本工具 | GUI | ✓ 完整列舉 | ✓ Token 複製法 | ✓ 一鍵啟用+註冊表持久化 |
GUI RunAs 將繁瑣的 LogonUser/CreateProcessAsUser/Token 操作封裝為直覺介面,並解決桌面隔離、SYSTEM 啟動、特權持久化等進階痛點。完整原始碼 (VS2005/VC6 雙專案、Unicode、錯誤處理、日誌) 請參考文章附件。