1. 程式人生 > >《Windows核心編程》第3章——深入理解handle

《Windows核心編程》第3章——深入理解handle

字節 參考 com 17. 文件路徑 db2 cto tro net

本文借助windbg來理解程序中的函數如何使用handle對句柄表進行查詢的。所以先要開啟Win7下Windbg的內和調試功能。

  • 解決win7下內核調試的問題
win7下debug默認無法進行內核調試(!process等命令無法使用),除非是雙機調試。或改用livekd進行調試。 嘗試http://blog.csdn.net/hutao1101175783/article/details/50522767中提出的方法,開啟windbg的內和調試功能: 技術分享圖片

重啟之後開啟Local Kernel Debugging:

技術分享圖片

技術分享圖片

開啟成功:

技術分享圖片

加載符號表之後,就可以使用!process命令了:

技術分享圖片

  • 解決windbg源碼調試的問題:

添加源文件路徑:

技術分享圖片

開啟源碼級別的調試:

技術分享圖片

給TestHandle.exe的main函數下斷點: 技術分享圖片 運行後自動彈出源碼調試:

技術分享圖片

  • 研究句柄

再開一個windbg用內核調試。!process 0 0 命令找到TestHandle.exe的信息:

技術分享圖片

查看這個進程的所有句柄信息(同時也顯示出了OBJECT的信息,來給我們提供驗證):

技術分享圖片

下面,借助對TestHandle.exe的調試我們知道38號句柄是hEvent:

技術分享圖片

查看0x38號句柄的信息(這個信息被我當做“結果”來驗證我的“推理”過程):

技術分享圖片

  • 推理步驟

查看TestHandle的EProcess結構:

技術分享圖片

得到TableCode,這個值指向一級、二級或三級句柄表(具體是幾級句柄表由末尾數決定):

技術分享圖片

根據低兩位判斷句柄表的層級。TableCode低位是1,說明是一個二級句柄表(可以參考這個文章的分析:https://www.cnblogs.com/lsh123/p/7296423.html):

技術分享圖片 這裏顯示了兩個一級句柄表。 不同級別的句柄表可以參考文章:https://www.2cto.com/kf/201609/543902.html 和圖: 技術分享圖片

那麽句柄值乘以4再加上fffff8a0`19ca8000就是指向對應的handle_table_entry://為什麽這裏要乘以4?句柄是0x38,索引就是0x38/4,又由於每個handle_table_entry的大小是16字節。那麽為什麽索引是0x38/4?後面會回答

找到對應的handle_table_entry:

技術分享圖片

其中fffffa80`11399951 就是Object指針,偏移0x30-1就可以定位到OBJECT:

技術分享圖片

因為是在64位系統下,所以偏移是0x30-1,偏移發生了變化(32位系統下就是0x17):

技術分享圖片

這樣就通過句柄取到了內核對象,整個流程思路參考了:http://www.cppblog.com/sleepwom/archive/2011/10/19/72591.html 並參考了圖片: 技術分享圖片

  • handle的類型

在WinNT.h中定義的handle是這樣的: typedef void* handle;

技術分享圖片

而DECLARE_HANDLE(HWND);就是:   struct HWND__ { int unused;};   typedef struct HWND__ *HWND; 所以DECLARE_HANDLE的作用就是將name定義為一個指向結構體的指針。 handle是一個無類型指針,而HWND是一個指向結構體的指針。 Handle是一個void存儲著一個整形數據類型作為“偽索引”。 參考:https://www.cnblogs.com/zpcdbky/p/4656449.html http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece7631046893b4c4380143fd3d1027fa3c215cc79051a0071e4cf6678475886d27b135bfc1541baae6b272a4266e4dd93d957deb0902f248b2631701c844213d719a9c84524c627935ee3aa04f3ffad72c5a1888083020d9d44050bc2b4d60156&p=c449ca5f86cc41ac52a5d02d021494&newp=81798f16d9c111a058ee9e124f43c9231610db2151d4d2116b82c825d7331b001c3bbfb423251007d7c07d6304aa4858eff6357033092ba3dda5c91d9fb4c57479&user=baidu&fm=sc&query=handle+pvoid&qid=b9f8680100001e9b&p1=5
  • 為什麽要除以4?
如果要根據句柄查找相應的handle_table_entry,就會調用這個函數: ExMapHandleToPointer ( __in PHANDLE_TABLE HandleTable, __in HANDLE Handle )

這裏的handle就是我們本例中傳入的0x38。ExMapHandleToPointer 中又會調用ExpLookupHandleTableEntry。 在使用句柄去查找進程的句柄表時會調用函數ExpLookupHandleTableEntry,其原型如下:

技術分享圖片

參數 HandleTable 是查找目標所在的 Handle table 地址,而 tHandle 是結構化的 Handle 值。參考:http://www.mamicode.com/info-detail-1539980.html handle與exhandle的關系如下: 技術分享圖片 這個 tHandle 結構將 Handle 值分為幾個部分,如下圖所示:

技術分享圖片

這個 TagBit 值占兩位(bit 0 到 bit 1),被清為 0 值。因此:tHandle.Value 值就是對齊在 4 bytes 邊界上。(出於某種原因)使用高30位作為索引來查找句柄表,低兩位的存在沒有意義。參考:https://www.cnblogs.com/ck1020/p/5897460.html

現在低兩位沒有意義不代表將來低兩位沒有意義,handle的含義和使用可能在未來發生變化。

《Windows核心編程》第3章——深入理解handle