• 一句代码提升进程权限


    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(-2400&TokenHandle);
    else
        result 
    = NtOpenProcessToken(-140&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, 真, 
    00

    转载:pediy

  • 相关阅读:
    谁说固态硬盘没容量?4TB诞生、明年8TB!
    微软.NET Framework 4.5.2 RTM正式版
    Chrome 应用推荐
    MS14-021: Internet Explorer 安全更新: 2014 年 5 月 1 日
    百视通与微软共同宣布9月在华发布Xbox One
    支付宝5月4日起将停止收款主页业务 保留三种收款方式
    Chrome 应用推荐
    为什么《舌尖上的中国》让你欲罢不能?
    求连续子数组的最大乘积
    损失函数与代价函数区别
  • 原文地址:https://www.cnblogs.com/Chinasf/p/1646473.html
Copyright © 2020-2023  润新知