标题: 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 (fffff800
82ffc340)]
index = ObHeaderCookie ^ ObjectHeader->TypeIndex ^ ( ( ObjectHeader >> 8 ) & 0xff );
上面的ObjectHeader本来不是这个名字,但我知道这个混淆算法细节,自然推断出哪 个是ObjectHeader。
然后在F5结果中向低址方向寻找对ObjectHeader的赋值操作:
kd> u nt!ObpReferenceObjectByHandleWithTag+0xe4 l 4
fffff80083132404 488bd6 mov rdx,rsi // Handle
fffff800
83132407 498bc9 mov rcx,r9 // HandleTable
fffff8008313240a e801050000 call nt!ExpLookupHandleTableEntry
fffff800
8313240f 488bf8 mov rdi,rax // rdi=ObjectTableEntry
kd> u nt!ObpReferenceObjectByHandleWithTag+0x33e l 5
fffff8008313265e 488b1f mov rbx,qword ptr [rdi] // rdi=ObjectTableEntry
fffff800
83132661 488bcf mov rcx,rdi
fffff80083132664 0f1007 movups xmm0,xmmword ptr [rdi]
fffff800
83132667 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
fffff800
831324b1 48c1e808 shr rax,8
fffff800831324b5 0fb6c8 movzx ecx,al // ecx=( ObjectHeader >> 8 ) & 0xff
fffff800
831324b8 0fb64318 movzx eax,byte ptr [rbx+18h] // eax=ObjectHeader->TypeIndex
fffff800831324bc 33c8 xor ecx,eax
fffff800
831324be 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个字节的意思。