在 Phate 上看見了 asusp4b533 大大的對於 Handle Tree 的文章後
便想自己實際演練一次並存起來, 當作日後我可以方便的複習

首先每一個 Process 都會有一個叫做 _EPPROCESS 的 Structure
( 當然你可以使用 !process 發現 _EPPROCESS 實際的 Address )

而在這個 _EPPROCESS + 0x0c4 就指向了一個 ObjectTable
其實這個 ObjectTable 也就是 Handle Table

假設 Handle Table 上 的位置是 0xe1a4f178
則我可以 dt _HANDLE_TABLE 0xe1a4f178 得到下面的結果


nt!_HANDLE_TABLE
+0x000 TableCode : 0xe12b5000
+0x004 QuotaProcess : 0x81acd500 _EPROCESS
+0x008 UniqueProcessId : 0x00000880
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY [ 0x8055c4c8 - 0xe1243a5c ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : (null)
+0x02c ExtraInfoPages : 0
+0x030 FirstFree : 0x144
+0x034 LastFree : 0
+0x038 NextHandleNeedingPool : 0x800
+0x03c HandleCount : 79
+0x040 Flags : 0
+0x040 StrictFIFO : 0y0

上面這個結果最重要的就是 TableCode 了, 他代表了一個指向 Handle Tree 的 Address
由於 Alignment 的關係, 實際上的 Handle Tree 位置應該要做一個 addr &= 0xfffffffc 的處理
它的最低兩個 bit 代表了整顆 Tree 總共有幾層 (1 ~ 3 層)
Handle Tree 的三層是這樣定義的9 ]: n: A7 \. }1 ~) \
最低層定義為一個 HANDLE_TABLE_ENTRY 的陣列,共有512個
8 x3 k6 B& d3 r" R5 Z中間層定義為一個 ULONG 的陣列,共2048個,每個元素存著一個位址,指向一個最低層陣列
1 C& n! p+ D5 ^) a  m最高層也是個 ULONG 陣列,共32個,每個元素存著一個位址,指向一個中間層陣列8 J" S8 Y( f- ^$ `. \  ?
而在 Handle 的 32 bits 裡面
0 ~ 1 的 bit 是忽略的
2 ~ 10 的 bit 儲存著最低層陣列的 Index
2 Z/ n2 d  @8 l) P1 W' I( N11 ~ 20 的 bit 儲存中間層陣列的 Index# c, j9 y3 u& M
21 ~ 25 的 bit 儲存最高層陣列的 Index

如果 TableCode 的低 2 bit 為 0,代表只有一層,那麼 TableCode 便指向最低層陣列
' @2 c$ a' q, j  M3 ]& s" t, C若為 1,那麼便指向中間層陣列! W( B* t/ [2 v" c
若為 2,那麼便指向最高層陣列

從上面得知了我的 Tree Address 應該為 0xe12b5000, 所以再 dt _HANDLE_TABLE_ENTRY 0xe12b5000
則我可以得到下面的結果

nt!_HANDLE_TABLE_ENTRY
+0x000 Object : (null)
+0x000 ObAttributes : 0
+0x000 InfoTable : (null)
+0x000 Value : 0
+0x004 GrantedAccess : 0xfffffffe
+0x004 GrantedAccessIndex : 0xfffe
+0x006 CreatorBackTraceIndex : 0xffff
+0x004 NextFreeTableEntry : -2

可以發現這個是個無效的 Entry, 這是由於 Windows 不使用第一個 Entry
但是這整個 Entry 是在一塊連續的空間上, 所以可以很容易得到第二個 Entry
所以再 dt _HANDLE_TABLE_ENTRY 0xe12b5008, 可以得到

nt!_HANDLE_TABLE_ENTRY
+0x000 Object : 0xe1006fd9
+0x000 ObAttributes : 0xe1006fd9
+0x000 InfoTable : 0xe1006fd9 _HANDLE_TABLE_ENTRY_INFO
+0x000 Value : 0xe1006fd9
+0x004 GrantedAccess : 0xf0003
+0x004 GrantedAccessIndex : 3
+0x006 CreatorBackTraceIndex : 0xf
+0x004 NextFreeTableEntry : 983043

上面的結果顯示了 Object 的位址是 0xe1006fd8 ( 0xe1006fd9 & 0xfffffffc )
再來要加上 0x18 的 Offset 才能取得真正的 Object Body
所以實際上的 Object Body 位址是 0xe1006ff0 ( 加 0x18 的原因看下面 )

nt!_OBJECT_HEADER
+0x000 PointerCount : Int4B
+0x004 HandleCount : Int4B
+0x004 NextToFree : Ptr32 Void
+0x008 Type : Ptr32 _OBJECT_TYPE
+0x00c NameInfoOffset : UChar
+0x00d HandleInfoOffset : UChar
+0x00e QuotaInfoOffset : UChar
+0x00f Flags : UChar
+0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : Ptr32 Void
+0x014 SecurityDescriptor : Ptr32 Void
+0x018 Body : _QUAD


所以顯示出這個 Object 來看看 ( !object e1006ff0 ), 得到

Object: e1006ff0 Type: (81bb9e70) KeyedEvent
ObjectHeader: e1006fd8 (old version)
HandleCount: 24 PointerCount: 25
Directory Object: e10015f0 Name: CritSecOutOfMemoryEvent

所以我可以根據 HANDLE 的數值取得一個最低層陣列的 Index
就可以取得最後一個 Object ( 它會跟 !handle 的內容完全一樣 )

下面這是 asusp4b533 大大的 Code

ULONG HighLevelTableIndex;
ULONG MidLevelTableIndex;
ULONG LowLevelTableIndex;
PVOID pHandleTable;
ULONG TableCode;
PULONG pHighLevelTable;
PULONG pMidLevelTable;
PHANDLE_TABLE_ENTRY pLowLevelTable;
ULONG HandleValue;
HighLevelTableIndex=((ULONG)Handle & 0x3e00000)/0x200000;
MidLevelTableIndex=((ULONG)Handle & 0x1ff800)/0x800;
LowLevelTableIndex=((ULONG)Handle & 0x7fc)/0x4;
pHandleTable=(PVOID)*(PULONG)((ULONG)PsInitialSystemProcess+EPROCESS_ObjectTable);
TableCode=*(PULONG)pHandleTable;
switch(TableCode & 3){
   case 0:
     pLowLevelTable=(PHANDLE_TABLE_ENTRY)(TableCode & 0xfffffffc);
     *pObject=(PVOID)(((ULONG)pLowLevelTable[LowLevelTableIndex].Object & 0xfffffff8)-OBJECT_HEADER_OFFSET);
     break;
   case 1:
     pMidLevelTable=(PULONG)(TableCode & 0xfffffffc);
     pLowLevelTable=(PHANDLE_TABLE_ENTRY)pMidLevelTable[MidLevelTableIndex];
     *pObject=(PVOID)(((ULONG)pLowLevelTable[LowLevelTableIndex].Object & 0xfffffff8)-OBJECT_HEADER_OFFSET);
     break;
   case 2:
     pHighLevelTable=(PULONG)(TableCode & 0xfffffffc);
     pMidLevelTable=(PULONG)pHighLevelTable[HighLevelTableIndex];
     pLowLevelTable=(PHANDLE_TABLE_ENTRY)pMidLevelTable[MidLevelTableIndex];
     *pObject=(PVOID)(((ULONG)pLowLevelTable[LowLevelTableIndex].Object & 0xfffffff8)-OBJECT_HEADER_OFFSET);
     break;
   default:
     return STATUS_UNSUCCESSFUL;
     break;
 }
 return STATUS_SUCCESS;

arrow
arrow
    全站熱搜

    kloerhe 發表在 痞客邦 留言(0) 人氣()