核心難點:NT 內核系統需提權調用電源管理 API
ExitWindowsEx/SetSystemPowerState 直接調用即可,無權限隔離。SE_SHUTDOWN_NAME 特權。
#include
#include
#define RTN_ERROR 13
// 錯誤報告輔助
void ReportError(LPCTSTR szAPI, DWORD dwErr) {
LPTSTR pMsg = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dwErr, LANG_NEUTRAL, (LPTSTR)&pMsg, 0, NULL);
_tprintf(_T("%s 失敗 (錯誤碼: %lu): %s\n"), szAPI, dwErr, pMsg ? pMsg : _T("未知"));
LocalFree(pMsg);
}
// 核心函數:設置系統電源狀態
// bHibernate: TRUE=休眠, FALSE=待機
// bForce: TRUE=強制(不通知應用), FALSE=正常
BOOL SetPowerState(BOOL bHibernate, BOOL bForce) {
HANDLE hToken = NULL;
TOKEN_PRIVILEGES tp = {0};
LUID luid;
// 1. 打開當前進程令牌
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
ReportError(_T("OpenProcessToken"), GetLastError());
return FALSE;
}
// 2. 查找關機特權 LUID
if (!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &luid)) {
ReportError(_T("LookupPrivilegeValue"), GetLastError());
CloseHandle(hToken);
return FALSE;
}
// 3. 構造特權結構並啟用
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)) {
ReportError(_T("AdjustTokenPrivileges"), GetLastError());
CloseHandle(hToken);
return FALSE;
}
// 注意:AdjustTokenPrivileges 成功不代表特權生效,需檢查 GetLastError() == ERROR_SUCCESS
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
_tprintf(_T("當前用戶無關機特權,請以管理員身份運行或組策略授予。\n"));
CloseHandle(hToken);
return FALSE;
}
// 4. 調用電源管理 API
if (!SetSystemPowerState(bHibernate, bForce)) {
ReportError(_T("SetSystemPowerState"), GetLastError());
CloseHandle(hToken);
return FALSE;
}
CloseHandle(hToken);
return TRUE;
}
int _tmain() {
_tprintf(_T("1. 待機 (Sleep)\n2. 休眠\n選擇: "));
int choice; _tscanf(_T("%d"), &choice);
if (choice == 1) SetPowerState(FALSE, FALSE);
else if (choice == 2) SetPowerState(TRUE, FALSE);
else _tprintf(_T("無效選項\n"));
return 0;
}
SE_SHUTDOWN_NAME:對應「關閉系統」用戶權限。組策略:本地策略 → 用戶權限分配 → 關閉系統。SetSystemPowerState 參數:
bHibernate:TRUE = 休眠 (S4,內存寫入硬盤斷電);FALSE = 待機 (S3,內存供電)。bForce:TRUE 強制掛起,應用無法攔截 WM_POWERBROADCAST/PBT_APMQUERYSUSPEND;FALSE 允許應用阻止(如燒錄軟體)。| 現象 | 原因 | 解決 |
|---|---|---|
| 返回 FALSE,錯誤碼 1300 (ERROR_NOT_ALL_ASSIGNED) | 用戶無 SE_SHUTDOWN_NAME 特權 | 管理員運行 / 組策略添加用戶到「關閉系統」 |
| 調用成功但系統不休眠 | 未啟用休眠 / 驅動不支持 / 內存不足無法寫入休眠文件 | 電源選項啟用休眠 / 更新驅動 / 增加頁面文件 |
| 立即喚醒 | USB 設備/網卡喚醒 / 定時任務 | 設備管理器禁用「允許喚醒」 / powercfg -devicequery wake_armed |
BOOL SystemPowerAction(UINT uAction) {
// uAction: EWX_LOGOFF, EWX_SHUTDOWN, EWX_REBOOT, EWX_POWEROFF
// 需同樣提權 SE_SHUTDOWN_NAME
return ExitWindowsEx(uAction | EWX_FORCE, SHTDN_REASON_MAJOR_APPLICATION);
}
掌握特權提升模式,是開發系統級工具(服務管理、驅動加載、電源控制)的必備基礎。