Windows内核实验:系统调用(system call)

Windows内核实验:系统调用(system call)

实现两个系统调用,读和申请内核空间

DWORD ReadMem(DWORD address) 
DWORD AllocMem(DWORD size)

ExAllocatePool分配一块内存或者在内核里找一块安全的内核不会用到的内存来存放指令

选取下面的空余内核内存

kd> dq @gdtr l80
8003f000 00000000`00000000 00cf9b00`0000ffff
....... SystemCallEntry
8003f120 00000000`8003f128 00000000`8003f130
8003f130 00000000`8003f138 00000000`8003f140
8003f140 00000000`8003f148 00000000`8003f150
8003f150 00000000`8003f158 00000000`8003f160
8003f160 00000000`8003f168 00000000`8003f170
8003f170 00000000`8003f178 00000000`8003f180
8003f180 00000000`8003f188 00000000`8003f190
8003f190 00000000`8003f198 00000000`8003f1a0
8003f1a0 00000000`8003f1a8 00000000`8003f1b0
8003f1b0 00000000`8003f1b8 00000000`8003f1c0
8003f1c0 00000000`8003f1c8 00000000`8003f1d0
........ ReadMem
8003f1d0 00000000`8003f1d8 00000000`8003f1e0
8003f1e0 00000000`8003f1e8 00000000`8003f1f0
8003f1f0 00000000`8003f1f8 00000000`8003f200
8003f200 00000000`8003f208 00000000`8003f210
........ AllocMem
8003f210 00000000`8003f218 00000000`8003f220
8003f220 00000000`8003f228 00000000`8003f230
8003f230 00000000`8003f238 00000000`8003f240
8003f240 00000000`8003f248 00000000`8003f250
........
8003f250 00000000`8003f258 00000000`8003f260
8003f260 00000000`8003f268 00000000`8003f270
........Service Table
8003f270 00000000`8003f278 00000000`8003f280

系统调用入口函数SystemCallEntry来通过eax的值在系统调用表Service Table里确定系统函数做系统调用

makeKernel.exe

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
enum { AD_CALLENTRY, AD_READ, AD_ALLOC };
DWORD Address[3] = { 0x8003f120 ,0x8003f1d0,0x8003f210 };
PDWORD ServiceTable = (PDWORD)0x8003f270;
PDWORD IdtAddress = (PDWORD)0x8003f508;
size_t i;
char* des;
void SystemCallEntry();
void ReadMem();
void AllocMem();
void __declspec(naked) IdtEntry() {
__asm {
push 0x30
pop fs
sti
}
des = (char*)Address[AD_CALLENTRY];
for (i = 0; i < 0xb0; i++) {
*des = ((char*)SystemCallEntry)[i];
des++;
}
des = (char*)Address[AD_READ];
for (i = 0; i < 0x40; i++) {
*des = ((char*)ReadMem)[i];
des++;
}
des = (char*)Address[AD_ALLOC];
for (i = 0; i < 0x40; i++) {
*des = ((char*)AllocMem)[i];
des++;
}
//构建系统调用表
ServiceTable[0] = Address[AD_READ];
ServiceTable[1] = Address[AD_ALLOC];
//构建21号中断为我们的系统调用入口SystemCallEntry地址
//eq 8003f508 8003ee00`0008f120
IdtAddress[0] = 0x0008f120;
IdtAddress[1] = 0x8003ee00;
__asm {
cli
push 0x3B
pop fs
iretd
}
}
void __declspec(naked) SystemCallEntry() {
__asm {
push 0x30
pop fs
sti
//中断后在内核栈里依次为 (可选出错码) r0_ret_eip r3_cs r3_eflag r3_esp r3_ss
//+0xc取出三环的esp
mov ebx, ss: [esp + 0xc]
//从三环栈里取出第一个参数给到rdi做fastcall(习惯了linux的fastcall,最后发现windows是ecx,edx懒得改了)
mov edi, ds: [ebx + 4]
//根据eax在调用表里找到函数
mov ebx, 0x8003f270
mov edx, [ebx + eax * 4]
call edx

cli
push 0x3b
pop fs
iretd
}
}
void __declspec(naked) ReadMem() {
__asm {
mov eax, ds: [edi]
ret
}
}
void __declspec(naked) AllocMem() {
__asm {
push edi
push 0
mov edx, 0x80533708
//ExAllocatePool = 0x80533708;
//ExAllocatePool是个stdcall,内平栈,不需要我们平栈
call edx
ret
}
}

void interrupt() {
__asm {
int 0x20
}
}
int main() {
if (0x401040 != (DWORD)IdtEntry) {
printf("IdtRntry address wrong");
system("pause");
exit(-1);
}
interrupt();
system("pause");
}

三环测试程序ntdll.exe

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
DWORD __declspec(naked) ReadMem(DWORD address) {
__asm {
mov eax,0//系统调用号
int 0x21
ret
}
}
DWORD __declspec(naked) AllocMem(DWORD size) {
__asm {
mov eax, 1////系统调用号
int 0x21
ret
}
}
int main() {
printf("0x%x\n",ReadMem(0x8003f00c));
printf("0x%x",AllocMem(0x10));
system("pause");
}

image-20230531153550640