Windows内核实验:开中断&&API调用

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:指定内存池的类型,可以是NonPagedPoolPagedPoolNonPagedPool是非分页池,用于分配不能交换到磁盘的内存;PagedPool是分页池,用于分配可以交换到磁盘的内存。
  • NumberOfBytes:指定要分配的内存大小(以字节为单位)。

image-20230529210100412

image-20230529211226588

这样我们就有了内核注入的基础