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;
}

Windows下提升进程权限(转)的更多相关文章

  1. Windows下提升进程权限

    windows的每个用户登录系统后,系统会产生一个访问令牌(access token) ,其中关联了当前用户的权限信息,用户登录后创建的每一个进程都含有用户access token的拷贝,当进程试图执 ...

  2. Windows下使用Xshell建立反向隧道

    反向隧道是一个进行内网穿透的简单而有用的方法.在Linux下通过OpenSSH和AutoSSH可以很容易地建立稳定的反向隧道.但是在Windows下,还能看到有人特意装个Cygwin来运行这些工具…… ...

  3. redis windows下使用及redis命令

    出自:http://www.cnblogs.com/chenping-987123/archive/2012/01/29/2331079.html Redis 是一个开源,高级的键值对的存储.它经常作 ...

  4. Windows下干活儿辅助软件

    桌面下高速文件搜索软件:Listary Pro(收费)和Everything(开源免费),Everything推荐Beta版,明显比老旧的稳定版好用. 桌面太乱,可以试试Fences(收费). 需要文 ...

  5. 提升进程权限为DEBUG权限

    在网上也看到了一些提升进程令牌的函数但都不怎么好用,最后我还是从一个黑客后门程序的源代码中提取出了一个好的提升进程令牌的函数,不敢独享,跟大家分享下.那个后门真的写的很好... Hysia提示你: 这 ...

  6. Qt Windows下链接子系统与入口函数(终结版)(可同时存在main和WinMain函数)

    Qt Windows下链接子系统与入口函数(终结版) 转载自:http://blog.csdn.net/dbzhang800/article/details/6358996 能力所限,本讨论仅局限于M ...

  7. 【1】windows下IOS开发基础环境搭建

    一.目的 本文的目的是windows下IOS开发基础环境搭建做了对应的介绍,大家可根据文档步骤进行mac环境部署: 二.安装虚拟机 下载虚拟机安装文件绿色版,点击如下文件安装 获取安装包:       ...

  8. Windows下使用MakeFile(Mingw)文件

    下面是我基于<C++GUI QT4编程(第二版)> 2.3节快速设计对话框编写例子地址: https://files.cnblogs.com/files/senior-engineer/g ...

  9. PythonQt在windows下的编译

    笔者最近在做Qt方面的开发工作,然后需要用到脚本程序对程序内部进行扩展,就很自然的想到了Python,度娘一下发现了一款神器,也就是今天给大家介绍的主角:PythonQt 今天首先给大家介绍下Pyth ...

随机推荐

  1. Exception Handling in ASP.NET Web API

    public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErr ...

  2. 如风一样,飞翔------Day37

    我一直都觉得自己是个反应没有那么敏锐的人,而不幸的是其实也是,所以,在菜鸟的头衔上,我不得不再背负上一个笨鸟的"光芒".我不苛求一飞冲天的传奇,却也有着不甘寂寞的激昂,我选择先飞, ...

  3. sqlserver 死锁查看辅助存储过程

    USE [master] GO /****** Object: StoredProcedure [dbo].[sp_who_lock] Script Date: 03/23/2016 14:17:49 ...

  4. 改良版的SQL Service 通用存储过程分页

    上次写了通用存储过程.感觉还是有很大的BUG.就是条件不能参数画化.这个BUG可以说是致命的.但是我一直想在用什么方法能解决这个东西.其实我只是想写少量的代码来做更多的事情.我想能不能传集合给存储过程 ...

  5. vs2010打开设计器出现错误

    vs2010打开设计器出现此界面,  错误多种,还有“未将对象引用设置到对象的实例”  ,我项目用到了第三方控件(没有安装,bin文件夹导入DLL文件,项目直接引用的DLL文件),看下面的堆栈信息,显 ...

  6. iOS极光推送的基本使用

    昨天花了一下午的时间研究了下极光推送,也前也是没做过,不知道从何下手!才开始的时候一看官方的SDK感觉好难,不过经过一系列的捣鼓之后,手机收到了推送信息,感觉其实并没有那么难! 1.配置开发证书(得有 ...

  7. navicat查看mysql数据表记录数不断变化

    在使用navicat进行数据库管理的时候,在查看表对象的时候会发现,每次刷新,数据表的记录数不断变化,尤其是大表. 对于100万的数据经常会显示九十几万,当然通过count(*)出来的数据是正确的. ...

  8. JQuery easyui (3) Resizable(调整大小)组件

    Resizable  动态调整元素大小  不依赖其他组件 Resizable的加载方法 <div class="easyui-resizable"></div&g ...

  9. (转载) css实现小三角(尖角)

    在各种网站里面,我们会经常看到类似于这样的尖角:(示例:新浪微博) 它实现的方式有多种,哪种才是最简单的?哪种才是最优秀的?首先我声明一下,我还不清楚这个东西具体叫什么名字(哪位知道还望告知),暂且叫 ...

  10. this的用法this.name=name 这个什么意思

    public Employee(string name, string alias){ // Use this to qualify the fields, name and alias: this. ...