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; }
从此山高路远,纵马扬鞭。愿往后旅途,三冬暖,春不寒,天黑有灯,下雨有伞。此生尽兴,不负勇往。