欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

(34)内核编程基础

程序员文章站 2022-07-14 16:26:10
...

一、未文档化函数、未导出函数

未文档化就是WDK文档里搜不到,但是在导出表里的函数,要使用这种函数可以使用GetProcAddress函数获取函数地址;

未导出函数就是不在导出表的函数,可以通过特征码搜索或者解析内核PDB的方式找到函数地址,通过函数指针调用。

二、WDK数据类型

WDK数据类型在ntdef.h中定义,下面列举部分,注意,并没有UINT

typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned long ULONG;

三、NTSTATUS 返回值

很多内核函数的返回值都是 NTSTATUS,这是一个4字节整型。
例如:

STATUS_SUCCESS		0x00000000	成功		
STATUS_INVALID_PARAMETER	0xC000000D	参数无效	
STATUS_BUFFER_OVERFLOW	0x80000005	缓冲区长度不够

四、内核异常处理

在内核中,一个小小的错误就可能导致蓝屏,比如:读写一个无效的内存地址。为了让自己的内核程序更加健壮,强烈建议大家在编写内核程序时,使用异常处。
Windows提供了结构化异常处理机制,一般的编译器都是支持的,如下:

__try{
	//可能出错的代码
}
__except(filter_value) {
	//出错时要执行的代码
}

出现异常时,可根据filter_value的值来决定程序该如果执行,当filter_value的值为:
EXCEPTION_EXECUTE_HANDLER(1),代码进入except块
EXCEPTION_CONTINUE_SEARCH(0),不处理异常,由上一层调用函数处理
EXCEPTION_CONTINUE_EXECUTION(-1),回去继续执行错误处的代码

用一段代码演示:

__try
{
	PULONG ptr = NULL;
	*ptr = 0x1234;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{		
	DbgPrint("非法访问内存.\r\n");
}

(34)内核编程基础

五、常用的内核内存函数

C语言 内核
malloc ExAllocatePool
memset RtlFillMemory
memcpy RtlMoveMemory
free ExFreePool

六、内核字符串及常用字符串函数

为了提高安全性,内核中的字符串不再是字符串首地址指针作为开始,0作为结尾,而是采用了以下两个结构体:

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;

下面的表格列出了常用的字符串函数:

功能 ANSI_STRING字符串 UNICODE_STRING字符串
创建 RtlInitAnsiString RtlInitUnicodeString
复制 RtlCopyString RtlCopyUnicodeString
比较 RtlCompareString RtlCompareUnicoodeString
转换 RtlAnsiStringToUnicodeString RtlUnicodeStringToAnsiString

七、课后练习

1、申请一块内存,并在内存中存储GDT、IDT的所有数据。然后在debugview中显示出来,最后释放内存。

#include <ntddk.h>
#include <ntdef.h>

// 卸载函数
VOID DriverUnload(PDRIVER_OBJECT driver)
{
	DbgPrint("驱动程序停止运行了.\r\n");	
}

// 入口函数,相当于main
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{	
	UCHAR GDT[6];
	UCHAR IDT[6];
	ULONG GdtAddr,GdtLen,IdtAddr,IdtLen;
	PUCHAR pBuffer = NULL;
	ULONG i;
	// 设置一个卸载函数,便于退出
	driver->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;
	// DbgPrint("GDT: %08X size: %04X\r\n", GdtAddr, GdtLen);
	// DbgPrint("IDT: %08X size: %04X\r\n", IdtAddr, IdtLen);
	// 申请内存
	pBuffer = (PUCHAR)ExAllocatePool(PagedPool, GdtLen + IdtLen);
	// 检查申请是否成功
	if (NULL == pBuffer)
	{
		DbgPrint("申请内存失败.\r\n");
		return STATUS_UNSUCCESSFUL;
	}
	// 拷贝GDT, IDT数据
	RtlMoveMemory(pBuffer, (PUCHAR)GdtAddr, GdtLen);
	RtlMoveMemory(pBuffer + GdtLen, (PUCHAR)IdtAddr, IdtLen);
	// 打印数据
	DbgPrint("打印GDT\r\n");
	for (i = 0; i < GdtLen; i += 16)
	{
		DbgPrint("%08X  %08X %08X %08X %08X\r\n", GdtAddr + i, ((PULONG)(GdtAddr + i))[0],((PULONG)(GdtAddr + i))[1],((PULONG)(GdtAddr + i))[2],((PULONG)(GdtAddr + i))[3]);
	}
	DbgPrint("打印IDT\r\n");
	for (i = 0; i < IdtLen; i += 16)
	{
		DbgPrint("%08X  %08X %08X %08X %08X\r\n", IdtAddr + i, ((PULONG)(IdtAddr + i))[0],((PULONG)(IdtAddr + i))[1],((PULONG)(IdtAddr + i))[2],((PULONG)(IdtAddr + i))[3]);
	}
	// 释放内存
	ExFreePool(pBuffer);		
	
	return STATUS_SUCCESS;
}

(34)内核编程基础

2、编写代码,实现如下功能:

<1> 初始化一个字符串

<2> 拷贝一个字符串

<3> 比较两个字符串是否相等

<4> ANSI_STRING与UNICODE_STRING字符串相互转换

不知为何,Unicode字符串中如果有中文,dbgview和windbg打印出来是空白。

#include <ntddk.h>
#include <ntdef.h>

// 卸载函数
VOID DriverUnload(PDRIVER_OBJECT driver)
{
	DbgPrint("驱动程序停止运行了.\r\n");	
}

// 入口函数,相当于main
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{	
	// 创建字符串
	ANSI_STRING AnsiSrc;
	ANSI_STRING AnsiDst;
	UNICODE_STRING UnicodeString;
	// 初始化字符串	
	RtlInitAnsiString(&AnsiSrc,"my first ANSI_STRING");
	RtlInitUnicodeString(&UnicodeString,L"my first UNICODE_STRING");
	// 打印字符串
	DbgPrint("%s Length: %d MaximumLength: %d\r\n", AnsiSrc.Buffer, AnsiSrc.Length, AnsiSrc.MaximumLength);
	DbgPrint("%ws Length: %d MaximumLength: %d\r\n", UnicodeString.Buffer, UnicodeString.Length, UnicodeString.MaximumLength);
	// 拷贝字符串
	RtlCopyString(&AnsiDst, &AnsiSrc);
	// 比较字符串
	if (RtlCompareString(&AnsiSrc, &AnsiDst, TRUE) == 0)
	{
		DbgPrint("字符串相等.\r\n");
	}
	else
	{
		DbgPrint("字符串不相等.\r\n");
	}
	// Unicode转Ansi
	DbgPrint("Unicode转Ansi\r\n");
	RtlUnicodeStringToAnsiString(&AnsiDst,&UnicodeString,TRUE);	
	DbgPrint("%s Length: %d MaximumLength: %d\r\n", AnsiDst.Buffer, AnsiDst.Length, AnsiDst.MaximumLength);
	// 设置一个卸载函数,便于退出
	driver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

(34)内核编程基础

相关标签: Windows内核