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; }