windows内核编程之常用数据结构
1.返回状态
绝大部分的内核api返回值都是一个返回状态,也就是一个错误代码。这个类型为NTSTATUS.我们自己写的函数也大部分这样做。
NTSTATUS MyFunction()
{
NTSTATUS status;
….
return status;
}
如果碰到一个函数返回了奇特的NTSTATUS值,正确的方法是在WDK的头文件比如(NTSTATUS.h)中去寻找答案。
2.字符串
驱动里的字符串一般用这个结构来容纳。
typedef struct _UNICODE_STRING{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
}UNICODE_STRING *PUNICODE_STRING;
这个字符串是宽字符,是双字节。
UNICODE_STRING STR=RTL_CONSTANT_STRING(L”FIRST,HELLO WORLD!”);
DbgPrint(“%wZ”,str);
重要的数据结构
1.驱动对象
windows内核采用OO的编程方式,使用的却是C,windows内核对象是用C对OO的一种模拟。
当windows启动以后,内核对象都在内存中。如果我们在内核中写代码,则可以随意访问他们。每一个种类的内核对象都用一个结构体来表示。
typedef struct _DRIVER_OBJECT { //结构的类型和大小
CSHORT Type; CSHORT Size;
//设备对象 这里实际是一个设备对象链表的开始, PDEVICE_OBJECT DeviceObject; ULONG Flags; //这个内核对象在内核空间中的开始地址和大小 PVOID DriverStart; ULONG DriverSize; PVOID DriverSection; PDRIVER_EXTENSION DriverExtension; // // The driver name field is used by the error log thread // determine the name of the driver that an I/O request is/was bound. // UNICODE_STRING DriverName; …. // // The following section contains the optional pointer to an array of // alternate entry points to a driver for "fast I/O" support. Fast I/O // is performed by invoking the driver routine directly with separate // parameters, rather than using the standard IRP call mechanism. Note // that these functions may only be used for synchronous I/O, and when // the file is cached. // PFAST_IO_DISPATCH FastIoDispatch; // // The following section describes the entry points to this particular // driver. Note that the major function dispatch table must be the last // field in the object so that it remains extensible. // PDRIVER_INITIALIZE DriverInit; PDRIVER_STARTIO DriverStartIo; PDRIVER_UNLOAD DriverUnload; PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; } DRIVER_OBJECT; typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;
如果写一个驱动程序或一个内核,要在windows中加载,必须写这样一个结构,来告诉windows提供了哪些功能。
windows内核模块不生成一个进程,只是填写一组回调函数,让windows来调用,而且这些回调函数必须符合windows的规定。
这些回调函数主要包括上面的普通分发函数,快速分发函数。这些函数用来处理发送给这个内核模块的请求。
2.设备对象
设备对象就像WINDOWSGUI编程中的窗口,窗口是唯一可以接收消息的对象。在内核世界,大部分的消息是以请求(IRP)的方式传递,而设备对象是唯一可以接收请求的实体。
任何一个请求都是发送给某个设备对象的。
我们总是在内核程序中生成一个DO,而一个内核程序是用一个驱动对象表示的,所以一个DO总是属于一个驱动对象。
驱动对象生成多个DO,而windows向DO发请求,是被驱动对象的分发函数捕获。
在wdm.h中可以找到DO和IRP的结构定义。
常用的函数:
Zw开头的几个函数,主要用于文件操作。
在进行字符串操作的时候,Rtl-函数将会被大量用到。以Io开头的函数非常重要,因为涉及到IO管理器,IO管理器是将用户调用的API函数翻译成IRP或者将等价请求发送到内核
各个不同设备的关键组件。
ps-系列函数大多是与进程线程信息相关的。
掌握操作系统内核的体系结构,熟悉操作系统中常见的基本知识在windows中的具体体现,以及掌握系统底层的编程和调试技巧,是学习内核编程最重要的事。