selph
selph
Published on 2021-11-27 / 1,197 Visits
0
0

Windows 内核编程 ch2--开始内核开发

本章内容主要就是带着写了第一个驱动程序,书上当前章节没有介绍如何配置双机调试环境,也没介绍如何禁用驱动强制签名,本文来介绍一下这些东西。

Win7 10 双机调试配置

开发机环境准备

Windows 10 + VS 2019

在 Visual Studio Installer 里安装 SDK,官网下载安装 WDK

遇到的问题解决方案:

https://blog.csdn.net/wangzhichunnihao/article/details/108584295

虚拟机设置

安装好虚拟机,关机,设置虚拟机:

  • 移除打印机
  • 添加串行端口,设置如图:
    image-20210323154539050

Windbg 启动参数

-y srv*D:\Symbols\Windows7sp17601\Symbols -b -k com:port=\\.\pipe\com_1,baud=115200,pipe

注意:

Windows 7 x86 使用 windbg(x86) 版本

Windows 7 x64 使用 windbg(x64) 版本

开启调试模式

开启虚拟机,以管理员运行 cmd,执行如下命令:

bcdedit /dbgsettings serial baudrate:115200 debugport:1
bcdedit /copy {current} /d DebugEntry
bcdedit /displayorder {current} {ID}
bcdedit /debug {ID} ON

顺利的话,到此,调试模式启动成功

驱动加载测试

Win7x86 可直接加载驱动服务安装启动

Win7x64 版本新增了强制签名机制,需要禁用强制签名才能直接加载驱动安装启动(或者安装签名)禁用方法有 2 个(Windows10 也适用):

  1. 开机的时候按 F8 进入安全模式,选择禁用驱动程序签名强制(该方法单次有效,重启后失效)

  2. 以管理员运行 cmd,输入如下命令:(不一定成功,可能因为一些林域问题失败)

    bcdedit -set loadoptions DDISABLE_INTEGRITY_CHECKS
    bcdedit -set TESTSIGNING ON
    

    如果要设置回来,输入如下命令:

    bcdedit -set loadoptions ENABLE_INTEGRITY_CHECKS
    bcdedit -set TESTSIGNING OFF
    

SXS 输出一大堆信息怎么处理

windbg:

ed nt!kd_fusion_mask 0

驱动中的 Hello world

开发环境:Windows 10 + VS2019

当前开发学习的是 NT 式驱动,使用 WDM 驱动开发就行了(WDM 和 NT 驱动混合了)

创建项目

创建项目 WDM

项目文件中有个 inf 文件,写其他驱动的时候可能会有用,但是写 NT 式驱动会出现错误,这里要删掉

源文件,新建项,添加 c 文件

用.cpp 写需要将入口函数使用extern "c"进行修饰,使用C的方式进行导出

项目设置

配置设置:所有配置、所有平台

C/C++:常规,将警告视为错误,关掉

Driver Settings:General,Target OS Version,安装到什么系统上就选什么

到这里就设置完了,可以开始写程序了

第一个程序

#include <ntddk.h>
//包含wdm.h,ntifs.h差不多,类似R3开发的Windows.h

//卸载需要单独提供一个卸载函数,不然不能卸载
//卸载函数
VOID DriverUnload(PDRIVER_OBJECT pDriver) {
	//处理未引用的形参,微软提供了个宏
	UNREFERENCED_PARAMETER(pDriver);
	DbgPrint("Bye World!\n");
}

//主函数:以前是Main,WinMain,现在是DriverEntry
//参数以前可以不带,驱动程序必须带:
//参数1:驱动对象指针
//参数2:内核字符串指针,内核字符串和R3不一样,不使用0作为结尾,而是用结构体表示,这里是注册表路径
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath){	
	UNREFERENCED_PARAMETER(pRegPath);
	//卸载函数需要指定一下
	pDriverObject->DriverUnload = DriverUnload;
	//Ring3打印:printf
	DbgPrint("Hello World!\n");
	return STATUS_SUCCESS;//状态成功,实际上就是0(内核中0代表成功),状态码实际上就是数字,但一定要返回STATUS_SUCCESS,这代表成功
}

头文件 #include<ntddk.h> 相当于 R3 开发的时候用的 <windows.h>,每次写代码都要包含的;

从主函数 DriverEntry 开始看,首先驱动程序的主程序必须带参数,参数是固定的,分别是驱动对象指针和内核字符串指针,参数后面会介绍;

驱动程序里不允许出现未引用的变量,需要通过微软提供的宏 UNREFERENCED_PARAMETER(var) 进行处理;

卸载驱动程序的卸载函数需要在驱动对象指针中指定;

DbgPrint() 是驱动中的 print 函数;

STATUS 是类型是驱动程序中用的类型,需要用宏来表示;

编译项目

右键项目名称,重新生成:

生成了三个东西

  • cer 测试证书,毛用没有
  • pdb 符号文件,调试的时候会用
  • sys 驱动程序

加载测试

拖入虚拟机,打开 dbgview,用 INSTDRV 安装驱动,启动、关闭、卸载:

image-20210323163006397

驱动一般是以服务形式来加载的

首先,驱动作为一个服务来进行安装,启动,停止是对服务的,卸载也是,实际上是一套服务的一套流程

程序参数里的注册表路径就是作为服务的注册表路径

不要问为啥,就是微软规定的

调试测试

这里以 x64 为例,调试方法:

  • 在代码里使用内联汇编 int 3 进行中断
  • 使用微软提供的中断方式:DbgBreakPoint() 函数(函数功能就是下个断点让程序停在这里)

在代码中加个断点

#include <ntddk.h>
VOID DriverUnload(PDRIVER_OBJECT pDriver) {
	UNREFERENCED_PARAMETER(pDriver);
	DbgPrint("Bye World!\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath){	
	UNREFERENCED_PARAMETER(pRegPath);
	pDriverObject->DriverUnload = DriverUnload;
    // 断点
	DbgBreakPoint();
	DbgPrint("Hello World!\n");
	return STATUS_SUCCESS;
}

Comment