内核编程基础
一、未导出函数的使用
WDK说明文档中只包含了内核模块导出的函数,对于未导出的函数,则不能直接使用。
如果要使用未导出的函数,只要自己定义一个函数指针,并且为函数指针提供正确的函数地址就可以使用了。有两种办法都可以获取为导出的函数地址:
- 特征码搜索
- 解析内核PDB文件
二、返回值
大部分内核函数的返回值都是NTSTATUS类型,例如
NTSTATUS PsCreateSystemThread();
NTSTATUS ZwOpenProcess();
NTSTATUS ZwOpenEvent();
这个值能说明函数执行的结果,例如
- STATUS_SUCCESS 0x00000000 成功
- STATUS_INVALID_PARAMETER 0xC000000D 参数无效
- STATUS_BUFFER_OVERFLOW 0X80000005 缓冲区长度不够
当你调用的内核函数,如果返回值不是STATUS_SUCCESS,就说明函数执行中遇到了问题,可以在ntstatus.h文件中查看
三、内核中的异常处理
Windows提供了结构化异常处理机制,一般的编译器都是支持的,如下:
__try{
//可能出错的代码
}
__except(fiter_value){
//出错要执行的代码
}
出现异常时,可根据filter_value的值来决定程序该如何执行,当filter_value的值为:
- EXCEPTION_EXECUTE_HANDLER(1),代码进入except块
- EXCEPTION_CONTINUE_SEARCH(0),不处理异常,由上一层调用函数处理
- EXCEPTION_CONTINUE_EXECUTION(-1),回去继续执行错误处的代码
四、常用的内核内存函数
五、内核字符串种类
CHAR(char)/WCHAR(wchar_t)/ANSI_STRING/UNICODE_STRING
ANSI_STRING字符串:
typedef struct _STRING
{
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
}STRING;
UNICODE_STRING字符串:
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaxmumLength;
PWSTR Buffer;
}UNICODE_STRING;
六、内核字符串常用函数、
字符串常用的功能无非就是:
创建、复制、比较以及转换等等
七、课后作业
申请一块内存,并在内存中存储GDT、IDT的所有数据。然后在DebugView中显示出来,最后释放内存
#include<ntddk.h>
#include<ntstatus.h>
VOID DriverUnload(PDRIVER_OBJECT driver)
{
DbgPrint("驱动停止运行.\r\n");
}
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{
UCHAR GDT[6];
UCHAR IDT[6];
ULONG GdtAddr, GdtLen, IdtAddr, IdtLen;
PUCHAR pBuffer = NULL;
ULONG i;
// 设置一个卸载函数,便于退出
pDriver->DriverUnload = DriverUnload;
// 读取GDT, IDT
__asm
{
sgdt fword ptr GDT
sidt fword ptr IDT
}
GdtAddr = *(PULONG)(GDT + 2);
GdtLen = *(PUSHORT)GDT;
IdtAddr = *(PULONG)(IDT + 2);
IdtLen = *(PUSHORT)IDT;
pDriver->DriverUnload = DriverUnload;
//申请内存
//参数pagepool代表是系统可用内存
PUCHAR SMemory = (PUCHAR)ExAllocatePool(PagedPool,IdtLen+GdtLen);
if (SMemory == NULL)
{
DbgPrint("申请内存失败.\r\n");
return STATUS_SUCCESS;
}
//将gdt与idt的数据赋值到自己申请的内存中
RtlMoveMemory(SMemory, (PUCHAR)GdtAddr, GdtLen);
RtlMoveMemory(SMemory + GdtLen, (PUCHAR)IdtAddr, IdtLen);
//打印表
DbgPrint("Print GDT Table:\n");
for (ULONG i = 0; i < GdtLen; i+=16)
{
DbgPrint("%08x\t%08x`%08x\t%08x`%08x\n", (ULONG)(SMemory + i), ((PULONG)(SMemory + i))[0], ((PULONG)(SMemory + i))[1], ((PULONG)(SMemory + i))[2], ((PULONG)(SMemory + i)[3]));
}
DbgPrint("Print IDT TABLE:\n");
for (ULONG i = 0; i < IdtLen; i += 16)
{
DbgPrint("%08x\t%08x`%08x\t%08x`%08x\n", (ULONG)(SMemory + GdtLen+ i), ((PULONG)(SMemory + GdtLen + i))[0], ((PULONG)(SMemory + GdtLen + i))[1], ((PULONG)(SMemory + GdtLen + i))[2], ((PULONG)(SMemory + GdtLen + i)[3]));
}
//释放内存
ExFreePool(SMemory);
return STATUS_SUCCESS;
}
运行结果截图