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. iOS 性能测试 - FBMemoryProfiler

    FBMemoryProfiler 是Facebook开源的一款用于分析iOS内存使用和检测循环引用的工具库. 脑补:http://www.cocoachina.com/ios/20160421/159 ...

  2. C# NameValueCollection集合 .

    案例: NameValueCollection nameValueCollection = Request.Params;//获得连接地址中的所有参数 //获取各个参数,eg:            ...

  3. Android Handler Leak

    转自:Android中使用Handler引发的内存泄露 在Activity中,经常会用到自定义的Handler来处理主线程收到的Message,但是ADT20以后,直接定义的如下定义的内部会有提示说这 ...

  4. IsPostBack是什么意思,如何运用?

    IsPostBack是Page类的一个属性,返回值为一个布尔值.一般放在Page_Load事件中.当页面是第一次打开时其值为False,若当前页面为一个提交后的页面其值为True. if (!IsPo ...

  5. oracle丢失temp表空间处理

    之前有做临时表空间的切换,切换后没drop tablespace就删除了temp01.dbf结果排序跟查dba_temp_files报错 SQL Mbytes from dba_temp_files; ...

  6. Csharp递归和循环实现折半查找

    static bool whilehalf(int n) { ; //低位 ; //高位 ; while(low <= hight) { if(n> arr[c]) { low = c + ...

  7. gtest的Linux使用(Google test)

    GTest是Google开发的跨平台而且开源的C++单元测试框架,很好很强大. 下载地址:https://code.google.com/p/googletest/ . 关于GTest在Windows ...

  8. Programming C#.Inheritance and Polymorphism

    继承 C#中,创建派生类要在派生类的名字后面加上冒号,后面再跟上基类的名字: public class ListBox : Control 提示:C++程序员注意了,C#没有私有或者保护继承 多态 继 ...

  9. QF——OC内存管理详解

    堆的内存管理: 我们所说的内存管理,其实就是堆的内存管理.因为栈的内存会自动回收,堆的内存需要我们手动回收. 栈中一般存储的是基本数据类型变量和指向对象的指针(对象的引用),而真实的对象存储在堆中.因 ...

  10. Android 树形菜单

    首先来一张萌萌哒的效果图(比较懒 - -) 然后是代码: // Node package com.example.treeview.utils; import java.util.ArrayList; ...