1. 数据类型的定义,一般使用重定义的方式,例如ULONG,UCHAR等,x86到x64平台,指针从4字节转变成8字节。
2. 大多数的内核API都返回一个状态,这个状态的类型为NTSTATUS。一般用宏NT_SUCCESS()来判断返回值是否成功
3. DbgPrint()输出的字符串可以在debugview下观察到
UNICODE_STRING str = RTL_CONSTANT_STRING(L”first-ddddd”);,如此定义Unicode字符串
打印unicode字符串,利用%wZ, 因为这是一个结构指针。DbgPrint(“%wZ”,&str);
4. 驱动对象
Windows内核是面向对象,但是的是C语言
驱动对象的结构
typedef struct _DRIVER_OBJECT {
// 结构的类型和大小。
CSHORT Type;
CSHORT Size;
// 设备对象,这里实际上是一个设备对象的链表的开始。因为DeviceObject
// 中有相关链表信息。读下一小节“设备对象”会得到更多的信息。
PDEVICE_OBJECT DeviceObject;
……
// 驱动的名字
UNICODE_STRING DriverName;
……
// 快速IO 分发函数
PFAST_IO_DISPATCH FastIoDispatch;
……
// 驱动的卸载函数
PDRIVER_UNLOAD DriverUnload;
// 普通分发函数
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
内核模块不是一个进程,只是一组回调函数让windows来调用
有两个概念,“普通分发函数”和“快速IO分发函数”,引申的一个概念就是分发函数的Hook技术
5. IRP和设备对象DEVICE_OBJECT
DO用来接收IRP, IRP 都是发送给设备对象的,以下是wdm.h中定义的DEVICE_OBJECT的结构
Typedef struct DECLSPEC_ALLGN(MEMORY_ALLOCATION_ALIGNMENT)
_DEVICE_OBJECT{
CSHORT Type;
USHORT Size;
// 引用计数
ULONG ReferenceCount;
// 这个设备所属的驱动对象
Struct _DRIVER_OBJECT *DriverObject;
// 指向下一个设备对象,如果驱动对象中存在n个设备时,这些设备会组成一个单向链表。
Struct _DEVICE_OBJECT *NextDevice;
// 设备类型
DEVICE_TYPE DeviceType;
// IRP栈大小
HAR StackSize
}DEVICE_OBJECT
当Windows向设备对象发送请求时,驱动对象的分发函数中的某一个会被调用。分发函数的原型如下:
第一参数是请求目标的device,第二参数irp是请求的指针
NTSTATUS MyDispatch(PDEVICE_OBJECT deivce, PIRP irp);
IRP也是一个结构,这个结构很复杂,注意IRP栈空间。一个IRP往往需要传递n个设备才能完成,在传递过程中,有可能会一些“中间变换”,导致请求参数的变化,我们给每次“中转”都保留一个“栈空间”,用来保存中间参数,所以每个函数调用IRP都会分配一个空间。
6. WDK的函数
WDK的函数根据不同的分类,有着不同的前缀名,Ndis-开头都是网络启动开发相关的函数。
相对于windows API 比较常用的函数,WDK的函数对应为
ExAllocatePool 内存分配函数,相对于CRumTime库里的malloc
ExFreePool 内存释放,相对与CRunTime库里的free
ExAcquireFastMutex,获取一个快速互斥体,用于在多线程环境下的同步。
ExReleaseFastMutex,释放一个快速互斥体
ExRasieStatus,抛出一个异常,类似try exception。
Zw-和同名的Nt-函数有着同样的功能,中间实际上是从Zw-函数到Nt-函数的简单跳转关系。
常用的函数还包括Rtl-系列函数
RtlInitUnicodeString 初始化一个unicode字符串
RtlCopyUnicodeString 拷贝字符串
RtlAppendUnicodeToString 一个字符串追加到到另一个字符串后
RtlStringCbPrintf 打印字符串到另一个字符串中,相当与sprintf
RtlCopyMemory 内存数据块拷贝
RtlMoveMemory 内存数据移动
RtlZeroMemory 内存数据清零
RtlCompareMemory 比较内存
RtlGetVersion 获得当前windows的版本
Io-系列函数涉及IO管理器,所以它一般处于更低层,
IoCreateDevice,生成一个设备对象