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为我们提供的结构化异常处理机制
__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
// 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 |
内核空间与内核模块
由于进程的内核空间都是共享的,所以我们在内核空间做的改动将影响到所有的进程
我们来做一个小实验
#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结构体的地址信息
#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
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 // 解析地址对应的结构体
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 ''
主要看四个成员
- +0x000 InLoadOrderLinks // 这个内核模块的下一个模块地址
- +0x030 DllBase // 这个内核模块从什么位置开始
- +0x040 SizeOfImage // 这个内核模块的大小
- +0x048 FullDllName // 这个内核模块完整的路径名