1 實例
GetCurrentProcess獲取當前進程的句柄灿巧,OpenProcessToken函數(shù)用來打開與進程相關聯(lián)的訪問令牌,LookupPrivilegeValueW查看系統(tǒng)權限的特權值,返回信息到一個LUID結構體里(第三個參數(shù))。NewState是一個TOKEN_PRIVILEGES結構體:
typedef struct _TOKEN_PRIVILEGES
{
ULONG PrivilegeCount; //數(shù)組元素的個數(shù)
LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; //數(shù)組.類型為LUID_AND_ATTRIBUTES
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
Attributes=2葵诈,即SE_PRIVILEGE_ENABLED時將打開Luid對應的特權锻狗,而禁用特權是設置Attributes=0。設置完成后狰住,我們需要調(diào)用AdjustTokenPrivileges函數(shù)通知操作系統(tǒng)將指定的access token權限中的特權置為打開狀態(tài)
2 原理
來源:http://blog.csdn.net/zacklin/article/details/7663129
windows的每個用戶登錄系統(tǒng)后张吉,系統(tǒng)會產(chǎn)生一個訪問令牌(access token),其中關聯(lián)了當前用戶的權限信息催植,用戶登錄后創(chuàng)建的每一個進程都含有用戶access token的拷貝肮蛹,當進程試圖執(zhí)行某些需要特殊權限的操作或是訪問受保護的內(nèi)核對象時,系統(tǒng)會檢查其acess token中的權限信息以決定是否授權操作创南。Administrator組成員的access token中會含有一些可以執(zhí)行系統(tǒng)級操作的特權(privileges)伦忠,如終止任意進程、關閉/重啟系統(tǒng)稿辙、加載設備驅動和更改系統(tǒng)時間等(這里的特權和UAC中的不一樣昆码,UAC主要是讀寫一些敏感的文件等,安裝程序等,這些是管理員權限赋咽,繞過UAC主要是不彈出那個提示框旧噪;這里的這些特權即使是管理員權限也需要調(diào)用代碼獲取(或者叫開啟),像一些注入里脓匿,經(jīng)常會用到這些特權提升代碼)淘钟,不過這些特權默認是被禁用的,當Administrator組成員創(chuàng)建的進程中包含一些需要特權的操作時陪毡,進程必須首先打開這些禁用的特權以提升自己的權限米母,否則系統(tǒng)將拒絕進程的操作。注意毡琉,(貌似win7以后)非Administrator組成員創(chuàng)建的進程無法提升自身的權限铁瞒,因此下面提到的進程均指Administrator組成員創(chuàng)建的進程。
Windows以字符串的形式表示系統(tǒng)特權绊起,如“SeCreatePagefilePrivilege”表示該特權用于創(chuàng)建頁面文件精拟,“SeDebugPrivilege”表示該特權可用于調(diào)試及更改其它進程的內(nèi)存,為了便于在代碼中引用這些字符串虱歪,微軟在winnt.h中定義了一組宏蜂绎,如 #define SE_DEBUG_NAME TEXT("SeDebugPrivilege")。完整的特權列表可以查閱msdn的security一章笋鄙。
下列只是一部分师枣,完整的:https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx; https://msdn.microsoft.com/en-us/library/windows/desktop/aa375728(v=vs.85).aspx#privilege_constants
SeAssignPrimaryTokenPrivilege ? ? 替換經(jīng)常級令牌
SeBackupPrivilege? ? ? ? ? ? ? ? ? 備份文件和目錄
SeDebugPrivilege? ? ? ? ? ? ? ? ? ? 調(diào)試程序
SeIncreaseQuotaPrivilege? ? ? ? ? 調(diào)整進程的內(nèi)存配額
SeTcbPrivilege? ? ? ? ? ? ? ? ? ? ? 作為操作系統(tǒng)的一部分
? ? ? ? ? ?
雖然Windows使用字符串表示特權萧落,但查詢或更改特權的API需要LUID來引用相應的特權践美,LUID表示local unique identifier,它是一個64位值找岖,在當前系統(tǒng)中是唯一的陨倡。為了提升進程權限到指定的特權,我們必須先找到該特權對應的LUID许布,這時要調(diào)用LookupPrivilegeValue函數(shù)兴革。
獲得特權對應的LUID之后,我們要打開該特權蜜唾。此時要用到LUID_AND_ATTRIBUTES結構杂曲,其定義如下:
typedef struct _LUID_AND_ATTRIBUTES {
LUID Luid;
DWORD Attributes;
} LUID_AND_ATTRIBUTES, * PLUID_AND_ATTRIBUTES;
Attributes取SE_PRIVILEGE_ENABLED時將打開Luid對應的特權。設置完成后袁余,我們需要調(diào)用AdjustTokenPrivileges函數(shù)通知操作系統(tǒng)將指定的access token權限中的特權置為打開狀態(tài)擎勘,前面我們說過,進程執(zhí)行需要特列權限的操作時系統(tǒng)將檢查其access token颖榜,因此更改了進程的access token特權設置棚饵,也就是更改了所屬進程的特權設置煤裙。AdjustTokenPrivileges函數(shù)的原型如下:
BOOL WINAPI AdjustTokenPrivileges(
__in? ? ? ? ? HANDLE TokenHandle,
__in? ? ? ? ? BOOL DisableAllPrivileges,
__in_opt? ? ? PTOKEN_PRIVILEGES NewState,
__in? ? ? ? ? DWORD BufferLength,
__out_opt? ? PTOKEN_PRIVILEGES PreviousState,
__out_opt? ? PDWORD ReturnLength
);
TokenHandle是要更改特權設置的acess token的句柄,DisableAllPrivileges表示是否禁用該access token的所有特權蟹地,NewState用來傳遞要新的特權設置积暖,注意它的類型是PTOKEN_PRIVILEGES,PTOKEN_PRIVILEGES是TOKEN_PRIVILEGES結構的指針怪与,定義如下:
typedef struct _TOKEN_PRIVILEGES {
DWORD PrivilegeCount;
LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
其中ANYSIZE_ARRAY被定義為1,可以看到TOKEN_PRIVILEGES中包含了用于設置特權信息的LUID_AND_ATTRIBUTES結構缅疟,在使用時分别,只需要將PrivilegeCount賦為1,然后把Privileges數(shù)組的第1個元素(Privileges[0])的Luid域設置為指定特權的Luid存淫,再將其Attributes域設置為SE_PRIVILEGE_ENABLED耘斩,就可以完成TokenHandle表示的access token權限的提升了。
下面是一個實際的例子桅咆,用來將執(zhí)行promoteProcessPrivilege的當前進程的指定特權打開括授,函數(shù)參數(shù)為指定的特權名,可以傳遞其宏定義岩饼,也可以是完整的字符串表示:
BOOL promoteProcessPrivileges(const TCHAR* newPrivileges)
{
HANDLE tokenHandle;
//獲得當前進程的access token句柄
if(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle) == FALSE)
return FALSE;
TOKEN_PRIVILEGES structTkp;
//查找newPrivileges參數(shù)對應的Luid荚虚,并將結果寫入structTkp.Privileges[0]的Luid域中
if(::LookupPrivilegeValue(NULL, newPrivileges, &structTkp.Privileges[0].Luid) == FALSE){
CloseHandle(tokenHandle);
return FASLE;
}
//設置structTkp結構
structTkp.PrivilegeCount = 1;
structTkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//通知操作系統(tǒng)更改權限
if(::AdjustTokenPrivileges(tokenHandle, FALSE, &structTkp, sizeof(structTkp), NULL, NULL) == FALSE){
CloseHandle(tokenHandle);
return FALSE;
}
CloseHandle(tokenHandle);
return TRUE;
}
我們來用一個簡單的例子驗證promoteProcessPrivileges函數(shù)。下面的traceSystemProcess用于遍歷當前系統(tǒng)進程籍茧,如果調(diào)用traceSystemProcess函數(shù)的進程以默認權限運行版述,對于如csrss.exe之類的進程,函數(shù)將沒有足夠的權限獲得其模塊名寞冯。如果在traceSystemProcess之前調(diào)用了promoteProcessPrivileges將進程權限提升至SE_DEBUG_NAME級別渴析,traceSystemProcess函數(shù)將能正確打印出如csrss.exe等關鍵進程的路徑:
BOOL traceSystemProcess()
{
PROCESSENTRY32 processEntry;
processEntry.dwSize = sizeof(processEntry);
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hProcessSnap == INVALID_HANDLE_VALUE){
_tprintf(_T("CreateToolhelp32Snapshot 調(diào)用失敗!/n"));
return FALSE;
}
BOOL bMore = ::Process32First(hProcessSnap, &processEntry);
while(bMore){
_tprintf(_T("進程名稱:%s /n"), processEntry.szExeFile);
_tprintf(_T("進程ID號:%u /n"), processEntry.th32ProcessID);
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, processEntry.th32ProcessID);
if(hProcess != NULL){
TCHAR szBuffer[MAX_PATH] = {_T('/0')};
if(::GetModuleFileNameEx(hProcess, NULL, szBuffer, MAX_PATH)){
_tprintf(_T("進程路徑:%s /n"), szBuffer);
}
::CloseHandle(hProcess);
}
_tprintf(_T("/n"));
bMore = ::Process32Next(hProcessSnap,&processEntry);
}
::CloseHandle(hProcessSnap);
return TRUE;
}
測試結果不再列出,有興趣的朋友可以自己試一試吮龄。