Windows内核实验:开中断&&API调用
开中断
前面验证过中断后eflags寄存器的第九位IF变为0,关中断
void __declspec(naked) IdtEntry() { __asm { label: jmp label iretd } }
|
这个时候时钟中断是不起作用的,这段代码一定是卡死的,如果我们直接开中断呢
void __declspec(naked) IdtEntry() { __asm { sti label: jmp label iretd } }
|
这个时候没有卡死,但是崩溃了
这是因为内核环境不对
_KiFastCallEntry函数主要用在ring3到ring0的特权级变换,为进入和返回内核模式做准备,他在开中断前做了一些准备工作
text:00469510 _KiFastCallEntry proc near ; DATA XREF: KiLoadFastSyscallMachineSpecificRegisters(x)+24↑o .text:00469510 ; _KiTrap01+74↓o .text:00469510 .text:00469510 var_B= byte ptr -0Bh .text:00469510 .text:00469510 ; FUNCTION CHUNK AT .text:004694DD SIZE 00000026 BYTES .text:00469510 ; FUNCTION CHUNK AT .text:004697B0 SIZE 00000014 BYTES .text:00469510 .text:00469510 B9 23 00 00 00 mov ecx, 23h ; '#' .text:00469515 6A 30 push 30h ; '0' .text:00469517 0F A1 pop fs .text:00469519 8E D9 mov ds, ecx .text:0046951B 8E C1 mov es, ecx .text:0046951D 64 8B 0D 40 00 00 00 mov ecx, large fs:40h .text:00469524 8B 61 04 mov esp, [ecx+4] .text:00469527 6A 23 push 23h ; '#' .text:00469529 52 push edx .text:0046952A 9C pushf
|
最主要的时fs寄存器,其余的ds es 和用户态是一样的
.text:00469515 6A 30 push 30h ; '0' .text:00469517 0F A1 pop fs
|
fs寄存器在内核模式下指向处理器控制区(KPCR),选择子为30h。KPCR中存储了CPU本身要用的一些重要数据:GDT、IDT以及线程相关的一些信息
void __declspec(naked) IdtEntry() { __asm { push 0x30 pop fs sti label: jmp label push 0x3B pop fs iretd } }
|
这样的话,时钟中断可以工作了,但是进程是杀不死的,关机也是关不了的,调试器接管去改掉这个循环就可以
最后返回3环时要把fs再恢复
TODO
目前的所学知识还不能解释太清楚KPCR,再等等
API调用
有了上面的基础之后,我们就可以不太安全的调用内核函数了(不太安全是因为我们的内核环境构建不够完整,只构建了最基础的fs寄存器)
#include <stdio.h> #include <stdlib.h> #include <windows.h> typedef PVOID (__stdcall *EX_AllOCATEPOOl)(DWORD PoolType, SIZE_T NumberOfBytes); PVOID g_pointer; EX_AllOCATEPOOl ExAllocatePool=(EX_AllOCATEPOOl)0x80536FEC; void __declspec(naked) IdtEntry() { __asm { push 0x30 pop fs sti } g_pointer=ExAllocatePool(0,4096); __asm { push 0x3B pop fs iretd } } void interrupt() { __asm { int 0x20 } } int main() { if (0x401040 != IdtEntry) { printf("IdtRntry address wrong"); system("pause"); exit(-1); } interrupt(); printf("%p", g_pointer); system("pause"); }
|
ExAllocatePool是驱动ntkrnplpa里一个导出函数,用于在内核模式下分配内存。
PVOID ExAllocatePool( _In_ POOL_TYPE PoolType, _In_ SIZE_T NumberOfBytes );
|
PoolType
:指定内存池的类型,可以是NonPagedPool
或PagedPool
。NonPagedPool
是非分页池,用于分配不能交换到磁盘的内存;PagedPool
是分页池,用于分配可以交换到磁盘的内存。
NumberOfBytes
:指定要分配的内存大小(以字节为单位)。
这样我们就有了内核注入的基础