lanjingling888 发表于 2018-2-9 00:38:54

[原创]驱动里获取指定PID的完整性级别(Integrity Level)


本人菜鸟,大神飘过
背景:有个软件需要在驱动里找一个具有system权限的svchost,借它做点非常正规的事情.此处省略一万字.
本着从贵站也学习也奉贤的原则.开始如下:
首先想到了之前写过用户层的,先发出代码.

'SECURITY_MANDATORY_UNTRUSTED_RID = $00000000;      -0
'SECURITY_MANDATORY_LOW_RID = $00001000;            -4096
'SECURITY_MANDATORY_MEDIUM_RID = $00002000;         -8192 普通用户权限
'SECURITY_MANDATORY_HIGH_RID = $00003000;             -12288 管理员权限
'SECURITY_MANDATORY_SYSTEM_RID = $00004000;         -16384 system权限
'SECURITY_MANDATORY_PROTECTED_PROCESS_RID = $00005000;-20480

Option Explicit
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Private Declare Function GetTokenInformation Lib "advapi32.dll" (ByVal TokenHandle As Long, ByRef TokenInformationClass As TOKEN_INFORMATION_CLASS, ByRef TokenInformation As Any, ByVal TokenInformationLength As Long, ByRef ReturnLength As Long) As Long
Private Declare Function GetSidSubAuthorityCount Lib "advapi32.dll" (ByVal pSid As Long) As Long
Private Declare Function GetSidSubAuthority Lib "advapi32.dll" (ByVal pSid As Long, ByVal nSubAuthority As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Type SID_AND_ATTRIBUTES
    SID As Long
    Attributes As Long
End Type
Private Type TOKEN_MANDATORY_LABEL
    Label As SID_AND_ATTRIBUTES
End Type
Private Enum TOKEN_INFORMATION_CLASS
    TokenUser = 1
    TokenGroups
    TokenPrivileges
    TokenOwner
    TokenPrimaryGroup
    TokenDefaultDacl
    TokenSource
    tokenType
    TokenImpersonationLevel
    TokenStatistics
    TokenRestrictedSids
    TokenSessionId
    TokenGroupsAndPrivileges
    TokenSessionReference
    TokenSandBoxInert
    TokenAuditPolicy
    TokenOrigin
    TokenElevationType
    TokenLinkedToken
    TokenElevation
    TokenHasRestrictions
    TokenAccessInformation
    TokenVirtualizationAllowed
    TokenVirtualizationEnabled
    TokenIntegrityLevel
    TokenUIAccess
    TokenMandatoryPolicy
    TokenLogonSid
    TokenIsAppContainer
    TokenCapabilities
    TokenAppContainerSid
    TokenAppContainerNumber
    TokenUserClaimAttributes
    TokenDeviceClaimAttributes
    TokenRestrictedUserClaimAttributes
    TokenRestrictedDeviceClaimAttributes
    TokenDeviceGroups
    TokenRestrictedDeviceGroups
    TokenSecurityAttributes
    TokenIsRestricted
    MaxTokenInfoClass
End Enum
Private Const TOKEN_QUERY = &H8
Private Const TOKEN_QUERY_SOURCE = &H10

Public Function GetIntegrityLevel() As Long
    Dim hProcess As Long
    Dim hToken As Long
    Dim dwSize As Long
    Dim pUser As TOKEN_MANDATORY_LABEL
    Dim psaCount As Long
    Dim SubAuthority As Long
    Dim lRet As Long
    Dim lpBuffer() As Long
    hProcess = GetCurrentProcess()
    If hProcess Then
            Call OpenProcessToken(hProcess, TOKEN_QUERY Or TOKEN_QUERY_SOURCE, hToken)
            If hToken Then
                  Call GetTokenInformation(hToken, ByVal TokenIntegrityLevel, ByVal 0&, 0, dwSize)
                  If dwSize Then
                            ReDim lpBuffer(dwSize) As Long
                            lRet = GetTokenInformation(hToken, ByVal TokenIntegrityLevel, lpBuffer(0), dwSize, dwSize)
                            If lRet Then
                                    Call CopyMemory(pUser, lpBuffer(0), LenB(pUser))
                                    psaCount = GetSidSubAuthorityCount(pUser.Label.SID)
                                    If psaCount Then
                                          CopyMemory SubAuthority, ByVal psaCount, 4
                                          SubAuthority = SubAuthority - 1
                                          lRet = GetSidSubAuthority(pUser.Label.SID, SubAuthority)
                                          If lRet Then
                                                    CopyMemory GetIntegrityLevel, ByVal lRet, 4
                                          End If
                                    End If
                            End If
                            Erase lpBuffer()
                  End If
                  CloseHandle hToken
            End If
    End If
End Function

再来c++版

#include<windows.h>
#ifndef _TOKEN_MANDATORY_LABEL
typedef struct _TOKEN_MANDATORY_LABEL {
SID_AND_ATTRIBUTES Label;
} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
#endif
#ifndef TokenIntegrityLevel
#define TokenIntegrityLevel 0x19
#endif
DWORD GetIntegrityLevel()
{
    HANDLE hProcess = NULL, hToken = NULL;
    DWORD dwSize = 0, dwRet = 0;
    PTOKEN_MANDATORY_LABEL pTokenInfo = NULL;
    hProcess = GetCurrentProcess();
    if (hProcess != NULL)
    {
      OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_QUERY_SOURCE, &hToken);
      if (hToken != NULL)
      {
            GetTokenInformation(hToken,TokenIntegrityLevel , NULL, 0, &dwSize);
            if (dwSize != 0)
            {
                pTokenInfo = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, dwSize);
                dwRet = GetTokenInformation(hToken,TokenIntegrityLevel , pTokenInfo, dwSize, &dwSize);
                if (dwRet != 0)
                {
                  dwRet = *GetSidSubAuthority(pTokenInfo->Label.Sid, *GetSidSubAuthorityCount(pTokenInfo->Label.Sid) - 1);
                }
                LocalFree(pTokenInfo);
            }
            CloseHandle(hToken);
      }
    }
    return dwRet;
}
int main()
{
    printf("%d\n",GetIntegrityLevel());
    system("pause");
    return 1;
}

现在的问题是需要在驱动里面实现,乍一碰到,有点手麻,不知道杂去搜索。可以想到搜出来的内容要是没点关键词那肯定是毛用都没。
既然没办法了,那就自己手动分析处理。
先看关键函数GetSidSubAuthority,一搜知道是advapi32.dll里面的。那么来看看。代码如下
.text:77DB5550 ; PDWORD __stdcall GetSidSubAuthority(PSID pSid, DWORD nSubAuthority)
.text:77DB5550               public _GetSidSubAuthority@8
.text:77DB5550 _GetSidSubAuthority@8 proc near         ; DATA XREF: .text:off_77DA16CCo
.text:77DB5550
.text:77DB5550 pSid            = dword ptr8
.text:77DB5550 nSubAuthority   = dword ptr0Ch
.text:77DB5550
.text:77DB5550               mov   edi, edi
.text:77DB5552               push    ebp
.text:77DB5553               mov   ebp, esp
.text:77DB5555               push    0               ; dwErrCode
.text:77DB5557               call    ds:__imp__SetLastError@4 ; SetLastError(x)
.text:77DB555D               pop   ebp
.text:77DB555E               jmp   ds:__imp__RtlSubAuthoritySid@8 ; RtlSubAuthoritySid(x,x)
.text:77DB555E _GetSidSubAuthority@8 endp

还真是够简单的。啥也没有,直接就是调用 RtlSubAuthoritySid
心想这下有更进一步的关键词了。下来看看 ntkrnlpa.exe(我在xp里实验)其他环境得(ntoskrnl.exe)
看了一下导出表如下
序列 地址 名字
00000486 00456160 RtlSplay
00000487 00511E3C RtlStringFromGUID
00000488 0050BF36 RtlSubAuthorityCountSid
00000489 0050BF1E RtlSubAuthoritySid
0000048A 004562F0 RtlSubtreePredecessor
0000048B 004562CC RtlSubtreeSuccessor
0000048C 00454DDE RtlTestBit
心里想肯定就是它了。同样的方法OpenProcessToken和GetTokenInformation也可以进一步的得到
ZwOpenProcessTokenEx和ZwQueryInformationToken
于是就有了完整的代码如下:
BOOLEAN IsSystemIntegrity(HANDLE pid)
{
NTSTATUS ret;
PEPROCESS proc;
HANDLE hProcHandle;
HANDLE hToken;
BOOLEAN bSystemIntegrity = FALSE;
ULONG size;
TOKEN_MANDATORY_LABEL *pLabel;
DWORD dwIntegrityLevel = 0;

if (NT_SUCCESS(ret = PsLookupProcessByProcessId(pid, &proc)))
{
if (NT_SUCCESS(ret = ObOpenObjectByPointer(proc, OBJ_KERNEL_HANDLE, NULL, 0, *PsProcessType, KernelMode, &hProcHandle)))
{
   if (NT_SUCCESS(ret = ZwOpenProcessTokenEx(hProcHandle, TOKEN_QUERY, OBJ_KERNEL_HANDLE, &hToken)))
   {
    if (STATUS_BUFFER_TOO_SMALL == (ret = ZwQueryInformationToken(hToken, TokenIntegrityLevel, NULL, 0, &size)))
    {
   if (pLabel = ExAllocatePoolWithTag( PagedPool ,size,'_EL_'))
   {
      if (NT_SUCCESS(ret = ZwQueryInformationToken(hToken, TokenIntegrityLevel, pLabel, size, &size)))
      {
       dwIntegrityLevel = *RtlSubAuthoritySid(pLabel->Label.Sid,(DWORD)(UCHAR)(*RtlSubAuthorityCountSid(pLabel->Label.Sid)-1));
       DbgPrint(("DEMO:%-4d dwIntegrityLevel = %d.\n", __LINE__,dwIntegrityLevel));
       if (SECURITY_MANDATORY_SYSTEM_RID == dwIntegrityLevel)
      bSystemIntegrity = TRUE;
      }
      ExFreePoolWithTag(pLabel, '_EL_');
   }
    }
   }
}
}

return bSystemIntegrity;
}
HANDLE PsGetSystemSvchost()
{
NTSTATUS ret = STATUS_SUCCESS;
PSYSTEM_PROCESS_INFORMATION pInfo = NULL, buf;
ULONG len = 0;
HANDLE dwPid = 0;
ULONG os;

PsGetVersion(NULL, NULL, &os, NULL);
if (STATUS_INFO_LENGTH_MISMATCH == (ret = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, pInfo, len, &len)))
{
if (!(pInfo = (PSYSTEM_PROCESS_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, len, '_EL_')))
{
   DbgPrint(("DEMO:%-4d ExAllocatePoolWithTag failed with size %d.\n", __LINE__, len));
}
else
{
   buf = pInfo;
   if (NT_SUCCESS(ret = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, pInfo, len, &len)))
   {
    for (;;)
    {
   LPWSTR pszProcessName = pInfo->ImageName.Buffer;
   if (pszProcessName == NULL)
      pszProcessName = L"NULL";
   if (_wcsnicmp(pszProcessName,L"svchost.exe",wcslen(L"svchost.exe")) == 0)
   {
      if (os < 6000)
      {
       dwPid = pInfo->ProcessId;
       break;
      }
      else
      {
       if (IsSystemIntegrity(pInfo->ProcessId))
       {
      dwPid = pInfo->ProcessId;
      break;
       }
      }
   }
   if (!pInfo->NextEntryOffset)
      break;
   pInfo = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo) + pInfo->NextEntryOffset);
    }
   }
   ExFreePoolWithTag(buf, '_EL_');
}
}
else
{
DbgPrint(("DEMO:%-4d ZwQuerySystemInformation failed with 0x%p.\n", __LINE__, ret));
}

return dwPid;
}
事后根据自己写好的关键词去一搜索,哎呀,网上还真不少。都是自己孤漏寡闻。
写代码的事情就是这个样子,自认为需要研究的东西,或者是自己觉的很有难度的东西,曾经在n年前,都被n个大牛研究的烂了,都不稀罕研究了
写代码最大的悲哀或许就是如此~没啥成就感。。。

woshidc523 发表于 2018-2-9 15:24:16

赞一个哦楼主~
信息很详细,我感觉现在最需要提升的就是搜索能力,我搜一个知识点搜半天,同事一下就搜到了,真的是尴尬。实现代码感觉都是次要的,因为能找到相关信息就一定能弄好,只是时间问题罢了。
向楼主学习,我也要好好钻研vt(T_T)

Tesla.Angela 发表于 2018-2-10 11:23:13

这个不错,稍加改造还可以获取【该进程】【所属用户的】【所属HKCU】。

海浪人生 发表于 2018-7-2 18:09:52

很好 支持下,学习了
页: [1]
查看完整版本: [原创]驱动里获取指定PID的完整性级别(Integrity Level)