函式功能
OpenProcessToken函式用來打開與進程相關聯的訪問令牌。
簡介
要對一個任意進程(包括系統安全進程和服務進程)進行指定了寫相關的訪問權的
OpenProcess操作,只要當前進程具有SeDeDebug許可權就可以了。要是一個用戶是Administrator或是被給予了相應的許可權,就可以具有該許可權。可是,就算我們用Administrator帳號對一個系統安全進程執行OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)還是會遇到“訪問拒絕”的錯誤。什麼原因呢?原來在默認的情況下進程的一些訪問許可權是沒有被啟用(Enabled)的,所以我們要做的首先是啟用這些許可權。與此相關的一些
API函式有OpenProcessToken、
LookupPrivilegevalue、
AdjustTokenPrivileges。我們要修改一個進程的訪問令牌,首先要獲得進程訪問令牌的句柄,這可以通過OpenProcessToken得到,函式的原型如下:
BOOL OpenProcessToken(
__in HANDLE ProcessHandle, //要修改訪問許可權的進程句柄
__in DWORD DesiredAccess, //指定你要進行的操作類型
__out PHANDLE TokenHandle //返回的訪問令牌
指針);
第一參數是要修改訪問許可權的進程句柄;第三個參數就是返回的訪問令牌指針;第二個參數指定你要進行的操作類型,如要修改訪問令牌的特權,我們要指定第二個參數為TOKEN_ADJUST_PRIVILEGES = &H20(其它一些參數可參考Platform SDK)。通過這個函式我們就可以得到當前進程的訪問令牌的句柄(指定函式的第一個參數為
GetCurrentProcess()就可以了)。接著我們可以調用
AdjustTokenPrivileges對這個訪問令牌進行修改。AdjustTokenPrivileges的原型如下:
BOOL AdjustTokenPrivileges(
HANDLE TokenHandle, // handle to token
BOOL DisableAllPrivileges, // disabling option
PTOKEN_PRIVILEGES NewState, // privilege information
DWORD BufferLength, // size of buffer
PTOKEN_PRIVILEGES PreviousState, // original state buffer
PDWORD ReturnLength // required buffer size
);
第一個參數是訪問令牌的句柄;第二個參數決定是進行許可權修改還是喪失(
Disable)所有許可權;第三個參數指明要修改的許可權,是一個指向
TOKEN_PRIVILEGES結構的指針,該結構包含一個
數組,數據組的每個項指明了許可權的類型和要進行的操作; 第四個參數是結構
PreviousState 指針所指向的緩衝區的大小,如果
PreviousState參數為空,該參數應為NULL;第五個參數也是一個指向TOKEN_PRIVILEGES結構的指針,存放修改前的訪問許可權的信息,可空;最後一個參數為實際PRIVILEGES NewState結構返回的大小。在使用這個函式前再看一下
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只要保證局部唯一,就是指在系統的每一次運行期間保證是唯一的就可以了。另外和GUID相同的一點,LUID也是一個64位的值,相信大家都看過GUID那一大串的值,我們要怎么樣才能知道一個許可權對應的LUID值是多少呢?這就要用到另外一個
API函式LookupPrivilegevalue,其原形如下:
BOOL LookupPrivilegevalue(
LPCTSTR lpSystemName, // system name
LPCTSTR lpName, // privilege name
PLUID lpLuid // locally unique identifier
);
第一個參數是系統的名稱,如果是本地系統只要指明為NULL就可以了,第三個參數就是返回LUID的
指針,第二個參數就是指明了許可權的名稱,如“SeDebugPrivilege”。在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("SeDebugPrivilege")
這樣通過這三個函式的調用,我們就可以用
OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)來打獲得任意進程的句柄,並且指定了所有的訪問權
BOOL InitiateSystemShutdown(lpszMachineName,lpszMessage,dwTimeout,fForce App
sClosed,fReboot)
參數:lpszMachineName
指定以NULL終止的用來指定要關機的網路名稱的字元串。如果lpszMachineName為NULL,
或指向一個空串,則該函式關掉本地計算機。
LpszMessage
指向一個以NULL終止的指定要顯示在關機對話框中的訊息的字元串。如果不需要訊息,
該參數可以為NULL。
DwTimeout
指定對話框應該顯示的時間(按秒計)。在此對話框顯示期間,可通過調用AbortSyste
mShutdown函式將關機停止。
話框。該對話框顯示調用此函式的用戶名,顯示由lpszMessage參數指定的訊息,並提示
用戶退出系統。當對話框被創建時發出嘟嘟聲,並保持位於系統中其它視窗的上面。此
對話框可以被移動,但不能被關閉。定時器倒記在強制關機之前剩餘的時間。如果用戶
退出系統,系統立即關閉。否則,當定時器到時間計算機才關機。
如果DwTimeout為零時,計算機關機,但不顯示此對話框,並且不能用AbortSystem
Shutdown函式來停止關機。
fForce AppsClosed
指定對變化未做保存的應用程式是否被強制關閉。如果這個參數為TRUE,則這樣的
應用程式被關閉。如果這個參數為FALSE,則顯示一個對話框以提示用戶關閉這些套用程
序。
FReboot
指定計算機關機之後是否立即重啟。如果這個參數為TRUE,則計算機重啟。如果這
個參數為FALSE,則系統將所有高速快取刷新到磁碟上,清除螢幕,並且顯示一條訊息,
指示關掉電源是安全的。
返回值:如果函式成功,則返回值為TRUE;否則,返回值為FALSE。要獲得擴展錯誤信息
注釋:要關掉本地計算機,調用進程必須具有SE_SHUTDOWN_NAME特權。要關掉一台遠程
計算機,調用進程必須對此遠程計算機具有的SE_REMOTE_SHUTDOWN_NAME特權。預設情況
下,用戶具有對他們所有登錄計算機的SE_SHUTDOWN_NAME特權,管理員具有對遠程計算
機的SE_REMOTE_SHUTDOWN_NAME特權。
根據上面的內容,可獲得如下的套用:
BOOL fResult;
HANDLE hToken;
if (!OpenProcessToken(
GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hToken))
{
MessageBox("OpenProcessToken failed!"); //獲得進程句柄失敗
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
{
MessageBox("AdjustTokenPrivileges enable failed!"); //修改許可權失敗
}
NULL, // 要關的計算機用戶名
"由於系統不穩定,WINDOWS將在上面的時間內關機,請做好保存工作!", // 顯示訊息
0, // 關機所需的時間
FALSE, // 是否提示用戶
FALSE); //設為TRUE為重起,設為FALSE為關機