windows内核研究(驱动开发之内核编程)

驱动开发


内核编程

windows内核驱动WDK在线文档

在我们之前写3环应用程序时,可以使用windows为我们提供的各种API函数,只要导入头文件<windows.h>就可以了,但是在内核编程的时候,我们需要使用微软为内核程序提供的专用的API,如ntddk.h(前提是你有安装好对应版本的WDK)

WDK帮助文档中只包含了内核模块导出的函数,对于未导出的函数,则不能直接使用,如要使用就要自己定义一个函数指针,并且为该函数指针提供正确的函数地址(1.特征码搜索,2解析内核PDB文件)

返回值

大部分内核函数的返回值都是NTSTATUS类型(宏定义):

NTSTATUS PsCreateSystemThread();

NTSTATUS ZwOpenProcess();

NTSTATUS ZwOpenEvent();

...

这个值能说明执行的结果:

STATUS_SUCCESS 0x00000000 // 成功

STATUS_INVALID_PARAMETER 0xC000000D // 参数无效

STATUS_BUFFER_OVERFLOw 0x80000005 // 缓冲区长度不够

...

NTSTATUS的返回值是一个宏定义他的返回值还有很多很多,如果返回的是一个我们不清楚的宏定义,那么可以去ntstatus.h中查看

内核中的异常处理

在内核中,往往一个很小的错误就可能导致蓝屏,为了让自己的程序更加健壮,可以使用windows为我们提供的结构化异常处理机制

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

出现异常时,可以根据filter_value的值来决定程序该如何执行

  • 为EXCEPTION_EXECUTE_HANDLER(1) // 代码进入except块
  • 为EXCEPTION_CONTINUE_SEARCH(0) // 不处理异常,由上一层调用函数处理
  • 为EXCEPTION_CONTINUE_EXECUTION(-1) // 回去继续执行错误的代码

常用的内核内存函数

c语言 内核
malloc ExAllocatePool
memset RtIFillMemory
memcpy RtlMoveMemory
free ExFreePool

内核下的字符串种类

ANSI_STRING/UNICODE_STRING

c 复制代码
// 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 RtlCompareUnicodeString
RtAnsiStringToUnicodeString RtlUnicodeStringToAnsiString

内核空间与内核模块

由于进程的内核空间都是共享的,所以我们在内核空间做的改动将影响到所有的进程

我们来做一个小实验

c 复制代码
#include<ntddk.h>

// 定义一个全局变量
ULONG num = 0x12345678;

// 卸载函数
VOID DrvUnload(PDRIVER_OBJECT DriverObject) {
	DbgPrint("我被卸载了\n");
}

// 驱动入口函数,相当于main函数
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
	// 打印全局变量的地址
	DbgPrint("%X\n", &num);
	// 设置卸载函数
	DriverObject->DriverUnload = DrvUnload;
	return STATUS_SUCCESS;
}

可以看到这个地址打印出是FFFFF8043E1F3000

我们先在内核状态下查看这个地址看是什么

发现正是我们定义的全局变量值

我们在windbg中再打开一个程序(直接就看dbgview),看它这个进程的0x72433000这个地址里面存储的值是什么

复制代码
 .process 地址 // 用来切换当前进程的上下文


查看在dbgview下的FFFFF8043E1F3000地址

发现我们也同样读取到了这个地上的值并且是一样的

内核模块

DRIVER_OBJCET(驱动对象)结构体

  • DriverStart // 在内核模块开始的位置
  • DriverSize // 在内核模块的大小(结束的位置)
  • DriverName // 在内核模块中的名称

斜体样式打印DRIVER_OBJECT结构体的地址信息

c 复制代码
#include<ntddk.h>

// 卸载函数
VOID DrvUnload(PDRIVER_OBJECT DriverObject) {
	DbgPrint("我被卸载了\n");
}

// 驱动入口函数,相当于main函数
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
	// 打印DriverObject结构体的地址
	DbgPrint("%llX\n", &DriverObject);
	// 设置卸载函数
	DriverObject->DriverUnload = DrvUnload;
	return STATUS_SUCCESS;
}

输入的内核地址为:FFFFE6053C522B20

查看解析后的结构体

复制代码
dt _DRIVER_OBJECT FFFFE6053C522B20 // 解析FFFFE6053C522B20 地址对应的_DRIVER_OBJECT

在_DRIVER_OBJECT结构体中的DriverSection成员他是一个指针,指向的是一个结构体对象(_LDR_DATA_TABLE_ENTRY 是一个链表把内核中所有的模块都链在了一起)

复制代码
dt _LDR_DATA_TABLE_ENTRY
c 复制代码
2: kd> dt _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY
   +0x010 InMemoryOrderLinks : _LIST_ENTRY
   +0x020 InInitializationOrderLinks : _LIST_ENTRY
   +0x030 DllBase          : Ptr64 Void
   +0x038 EntryPoint       : Ptr64 Void
   +0x040 SizeOfImage      : Uint4B
   +0x048 FullDllName      : _UNICODE_STRING
   +0x058 BaseDllName      : _UNICODE_STRING
   +0x068 FlagGroup        : [4] UChar
   +0x068 Flags            : Uint4B
   +0x068 PackagedBinary   : Pos 0, 1 Bit
   +0x068 MarkedForRemoval : Pos 1, 1 Bit
   +0x068 ImageDll         : Pos 2, 1 Bit
   +0x068 LoadNotificationsSent : Pos 3, 1 Bit
   +0x068 TelemetryEntryProcessed : Pos 4, 1 Bit
   +0x068 ProcessStaticImport : Pos 5, 1 Bit
   +0x068 InLegacyLists    : Pos 6, 1 Bit
   +0x068 InIndexes        : Pos 7, 1 Bit
   +0x068 ShimDll          : Pos 8, 1 Bit
   +0x068 InExceptionTable : Pos 9, 1 Bit
   +0x068 ReservedFlags1   : Pos 10, 2 Bits
   +0x068 LoadInProgress   : Pos 12, 1 Bit
   +0x068 LoadConfigProcessed : Pos 13, 1 Bit
   +0x068 EntryProcessed   : Pos 14, 1 Bit
   +0x068 ProtectDelayLoad : Pos 15, 1 Bit
   +0x068 ReservedFlags3   : Pos 16, 2 Bits
   +0x068 DontCallForThreads : Pos 18, 1 Bit
   +0x068 ProcessAttachCalled : Pos 19, 1 Bit
   +0x068 ProcessAttachFailed : Pos 20, 1 Bit
   +0x068 CorDeferredValidate : Pos 21, 1 Bit
   +0x068 CorImage         : Pos 22, 1 Bit
   +0x068 DontRelocate     : Pos 23, 1 Bit
   +0x068 CorILOnly        : Pos 24, 1 Bit
   +0x068 ChpeImage        : Pos 25, 1 Bit
   +0x068 ReservedFlags5   : Pos 26, 2 Bits
   +0x068 Redirected       : Pos 28, 1 Bit
   +0x068 ReservedFlags6   : Pos 29, 2 Bits
   +0x068 CompatDatabaseProcessed : Pos 31, 1 Bit
   +0x06c ObsoleteLoadCount : Uint2B
   +0x06e TlsIndex         : Uint2B
   +0x070 HashLinks        : _LIST_ENTRY
   +0x080 TimeDateStamp    : Uint4B
   +0x088 EntryPointActivationContext : Ptr64 _ACTIVATION_CONTEXT
   +0x090 Lock             : Ptr64 Void
   +0x098 DdagNode         : Ptr64 _LDR_DDAG_NODE
   +0x0a0 NodeModuleLink   : _LIST_ENTRY
   +0x0b0 LoadContext      : Ptr64 _LDRP_LOAD_CONTEXT
   +0x0b8 ParentDllBase    : Ptr64 Void
   +0x0c0 SwitchBackContext : Ptr64 Void
   +0x0c8 BaseAddressIndexNode : _RTL_BALANCED_NODE
   +0x0e0 MappingInfoIndexNode : _RTL_BALANCED_NODE
   +0x0f8 OriginalBase     : Uint8B
   +0x100 LoadTime         : _LARGE_INTEGER
   +0x108 BaseNameHashValue : Uint4B
   +0x10c LoadReason       : _LDR_DLL_LOAD_REASON
   +0x110 ImplicitPathOptions : Uint4B
   +0x114 ReferenceCount   : Uint4B
   +0x118 DependentLoadFlags : Uint4B
   +0x11c SigningLevel     : UChar
复制代码
dt _LDR_DATA_TABLE_ENTRY ffffe605`3d51e500 // 解析地址对应的结构体
c 复制代码
2: kd> dt _LDR_DATA_TABLE_ENTRY ffffe605`3d51e500
ntdll!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0xfffff804`36e48210 - 0xffffe605`3c4fd4d0 ]
   +0x010 InMemoryOrderLinks : _LIST_ENTRY [ 0xfffff804`3e214000 - 0x00000000`0000003c ]
   +0x020 InInitializationOrderLinks : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
   +0x030 DllBase          : 0xfffff804`3e210000 Void
   +0x038 EntryPoint       : 0xfffff804`3e215000 Void
   +0x040 SizeOfImage      : 0x7000
   +0x048 FullDllName      : _UNICODE_STRING "\??\C:\Users\ygxdks\Desktop\MyDriver2.sys"
   +0x058 BaseDllName      : _UNICODE_STRING "MyDriver2.sys"
   +0x068 FlagGroup        : [4]  ""
   +0x068 Flags            : 0x49104000
   +0x068 PackagedBinary   : 0y0
   +0x068 MarkedForRemoval : 0y0
   +0x068 ImageDll         : 0y0
   +0x068 LoadNotificationsSent : 0y0
   +0x068 TelemetryEntryProcessed : 0y0
   +0x068 ProcessStaticImport : 0y0
   +0x068 InLegacyLists    : 0y0
   +0x068 InIndexes        : 0y0
   +0x068 ShimDll          : 0y0
   +0x068 InExceptionTable : 0y0
   +0x068 ReservedFlags1   : 0y00
   +0x068 LoadInProgress   : 0y0
   +0x068 LoadConfigProcessed : 0y0
   +0x068 EntryProcessed   : 0y1
   +0x068 ProtectDelayLoad : 0y0
   +0x068 ReservedFlags3   : 0y00
   +0x068 DontCallForThreads : 0y0
   +0x068 ProcessAttachCalled : 0y0
   +0x068 ProcessAttachFailed : 0y1
   +0x068 CorDeferredValidate : 0y0
   +0x068 CorImage         : 0y0
   +0x068 DontRelocate     : 0y0
   +0x068 CorILOnly        : 0y1
   +0x068 ChpeImage        : 0y0
   +0x068 ReservedFlags5   : 0y10
   +0x068 Redirected       : 0y0
   +0x068 ReservedFlags6   : 0y10
   +0x068 CompatDatabaseProcessed : 0y0
   +0x06c ObsoleteLoadCount : 1
   +0x06e TlsIndex         : 0x14
   +0x070 HashLinks        : _LIST_ENTRY [ 0xffff838d`03726e40 - 0x00000000`0000273b ]
   +0x080 TimeDateStamp    : 0
   +0x088 EntryPointActivationContext : 0xffffe605`36a47791 _ACTIVATION_CONTEXT
   +0x090 Lock             : (null) 
   +0x098 DdagNode         : 0x687af49a`00007000 _LDR_DDAG_NODE
   +0x0a0 NodeModuleLink   : _LIST_ENTRY [ 0xffffe605`3b848c08 - 0xffffe605`3b848c08 ]
   +0x0b0 LoadContext      : 0xfffff804`3e210003 _LDRP_LOAD_CONTEXT
   +0x0b8 ParentDllBase    : 0xfffff804`3e216fff Void
   +0x0c0 SwitchBackContext : 0x00000000`fffffffe Void
   +0x0c8 BaseAddressIndexNode : _RTL_BALANCED_NODE
   +0x0e0 MappingInfoIndexNode : _RTL_BALANCED_NODE
   +0x0f8 OriginalBase     : 0xffffe605`3c4fd5b8
   +0x100 LoadTime         : _LARGE_INTEGER 0xffffe605`3d51e638
   +0x108 BaseNameHashValue : 0
   +0x10c LoadReason       : 0 ( LoadReasonStaticDependency )
   +0x110 ImplicitPathOptions : 0x3d51e620
   +0x114 ReferenceCount   : 0xffffe605
   +0x118 DependentLoadFlags : 0
   +0x11c SigningLevel     : 0 ''

主要看四个成员

  1. +0x000 InLoadOrderLinks // 这个内核模块的下一个模块地址
  2. +0x030 DllBase // 这个内核模块从什么位置开始
  3. +0x040 SizeOfImage // 这个内核模块的大小
  4. +0x048 FullDllName // 这个内核模块完整的路径名
相关推荐
sukalot21 小时前
window显示驱动开发—以追溯方式要求自由线程 CalcPrivate DDI
驱动开发
菜鸟12号2 天前
Linux下SPI设备驱动开发
linux·arm开发·驱动开发
Evan_ZGYF丶2 天前
【RK3576】【Android14】SDK源码编译
驱动开发·android14·rk3576
Evan_ZGYF丶3 天前
【RK3576】【Android14】ADB工具说明与使用
android·驱动开发·android14·rk3576
情意绵绵6743 天前
VAS5081电动工具专用3-8节串联电池监控芯片奇力科技
驱动开发·汽车·硬件架构·硬件工程·pcb工艺
Evan_ZGYF丶4 天前
【RK3576】Android 14 驱动开发实战指南
驱动开发·android14·rk3576
一个平凡而乐于分享的小比特4 天前
MS1112驱动开发(iio框架)
驱动开发·ms1112·iio
小嵌同学4 天前
Linux 内存管理(2):了解内存回收机制
linux·运维·arm开发·驱动开发·嵌入式
qwertyuiop_i4 天前
windows内核研究(驱动开发-0环与3环的通信)
驱动开发·windows内核研究·3环程序与0环驱动通信