博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows下提升进程权限(转)
阅读量:5976 次
发布时间:2019-06-20

本文共 6017 字,大约阅读时间需要 20 分钟。

from: http://www.oschina.net/code/snippet_222150_19533

 

windows的每个用户登录系统后,系统会产生一个访问令牌(access token) ,其中关联了当前用户的权限信息,用户登录后创建的每一个进程都含有用户access token的拷贝,当进程试图执行某些需要特殊权限的操作或是访问受保护的内核对象时,系统会检查其acess token中的权限信息以决定是否授权操作。Administrator组成员的access token中会含有一些可以执行系统级操作的特权(privileges) ,如终止任意进程、关闭/重启系统、加载设备驱动和更改系统时间等,不过这些特权默认是被禁用的,当Administrator组成员创建的进程中包含一 些需要特权的操作时,进程必须首先打开这些禁用的特权以提升自己的权限,否则系统将拒绝进程的操作。注意,非Administrator组成员创建的进程 无法提升自身的权限,因此下面提到的进程均指Administrator组成员创建的进程。

Windows以字符串的形式表示系统特权,如“SeCreatePagefilePrivilege”表示该特权用于创建页面文 件,“SeDebugPrivilege”表示该特权可用于调试及更改其它进程的内存,为了便于在代码中引用这些字符串,微软在winnt.h中定义了一 组宏,如 #define SE_DEBUG_NAME TEXT("SeDebugPrivilege")。完整的特权列表可以查阅msdn的security一章。虽然Windows使用字符串表示特权,但 查询或更改特权的API需要LUID来引用相应的特权,LUID表示local unique identifier,它是一个64位值,在当前系统中是唯一的。为了提升进程权限到指定的特权,我们必须先找到该特权对应的LUID,这时要调用 LookupPrivilegeValue函数。

获得特权对应的LUID之后,我们要打开该特权。此时要用到LUID_AND_ATTRIBUTES结构,其定义如下:

typedef struct _LUID_AND_ATTRIBUTES {    LUID Luid;    DWORD Attributes;} LUID_AND_ATTRIBUTES, * PLUID_AND_ATTRIBUTES;

Attributes取SE_PRIVILEGE_ENABLED时将打开Luid对应的特权。设置完成后,我们需要调用 AdjustTokenPrivileges函数通知操作系统将指定的access token权限中的特权置为打开状态,前面我们说过,进程执行需要特列权限的操作时系统将检查其access token,因此更改了进程的access token特权设置,也就是更改了所属进程的特权设置。AdjustTokenPrivileges函数的原型如下:

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数组的第1个元素 (Privileges[0])的Luid域设置为指定特权的Luid,再将其Attributes域设置为SE_PRIVILEGE_ENABLED, 就可以完成TokenHandle表示的access token权限的提升了。

下面是一个实际的例子,用来将执行promoteProcessPrivilege的当前进程的指定特权打开,函数参数为指定的特权名,可以传递其宏定义,也可以是完整的字符串表示:

BOOL promoteProcessPrivileges(const TCHAR* newPrivileges){	HANDLE tokenHandle;	//获得当前进程的access token句柄	if(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle) == FALSE)		return FALSE;	TOKEN_PRIVILEGES structTkp;	//查找newPrivileges参数对应的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;	//通知操作系统更改权限	if(::AdjustTokenPrivileges(tokenHandle, FALSE, &structTkp, sizeof(structTkp), NULL, NULL) == FALSE){		CloseHandle(tokenHandle);		return FALSE;	}	CloseHandle(tokenHandle);		return TRUE;}

我们来用一个简单的例子验证promoteProcessPrivileges函数。下面的traceSystemProcess用于遍历当前系统进程, 如果调用traceSystemProcess函数的进程以默认权限运行,对于如csrss.exe之类的进程,函数将没有足够的权限获得其模块名。如果 在traceSystemProcess之前调用了promoteProcessPrivileges将进程权限提升至SE_DEBUG_NAME级 别,traceSystemProcess函数将能正确打印出如csrss.exe等关键进程的路径:

BOOL traceSystemProcess(){	PROCESSENTRY32 processEntry;	processEntry.dwSize = sizeof(processEntry);	HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);	if(hProcessSnap == INVALID_HANDLE_VALUE){		_tprintf(_T("CreateToolhelp32Snapshot 调用失败!/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;}
 
标签: <无>
 

代码片段(2)

1. [代码][C/C++]代码     

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
BOOL
promoteProcessPrivileges(
const
TCHAR
* newPrivileges)
{
    
HANDLE
tokenHandle;
    
//获得当前进程的access token句柄
    
if
(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle) == FALSE)
        
return
FALSE;
    
TOKEN_PRIVILEGES structTkp;
    
//查找newPrivileges参数对应的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;
    
//通知操作系统更改权限
    
if
(::AdjustTokenPrivileges(tokenHandle, FALSE, &structTkp,
sizeof
(structTkp), NULL, NULL) == FALSE){
        
CloseHandle(tokenHandle);
        
return
FALSE;
    
}
    
CloseHandle(tokenHandle);  
    
return
TRUE;
}

2. [代码][C/C++]代码     

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
BOOL
traceSystemProcess()
{
    
PROCESSENTRY32 processEntry;
    
processEntry.dwSize =
sizeof
(processEntry);
 
    
HANDLE
hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    
if
(hProcessSnap == INVALID_HANDLE_VALUE){
        
_tprintf(_T(
"CreateToolhelp32Snapshot 调用失败!/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;
}

转载于:https://www.cnblogs.com/wanxianga/p/5395987.html

你可能感兴趣的文章
【第一期】网站打开错误问题解决方法集合
查看>>
j2ee开发防范URL攻击是个重要话题
查看>>
RSync实现文件备份同步
查看>>
如何判断一个服务是否正在运行
查看>>
精品软件 推荐 相当优秀的轻量级文本编辑器 Notepad2
查看>>
Lync 2013快速入门手册之三:组织Lync会议
查看>>
SQL SERVER 2008 表与约束的创建维护
查看>>
我的友情链接
查看>>
zabbix企业应用之监控mysql 5.6版本
查看>>
我的友情链接
查看>>
BGP选路原则与专有命令的研究
查看>>
关于java的引用、C++的指针、引用的深入分析
查看>>
CMD 修改Host文件 BAT
查看>>
linux用户管理的命令及手动添加用户
查看>>
Windows 7 家庭版如何启用Administrator账户
查看>>
我的友情链接
查看>>
mfs权威指南
查看>>
只是你没那么重要罢了
查看>>
javabean的初步认识学习
查看>>
GTK 安装步骤
查看>>