Native API提权函数RtlAdjustPrivilege

来源:互联网 发布:可以照一寸照的软件 编辑:程序博客网 时间:2024/06/06 00:51

在枚举或结束系统进程,抑或是操作系统服务时,会出现自身进程权限不足而失败的情况,此时需要提升自身进程到系统权限,来完成这些特殊操作。


以下代码就是提升进程权限的一系列操作,具体的内容在《Windows核心编程》中有讲解,更多时候只需要使用就好。

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;}

但是每次提权都要调用这个函数有些不方便,使用Native API就能很快速的进行提权。

Native API中有一个非常好用的提权函数,包括打开其他进程,使用一些高权限的Native API都会使用RtlAdjustPrivilege进行权限提升。这个函数封装在NTDLL.dll中,该DLL在所有DLL加载前已经加载。

函数原型如下:

NTSTATUS RtlAdjustPrivilege(   ULONG    Privilege,   BOOLEAN  Enable,   BOOLEAN  CurrentThread,   PBOOLEAN Enabled)

各个参数的含义:

Privilege       [In] Privilege index to change.                         Enable          [In] If TRUE, then enable the privilege otherwise disable.  CurrentThread  [In] If TRUE, then enable in calling thread, otherwise process. Enabled         [Out] Whether privilege was previously enabled or disabled.

找出微软NTDLL.dll放入IDA进行逆向,可以看出大概的一个流程。

NTSTATUS WINAPIRtlAdjustPrivilege(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;}

根据WRK参考RtlAdjustPrivilege的源码,理解提权函数。

NTSTATUS RtlAdjustPrivilege(    ULONG Privilege,    BOOLEAN Enable,    BOOLEAN Client,    PBOOLEAN WasEnabled    )/*++Routine Description:    This procedure enables or disables a privilege process-wide.Arguments:    Privilege - The lower 32-bits of the privilege ID to be enabled or        disabled.  The upper 32-bits is assumed to be zero.    Enable - A boolean indicating whether the privilege is to be enabled        or disabled.  TRUE indicates the privilege is to be enabled.        FALSE indicates the privilege is to be disabled.    Client - A boolean indicating whether the privilege should be adjusted        in a client token or the process's own token.   TRUE indicates        the client's token should be used (and an error returned if there        is no client token).  FALSE indicates the process's token should        be used.    WasEnabled - points to a boolean to receive an indication of whether        the privilege was previously enabled or disabled.  TRUE indicates        the privilege was previously enabled.  FALSE indicates the privilege        was previously disabled.  This value is useful for returning the        privilege to its original state after using it.Return Value:    STATUS_SUCCESS - The privilege has been successfully enabled or disabled.    STATUS_PRIVILEGE_NOT_HELD - The privilege is not held by the specified context.    Other status values as may be returned by:            NtOpenProcessToken()            NtAdjustPrivilegesToken()--*/{    NTSTATUS        Status,        TmpStatus;    HANDLE        Token;    LUID        LuidPrivilege;    PTOKEN_PRIVILEGES        NewPrivileges,        OldPrivileges;    ULONG        Length;    UCHAR        Buffer1[sizeof(TOKEN_PRIVILEGES)+                ((1-ANYSIZE_ARRAY)*sizeof(LUID_AND_ATTRIBUTES))],        Buffer2[sizeof(TOKEN_PRIVILEGES)+                ((1-ANYSIZE_ARRAY)*sizeof(LUID_AND_ATTRIBUTES))];    RTL_PAGED_CODE();    NewPrivileges = (PTOKEN_PRIVILEGES)Buffer1;    OldPrivileges = (PTOKEN_PRIVILEGES)Buffer2;    //    // Open the appropriate token...    //    if (Client == TRUE) {        Status = NtOpenThreadToken(                     NtCurrentThread(),                     TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,                     FALSE,                     &Token                     );    } else {        Status = NtOpenProcessToken(                     NtCurrentProcess(),                     TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,                     &Token                    );    }    if (!NT_SUCCESS(Status)) {        return(Status);    }    //    // Initialize the privilege adjustment structure    //    LuidPrivilege = RtlConvertUlongToLuid(Privilege);    NewPrivileges->PrivilegeCount = 1;    NewPrivileges->Privileges[0].Luid = LuidPrivilege;    NewPrivileges->Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;    //    // Adjust the privilege    //    Status = NtAdjustPrivilegesToken(                 Token,                     // TokenHandle                 FALSE,                     // DisableAllPrivileges                 NewPrivileges,             // NewPrivileges                 sizeof(Buffer1),           // BufferLength                 OldPrivileges,             // PreviousState (OPTIONAL)                 &Length                    // ReturnLength                 );    TmpStatus = NtClose(Token);    ASSERT(NT_SUCCESS(TmpStatus));    //    // Map the success code NOT_ALL_ASSIGNED to an appropriate error    // since we're only trying to adjust the one privilege.    //    if (Status == STATUS_NOT_ALL_ASSIGNED) {        Status = STATUS_PRIVILEGE_NOT_HELD;    }    if (NT_SUCCESS(Status)) {        //        // If there are no privileges in the previous state, there were        // no changes made. The previous state of the privilege        // is whatever we tried to change it to.        //        if (OldPrivileges->PrivilegeCount == 0) {            (*WasEnabled) = Enable;        } else {            (*WasEnabled) =                (OldPrivileges->Privileges[0].Attributes & SE_PRIVILEGE_ENABLED)                ? TRUE : FALSE;        }    }    return(Status);}

贴了这么多源代码,具体该如何调用Native API,非常简单。

BOOLEAN bPrev;RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &bPrev);

下面是一个调试通过的例子,可以看出Native API是如何使用的。

#include <windows.h>const unsigned int SE_SHUTDOWN_PRIVILEGE = 0x13;typedef enum _SHUTDOWN_ACTION   {ShutdownNoReboot,ShutdownReboot,ShutdownPowerOff} SHUTDOWN_ACTION, *PSHUTDOWN_ACTION;typedef int (_stdcall *_RtlAdjustPrivilege)(int, BOOL, BOOL, int *);typedef int (_stdcall *_ZwShutdownSystem)(SHUTDOWN_ACTION);void HookPatch(DWORD OldFunc, DWORD NewFunc){DWORD Pro;VirtualProtect((LPVOID)OldFunc, 20, PAGE_READWRITE, &Pro);*(BYTE *)OldFunc = 0xE9;*(DWORD *)(OldFunc+1) = (NewFunc-OldFunc-5);}__stdcall void HookMessage(int){MessageBox(NULL, "ZwShutdownSystem have been hook", "HookMessage", MB_OK);}int main(){HMODULE hNtDll = LoadLibrary("ntdll.dll");_RtlAdjustPrivilege pfnRtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(hNtDll, "RtlAdjustPrivilege");_ZwShutdownSystem pfnZwShutdownSystem = (_ZwShutdownSystem)GetProcAddress(hNtDll, "ZwShutdownSystem");int nEn = 0;int nResult = pfnRtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, TRUE, &nEn);if(nResult == 0x0c000007c){nResult = pfnRtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &nEn);}HookPatch((DWORD)pfnZwShutdownSystem, (DWORD)HookMessage);system("pause");pfnZwShutdownSystem(ShutdownReboot);FreeLibrary(hNtDll);return 0;}