C++ 實現提升訪問令牌權限


在我們編程實現一些系統操作的時候,往往要求我們執行操作的進程擁有足夠的權限方可成功操作。比如,我們使用 ExitWindows 函數實現關機或重啟操作的時候,就要求我們的進程要有 SE_SHUTDOWN_NAME 的權限,否則,會忽視不執行操作。這時,我們唯一能夠做的,就是按照要求,提升我們進程的權限。

函數介紹

/* 
	打開與進程關聯的訪問令牌。
	如果函數成功,則返回值不為零。
*/ 
    BOOL WINAPI OpenProcessToken(
         _In_  HANDLE  ProcessHandle,			// 打開與進程關聯的訪問令牌。
         _In_  DWORD   DesiredAccess,			// 指定一個訪問掩碼,指定訪問令牌的請求類型。
         _Out_ PHANDLE TokenHandle				// 指向一個句柄的指針,用於標識當函數返回時新打開的訪問令牌。
    );


/*
	查看系統權限的特權值,返回信息到一個LUID結構體里。
	如果函數成功,函數將返回非零值
*/
    BOOL WINAPI LookupPrivilegeValue(
         _In_opt_ LPCTSTR lpSystemName,		// 指向以NULL結尾的字符串的指針,該字符串是指向要獲取特權值的系統名稱
         _In_     LPCTSTR lpName,			// 指向空終止字符串的指針,指定特權的名稱
         _Out_    PLUID   lpLuid			// 指向LUID變量的指針,該變量接收由lpSystemName參數指定的系統上已知權限的LUID。
    );

/*
	啟用或禁用指定的訪問令牌中的權限
	如果函數成功,則返回值不為零
*/
    BOOL WINAPI AdjustTokenPrivileges(
         _In_      HANDLE            TokenHandle,				// 訪問令牌的句柄,其中包含要修改的權限
         _In_      BOOL              DisableAllPrivileges,		// 指定該功能是否禁用所有令牌的權限
         _In_opt_  PTOKEN_PRIVILEGES NewState,					// 指向TOKEN_PRIVILEGES結構的指針,該結構指定特權數組及其屬性
         _In_      DWORD             BufferLength,				// 指定由PreviousState參數指向的緩沖區的大小
         _Out_opt_ PTOKEN_PRIVILEGES PreviousState,				// 接收修改權限的完整列表
         _Out_opt_ PDWORD            ReturnLength				// 接收由PreviousState參數指向的緩沖區所需的大小
    );

實現過程

首先,我們需要調用 OpenProcessToken 函數打開指定進程令牌,並獲取 TOKEN_ADJUST_PRIVILEGES 權限的令牌句柄。之所以要獲取進程令牌權限為 TOKEN_ADJUST_PRIVILEGES,是因為 AdjustTokenPrivileges 函數,要求要有此權限,方可修改進程令牌的訪問權限。

其中,第 1 個參數表示要打開進程令牌的進程句柄;第 2 個參數表示我們對進程令牌具有的權限,TOKEN_ADJUST_PRIVILEGES就表示,我們有修改進程令牌的權限;第 3 個參數表示返回的進程令牌句柄。

    //打開進程令牌並獲取具有 TOKEN_ADJUST_PRIVILEGES 權限的進程令牌句柄
    bRet = ::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);
    if (FALSE == bRet)
    {
        ShowError("OpenProcessToken");
        return FALSE;
    }

然后,我們調用 LookupPrivilegeValue 函數,獲取本地系統指定特權名稱的LUID值,這個LUID值就相當於該特權的身份標號。

其中,第 1 個參數表示系統,NULL表示本地系統,即要獲取本地系統的指定特權的LUID值;第 2 個參數表示特權名稱;第 3 個參數表示獲取到的LUID返回值。

    // 獲取本地系統的 pszPrivilegesName 特權的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;
        }
        // 獲取本地系統的 pszPrivilegesName 特權的LUID值
        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();

	//
	//提升當前進程權限函數("SeShutdownPrivilege"關機權限)
	//
	BOOL EnableShutdownPriv();

	//
	//提升當前進程權限函數("SeDebugPrivilege"讀、寫控制權限)
	//
	BOOL EnableDebugPriv();

	//
	//提升當前進程權限函數("SeBackupPrivilege"注冊表備份權限)
	//
	BOOL EnableBackupPriv();

	//
	//提升當前進程權限函數("SeRestorePrivilege"恢復數據權限)
	//
	BOOL EnableRestorePriv();

private:           //私有(內部使用的接口)

};


//
//設置當前進程優先級為最高(實時)
//
//返回值:“false”是失敗,“true”是成功。
BOOL CEnablePriv::SetRealTimePriority()
{
	if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS))
	{
		return false;
	}

	return true;
}

//
//提升當前進程權限函數("SeShutdownPrivilege"關機權限)
//
//返回值:“false”是失敗,“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;
}

//
//提升當前進程權限函數("SeDebugPrivilege"讀、寫控制權限)
//
//返回值:“false”是失敗,“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;
}

//
//提升當前進程權限函數("SeBackupPrivilege"備份數據權限)
//
//返回值:“false”是失敗,“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;
}

//
//提升當前進程權限函數("SeRestorePrivilege"恢復數據權限)
//
//返回值:“false”是失敗,“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);
		}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM