进程提权小结
一直在使用的进程提权,今天在这里做个简单的小结。
进程提权需要使用到一组Windows API有:
1.OpenProcessToken
2.LookupPrivilegeValue
3.AdjustTokenPrivileges
值得注意的是,使用这组函数提升权限的前提是进程具备该权限,只是访问令牌中没有启用该权限。如果进程的访问令牌中本身就没有关联该权限,那么AdjustTokenPrivileges函数调用将会返回ERROR_NOT_ALL_ASSIGNED(值为1300L)的错误码。
0x01 OpenProcessToken
1 2 3 4 5 | BOOL WINAPI OpenProcessToken( __in HANDLE ProcessHandle, //进程句柄(当前进程为GetCurrentProcess()为参数) __in DWORD DesiredAccess, //访问令牌特权 __out PHANDLE TokenHandle //返回的参数,就是AdjustTokenPrivileges的第一个参数 ); |
注意第二个参数令牌的权限,这个权限是要有修改权限的特权(TOKEN_ADJUST_PRIVILEGES),意思就是要把程序的权限修改得更高。所有权限可以写TOKEN_ALL_ACCESS ,去查看一个令牌特权可以用TOKEN_QUERY
1 2 3 4 5 6 7 | HANDLE ProcessHandle = GetCurrentProcess(); HANDLE TokenHandle = NULL; if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle)) { return FALSE; } |
0x02 TOKEN_PRIVILEGES结构
1 2 3 4 5 6 | typedef struct _TOKEN_PRIVILEGES { DWORD PrivilegeCount; //要修改的特权数目 LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; //特权数组 }TOKEN_PRIVILEGES; |
LUID_AND_ATTRIBUTES 结构体:
1 2 3 4 5 | typedef struct _LUID_AND_ATTRIBUTES { LUID Luid; //一个标志,不同的Luid代表着各种不同的特权类型 DWORD Attributes; //要这个特权干嘛,如启用这个特权(SE_PRIVILEGE_ENABLED) } LUID_AND_ATTRIBUTES; |
0x03 LookupPrivilegeValue
1 2 3 4 5 | BOOL WINAPI LookupPrivilegeValue( __in_opt LPCTSTR lpSystemName, //系统的名字,如果为NULL,就是本地名字(这里就填NULL) __in LPCTSTR lpName, //特权的名字 __out PLUID lpLuid //通过指针返回一个LUID类型的Luid的标识,这个值就就可以填入刚才的结构体里了。 ); |
0x04 AdjustTokenPrivilege
1 2 3 4 5 6 7 8 | BOOL WINAPI AdjustTokenPrivileges( __in HANDLE TokenHandle, //OpenProcessToken第三个指针参数传出的句柄值 __in BOOL DisableAllPrivileges, //是否禁用所有所有的特权(这里填false) __in_opt PTOKEN_PRIVILEGES NewState, //新的TOKEN_PRIVILEGES的特权结构体指针 __in DWORD BufferLength, //上面结构体的字节长度(sizeof) __out_opt PTOKEN_PRIVILEGES PreviousState, //接受原先的特权的结构体 __out_opt PDWORD ReturnLength //结构体的字节长度的指针 ); |
进程提权中后两个参数不用管。
MSDN叙述:
如果第五个参数不是NULL,在OpenProcessToken加特权时除了需要指定TOKEN_ADJUST_PRIVILEGES还必须指定TOKEN_QUERY
如果第五个参数是NULL,你不接受原先的结构体(第六个当然也是NULL), 就不用再指定附加的TOKEN_QUERY的特权了。
还要注意:
就算这个函数返回为真,还要调用GetLastError()来检验是否完全成功。如果GetLastError()==ERROR_SUCCESS就代表修改非常成功 ,这个非常重要!!
源代码:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | BOOL EnableSeDebugPrivilege(IN const CHAR * PriviledgeName, BOOL IsEnable); if (EnableSeDebugPrivilege( "DebugPrivilege" , TRUE) == FALSE) { } BOOL EnableSeDebugPrivilege(IN const CHAR * PriviledgeName, BOOL IsEnable) { // 打开权限令牌 HANDLE ProcessHandle = GetCurrentProcess(); HANDLE TokenHandle = NULL; TOKEN_PRIVILEGES TokenPrivileges = { 0 }; if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle)) { return FALSE; } LUID v1; if (!LookupPrivilegeValue(NULL, PriviledgeName, &v1)) // 通过权限名称查找uID { CloseHandle(TokenHandle); TokenHandle = NULL; return FALSE; } TokenPrivileges.PrivilegeCount = 1; // 要提升的权限个数 TokenPrivileges.Privileges[0].Attributes = IsEnable == TRUE ? SE_PRIVILEGE_ENABLED : 0; // 动态数组,数组大小根据Count的数目 TokenPrivileges.Privileges[0].Luid = v1; if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof (TOKEN_PRIVILEGES), NULL, NULL)) { CloseHandle(TokenHandle); TokenHandle = NULL; return FALSE; } CloseHandle(TokenHandle); TokenHandle = NULL; return TRUE; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗