在我们编程实现一些系统操作的时候,往往要求我们执行操作的进程拥有足够的权限方可成功操作。比如,我们使用 ExitWindows 函数实现关机或重启操作的时候,就要求我们的进程要有 SE_SHUTDOWN_NAME 的权限,否则,会忽视不执行操作。这时,我们唯一能够做的,就是按照要求,提升我们进程的权限。
函数介绍
BOOL WINAPI OpenProcessToken ( _In_ HANDLE ProcessHandle, _In_ DWORD DesiredAccess, _Out_ PHANDLE TokenHandle ) ; BOOL WINAPI LookupPrivilegeValue ( _In_opt_ LPCTSTR lpSystemName, _In_ LPCTSTR lpName, _Out_ PLUID lpLuid ) ; 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 ) ;
实现过程
首先,我们需要调用 OpenProcessToken
函数打开指定进程令牌,并获取 TOKEN_ADJUST_PRIVILEGES
权限的令牌句柄。之所以要获取进程令牌权限为 TOKEN_ADJUST_PRIVILEGES
,是因为 AdjustTokenPrivileges
函数,要求要有此权限,方可修改进程令牌的访问权限。
其中,第 1 个参数表示要打开进程令牌的进程句柄;第 2 个参数表示我们对进程令牌具有的权限,TOKEN_ADJUST_PRIVILEGES
就表示,我们有修改进程令牌的权限;第 3 个参数表示返回的进程令牌句柄。
bRet = ::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken); if (FALSE == bRet){ ShowError("OpenProcessToken" ); return FALSE; }
然后,我们调用 LookupPrivilegeValue
函数,获取本地系统指定特权名称的LUID
值,这个LUID
值就相当于该特权的身份标号。
其中,第 1 个参数表示系统,NULL表示本地系统,即要获取本地系统的指定特权的LUID值;第 2 个参数表示特权名称;第 3 个参数表示获取到的LUID返回值。
bRet = ::LookupPrivilegeValue(NULL , pszPrivilegesName, &luidValue); if (FALSE == bRet){ ShowError("LookupPrivilegeValue" ); return FALSE; }
接着,我们就开始对 TOKEN_PRIVILEGES
进程令牌特权结构体进行赋值设置,设置设置新特权的数量、特权对应的LUID值以及特权的属性状态。其中,tokenPrivileges.PrivilegeCount
表示设置新特权的特权数量;tokenPrivileges.Privileges[i].Luid
表示第 i 个特权对应的LUID值;tokenPrivileges.Privileges[0].Attributes
表示特权的属性;SE_PRIVILEGE_ENABLED
就表示启用该特权。
tokenPrivileges.PrivilegeCount = 1 ; tokenPrivileges.Privileges[0 ].Luid = luidValue; tokenPrivileges.Privileges[0 ].Attributes = SE_PRIVILEGE_ENABLED;
最后,我们调用 AdjustTokenPrivileges
函数对进程令牌的特权进行修改,将上面设置好的新特权设置到进程令牌中。
其中,第 1个参数表示进程令牌;第 2 个参数表示能是否禁用所有令牌的权限,FALSE则不禁用;第 3个参数是新设置的特权,指向设置好的令牌特权结构体;第 4 个参数表示返回上一个特权数据缓冲区的大小,不获取,则可以设为 0;第 5 个参数表示返回上一个特权数据缓冲区,不接收返回数据,可以设为 NULL;第 6 个参数表示接收返回上一个特权数据缓冲区应该有的大小。
bRet = ::AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0 , NULL , NULL ); if (FALSE == bRet){ ShowError("AdjustTokenPrivileges" ); return FALSE; }
但是,需要注意的是,AdjustTokenPrivileges
返回 TRUE,并不代表特权就设置成功,还需要使用 GetLastError
来判断错误吗返回值。若错误码返回值为ERROR_SUCCESS
,则所有特权设置成功;若为 ERROR_NOT_ALL_ASSIGNED
,则表示并不是所有特权都设置成功。
dwRet = ::GetLastError(); if (ERROR_SUCCESS == dwRet){ return TRUE; } else if (ERROR_NOT_ALL_ASSIGNED == dwRet){ ShowError("ERROR_NOT_ALL_ASSIGNED" ); return FALSE; }
换句话说,如果你只提升了一个特权,且错误码为ERROR_NOT_ALL_ASSIGNED
,那么这就是说明提升失败了。如果程序运行在 Win7 或者 Win7 以上版本的操作系统,可以试着以管理员身份运行程序,这样就可以成功提升进程令牌的访问权限。
编码实现
BOOL EnbalePrivileges (HANDLE hProcess, char *pszPrivilegesName) { HANDLE hToken = NULL ; LUID luidValue = {0 }; TOKEN_PRIVILEGES tokenPrivileges = {0 }; BOOL bRet = FALSE; DWORD dwRet = 0 ; bRet = ::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken); if (FALSE == bRet) { ShowError("OpenProcessToken" ); return FALSE; } bRet = ::LookupPrivilegeValue(NULL , pszPrivilegesName, &luidValue); if (FALSE == bRet) { ShowError("LookupPrivilegeValue" ); return FALSE; } tokenPrivileges.PrivilegeCount = 1 ; tokenPrivileges.Privileges[0 ].Luid = luidValue; tokenPrivileges.Privileges[0 ].Attributes = SE_PRIVILEGE_ENABLED; bRet = ::AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0 , NULL , NULL ); if (FALSE == bRet) { ShowError("AdjustTokenPrivileges" ); return FALSE; } else { dwRet = ::GetLastError(); if (ERROR_SUCCESS == dwRet) { return TRUE; } else if (ERROR_NOT_ALL_ASSIGNED == dwRet) { ShowError("ERROR_NOT_ALL_ASSIGNED" ); return FALSE; } } return FALSE; }
提权
class CEnablePriv { public: BOOL SetRealTimePriority () ; BOOL EnableShutdownPriv () ; BOOL EnableDebugPriv () ; BOOL EnableBackupPriv () ; BOOL EnableRestorePriv () ; private: }; BOOL CEnablePriv::SetRealTimePriority () { if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) { return false ; } return true ; } BOOL CEnablePriv::EnableShutdownPriv () { HANDLE hToken; LUID sedebugnameValue; TOKEN_PRIVILEGES tkp; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return false ; if (!LookupPrivilegeValue(NULL , SE_SHUTDOWN_NAME, &sedebugnameValue)) { CloseHandle(hToken); return false ; } tkp.PrivilegeCount = 1 ; tkp.Privileges[0 ].Luid = sedebugnameValue; tkp.Privileges[0 ].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL , NULL )) CloseHandle(hToken); return true ; } BOOL CEnablePriv::EnableDebugPriv () { HANDLE hToken; LUID sedebugnameValue; TOKEN_PRIVILEGES tkp; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return false ; if (!LookupPrivilegeValue(NULL , SE_DEBUG_NAME, &sedebugnameValue)) { CloseHandle(hToken); return false ; } tkp.PrivilegeCount = 1 ; tkp.Privileges[0 ].Luid = sedebugnameValue; tkp.Privileges[0 ].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL , NULL )) CloseHandle(hToken); return true ; } BOOL CEnablePriv::EnableBackupPriv () { HANDLE hToken; LUID sedebugnameValue; TOKEN_PRIVILEGES tkp; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return false ; if (!LookupPrivilegeValue(NULL , SE_BACKUP_NAME, &sedebugnameValue)) { CloseHandle(hToken); return false ; } tkp.PrivilegeCount = 1 ; tkp.Privileges[0 ].Luid = sedebugnameValue; tkp.Privileges[0 ].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL , NULL )) CloseHandle(hToken); return true ; } BOOL CEnablePriv::EnableRestorePriv () { HANDLE hToken; LUID sedebugnameValue; TOKEN_PRIVILEGES tkp; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return false ; if (!LookupPrivilegeValue(NULL , SE_RESTORE_NAME, &sedebugnameValue)) { CloseHandle(hToken); return false ; } tkp.PrivilegeCount = 1 ; tkp.Privileges[0 ].Luid = sedebugnameValue; tkp.Privileges[0 ].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL , NULL )) CloseHandle(hToken); return true ; }
调用
CEnablePriv a; if (a.EnableBackupPriv()){ MessageBox(NULL , L"EnableBackupPriv success" , L"" , NULL ); } if (a.EnableDebugPriv()){ MessageBox(NULL , L"EnableDebugPriv success." , L"" , NULL ); } if (a.EnableRestorePriv()){ MessageBox(NULL , L"EnableRestorePriv success ." , L"" , NULL ); } if (a.EnableShutdownPriv()){ MessageBox(NULL , L"EnableShutdownPriv success." , L"" , NULL ); } if (a.SetRealTimePriority()){ MessageBox(NULL , L"SetRealTimePriority success." , L"" , NULL ); }