主要使用ExitWindowsEx函數,在NT系統中必須先提權一下
開發環境:Win7+VC6.0
思路 :獲得本地進程句柄,新建令牌並賦予較高權限,通過進程句柄爲進程賦予新令牌,重啓操作
以下是自動重啓代碼:
#include <windows.h>
int main()
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
//取得系統版本
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(GetVersionEx(&osvi)== 0)
return false;
if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken))
return false;
//獲取本地唯一標識用於在特定系統中設置權限
LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//提升訪問令牌的權限
AdjustTokenPrivileges(hToken,FALSE,&tkp,0,(PTOKEN_PRIVILEGES)NULL,0);
}
//強制重啓
ExitWindowsEx(EWX_REBOOT|EWX_FORCE,0);
return 1;
}
以下對用到的一些數據結構以及函數進行詳解:
TOKEN_PRIVILEGES:
TOKEN_PRIVILEGES這個結構,其聲明如下:
typedef struct _TOKEN_PRIVILEGES {
DWORD PrivilegeCount;
LUID_AND_ATTRIBUTES Privileges[];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
PrivilegeCount指的數組元素的個數,接着是一個LUID_AND_ATTRIBUTES類型的數組,再來看一下LUID_AND_ATTRIBUTES這個結構的內容,聲明如下:
typedef struct _LUID_AND_ATTRIBUTES {
LUID Luid;
DWORD Attributes;
} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES
第二個參數就指明瞭我們要進行的操作類型,有三個可選項: SE_PRIVILEGE_ENABLED、SE_PRIVILEGE_ENABLED_BY_DEFAULT、 SE_PRIVILEGE_USED_FOR_ACCESS。要使能一個權限就指定Attributes爲SE_PRIVILEGE_ENABLED。第 一個參數就是指權限的類型,是一個LUID的值,LUID就是指locally unique identifier,我想GUID大家是比較熟悉的,和GUID的要求保證全局唯一不同,LUID只要保證局部唯一,就是指在系統的每一次運行期間保證 是唯一的就可以了。
我們要怎麼樣才能知道一個權限對應的LUID值是多少呢?這就要用到另外一個API函數
LookupPrivilegevalue,其原形如下:
BOOL LookupPrivilegevalue( LPCTSTR lpSystemName, // system name,爲NULL
LPCTSTR lpName, // privilege name
PLUID lpLuid // locally unique identifier,第三個參數就是返回LUID的指針,賦予這個lpLuid一個新的luid );
在Winnt.h中還定義了一些權限名稱的宏,如:
#define SE_BACKUP_NAME TEXT("SeBackupPrivilege") #define SE_RESTORE_NAME TEXT("SeRestorePrivilege")
#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") #define SE_DEBUG_NAME TEXT("SeDebugPrivileg")
OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)還是會遇到“訪問拒絕”的錯誤。什麼原因呢?原來在默認的情況下進程的一些訪問權限是沒有被使能(Enabled)的,所以我們 要做的首先是使能這些權限。與此相關的一些API函數有OpenProcessToken、LookupPrivilegevalue、 AdjustTokenPrivileges。我們要修改一個進程的訪問令牌,首先要獲得進程訪問令牌的句柄,這可以通過
OpenProcessToken 得到,函數的原型如下:
BOOL OpenProcessToken( __in HANDLE ProcessHandle, //要修改訪問權限的進程句柄,爲GetCurrentProcess()即可
__in DWORD DesiredAccess, //指定你要進行的操作類型
__out PHANDLE TokenHandle //返回的訪問令牌指針,即操作目標
);
如果希望獲得所有權限,可以爲TOKEN_ALL_ACCESS
AdjustTokenPrivileges的原型如下:
BOOL AdjustTokenPrivileges( HANDLE TokenHandle, // handle to token
BOOL DisableAllPrivileges, // disabling option,一般爲FALSE
PTOKEN_PRIVILEGES NewState, // privilege information,賦予的新令牌狀態
DWORD BufferLength, // size of buffer
PTOKEN_PRIVILEGES PreviousState, // original state buffer
PDWORD ReturnLength // required buffer size
);