1、OpenProcessToken函数
打开与进程关联的访问令牌
https://docs.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken
2、LookupPrivilegeValue函数
查看系统权限的特权值,返回信息到一个LUID结构体里
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupprivilegevaluea
3、AdjustTokenPrivileges函数
启用或禁用指定访问令牌中的权限。在访问令牌中启用或禁用权限时需要TOKEN_ADJUST_PRIVILEGES访问
https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokenprivileges
访问控制模型:https://docs.microsoft.com/zh-cn/windows/win32/secauthz/authorization-portal
进程访问令牌权限提升的实现步骤较为固定。要想提升访问令牌权限,首先要获取进程的访问令牌,然后将访问令牌的权限修改为指定权限,但是系统内部并不直接识别权限名称,而是识别LUID值,所以需要根据权限名称获取对应的LUID值,实现进程访问令牌权限的修改。
具体实现步骤如下所示.
首先,程序需要调用OpenProcessToken函数打开指定的进程令牌,并获取TOKEN_ADJUST_PRIVILEGES权限的令牌句柄。之所以要指定进程令牌权限为TOKEN_ADJUST_PRIVILEGES,是因为AdjustTokenPrivileges函数要求有此权限,方可修改进程令牌的访问权限。
//打开进程令牌并获取具有TOKEN_ADJUST_PRIVILEGES权限的进程令牌句柄 OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES,&hToken)l;
其中,第一个参数表示要打开的进程令牌的进程句柄;第二个参数表示程序对进程令牌具有的权限,TOKEN_ADJUST_PRIVILEGES表示具有修改进程令牌的权限;第三个参数表示返回的进程令牌句柄。
再接着调用LookupPrivilegeValue函数,获取本地系统指定特权名称的LUID值,这个LUID值相当于该特权的身份标识号。
//获取本地系统的pszPrivilegesName特权的LUID值 LookupPrivilegeValue(NULL,pszPrivilegesName,&luidValue);
其中,第一个参数表示系统,NULL表示本地系统;第二个参数表示特权名称;第三个参数表示获取到的LUID返回值。
接着,程序就开始对进程令牌特权结构体TOKEN_PRIVILEGES进行赋值,设置新特权的数量、特权对应的LUID值以及特权的属性状态。
//设置提升权限信息 tokenPrivileges.PrivilegeCount = 1; tokenPrivileges.Privileges[0].Luid = luidValue; tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
其中,PrivilegeCount表示设置新特权的数量;Privileges[0].Luid表示第一个特权对应的LUID值;Privileges[0].Attributes表示第一个特权的属性,SE_PRIVILEGE_ENABLED表示启动该特权。
最后,程序调用AdjustTokenPrivileges函数对进程令牌的特权进行修改,将上面设置好的新特权设置到进程令牌中,这样就完成了进程访问令牌的修改工作。
//修改进程令牌访问权限 AdjustTokenPrivileges(hToken,FALSE,&tokenPrivileges,0,NULL,NULL);
其中,第一个参数表示进程令牌;第二个参数表示是否禁用所有令牌的权限,FALSE表示不禁用;第三个参数是新设置的特权,指向设置好的令牌特权结构体;第四个参数表示返回上一个特权数据缓冲区的大小,若不获取,则可以设为零;第五个参数表示返回上一个特权数据缓冲区,若不接收返回数据,可以设为NULL;第六个参数表示返回上一个特权数据缓冲区应该有的大小。
AdjustTokenPrivileges.h
#ifndef _ADJUST_TOKEN_PRIVILEGES_H_ #define _ADJUST_TOKEN_PRIVILEGES_H_ #include <stdio.h> #include <tchar.h> #include <Windows.h> BOOL EnbalePrivileges(HANDLE hProcess, char* pszPrivilegesName); #endif
AdjustTokenPrivileges_Test.cpp
// AdjustTokenPrivileges_Test.cpp : 定义控制台应用程序的入口点。 // #include "AdjustTokenPrivileges.h" int _tmain(int argc, _TCHAR* argv[]) { // 修改当前进程令牌访问权限 if (FALSE == EnbalePrivileges(GetCurrentProcess(), SE_DEBUG_NAME)) { printf("Enable Privileges Error!\n"); } printf("Enable Privileges OK!\n"); system("pause"); return 0; }
AdjustTokenPrivilegesTest.cpp
#include "AdjustTokenPrivileges.h" void ShowError(char* pszText) { char szErr[MAX_PATH] = { 0 }; ::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError()); ::MessageBox(NULL, szErr, "ERROR", MB_OK); } BOOL EnbalePrivileges(HANDLE hProcess, char* pszPrivilegesName) { HANDLE hToken = NULL; LUID luidValue = { 0 }; TOKEN_PRIVILEGES tokenPrivileges = { 0 }; BOOL bRet = FALSE; DWORD dwRet = 0; // 打开进程令牌并获取具有 TOKEN_ADJUST_PRIVILEGES 权限的进程令牌句柄 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; }
以管理员身份运行程序
如果再程序中只提升一个访问令牌特权,且错误码为ERROR_NOT_ALL_ASSIGNED,则提升失败。如果程序运行再Windows 7或者以上版本的操作系统,可以尝试以管理员身份运行程序,然后在进行测试