内核开发知识第一讲.内核中的数据类型.重要数据结构.常用内核API函数.
2018-08-16 18:54
369 查看
一丶内核中的数据类型
在内核中.程序的编写不能简单的用基本数据类型了. 因为操作系统不同.很有可能造成数据类型的长度不一.而产生重大问题.所以在内核中.数据类型都一定重定义了.
数据类型 | 重定义数据类型 |
Unsigned long | ULONG |
Unsigned char | UCHAR |
Unsigned int | UINT |
Void | VOID |
Unsigned long * | PULONG |
Unsigned char * | PCHAR |
Unsigned int * | PUINT |
Void * | PVOID |
typedef struct _UNICODE_STRING{ USHORT Length //字符串长度 USHORT MaximumLength //字符串最大长度 PWSTR Buffer; //字符串指针 }UNICODE_STRING, *PUNICODE_STRING
typedef struct _STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } ANSI_STRING, *PANSI_STRING;
其中操作字符串都有相应的Kerner API. 可以查询MSDN 或者 WDK Document 进行操作.
二丶内核中的重要数据结构.
IRP请求会发送给设备对象.然后驱动对象会捕获.通过分发函数进行处理. 一个驱动对象可以有多个设备对象.在内核中. 有驱动对象.设备对象. 以及IRP请求.
驱动对象数据结构
typedef struct _DRIVER_OBJECT { CSHORT Type; //类型 CSHORT Size; //大小. PDEVICE_OBJECT DeviceObject; //设备对象链表开始,一个驱动对象可以有多个设备对象.其中DeviceObject结构体中有相关信息. ULONG Flags; PVOID DriverStart; //内核模块在内核中间的开始地址跟大小. ULONG DriverSize; PVOID DriverSection; PDRIVER_EXTENSION DriverExtension; UNICODE_STRING DriverName;//驱动的名字 PUNICODE_STRING HardwareDatabase; //快速IO分发函数. PFAST_IO_DISPATCH FastIoDispatch; 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;
设备对象数据结构
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT { CSHORT Type; //类型跟大小. USHORT Size; //引用计数 LONG ReferenceCount; //这个设备所属于驱动对象的指针. 保存了驱动对象. struct _DRIVER_OBJECT *DriverObject; //下一个设备对象.一个驱动对象可以有n个设备.用单向链表进行连接. struct _DEVICE_OBJECT *NextDevice; struct _DEVICE_OBJECT *AttachedDevice; struct _IRP *CurrentIrp; PIO_TIMER Timer; ULONG Flags; // See above: DO_... ULONG Characteristics; // See ntioapi: FILE_... __volatile PVPB Vpb; PVOID DeviceExtension; //设备对象类型 DEVICE_TYPE DeviceType; //堆栈大小. CCHAR StackSize; union { LIST_ENTRY ListEntry; WAIT_CONTEXT_BLOCK Wcb; } Queue; ULONG AlignmentRequirement; KDEVICE_QUEUE DeviceQueue; KDPC Dpc; // // The following field is for exclusive use by the filesystem to keep // track of the number of Fsp threads currently using the device // ULONG ActiveThreadCount; PSECURITY_DESCRIPTOR SecurityDescriptor; KEVENT DeviceLock; USHORT SectorSize; USHORT Spare1; struct _DEVOBJ_EXTENSION *DeviceObjectExtension; PVOID Reserved; } DEVICE_OBJECT; typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT;
IRP 请求包.
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _IRP { CSHORT Type; //类型 USHORT Size; //大小 // // Define the common fields used to control the IRP. // // // Define a pointer to the Memory Descriptor List (MDL) for this I/O // request. This field is only used if the I/O is "direct I/O". // PMDL MdlAddress; //内核描述符指针.读写的缓冲区. // // Flags word - used to remember various flags. // ULONG Flags; // // The following union is used for one of three purposes: // // 1. This IRP is an associated IRP. The field is a pointer to a master // IRP. // // 2. This is the master IRP. The field is the count of the number of // IRPs which must complete (associated IRPs) before the master can // complete. // // 3. This operation is being buffered and the field is the address of // the system space buffer. // union { //SystemBuffer里面看看请求是那个IO请求.来取决于用上面的缓冲区还是下面的缓冲区. struct _IRP *MasterIrp; __volatile LONG IrpCount; PVOID SystemBuffer; } AssociatedIrp; // // Thread list entry - allows queueing the IRP to the thread pending I/O // request packet list. // LIST_ENTRY ThreadListEntry; // // I/O status - final status of operation. // IO_STATUS_BLOCK IoStatus; // IO的请求状态.一般请求完成后的返回情况放在这里. // // Requestor mode - mode of the original requestor of this operation. // KPROCESSOR_MODE RequestorMode; // // Pending returned - TRUE if pending was initially returned as the // status for this packet. // BOOLEAN PendingReturned; // // Stack state information. // CHAR StackCount; //栈空间大小. CHAR CurrentLocation; //当前的IRP栈空间. // // Cancel - packet has been canceled. // BOOLEAN Cancel; // // Cancel Irql - Irql at which the cancel spinlock was acquired. // KIRQL CancelIrql; // // ApcEnvironment - Used to save the APC environment at the time that the // packet was initialized. // CCHAR ApcEnvironment; // // Allocation control flags. // UCHAR AllocationFlags; // // User parameters. // PIO_STATUS_BLOCK UserIosb; PKEVENT UserEvent; union { struct { union { PIO_APC_ROUTINE UserApcRoutine; PVOID IssuingProcess; }; PVOID UserApcContext; } AsynchronousParameters; LARGE_INTEGER AllocationSize; } Overlay; // // CancelRoutine - Used to contain the address of a cancel routine supplied // by a device driver when the IRP is in a cancelable state. // __volatile PDRIVER_CANCEL CancelRoutine; //用来取消一个未决请求的函数. // // Note that the UserBuffer parameter is outside of the stack so that I/O // completion can copy data back into the user's address space without // having to know exactly which service was being invoked. The length // of the copy is stored in the second half of the I/O status block. If // the UserBuffer field is NULL, then no copy is performed. // PVOID UserBuffer; //与MdlAddress 跟SystemBuffer一样都是缓冲区. //缓冲区的特性不同. // // Kernel structures // // The following section contains kernel structures which the IRP needs // in order to place various work information in kernel controller system // queues. Because the size and alignment cannot be controlled, they are // placed here at the end so they just hang off and do not affect the // alignment of other fields in the IRP. // union { struct { union { // // DeviceQueueEntry - The device queue entry field is used to // queue the IRP to the device driver device queue. // KDEVICE_QUEUE_ENTRY DeviceQueueEntry; struct { // // The following are available to the driver to use in // whatever manner is desired, while the driver owns the // packet. // PVOID DriverContext[4]; } ; } ; // // Thread - pointer to caller's Thread Control Block. // PETHREAD Thread; //发出这个请求的线程. // // Auxiliary buffer - pointer to any auxiliary buffer that is // required to pass information to a driver that is not contained // in a normal buffer. // PCHAR AuxiliaryBuffer; // // The following unnamed structure must be exactly identical // to the unnamed structure used in the minipacket header used // for completion queue entries. // struct { // // List entry - used to queue the packet to completion queue, among // others. // LIST_ENTRY ListEntry; union { // // Current stack location - contains a pointer to the current // IO_STACK_LOCATION structure in the IRP stack. This field // should never be directly accessed by drivers. They should // use the standard functions. // // 一个IRP 栈空间的元素. struct _IO_STACK_LOCATION *CurrentStackLocation; // // Minipacket type. // ULONG PacketType; }; }; // // Original file object - pointer to the original file object // that was used to open the file. This field is owned by the // I/O system and should not be used by any other drivers. // PFILE_OBJECT OriginalFileObject; } Overlay; // // APC - This APC control block is used for the special kernel APC as // well as for the caller's APC, if one was specified in the original // argument list. If so, then the APC is reused for the normal APC for // whatever mode the caller was in and the "special" routine that is // invoked before the APC gets control simply deallocates the IRP. // KAPC Apc; // // CompletionKey - This is the key that is used to distinguish // individual I/O operations initiated on a single file handle. // PVOID CompletionKey; } Tail; } IRP;
其中IRP注意的事项. 因为IRP发送给设备对象请求.所以有多个设备对象.而IRP结构体是固定的.所以在操作的时候.会有一些变动的参数.为了存储这些变动的参数.
所以IRP结构体中保存了当前IRP堆栈.如果获取这些变动的参数.可以通过IRP堆栈来操作.
其中: CurrentLocation表示的当前是哪一个IRP堆栈.
三丶内核中常用的kerner API
我们知道.在应用层中.我们有SDK开发工具包. 里面的API供我们使用.现在内核中也提供了Kerner(内核) API给我们使用.一般名字都有前缀.
IO EX Rtl Ke Zw Nt Ps开头.
常用的kerner API介绍.
1.Ex系列API
Ex内存系列API | |
ExAllocatePool | 申请内存,类似于C语言的malloc |
ExFreePool | 释放内存,C语言中的free |
ExAcquireFastMutex | 获取一个快速互斥体.多线程中使用. |
ExReleaseFastMutex | 释放一个快速互斥体 |
ExRaiseStatus | 抛出一个异常.带有错误Status的值 |
介绍API前介绍一下Nt函数. Zw函数跟Nt函数是简单的跳转关系. 用户态也有对应的API与之对应. 在内核中Nt函数是查询不到的.因为微软不建议使用Nt函数.
不过我们声明一下还是可以使用的.
Zw 文件设备操作API | 对应NT API | 作用 |
ZwCreateFile | NtCreateFile | 打开文件/设备 |
ZwReadFile | NtReadFile | 读文件/设备 |
ZwWriteFile | NtWriteFile | 写文件/设备 |
ZwQueryDirctoryFile | NtQueryDirctoryFile | 目录查询 |
ZwDeviceIoControFile | NtDeviceIoControlFile | 发送设备控制请求 |
ZwCreateKey | NtCreateKey | 打开一个注册表键 |
ZwQueryValueKey | NtQueryValueKey | 打开一个注册表值 |
我们知道内核中有了新的UNICODE_STRING 跟 ANSI_STRING的字符串.那么也有与之对应操作的API
Rtl函数 | 功能 |
RtlInitUnicodeString | 初始化一个Unicode字符串结构 |
RtlCopyUnicodeString | 拷贝字符串 |
RtlAppendUnicodeToString | 将一个字符串追加到另一个字符串后 |
RtlStringCbPrintf | 讲一个字符串打印到字符串中,相当于sprintf |
RtlCopyMemory | 内存数据块拷贝. |
RtlMoveMemory | 内存数据块移动. |
RtlZeroMemory | 内存块清零.注意不是释放内存,而是内存的值都变成0 |
RtlCompareMemory | 内存比较 |
RtlGetVersion | 获得当前Windows 版本 |
注意,IO函数比较重要. IO函数涉及IO管理器,而IO管理器就是将用户调用的API 翻译成IRP请求.或者讲等价的请求发送到内核中不同的设备.
是一个关键组件. 这个类别一般涉及到的都是IRP. 很关键.
IO函数 | 作用 |
IoCreateFile | 创建文件,比ZwCreateFile更加底层 |
IoCreateDevice | 生成一个设备对象 |
IoCallDriver | 发送请求 |
IoCompleteRequest | 完成请求,通知IO管理器完成了IRP请求 |
IoCopyCurrentIrpStackLocationToNext | 将当前的IRP堆栈拷贝到下一个栈空间 |
IoSkipCurrentIrpStackLoctionToNext | 跳过当前的IRP的栈空间 |
IoGetCurrentIrpStackLocation | 获得IRP的当前栈空间指针. |
Ps进程相关函数 | 作用 |
PsGetCurrentProcess | 获得当前的EPROCESS结构 |
PsGetCurrentProcessId | 获得当前的进程ID |
PsGetCurrentThread | 获得当前的ETHREAD结构 |
PsGetCurrentThreadId | 获得当前的线程ID |
PsIsSystemThread | 判断是否是系统线程. |
PsTerminateSystemThread | 结束系统线程. |
相关文章推荐
- 深入了解mysql的4种常用、重要的数据类型
- windows内核模式开发常用知识
- Java基本知识(连载)-数据类型和常用运算
- Mysql学习总结(4)——MySql基础知识、存储引擎与常用数据类型
- Java知识(002)--数据类型和常用运算
- SQL Server中开发常用的数据类型
- ABAP开发基础知识:7)数据类型的转换
- IOS开发第二讲 基本数据类型 类的新建 一些常用技巧
- 重拾C语言重要知识之数据类型
- Mysql学习总结(4)——MySql基础知识、存储引擎与常用数据类型
- ABAP开发基础知识:3) 自定义数据类型(User-Defined Data Types)
- Glib的数据类型和常用知识
- SQL Server中开发常用的数据类型
- Java JNI开发时常用数据类型与C++中数据类型转换
- IPHONE 开发 6 -- Object C 02 常用数据类型[整型浮点型,短长整型],数组(固定长度,变长)
- javaSE_8系列博客——Java语言的特性(二)--高级语言的基础知识(2)-- 变量和常用数据类型
- Windows内核驱动开发入门学习资料 + 内核数据类型和函数
- Mysql学习总结(4)——MySql基础知识、存储引擎与常用数据类型
- MySql基础知识、存储引擎与常用数据类型
- Mysql学习总结(4)——MySql基础知识、存储引擎与常用数据类型