ObpLookupDirectoryEntryEx函数逆向分析

0x00前言

操作系统:windows 11

工具:vs,IDA,windbg

这是《深入解析Windows Kenrel》系列文章的第3章对象管理

0x01逆向分析

这个函数主要查询指定的目录对象中是否包含某对象

函数原型

__int64 __fastcall ObpLookupDirectoryEntryEx(
        PADAPTER_OBJECT DmaAdapter,             // 被搜索的目录对象
        unsigned __int16 *a2,                   // 要搜索的名字
        char a3,                                // 是否区分大小写
        __int64 a4,                             // 是否查询shaow目录
        char a5,                                // shaow结构体
        __int64 a6)                             // 查询详细信息结构通过这个返回

ida伪代码分析

__int64 __fastcall ObpLookupDirectoryEntryEx(
        PADAPTER_OBJECT DmaAdapter,             // 被搜索的目录对象
        unsigned __int16 *a2,                   // 要搜索的名字
        char a3,                                // 是否区分大小写
        __int64 a4,                             // 是否查询shaow目录
        char a5,                                // shaow结构体
        __int64 a6)                             // 查询详细信息通过这个返回
{
  unsigned __int16 *v6; // rdi
  char v7; // r12
  bool v9; // r14
  unsigned int v10; // r11d
  unsigned __int64 v12; // rbx
  unsigned int v13; // r10d
  int v14; // r10d
  unsigned int v15; // edx
  int v16; // r10d
  __int64 v17; // rdx
  __int64 v18; // rsi
  __int64 v20; // r10
  __int64 v21; // rax
  __int128 v22; // rt0
  struct _DMA_ADAPTER *ShadowDirectory; // rbx
  __int64 v24; // r9

  v6 = (unsigned __int16 *)*((_QWORD *)a2 + 1); // name内容
  v7 = a4;
  v9 = (a3 & 0x40) != 0;                        // 是否区分大小写  64
  v10 = *a2 >> 1;                               // 宽字节  /2代表真实长度
  if ( v10 < 4 )
  {
    v13 = 0;                                    // hash值
  }
  else
  {
    v12 = 0i64;
    do
    {
      a4 = *(_QWORD *)v6;
      if ( (*(_QWORD *)v6 & 0xFF80FF80FF80FF80ui64) != 0 )
      {
        v20 = 4i64;
        do
        {
          v21 = (unsigned __int16)a4;
          if ( (unsigned __int16)a4 >= 0x61u )
          {
            if ( (unsigned __int16)a4 <= 0x7Au )
              v21 = (unsigned int)(unsigned __int16)a4 - 32;
            else
              v21 = (unsigned __int16)NLS_UPCASE((unsigned __int16)a4);
          }
          *(_QWORD *)&v22 = a4;
          *((_QWORD *)&v22 + 1) = v21;
          a4 = v22 >> 16;
          --v20;
        }
        while ( v20 );
      }
      else
      {
        a4 &= 0xFFDFFFDFFFDFFFDFui64;
      }
      v6 += 4;
      v10 -= 4;
      v12 = a4 + (v12 >> 1) + 3 * v12;
    }
    while ( v10 >= 4 );
    v13 = v12 + HIDWORD(v12);
  }
  while ( v10 )                                 // v10 真实长度
  {
    v15 = *v6;                                  // name的buffer
    v16 = (v13 >> 1) + 3 * v13;
    ++v6;
    --v10;
    if ( v15 < 0x61 )                           // 小于字符a 
      goto LABEL_12;
    if ( v15 > 0x7A )                           // 大于字符z
    {
      a4 = (unsigned __int16)NLS_UPCASE((unsigned __int16)v15);// hash值计算
      v13 = a4 + v14;
    }
    else
    {
      v16 -= 32;                                // 确保不是小写字母
LABEL_12:
      v13 = v15 + v16;
    }
  }
  LOBYTE(a4) = v9;                              // 是否忽略大小写
  *(_DWORD *)(a6 + 24) = v13;                   // context 参数的values 和index项
  *(_WORD *)(a6 + 28) = v13 % 0x25;             // hash表的大小是37
  v18 = ObpLookupDirectoryUsingHash(DmaAdapter, a2, a6, a4);// 返回判断是否找到这个对象
  if ( !v18 && v7 )                             // 没找到的话再去shadow 找
  {
    do
    {
      LOBYTE(v17) = a5;                         // shadow结构体
      ShadowDirectory = (struct _DMA_ADAPTER *)ObpGetShadowDirectory(DmaAdapter, v17);// 一直到找到为止
      if ( ShadowDirectory )                    // 是否可以
      {
        if ( *(_BYTE *)(a6 + 30) )
        {
          ObfReferenceObject(DmaAdapter);       // 增加引用计数
          ObpUnlockDirectory(DmaAdapter, a6);
          ObpLockDirectoryShared(a6, ShadowDirectory);
          HalPutDmaAdapter(DmaAdapter);
        }
        LOBYTE(v24) = v9;
        v18 = ObpLookupDirectoryUsingHash(ShadowDirectory, a2, a6, v24);
      }
      DmaAdapter = ShadowDirectory;
    }
    while ( !v18 && ShadowDirectory );
  }
  return v18;
}

过程比较简单主要unicode 字符串对比在

ObpLookupDirectoryUsingHash 函数实现
void *__fastcall ObpLookupDirectoryUsingHash(__int64 a1, const UNICODE_STRING *a2, __int64 a3, BOOLEAN a4)
{
  char v5; // bp
  __int64 **v9; // rsi
  __int64 *v10; // rdi
  int v11; // r15d
  void *v12; // rdi
  struct _DMA_ADAPTER *v13; // rcx
  void *result; // rax

  v5 = *(_BYTE *)(a3 + 30);
  v9 = (__int64 **)(a1 + 8i64 * *(unsigned __int16 *)(a3 + 28));
  if ( !v5 )
    ObpLockDirectoryShared(a3, a1);             // 是否有锁
  v10 = *v9;
  if ( !*v9 )
    goto LABEL_15;
  v11 = *(_DWORD *)(a3 + 24);                   // 长度
  do
  {
    if ( *((_DWORD *)v10 + 4) == v11            // 长度和内容一样
      && RtlEqualUnicodeString(                 // 比较2个unicode 是否相等
           a2,
           (PCUNICODE_STRING)(v10[1] - 48 - ObpInfoMaskToOffset[*(_BYTE *)(v10[1] - 48 + 26) & 3] + 8),
           a4) )
    {
      break;
    }
    v9 = (__int64 **)v10;                       // 强转2级指针
    v10 = (__int64 *)*v10;                      // 下一个节点
  }
  while ( v10 );
  if ( v10 )                                    // 是否找到了
  {
    v12 = (void *)v10[1];                       // object 对象
    ObfReferenceObject(v12);                    // 增加引用计数
    if ( !v5 )
    {
      ObpUnlockDirectory(a1, a3);               // 解封
      v9 = 0i64;
    }
    v13 = *(struct _DMA_ADAPTER **)(a3 + 8);
    if ( v13 )
      HalPutDmaAdapter(v13);
    *(_QWORD *)(a3 + 8) = v12;                  // a3 out参数
    result = v12;
    *(_QWORD *)(a3 + 16) = v9;                  // 返回值
  }
  else
  {
LABEL_15:
    if ( !v5 )
      ObpUnlockDirectory(a1, a3);
    return 0i64;
  }
  return result;
}

 

posted @ 2022-03-19 19:43  紅人  阅读(90)  评论(0编辑  收藏  举报