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;
}
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;
}
 
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下tomcat进程监控批处理程序

    在Windows下tomcat进程监控批处理程序脚本如下: @echo off ::tomcat安装目录 set _tomcatDir=E:\myFiles\apache-tomcat-8.5.31 ...

  2. Windows下查看进程及结束进程命令[转]

    Windows下查看进程及结束进程命令 1)查看占用8080端口的进程号 >netstat –aon | findstr “8080” 结果:TCP    0.0.0.0:8080        ...

  3. 拆分字符串,GetHtmlByWebBrowser,UnicodeToMBCS,提升进程权限

    1. // 根据字符串,拆分字符串,相当于vb中的split函数 function SplitString(const Source, ch: string): TStringList; var te ...

  4. windows下查看进程及结束进程命令

    windows下查看进程及结束进程命令 1)查看占用8080端口的进程号 >netstat –aon | findstr “8080” 结果:TCP    0.0.0.0:8080        ...

  5. windows下根据进程ID强制杀死进程

    [windows 进程ID PID]NTSD命令详解 1. ntsd -c q -p PID 2. ntsd -c q -pn ImageName 比如:ntsd -c q -pn qq.exe -c ...

  6. WINDOWS下kill进程的命令

    相信大家都有用命令行(CMD)解决问题的习惯,起码我感觉自己在处理Windows系统故障时越来越离不开Windows PE了,今天我想介绍两个很实用的命令:Tasklist与Tskill.命令:Tas ...

  7. [转]Windows 下的进程间通讯及数据共享

    http://blog.codingnow.com/2005/10/interprocess_communications.html Windows 下有很多方法实现进程间通讯,比如用 socket, ...

  8. 获取Windows下某进程监听的TCP/UDP端口

    1.在Windows下用CMD netstat命令可以获得当前进程监听端口号的信息,如netstat -ano可以看到IP.port.状态和监听的PID. 那么可以执行CMD这个进程得到监听的端口号信 ...

  9. Linux和Windows下的进程管理总结

    在Windows和Linux下都可以很方便地列出当前运行的进程.Windows下可以使用组合键CTRL+ALT+DEL打开任务管理器,在进程选项卡中就列举出了当前运行的所有进程,除此之外还可以在命令行 ...

随机推荐

  1. .net获取IP和MAC地址

    获取IP  解决request.UserHostAddress取不到真实IP private string GetClientIP()   {    string result = HttpConte ...

  2. Python.Scrapy.12-scrapy-source-code-analysis-part-2

    Scrapy 源代码分析系列-2 signals, signalmanager, project, conf 1. 模块: signals.py signalmanager.py project.py ...

  3. 11 个 Linux 上最佳的图形化 Git 客户端

    Git是软件开发和若干其他版本控制任务免费和开源的分布式版本控制系统.它被设计用来以应付一切从小到非常大的项目,基于速度,效率和数据完整性. Linux用户主要通过命令行管理Git,不过,一些图形用户 ...

  4. ActionScript语言函数重载

    更新:你见过JavaScript支持重载吗,规范就是这么定义的.如果不是研究Java和Flex对象的Serialization,我也不会注意它. 距离写这篇文章已有8年了,时光匆匆啊,今天整理资料时看 ...

  5. 学习python之练习(三)

    python排序算法 1.冒泡排序: import math def BubbleSort(list): lengthOfList = len(list) for i in range(0,lengt ...

  6. Tempter of the Bone---hdu1010(dfs+剪枝)

    http://acm.hdu.edu.cn/showproblem.php?pid=1010 折磨我一下午 题目大意: 从s点走到d点能否恰好走k步   刚开始以为是广搜,其实是深搜. dfs多优化一 ...

  7. dos 加用户

    net user lipeng 1qaz3EDC /addnet user zhangnan 1qaz3EDC /addnet localgroup "Remote Desktop User ...

  8. Oracle Ebs R12 SLA与GL关系变化

    http://www.cnblogs.com/bruce_zhao/p/3809886.html Oracle Ebs R12 SLA与GL关系变化 SLA概念:SLA(Subledger Accou ...

  9. 【Windows 10 IoT - 3】Windows 10 RTM安装及新特性(树莓派 Pi2)

    在<[Window 10 IoT - 1]Window 10系统安装(树莓派 Pi2)>中,我们介绍了Windows 10 IoT预览版的安装,正式版Windows 10 IOT(OS版本 ...

  10. 解决dnu restore时的“Cannot handle address family”问题

    前几天在使用基于 mono 的 dnx 中的 dnu restore 命令安装 nuget 包包时,遇到了 “Cannot handle address family” 错误,错误详情如下: Cann ...