Windows內核分析索引目錄:https://www.cnblogs.com/onetrainee/p/11675224.html
KPCR
1. IRQL
2. nt!KeNumberProcessors與nt!KiProcessorBlock
3. KPCR+0x34 KdVersionBlock
4. KeSetSystemAffinityThread() KeRevertToUserAffinityThread() 修改親核性
5. DPC - 主要用於看門狗
6. MiProcessLoaderEntry
7.幾個比較重要的知識點
1. IRQL
在32位存儲在KPCR+0x24中,但在64位存儲在CR8寄存器中,這個要明確。
IRQL 表示代碼運行到什么級別,之后我們會詳細說明的。
2. nt!KeNumberProcessors與nt!KiProcessorBlock
KeNumberProcessors 顯示存在幾核CPU,要查看可以通過這個查看。
KiProcessorBlock 顯示其對應的KPCRB結構體的地址,注意 KPCR+0x120其指向KPCRB,因此獲取KPCR要x-0x120。
其中KeNumberProcessors是導出變量,直接導出使用即可。
但是KiProcessorBlock需要手動尋找,其搜索路徑如下,之后在代碼中我們會在多核環境下遍歷該KPCR數組。
注意:該結構僅在0號CPU中運行,因此如果查找該結構,必須通過KeSetSystemAffinityThread()切換CPU到0號,然后再來查找有關CPU。
3. KPCR+0x34 KdVersionBlock
該成員指向一個_DBGKD_GET_VERSION64結構體(其也存在*32后綴的結構體,但是在XP以后都為_DBGKD_GET_VERSION64,其與操作系統位數無關)。
其存在兩個重要的成員:ntoskrl.exe模塊基址,模塊加載鏈表。 我們之前講到過使用NtQuerySystem和特征碼搜索,現在又多了一種方法,這個是要明確的。
4. KeSetSystemAffinityThread() KeRevertToUserAffinityThread() 修改親核性
KeSetSystemAffinityThread 當前代碼跑到幾號核CPU上,設置為多少就跑到多少核上。
KeRevertToUserAffinityThread 恢復到原來正在跑的線程。
5. DPC - 主要用於看門狗
模擬鍵盤時,1分鍾可以插入1000次,DPC級別,其DPC級別太高,則會讓線程一直來處理DPC。
Windows操作系統設置了DPC看門狗,當運行DPC超過多少時間,就會造成藍屏。
因此在寫模擬鍵盤鼠標時,不要插入太多,同時也不要寫延遲,這個要明確。
6. MiProcessLoaderEntry
我們在驅動隱藏時看到這個函數,將驅動從鏈表中卸載,也同樣可以卸載進程和線程,注意其傳入的是一個鏈表,這個我們在之后的實驗中會看到。
7.幾個比較重要的知識點
1)調用MiProcessLoaderEntry可以實現進程斷鏈,之前我們實現驅動斷鏈隱藏,但是同樣的,在這里也可以實現進程斷鏈。
2)通過在2中講到的nt!KiProcessorBlock,可以在多線程下遍歷全部KPCR的數據,其代碼如下:
// 遍歷全部核的KPCR NTSTATUS TraversProcessors() { // 先設置為0號CPU KeSetSystemAffinityThread(0); // 找到KiProcessorBlock,其kpcrb的數組 PDBGKD_GET_VERSION64 pVersion; _asm { mov eax, dword ptr fs: [0x34] ; mov pVersion, eax; } PULONG pDataList = (ULONG)pVersion->DebuggerDataList; PULONG kpcrb = (PULONG)*(PULONG)((PUCHAR)*(pDataList)+0x218); // 開始遍歷各個kpcrb中的元素找到對應的數據 for (int i = 0; i < KeNumberProcessors; i++) { PULONG CurrentKPCRB = kpcrb[i]; DbgPrint("kpcrb:%x %p\r\n", kpcrb[i],kpcrb); DbgPrint("第%x號CPU的IDT表地址為:%x,GDT表地址為:%x\r\n",i, MACRO_GETIDTBYKPCR(kpcrb[i]),MACRO_GETGDTBYKPCR(kpcrb[i])); } // 恢復原來的核號 KeRevertToUserAffinityThread(); return STATUS_SUCCESS; }