Skip to content

标题: Win10的HANDLE_TABLE_ENTRY.ObjectPointerBits

https://scz.617.cn/windows/201710261442.txt

kd> dt nt!_HANDLE_TABLE_ENTRY +0x000 VolatileLowValue : Int8B +0x000 LowValue : Int8B +0x000 InfoTable : Ptr64 _HANDLE_TABLE_ENTRY_INFO +0x008 HighValue : Int8B +0x008 NextFreeHandleEntry : Ptr64 _HANDLE_TABLE_ENTRY +0x008 LeafHandleValue : _EXHANDLE +0x000 RefCountField : Int8B +0x000 Unlocked : Pos 0, 1 Bit +0x000 RefCnt : Pos 1, 16 Bits +0x000 Attributes : Pos 17, 3 Bits +0x000 ObjectPointerBits : Pos 20, 44 Bits +0x008 GrantedAccessBits : Pos 0, 25 Bits +0x008 NoRightsUpgrade : Pos 25, 1 Bit +0x008 Spare1 : Pos 26, 6 Bits +0x00c Spare2 : Uint4B

Win10的HANDLE_TABLE_ENTRY没有Object成员,只有ObjectPointerBits,为了提取对 象(头)指针,必须这样:


PHANDLE_TABLE_ENTRY ObjectTableEntry; POBJECT_HEADER ObjectHeader;

/ * 方法A * * 在PDB中VolatileLowValue类型是int64 / ObjectHeader = ( ObjectTableEntry->VolatileLowValue ) >> 16 ) & 0xFFFFFFFFFFFFFFF0;

或者

/ * 方法B / ObjectHeader = ( ( ObjectTableEntry->ObjectPointerBits ) << 4 ) | 0xFFFF000000000000;


下面讲如何逆向得到上述两种算法。

反汇编nt!ObpReferenceObjectByHandleWithTag()。Win10使用TypeIndex时有个混淆 机制涉及全局变量ObHeaderCookie。去IDA中F5,Alt-T搜"ObHeaderCookie",定位:

kd> u nt!ObpReferenceObjectByHandleWithTag+0x19e l 1 fffff800831324be 0fb6057b9eecff movzx eax,byte ptr [nt!ObHeaderCookie (fffff80082ffc340)]


index = ObHeaderCookie ^ ObjectHeader->TypeIndex ^ ( ( ObjectHeader >> 8 ) & 0xff );

上面的ObjectHeader本来不是这个名字,但我知道这个混淆算法细节,自然推断出哪 个是ObjectHeader。

然后在F5结果中向低址方向寻找对ObjectHeader的赋值操作:

kd> u nt!ObpReferenceObjectByHandleWithTag+0xe4 l 4 fffff80083132404 488bd6 mov rdx,rsi // Handle fffff80083132407 498bc9 mov rcx,r9 // HandleTable fffff8008313240a e801050000 call nt!ExpLookupHandleTableEntry fffff8008313240f 488bf8 mov rdi,rax // rdi=ObjectTableEntry

kd> u nt!ObpReferenceObjectByHandleWithTag+0x33e l 5 fffff8008313265e 488b1f mov rbx,qword ptr [rdi] // rdi=ObjectTableEntry fffff80083132661 488bcf mov rcx,rdi fffff80083132664 0f1007 movups xmm0,xmmword ptr [rdi] fffff80083132667 48c1fb10 sar rbx,10h // rbx=ObjectTableEntry->VolatileLowValue fffff800`8313266b 4883e3f0 and rbx,0FFFFFFFFFFFFFFF0h // rbx=ObjectHeader

kd> u nt!ObpReferenceObjectByHandleWithTag+0x18e l 7 fffff800831324ae 488bc3 mov rax,rbx // rbx=ObjectHeader fffff800831324b1 48c1e808 shr rax,8 fffff800831324b5 0fb6c8 movzx ecx,al // ecx=( ObjectHeader >> 8 ) & 0xff fffff800831324b8 0fb64318 movzx eax,byte ptr [rbx+18h] // eax=ObjectHeader->TypeIndex fffff800831324bc 33c8 xor ecx,eax fffff800831324be 0fb6057b9eecff movzx eax,byte ptr [nt!ObHeaderCookie] fffff800`831324c5 33c8 xor ecx,eax

nt!ObpReferenceObjectByHandleWithTag+0x33e附近的代码用C语言描述:


/ * ObjectTableEntry第1个qword低20位与ObjectHeader无关,最终结果低4位恒为0 * * 在PDB中VolatileLowValue类型是int64 / ObjectHeader = ( ObjectTableEntry->VolatileLowValue ) >> 16 ) & 0xFFFFFFFFFFFFFFF0;


不考虑符号位扩展的情况下,前述C代码等价于:


ObjectHeader = ( ( ObjectTableEntry->ObjectPointerBits ) << 20 ) >> 16;

观察到ObjectPointerBits最高位总是1,此时若考虑符号位扩展,上述C代码修正成:


ObjectHeader = ( ( ( ObjectTableEntry->ObjectPointerBits ) << 20 ) >> 16 ) | 0xFFFF000000000000;

ObjectHeader = ( ( ObjectTableEntry->ObjectPointerBits ) << 4 ) | 0xFFFF000000000000;

在C编程时,将VolatileLowValue定义成int64,直接对之进行>>,方法A更接近汇编 语义;方法B强烈依赖于ObjectPointerBits最高位总是1的事实,偏离汇编语义。不 过,可能方法B更接近源代码C语义。因为只是逆向,权当瞎猜,微软用sar指令,可 能就是让ObjectPointerBits省2个字节的意思。