一句代码提升进程权限

简介:

RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,1,0,NULL);

这个函数封装在NtDll.dll中(在所有DLL加载之前加载),被微软严格保密,就是说你在MSDN上查不到关于他的任何信息。

.常量 SE_BACKUP_PRIVILEGE, "17", 公开
.常量 SE_RESTORE_PRIVILEGE, "18", 公开
.常量 SE_SHUTDOWN_PRIVILEGE, "19", 公开
.常量 SE_DEBUG_PRIVILEGE, "20", 公开


先来看看这个函数的定义(Winehq给出):
NTSTATUS RtlAdjustPrivilege
(
ULONG Privilege,
BOOLEAN Enable,
BOOLEAN CurrentThread,
PBOOLEAN Enabled
)

参数的含义:
Privilege [In] Privilege index to change.
// 所需要的权限名称,可以到MSDN查找关于Process Token & Privilege内容可以查到

Enable [In] If TRUE, then enable the privilege otherwise disable.
// 如果为True 就是打开相应权限,如果为False 则是关闭相应权限

CurrentThread [In] If TRUE, then enable in calling thread, otherwise process.
// 如果为True 则仅提升当前线程权限,否则提升整个进程的权限

Enabled [Out] Whether privilege was previously enabled or disabled.
// 输出原来相应权限的状态(打开 | 关闭)


很多人大概没有听说过他的大名,但是相信有很多人见过进程提权的过程
拷一段我写的提权上来吧

代码
BOOL ImproveProcPriv()
{
HANDLE token;
// 提升权限
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&token))
{
MessageBox(NULL, " 打开进程令牌失败... ", " 错误 ",MB_ICONSTOP);
return FALSE;
}
TOKEN_PRIVILEGES tkp;
tkp.PrivilegeCount = 1;
::LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tkp.Privileges[ 0].Luid);
tkp.Privileges[ 0].Attributes = SE_PRIVILEGE_ENABLED;
if(!AdjustTokenPrivileges(token,FALSE,&tkp, sizeof(tkp),NULL,NULL))
{
MessageBox(NULL, " 调整令牌权限失败... ", " 错误 ",MB_ICONSTOP);
return FALSE;
}
CloseHandle(token);
return TRUE;
}

看看吧,这个提权快要累死了...

但是 如果有这个函数就不一样了,你可以只用一个函数就实现这个功能,甚至功能远多于上面的代码...

通过恰当的IDE设置和必要的Defination,上面这个函数的功能你完全可以通过一行代码来实现。

RtlAdjustPrivilege(SE_DEBUG_NAME,1,0,NULL);


正文:

下面我们看一下这个函数是怎么运行的,顺便学习下强大的IDA
IDA 载入ntdll.dll (我这里载入的是 WinDBG自动下载的 Symbol里面的英文版本 可能不同的Windows版本略有不同)


先把函数的原型给输入IDA 方便一下阅读,然后开始阅读汇编代码了(党和国家考验我们的时候到了)。
看看Graph View 真的是很牛啊...
看看函数最开头...



复制代码
mov edi, edi ; 这句话是废指令
push ebp
mov ebp, esp
sub esp, 30h ; 48个字节的子过程域Auto变量
cmp [ebp+CurrentThread], 1 ; 判断CurrentThread参数是否被指定为1
mov eax, dword_7C97B0C8
mov [ebp+var_4], eax
mov eax, [ebp+Enabled]
mov [ebp+IsEnabled], eax ; BOOL *IsEnabled = Enabled;
lea eax, [ebp+var_28]
push eax
jz loc_7C93378B


判断是调整进程权限还是线程权限,
CurrentThread == TRUE
push 0
push 28h ; TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
push 0FFFFFFFEh ; GetCurrentThread()
call ZwOpenThreadToken
jmp loc_7C929A7A


CurrentThread == FALSE
push 28h ; TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
push 0FFFFFFFFh ; GetCurrentProcess()
call NtOpenProcessToken


然后两个代码块同时指向这里
loc_7C929A7A: ; 很明白了吧 判断进程/线程令牌是否成功被打开
test eax, eax
jl short loc_7C929AE4 ; 没成功则跳


若 执行成功

mov eax, [ebp+Privilege]
mov [ebp+dwPrivilege], eax
mov al, [ebp+Enable]
xor ecx, ecx ; ecx清零
neg al
push esi
mov [ebp+NewState], 1
mov [ebp+var_C], ecx
sbb eax, eax
and eax, 2
mov [ebp+var_8], eax
lea eax, [ebp+ReturnLength] ; 实际返回长度
push eax
lea eax, [ebp+OldState]
push eax ; 旧的特权 指针
push 10h ; sizeof(TOKEN_PRIVILEGES)
lea eax, [ebp+NewState]
push eax ; 新的特权 指针
push ecx ; FALSE 因为上面有xor ecx,ecx
push [ebp+TokenHandle]
call NtAdjustPrivilegesToken ; 调用 AdjustPrivilegesToken提权
push [ebp+TokenHandle]
mov esi, eax ; eax备份
call ZwClose ; 关闭 内核对象句柄
cmp esi, 106h ; 判断NtAdjustPrivilege执行情况 106h = STATUS_NOT_ALL_ASSIGNED
jz loc_7C947DF2

判断是否执行成功之后,开始输出最后一个参数

cmp [ebp+OldState], 0
mov ecx, [ebp+IsEnabled]
jnz loc_7C929E99


若 OldState != 0

mov al, [ebp+Enable] ; 应该很明显了 把Enable变量赋给al 也就是eax最后两位


若 OldState == 0

mov eax, [ebp+var_18]
shr eax, 1
and al, 1
jmp loc_7C929ADF
复制代码

这个函数大致流程就是这样。

到这里差不多可以按一下传说中的F5了

复制代码
int __stdcall RtlAdjustPrivilege( int Privilege, char Enable, char CurrentThread, int Enabled)
{
int result; // eax@2
signed int AdjustResult; // esi@4
char returnValue; // al@7
int v7; // [sp+2Ch] [bp-4h]@1
int IsEnabled; // [sp+4h] [bp-2Ch]@1
int TokenHandle; // [sp+8h] [bp-28h]@2
int dwPrivilege; // [sp+20h] [bp-10h]@4
signed int NewState; // [sp+1Ch] [bp-14h]@4
int v12; // [sp+24h] [bp-Ch]@4
int v13; // [sp+28h] [bp-8h]@4
int OldState; // [sp+Ch] [bp-24h]@4
char ReturnLength; // [sp+0h] [bp-30h]@4
unsigned int v16; // [sp+18h] [bp-18h]@11

v7 = dword_7C97B0C8;
IsEnabled = Enabled;
if ( CurrentThread == 1 )
result = ZwOpenThreadToken(- 2, 40, 0, &TokenHandle);
else
result = NtOpenProcessToken(- 1, 40, &TokenHandle);
if ( result >= 0 )
{
dwPrivilege = Privilege;
NewState = 1;
v12 = 0;
v13 = -(Enable != 0) & 2;
AdjustResult = NtAdjustPrivilegesToken(TokenHandle, 0, &NewState, 16, &OldState, &ReturnLength);
ZwClose(TokenHandle);
if ( AdjustResult == 262 )
AdjustResult = - 1073741727;
if ( AdjustResult >= 0 )
{
if ( OldState )
returnValue = (v16 >> 1) & 1;
else
returnValue = Enable;
*(_BYTE *)IsEnabled = returnValue;
}
result = AdjustResult;
}
return result;
}
复制代码

可读性好像仍然不高,看看这个...

复制代码
/* *****************************************************************************
* RtlAdjustPrivilege [NTDLL.@]
*
* Enables or disables a privilege from the calling thread or process.
*
* PARAMS
* Privilege [I] Privilege index to change.
* Enable [I] If TRUE, then enable the privilege otherwise disable.
* CurrentThread [I] If TRUE, then enable in calling thread, otherwise process.
* Enabled [O] Whether privilege was previously enabled or disabled.
*
* RETURNS
* Success: STATUS_SUCCESS.
* Failure: NTSTATUS code.
*
* SEE ALSO
* NtAdjustPrivilegesToken, NtOpenThreadToken, NtOpenProcessToken.
*
*/
NTSTATUS WINAPI
RtlAdjustPrivilege(ULONG Privilege,
BOOLEAN Enable,
BOOLEAN CurrentThread,
PBOOLEAN Enabled)
{
TOKEN_PRIVILEGES NewState;
TOKEN_PRIVILEGES OldState;
ULONG ReturnLength;
HANDLE TokenHandle;
NTSTATUS Status;

TRACE( " (%d, %s, %s, %p)\n ", Privilege, Enable ? " TRUE " : " FALSE ",
CurrentThread ? " TRUE " : " FALSE ", Enabled);

if (CurrentThread)
{
Status = NtOpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&TokenHandle);
}
else
{
Status = NtOpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&TokenHandle);
}

if (!NT_SUCCESS(Status))
{
WARN( " Retrieving token handle failed (Status %x)\n ", Status);
return Status;
}

OldState.PrivilegeCount = 1;

NewState.PrivilegeCount = 1;
NewState.Privileges[ 0].Luid.LowPart = Privilege;
NewState.Privileges[ 0].Luid.HighPart = 0;
NewState.Privileges[ 0].Attributes = (Enable) ? SE_PRIVILEGE_ENABLED : 0;

Status = NtAdjustPrivilegesToken(TokenHandle,
FALSE,
&NewState,
sizeof(TOKEN_PRIVILEGES),
&OldState,
&ReturnLength);
NtClose (TokenHandle);
if (Status == STATUS_NOT_ALL_ASSIGNED)
{
TRACE( " Failed to assign all privileges\n ");
return STATUS_PRIVILEGE_NOT_HELD;
}
if (!NT_SUCCESS(Status))
{
WARN( " NtAdjustPrivilegesToken() failed (Status %x)\n ", Status);
return Status;
}

if (OldState.PrivilegeCount == 0)
*Enabled = Enable;
else
*Enabled = (OldState.Privileges[ 0].Attributes & SE_PRIVILEGE_ENABLED);

return STATUS_SUCCESS;
}
复制代码

易语言代码:

复制代码
.版本 2

.常量 SE_BACKUP_PRIVILEGE, " 17 ", , 公开
.常量 SE_RESTORE_PRIVILEGE, " 18 ", , 公开
.常量 SE_SHUTDOWN_PRIVILEGE, " 19 ", , 公开
.常量 SE_DEBUG_PRIVILEGE, " 20 ", , 公开

.DLL命令 提升自身进程权限, 整数型, " ntdll.dll ", " RtlAdjustPrivilege "
.参数 Privilege, 整数型, , 需要的权限,以SE_开头的常量,比如SE_DEBUG_PRIVILEGE表示提升到调试权限
.参数 Enable, 逻辑型, , 如果为真就是打开相应权限,如果为假则是关闭相应权限
.参数 CurrentThread, 整数型, , 如果为真则仅提升当前线程权限,否则提升整个进程的权限
.参数 RetEnable, 整数型, 传址, 输出原来相应权限的状态(打开 | 关闭)

.版本 2

提升自身进程权限 (#SE_DEBUG_PRIVILEGE, 真, 0, 0



本文转自suifei博客园博客,原文链接:http://www.cnblogs.com/Chinasf/archive/2010/01/13/1646473.html,如需转载请自行联系原作者
相关文章
|
机器学习/深度学习 负载均衡 算法
计算机网络编程 | 并发服务器代码实现(多进程/多线程)
计算机网络编程 | 并发服务器代码实现(多进程/多线程)
176 0
|
4月前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
72 3
|
6月前
|
Shell
【进程通信】利用管道创建进程池(结合代码)
【进程通信】利用管道创建进程池(结合代码)
|
3月前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
6月前
|
安全 Linux 开发者
⭐⭐⭐⭐⭐Linux C/C++ 进程崩溃诊断以及有效数据收集:解锁代码问题快速定位与修复的方法
⭐⭐⭐⭐⭐Linux C/C++ 进程崩溃诊断以及有效数据收集:解锁代码问题快速定位与修复的方法
400 1
|
3月前
|
网络协议 安全 Unix
从孤岛到大陆:Python进程间通信,让你的代码世界不再有隔阂
【8月更文挑战第1天】在编程领域,Python进程曾像孤岛般各自运行于独立内存中。随项目复杂度增长,进程协同变得重要。Python提供了多种机制搭建这些孤岛间的桥梁。本文介绍四种常见进程间通信(IPC)方式:管道(Pipes)、队列(Queues)、共享内存(Shared Memory)及套接字(Sockets),并附示例代码展示如何实现信息自由流通,使进程紧密相连,共建复杂程序世界。
29 2
|
5月前
|
Python Windows
在 Windows 平台下打包 Python 多进程代码为 exe 文件的问题及解决方案
在使用 Python 进行多进程编程时,在 Windows 平台下可能会出现将代码打包为 exe 文件后无法正常运行的问题。这个问题主要是由于在 Windows 下创建新的进程需要复制父进程的内存空间,而 Python 多进程机制需要先完成父进程的初始化阶段后才能启动子进程,所以在这个过程中可能会出现错误。此外,由于没有显式导入 Python 解释器,也会导致 Python 解释器无法正常工作。为了解决这个问题,我们可以使用函数。
124 5
|
4月前
|
Unix Linux Python
`subprocess`模块是Python中用于生成新进程、连接到它们的输入/输出/错误管道,并获取它们的返回(退出)代码的模块。
`subprocess`模块是Python中用于生成新进程、连接到它们的输入/输出/错误管道,并获取它们的返回(退出)代码的模块。
后端登录接口使用postman,无法接收返回数据,怎样解决,认真比较与原项目的代码,看看有没有写的不一样的,问题就能解决,不要多少写,根据postman的提示先找到错误的进程,看错误进程出现在那个进程
后端登录接口使用postman,无法接收返回数据,怎样解决,认真比较与原项目的代码,看看有没有写的不一样的,问题就能解决,不要多少写,根据postman的提示先找到错误的进程,看错误进程出现在那个进程
|
6月前
【进程通信】Syetem V 共享内存(结合代码模拟通信)
【进程通信】Syetem V 共享内存(结合代码模拟通信)

热门文章

最新文章

相关实验场景

更多