Windows驱动开发学习笔记(二)—— 驱动调试&内核编程基础
Windows驱动开发学习笔记(二)—— 驱动调试&内核编程基础前言基础知识驱动调试PDB(Program Debug Database)WinDbg 加载 PDB实验:调试 .sys 文件第一步:编译代码第二步:将 .sys 文件拷贝到虚拟机中第三步:添加 pdb 文件路径第四步:部署 .sys 文件并运行内核编程基础内核API的使用未导出函数的使用基本数据类型返回值内核中的异常处理常用
·
Windows驱动开发学习笔记(二)—— 驱动调试&内核编程基础
基础知识
- 驱动程序无法在当前系统中进行调试,否则会导致系统卡死
- 可以采用双机调试的方式调试驱动程序
驱动调试
当我们使用 windbg 查看某一个地址的反汇编时,例如:
windbg 能够自动帮我们识别出该地址属于哪个函数(红框部分)
思考:windbg 是如何识别出该地址对应的函数的?
PDB(Program Debug Database)
- PDB文件是在我们编译工程的时候产生的,它是和对应的模块(exe或dll)一起生成出来的
- 每个模块编译的时候都可以生成自己的PDB文件,比如
.exe
/.dll
/.sys
等等 - 0环调试器(例如 WinDbg)正是通过解析pdb文件来找到函数与地址之间的对应关系
WinDbg 加载 PDB
实验:调试 .sys 文件
第一步:编译代码
#include "ntddk.h"
//卸载函数
VOID DriverUnload(PDRIVER_OBJECT driver)
{
DbgPrint("驱动程序已停止.\r\n");
}
//驱动程序入口函数,相当于控制台的main函数
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
__asm
{
int 3
mov eax, eax
mov eax, eax
mov eax, eax
}
DbgPrint("驱动程序已运行.\r\n");
//设置一个卸载函数 便于退出
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
第二步:将 .sys 文件拷贝到虚拟机中
第三步:添加 pdb 文件路径
第四步:部署 .sys 文件并运行
WinDbg 成功截获中断即可
内核编程基础
内核API的使用
- 在应用层编程时,可以使用WINDOWS提供的各种API函数,只要导入头文件<windows.h>就可以了。但是在内核编程的时候,不能像在Ring3那样直接使用
- 微软为内核程序提供了专用的API,只要在程序中包含相应的头文件就可以使用了,如:#include <ntddk.h> (前提是已经正确安装了WDK)
- 在应用层编程的时候,我们通过MSDN来了解函数的详细信息,在内核编程的时候,要使用WDK自己的帮助文档
未导出函数的使用
描述:
- WDK说明文档中只包含了内核模块导出的函数,对于未导出的函数,则不能直接使用。
- 如果要使用未导出的函数,只要自己定义一个函数指针,为函数指针提供正确的函数地址就可以使用了
获取未导出的函数地址:
- 特征码搜索
- 解析内核PDB文件
基本数据类型
在内核编程的时候,强烈建议大家遵守WDK的编码习惯,不要这样写:
unsigned long length;
WDK类型:
ULONG(unsigned long) PULONG(unsigned long *)
UCHAR(unsigned char) PUCHAR(unsigned char *)
UINT(unsigned int) PUNIT(unsigned int *)
VOID(void) PVOID(void *)
返回值
大部分内核函数的返回值都是NTSTATUS类型,如:
NTSTATUS PsCreateSystemThread();
NTSTATUS ZwOpenProcess();
NTSTATUS ZwOpenEvent();
这个值能说明函数执行的结果,如:
STATUS_SUCCESS 0x00000000 成功
STATUS_INVALID_PARAMETER 0xC000000D 参数无效
STATUS_BUFFER_OVERFLOW 0x80000005 缓冲区长度不够
当调用的内核函数时,如果返回的结果不是STATUS_SUCCESS,就说明函数执行中遇到了问题,具体是什么问题,可以在ntstatus.h文件中查看
内核中的异常处理
描述:
- 在内核中,一个小小的错误就可能导致蓝屏,比如:读写一个无效的内存地址
- 为了让自己的内核程序更加健壮,强烈建议大家在编写内核程序时,使用异常处理
Windows提供了结构化异常处理机制,一般的编译器都是支持的,如下:
__try{
//可能出错的代码
}
__except(filter_value) {
//出错时要执行的代码
}
filter_value:
EXCEPTION_EXECUTE_HANDLER(1) //代码进入except块
EXCEPTION_CONTINUE_SEARCH(0) //不处理异常,由上一层调用函数处理
EXCEPTION_CONTINUE_EXECUTION(-1) //回去继续执行错误处的代码
常用内核函数(内存操作)
内核字符串种类
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;
内核字符串常用函数
更多推荐
已为社区贡献4条内容
所有评论(0)