私有句柄表(内核对象,并非用户对象),全局句柄表
文章目錄
- 私有句柄表
- 1.什么是句柄(內核對象)
- 2.為什么要有句柄?
- Windows設計理念:
- 3.句柄表在哪?
- 全局句柄表
- 注意
私有句柄表
1.什么是句柄(內核對象)
當一個進程創建或者打開一個內核對象時,將獲得一個句柄,通過這個句柄可以訪問內核對象
(注意:這里所說的句柄往往對應一個內核對象,調用窗口相關的函數時,也會得到所謂的句柄,但是那種句柄和這里所說的句柄是兩回事,這里所說的句柄一定對應一個內核對象,而且這個內核對象其實也就是一個結構體,在0環才能夠進行讀寫的。并非普通窗口,筆刷,字體等對象的句柄,這種對象我們通常稱為用戶對象,并非內核對象)
如:
HANDLE g_hMutex=::CreateMutex(NULL,FALSE,“XYZ”)
HANDLE g_hMutex=::OpenMutex(MUTEX_ALL_ACCESS,FALSE,“XYZ”)
HANDLE g_hEvent=::CreateEvent(NULL,TRUE,FALSE,NULL)
HANDLE g_hThread=::CreateThread(NULL,0,NULL,0,NULL)
2.為什么要有句柄?
句柄存在的目的是為了避免在應用層直接修改內核對象
HANDLE g_hEvent=::CreateEvent(NULL,TRUE,FALSE,NULL)
如果g_hEvent存儲的就是EVENT內核對象的地址,那么就意味著我們可以在應用層修改這個地址,一旦指向了無效的內核內存地址就會藍屏
如果我們在3環訪問一個無效地址,那么最多也就是程序退出。
Windows設計理念:
1.隱藏內核對象指針
2.句柄就是個索引
(每個進程都有一個的表,用來存放進程創建或者打開(Open并不會創建新的內核對象,而是直接返回這個內核對象的地址,然后在表中創建一個索引值)的內核對象的句柄值,)
然后把這個在0環創建的句柄表中的索引值,返回給3環去使用。
3.句柄表在哪?
dt _EPROCESS
+0x0c4 ObjectTable :_HANDLE_TABLE
dt _HANDLE_TABLE
+0x000 TableCode (句柄表地址)
+0x004 QuotaProcess
+0x008 UniqueProcessId
+0x00c HandleTableLock
+0x01c HandleTableList
實際測試:
運行結果
找到當前進程EPROCESS中的_HANDLE_TABLE
然后查看TableCode
684是個索引,需要用684/4=1A1(因為是以4為單位的(為了這個函數保證在其它情況下能用)),但句柄表里的句柄成員每個是8字節,
算法也就是 0xe1cf6000+1A1*8
如下圖,轉換為8個字節為一組的句柄表值
(因為是使用打開的方式并非使用創建的方式,所以內核對象都是同一個,所以地址都一樣)
下面接下來解釋一下,3環的函數對句柄表中表項的操作
(1)這一塊共兩個字節,低字節保留位恒為0,高字節是給SetHandleInformation這個函數用的,比如寫成函數SetHandleInformation(Handle,HANDLE_FLAG_PROTECT_FROM_CLOSE,HANDLE_FLAG_PROTECT_FROM_CLOSE),那么這個位置將會被寫入0x02;
HANDLE_FLAG_PROTECT_FROM_CLOSE宏的值為0x00000002,取最低字節,最終(1)這塊是0x0200
(2)這塊是訪問掩碼,是給OpenProcess這個函數用的
OpenProcess(dwDesiredAccess,BInheritHandle,dwProcessId);具體的存的就是這個函數的第一個參數的值
(3)和(4)這兩塊共計四個字節,其中bit0-bit2存的是這個句柄的屬性,其中bit2 bit0 默認為0,1;bit1表示的函數是該句柄是否可繼承;OpenProcess的第二個參數與bit1有關;
bit31-bit3則是存放的該內核對象在內核中的具體的地址
真正的內核對象都是以OBJECT_HEADER開頭的,也就是說,以前我們所看到的EPROCESS,ETHREAD都不是完整的內核對象,而是需要再加0x18的OBJECT_HEADER的頭
句柄表中指向的內核進程對象(即EPROCESS)的值,把低三位清掉,即0x86050d48,這個地址指向的是有0x18的OBJECT_HEADER頭的EPROCESS內核對象。因為程序中是OpenProcess,所以是EPROCESS內核對象
0x174偏移是進程名,毫無疑問,正確
提示:利用句柄表可以做出反調試,掃描全部進程的句柄表,觀察句柄表中是否有指向此進程的EPROCESS內核對象的地址,有的話那就說明此進程被打開(正在被調試。。)
全局句柄表
1.所有的進程和線程無論是否打開,都在這個表中。
2.每個進程和線程都有一個唯一的編號:PID和CID,這兩個值其實就是全局句柄表中的索引,
進程和線程得到查詢,主要是以下三個函數,按照給定的PID和CID從PspCidTable從查找響應的進線程對象:
PsLookupProcessThreadByCid()
PsLookupProcessProcessId()
PsLookupThreadByThreadId()
句柄表結構
如果為1級句柄表的話,那么TableCode低2位為0((4KB)個數最多512個)
如果為2級句柄表的話,那么TableCode低2位為1(第一級存儲的都是一個地址,也就是第一級可以存儲1024個地址,第二級存儲真正句柄信息,也就是可以存1024X512個)
如果為3級句柄表的話,那么TableCode低2位為2(第一級存儲的都是一個地址,第二級存儲的都是一個地址,第三級存儲真正句柄信息,句柄數量也就是1024X1024X512個)
首先通過全局變量PspCidTable查找全局句柄表
然后通過_HANDLE_TABLE查看
找到了TableCode后直接進入
然后假如PID是1044
那么1044/4=261,索引也就是261,轉換成16進制后是0x105
然后0x105乘以8
值為0x86201781,去掉低3位為0x86201780,它直接指向了EPROCESS,沒有OBJECT_HEADER頭結構
注意
全局句柄表和私有句柄表有差異,私有句柄表中指向的是帶有OBJECT_HEADER頭的內核對象,但是全局句柄表中指向的并沒有帶OBJECT_HEADER頭
總結
以上是生活随笔為你收集整理的私有句柄表(内核对象,并非用户对象),全局句柄表的全部內容,希望文章能夠幫你解決所遇到的問題。