分享

Native API提权函数RtlAdjustPrivilege

 herowuking 2014-12-19

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


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

  1. BOOL ImproveProcPriv()  
  2. {  
  3.     HANDLE token;  
  4.       
  5.     if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&token))  
  6.     {  
  7.         MessageBox(NULL,"打开进程令牌失败","错误",MB_ICONSTOP);  
  8.         return FALSE;  
  9.     }  
  10.     TOKEN_PRIVILEGES tkp;  
  11.     tkp.PrivilegeCount = 1;  
  12.     ::LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tkp.Privileges[0].Luid);   
  13.     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;  
  14.     if(!AdjustTokenPrivileges(token,FALSE,&tkp,sizeof(tkp),NULL,NULL))  
  15.     {  
  16.         MessageBox(NULL,"调整令牌权限失败","错误",MB_ICONSTOP);  
  17.         return FALSE;  
  18.     }  
  19.     CloseHandle(token);  
  20.     return TRUE;  
  21. }  

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

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

函数原型如下:

  1. NTSTATUS RtlAdjustPrivilege  
  2. (  
  3.    ULONG    Privilege,  
  4.    BOOLEAN  Enable,  
  5.    BOOLEAN  CurrentThread,  
  6.    PBOOLEAN Enabled  
  7. )  

各个参数的含义:

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

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

  1. NTSTATUS WINAPI  
  2. RtlAdjustPrivilege(ULONG Privilege,  
  3.                    BOOLEAN Enable,  
  4.                    BOOLEAN CurrentThread,  
  5.                    PBOOLEAN Enabled)  
  6. {  
  7.     TOKEN_PRIVILEGES NewState;  
  8.     TOKEN_PRIVILEGES OldState;  
  9.     ULONG ReturnLength;  
  10.     HANDLE TokenHandle;  
  11.     NTSTATUS Status;  
  12.     TRACE("(%d, %s, %s, %p)\n", Privilege, Enable ? "TRUE" :   
  13. "FALSE",  
  14.         CurrentThread ? "TRUE" : "FALSE", Enabled);  
  15.     if (CurrentThread)  
  16.     {  
  17.         Status = NtOpenThreadToken(GetCurrentThread(),  
  18.                                    TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,  
  19.                                    FALSE,  
  20.                                    &TokenHandle);  
  21.     }  
  22.     else  
  23.     {  
  24.         Status = NtOpenProcessToken(GetCurrentProcess(),  
  25.                                     TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,  
  26.                                     &TokenHandle);  
  27.     }  
  28.     if (!NT_SUCCESS(Status))  
  29.     {  
  30.         WARN("Retrieving token handle failed (Status %x)\n", Status);  
  31.         return Status;  
  32.     }  
  33.     OldState.PrivilegeCount = 1;  
  34.     NewState.PrivilegeCount = 1;  
  35.     NewState.Privileges[0].Luid.LowPart = Privilege;  
  36.     NewState.Privileges[0].Luid.HighPart = 0;  
  37.     NewState.Privileges[0].Attributes = (Enable) ? SE_PRIVILEGE_ENABLED : 0;  
  38.     Status = NtAdjustPrivilegesToken(TokenHandle,  
  39.                                      FALSE,  
  40.                                      &NewState,  
  41.                                      sizeof(TOKEN_PRIVILEGES),  
  42.                                      &OldState,  
  43.                                      &ReturnLength);  
  44.     NtClose (TokenHandle);  
  45.     if (Status == STATUS_NOT_ALL_ASSIGNED)  
  46.     {  
  47.         TRACE("Failed to assign all privileges\n");  
  48.         return STATUS_PRIVILEGE_NOT_HELD;  
  49.     }  
  50.     if (!NT_SUCCESS(Status))  
  51.     {  
  52.         WARN("NtAdjustPrivilegesToken() failed (Status %x)\n", Status);  
  53.         return Status;  
  54.     }  
  55.     if (OldState.PrivilegeCount == 0)  
  56.         *Enabled = Enable;  
  57.     else  
  58.         *Enabled = (OldState.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED);  
  59.     return STATUS_SUCCESS;  
  60. }  

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

  1. NTSTATUS   
  2. RtlAdjustPrivilege(  
  3.     ULONG Privilege,  
  4.     BOOLEAN Enable,  
  5.     BOOLEAN Client,  
  6.     PBOOLEAN WasEnabled  
  7.     )  
  8.   
  9. /*++ 
  10.  
  11. Routine Description: 
  12.  
  13.     This procedure enables or disables a privilege process-wide. 
  14.  
  15. Arguments: 
  16.  
  17.     Privilege - The lower 32-bits of the privilege ID to be enabled or 
  18.         disabled.  The upper 32-bits is assumed to be zero. 
  19.  
  20.     Enable - A boolean indicating whether the privilege is to be enabled 
  21.         or disabled.  TRUE indicates the privilege is to be enabled. 
  22.         FALSE indicates the privilege is to be disabled. 
  23.  
  24.     Client - A boolean indicating whether the privilege should be adjusted 
  25.         in a client token or the process's own token.   TRUE indicates 
  26.         the client's token should be used (and an error returned if there 
  27.         is no client token).  FALSE indicates the process's token should 
  28.         be used. 
  29.  
  30.     WasEnabled - points to a boolean to receive an indication of whether 
  31.         the privilege was previously enabled or disabled.  TRUE indicates 
  32.         the privilege was previously enabled.  FALSE indicates the privilege 
  33.         was previously disabled.  This value is useful for returning the 
  34.         privilege to its original state after using it. 
  35.  
  36.  
  37. Return Value: 
  38.  
  39.     STATUS_SUCCESS - The privilege has been successfully enabled or disabled. 
  40.  
  41.     STATUS_PRIVILEGE_NOT_HELD - The privilege is not held by the specified context. 
  42.  
  43.     Other status values as may be returned by: 
  44.  
  45.             NtOpenProcessToken() 
  46.             NtAdjustPrivilegesToken() 
  47.  
  48.  
  49. --*/  
  50.   
  51. {  
  52.     NTSTATUS  
  53.         Status,  
  54.         TmpStatus;  
  55.   
  56.     HANDLE  
  57.         Token;  
  58.   
  59.     LUID  
  60.         LuidPrivilege;  
  61.   
  62.     PTOKEN_PRIVILEGES  
  63.         NewPrivileges,  
  64.         OldPrivileges;  
  65.   
  66.     ULONG  
  67.         Length;  
  68.   
  69.     UCHAR  
  70.         Buffer1[sizeof(TOKEN_PRIVILEGES)+  
  71.                 ((1-ANYSIZE_ARRAY)*sizeof(LUID_AND_ATTRIBUTES))],  
  72.         Buffer2[sizeof(TOKEN_PRIVILEGES)+  
  73.                 ((1-ANYSIZE_ARRAY)*sizeof(LUID_AND_ATTRIBUTES))];  
  74.   
  75.   
  76.     RTL_PAGED_CODE();  
  77.   
  78.     NewPrivileges = (PTOKEN_PRIVILEGES)Buffer1;  
  79.     OldPrivileges = (PTOKEN_PRIVILEGES)Buffer2;  
  80.   
  81.     //  
  82.     // Open the appropriate token...  
  83.     //  
  84.   
  85.     if (Client == TRUE) {  
  86.         Status = NtOpenThreadToken(  
  87.                      NtCurrentThread(),  
  88.                      TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,  
  89.                      FALSE,  
  90.                      &Token  
  91.                      );  
  92.     } else {  
  93.   
  94.         Status = NtOpenProcessToken(  
  95.                      NtCurrentProcess(),  
  96.                      TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,  
  97.                      &Token  
  98.                     );  
  99.     }  
  100.   
  101.     if (!NT_SUCCESS(Status)) {  
  102.         return(Status);  
  103.     }  
  104.   
  105.   
  106.   
  107.     //  
  108.     // Initialize the privilege adjustment structure  
  109.     //  
  110.   
  111.     LuidPrivilege = RtlConvertUlongToLuid(Privilege);  
  112.   
  113.   
  114.     NewPrivileges->PrivilegeCount = 1;  
  115.     NewPrivileges->Privileges[0].Luid = LuidPrivilege;  
  116.     NewPrivileges->Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;  
  117.   
  118.   
  119.   
  120.     //  
  121.     // Adjust the privilege  
  122.     //  
  123.   
  124.     Status = NtAdjustPrivilegesToken(  
  125.                  Token,                     // TokenHandle  
  126.                  FALSE,                     // DisableAllPrivileges  
  127.                  NewPrivileges,             // NewPrivileges  
  128.                  sizeof(Buffer1),           // BufferLength  
  129.                  OldPrivileges,             // PreviousState (OPTIONAL)  
  130.                  &Length                    // ReturnLength  
  131.                  );  
  132.   
  133.   
  134.     TmpStatus = NtClose(Token);  
  135.     ASSERT(NT_SUCCESS(TmpStatus));  
  136.   
  137.   
  138.     //  
  139.     // Map the success code NOT_ALL_ASSIGNED to an appropriate error  
  140.     // since we're only trying to adjust the one privilege.  
  141.     //  
  142.   
  143.     if (Status == STATUS_NOT_ALL_ASSIGNED) {  
  144.         Status = STATUS_PRIVILEGE_NOT_HELD;  
  145.     }  
  146.   
  147.   
  148.     if (NT_SUCCESS(Status)) {  
  149.   
  150.         //  
  151.         // If there are no privileges in the previous state, there were  
  152.         // no changes made. The previous state of the privilege  
  153.         // is whatever we tried to change it to.  
  154.         //  
  155.   
  156.         if (OldPrivileges->PrivilegeCount == 0) {  
  157.   
  158.             (*WasEnabled) = Enable;  
  159.   
  160.         } else {  
  161.   
  162.             (*WasEnabled) =  
  163.                 (OldPrivileges->Privileges[0].Attributes & SE_PRIVILEGE_ENABLED)  
  164.                  TRUE : FALSE;  
  165.         }  
  166.     }  
  167.   
  168.     return(Status);  
  169. }  

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

  1. BOOLEAN bPrev;  
  2. RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &bPrev);  

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

  1. #include <windows.h>  
  2.   
  3. const unsigned int SE_SHUTDOWN_PRIVILEGE = 0x13;  
  4.   
  5. typedef enum _SHUTDOWN_ACTION     
  6. {  
  7.     ShutdownNoReboot,  
  8.     ShutdownReboot,  
  9.     ShutdownPowerOff  
  10. } SHUTDOWN_ACTION, *PSHUTDOWN_ACTION;  
  11.   
  12. typedef int (_stdcall *_RtlAdjustPrivilege)(int, BOOL, BOOL, int *);  
  13. typedef int (_stdcall *_ZwShutdownSystem)(SHUTDOWN_ACTION);  
  14.   
  15. void HookPatch(DWORD OldFunc, DWORD NewFunc)  
  16. {  
  17.     DWORD Pro;  
  18.     VirtualProtect((LPVOID)OldFunc, 20, PAGE_READWRITE, &Pro);  
  19.     *(BYTE *)OldFunc = 0xE9;  
  20.     *(DWORD *)(OldFunc+1) = (NewFunc-OldFunc-5);  
  21. }  
  22.   
  23. __stdcall void HookMessage(int)  
  24. {     
  25.     MessageBox(NULL, "ZwShutdownSystem have been hook", "HookMessage", MB_OK);  
  26. }  
  27.   
  28. int main()  
  29. {     
  30.     HMODULE hNtDll = LoadLibrary("ntdll.dll");    
  31.     _RtlAdjustPrivilege pfnRtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(hNtDll, "RtlAdjustPrivilege");    
  32.     _ZwShutdownSystem pfnZwShutdownSystem = (_ZwShutdownSystem)GetProcAddress(hNtDll, "ZwShutdownSystem");  
  33.       
  34.     int nEn = 0;  
  35.     int nResult = pfnRtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, TRUE, &nEn);  
  36.     if(nResult == 0x0c000007c)    
  37.     {     
  38.         nResult = pfnRtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &nEn);    
  39.     }  
  40.       
  41.     HookPatch((DWORD)pfnZwShutdownSystem, (DWORD)HookMessage);  
  42.     system("pause");  
  43.     pfnZwShutdownSystem(ShutdownReboot);  
  44.     FreeLibrary(hNtDll);  
  45.     return 0;  
  46. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多