《Windows内核安全与驱动开发》阅读笔记 -- 索引目录

《Windows内核安全与驱动开发》 7.1&7.2&7.3 串口的过滤

一、设备绑定的内核API

  1. 进行过滤的最主要的方法是对一个____进行绑定。
  2. 我们可以首先认为:一个真实的设备对应一个_____。通过编程可以生成一个__的____,并绑定到一个___的设备上。一旦绑定,则本来操作系统发送给____的请求,就会发送到____上。
  3. 一个简单的API绑定函数是_____,必须是有____的设备,才能使用这个内核API进行绑定。
  4. 如果这个设备被其他设备绑定了,它们在一起组成一组设备,被称为____。实际上,IoAttachDevice总是会绑定___上最__层的那个设备。

二、生成过滤设备并绑定 与 从名字获得设备对象

  1. 在绑定一个设备之前,首先要知道如何生成一个用于____的设备,函数_____被用于生成过滤设备。
  2. 在绑定一个设备之前,应该把这个设备对象的多个____和要绑定的目标对象一致,包括标志和特征。
  3. 在知道一个设备名字的情况下,可以使用函数____来获得这个设备对象的指针。该函数的FileObject是一个返回参数,在获得这个设备对象的同时会获得一个____,就打开串口而言没什么用,但使用这个函数之后必须把这个对象____,否则会引起____。

三、绑定所有串口

  1. 串口x的设备名为____。

四、请求的区分

  1. 每个驱动程序只有__个驱动对象。
  2. 每个驱动对象可以生成___个驱设备对象。
  3. 若干个设备(它们可以属于__的驱动)依次绑定形成一个____,总是最__端的设备先收到请求。

五、请求的结局

  1. 对请求的过滤,有三种结局:____、_____、_____。
  2. 处理第一种最简单,首先调用函数____跳过当前栈空间;然后调用____把这个请求发送给___的设备。请注意,因为____的设备已经被过滤设备所绑定,因此首先接收到IRP的是过滤设备的对象。

六、写请求的数据

  1. 一个写请求保存在那里呢?IRP有三种,一种是___,一种是___,一种是____。不同的__类别,IRP的缓冲不同。
  2. ____是最有效率的解决方案。应用层的缓冲区地址直接放在___里,在内核层去访问。在____和_____一致的情况下,是完全正确的。但一旦内核进程进行____,这个访问就结束了。
  3. 一种更简单的解决的方案是把__层的地址空间映射到__空间,这需要在__中增加一个映射。当然这不需要编程者手动去修改,通过构造__就能实现这个功能。其可以翻译为____。

答案

一、设备绑定的内核API

  1. 设备对象
  2. 设备对象  虚拟 设备对象  真实 真实设备 虚拟设备
  3. IoAttchDevice 名称
  4. 设备栈 设备栈 顶

二、生成过滤设备并绑定 与 从名字获得设备对象

  1. 过滤 IoCreateDevice
  2. 子域
  3. IoGetDeviceObjectPointer 文件对象 关闭 内存泄漏

三、绑定所有串口

  1. \Device\Serialx

四、请求的区分

  1. 一个
  2. 若干
  3. 设备栈 顶

五、请求的结局

  1. 请求被允许通过了 请求直接被否决了 过滤完成了这个请求
  2. IoSkipCurrentIrpStackLocation IoCallDriver 真实

六、写请求的数据

  1. irp->MDLAddress irp->UserBuffer irp->AssociatedIrp.SystemBuffer
  2. UserBuffer UserBuffer 当前进程  发送请求进程   进程切换
  3. 应用层 内核层 页表 MDL 内存描述符链

三个基本概念

一、过滤的概念

  过滤的概念本质就是在一个驱动中对每个串口生成一个过滤设备,将每个过滤设备附加到对应的设备栈中。

  消息自上而下发送,在到达串口前必须经过过滤设备,这样来对此进行过滤。

  

二、设备栈的概念

  拿一个函数来举个例子

NTSTATUS IoAttachDeviceToDeviceStackSafe(
IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice,
OUT PDEVICE_OBJECT *AttachedToDeviceObject
);

  其中之所以会输出 AttchedToDeviceObject,是因为当将过滤设备SourceDevice卸载时需要这个参数。

  

三、设备、驱动与IRP请求的概念

  如图,一个驱动对象可以只绑定一个分发函数来处理所有设备的请求。

  因为分发函数的第一个参数就是对应的设备对象,我们可以通过该成员来进行区分是来自该驱动对象的哪个设备的。

  


利用过滤设备实现监控的代码

该代码实现了一个驱动过滤的例子。

一、实验效果

使用超级终端,端口2来建立连接(windbg往往使用端口1,再测试时无法接收信息,后来端口2则可以收到请求)

二、源代码

/*********
作者:OneTrianee
编写时间:2019/12/8
编译环境:Win10+vs2019+"Empty WDM Driver"
代码作用:生成过滤设备,绑定端口监视输入数据
参考资料:《Windows内核安全与驱动开发》
注意事项:
1. 虚拟机中windbg往往会占用COM1,此时通信应该使用COM2(如果没有,关闭去虚拟机设置中开一个。)
2. 开机时绑定端口2成功,但是卸载之后再绑定就只能绑定端口1,暂时不清楚原因(接触绑定没发现问题..)
效果(DebugView):
分发函数接收到请求了!!
comcap: Send Data: 61
分发函数接收到请求了!!
comcap: Send Data: 73
***********/ #include <ntddk.h>
#include <ntstrsafe.h> // sleep 时用到的宏
#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
#define DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND*1000) #define CCP_MAX_COM_ID 32 // 假设有32个端口 //
// 函数声明
//
NTSTATUS ccpDispatch(PDEVICE_OBJECT device, PIRP irp); // 设备分发函数
void ccpUnload(PDRIVER_OBJECT drv); // 动态卸载驱动函数
void ccpAttachAllComs(PDRIVER_OBJECT driver); // 绑定所有串口函数
PDEVICE_OBJECT ccpOpenCom(ULONG id, NTSTATUS* status); // 打开端口设备对象
NTSTATUS ccpAttachDevice(PDRIVER_OBJECT driver,
PDEVICE_OBJECT oldobj,
PDEVICE_OBJECT* fltobj,
PDEVICE_OBJECT* next
); // 将设备与驱动对象进行绑定 //
// 设备栈:
//
// IRP消息 ↓
// ----------
// |过滤设备|
// ----------
// |端口设备|
// ----------
//
static PDEVICE_OBJECT s_fltobj[CCP_MAX_COM_ID] = { }; // 过滤设备
static PDEVICE_OBJECT s_nextobj[CCP_MAX_COM_ID] = { }; // 端口设备(绑定后会返回) /*
函数名:ccpDispatch
函数作用:分发函数,分发设备的irp请求
参数1 - PDEVICE_OBJECT device:发送请求的目标设备
参数2 - PIRP irp: IRP请求内容
*/
NTSTATUS ccpDispatch(PDEVICE_OBJECT device, PIRP irp) {
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
NTSTATUS status;
ULONG i, j; //
// 判断是发送给哪个过滤设备
// 如果设备存在,则打印出设备内容
//
DbgPrint("分发函数接收到请求了!!\n");
for (i = ; i < CCP_MAX_COM_ID; i++) {
if (s_fltobj[i] == device) {
// 所有电源操作,全部直接放过。
if (irpsp->MajorFunction == IRP_MJ_POWER)
{
// 直接发送,然后返回说已经被处理了。
PoStartNextPowerIrp(irp);
IoSkipCurrentIrpStackLocation(irp);
return PoCallDriver(s_nextobj[i], irp);
}
// 我们只考虑写请求,如果为写请求,则打印出来
if (irpsp->MajorFunction == IRP_MJ_WRITE) {
// 获取长度
ULONG len = irpsp->Parameters.Write.Length;
//
// 获取缓冲区(三中一个)
//
PUCHAR buf = NULL;
if (irp->MdlAddress != NULL)
buf = (PUCHAR)MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
else
buf = (PUCHAR)irp->UserBuffer;
if (buf == NULL)
buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer; // 打印内容
for (j = ; j < len; j++) {
DbgPrint("comcap: Send Data: %2x\r\n", buf[j]);
}
} // 这些请求直接下发即可。我们并不禁止或改变它。
IoSkipCurrentIrpStackLocation(irp);
return IoCallDriver(s_nextobj[i], irp);
}
} // 如果根本就不在被绑定的设备中,那是有问题的,直接返回错误参数。
irp->IoStatus.Information = ;
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
} /*
函数名:ccpAttchAllComs
函数功能:生成过滤设备,
参数1 - dirver:生成过滤设备需要指明其在哪个驱动中。
*/
void ccpAttachAllComs(PDRIVER_OBJECT driver) {
ULONG i;
PDEVICE_OBJECT com_ob;
NTSTATUS status;
for (i = ; i < CCP_MAX_COM_ID; i++) {
// 获取端口设备对象
com_ob = ccpOpenCom(i, &status);
if (com_ob == NULL) // 获取失败,继续获取下一个
continue;
else
DbgPrint("绑定端口号%u成功!", i);
// 在这里绑定,并不管绑定是否成功
ccpAttachDevice(driver, com_ob, &s_fltobj[i], &s_nextobj[i]);
} } /*
函数名:ccpOpenCom
函数功能:打开驱动端口设备
参数1 - ULONG id:打开的端口号ID,函数内自动给转换为设备名,然后打开
参数2 - NTSTATUS* status:操作状态
返回值 - PDEVICE_OBJECT:如果打开成功,返回端口设备句柄指针
*/
PDEVICE_OBJECT ccpOpenCom(ULONG id, NTSTATUS* status) {
UNICODE_STRING name_str;
static WCHAR name[] = { };
PFILE_OBJECT fileobj = NULL;
PDEVICE_OBJECT devobj = NULL; //
// 将 ID 转换为相应的端口设备名UNICODE_STRING
//
memset(name, , sizeof(WCHAR) * );
RtlStringCchPrintfW(
(NTSTRSAFE_PWSTR)name, ,
(NTSTRSAFE_PWSTR)L"\\Device\\Serial%d", id);
RtlInitUnicodeString(&name_str, name); //
// 打开设备对象
// 如果打开成功,删除文件对象,防止内存泄漏
//
*status = IoGetDeviceObjectPointer(&name_str, FILE_ALL_ACCESS, &fileobj, &devobj);
if (*status == STATUS_SUCCESS)
ObDereferenceObject(fileobj); // 返回端口设备句柄
return devobj; } /*
函数名:
函数功能:生成过滤设备,并绑定串口设备,保存过滤设备fltobj和原栈顶设备next
参数1 - PDRIVER_OBJECT driver:生成过滤设备时所在的驱动对象
参数2 - PDEVICE_OBJECT oldobj:已生成的端口设备
参数3 - PDEVICE_OBJECT* fltobj:生成的过滤设备(保存在数组中)
参数4 - PDEVICE_OBJECT* next:原设备栈顶的设备
*/
NTSTATUS ccpAttachDevice(PDRIVER_OBJECT driver,
PDEVICE_OBJECT oldobj,
PDEVICE_OBJECT* fltobj,
PDEVICE_OBJECT* next
) {
NTSTATUS status;
PDEVICE_OBJECT topdev = NULL; //
// 生成过滤设备,
// 注意生成设备的属性与被绑定设备一致
//
status = IoCreateDevice(driver,
,
NULL,
oldobj->DeviceType,
,
FALSE,
fltobj);
if (status != STATUS_SUCCESS)
return status; //
// 拷贝重要的标志位
//
if (oldobj->Flags & DO_BUFFERED_IO)
(*fltobj)->Flags |= DO_BUFFERED_IO;
if (oldobj->Flags & DO_DIRECT_IO)
(*fltobj)->Flags |= DO_DIRECT_IO;
if (oldobj->Flags & DO_BUFFERED_IO)
(*fltobj)->Flags |= DO_BUFFERED_IO;
if (oldobj->Characteristics & FILE_DEVICE_SECURE_OPEN)
(*fltobj)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
(*fltobj)->Flags |= DO_POWER_PAGABLE; //
// 绑定过滤设备到端口的设备栈中
//
topdev = IoAttachDeviceToDeviceStack(*fltobj, oldobj);
if (topdev == NULL) {
// 如果绑定失败,则销毁设备,之后重新来过
IoDeleteDevice(*fltobj);
*fltobj = NULL;
status = STATUS_UNSUCCESSFUL;
return status;
}
*next = topdev; // 存储原来栈顶的设备 //
// 设置这个设备已京启动
//
(*fltobj)->Flags = (*fltobj)->Flags & ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
} /*
函数名:ccpUnload
函数作用:动态卸载驱动对象
参数1 - PDRIVER_OBJECT drv:需要卸载的驱动对象指针
*/
void ccpUnload(PDRIVER_OBJECT drv) {
ULONG i;
LARGE_INTEGER interval; // 首先解除绑定
for (i = ; i < CCP_MAX_COM_ID; i++) {
if (s_nextobj[i] != NULL)
/*
|--------|
|过滤设备|
|--------|
|next设备| // 将该层上面的过滤设备给卸载掉
|--------|
|xxxx设备|
|--------|
|端口设备|
|--------|
*/
IoDetachDevice(s_nextobj[i]);
} // 睡眠5秒,等待所有irp处理结束
interval.QuadPart = ( * * DELAY_ONE_MILLISECOND);
KeDelayExecutionThread(KernelMode, FALSE, &interval); // 删除这些设备
for (i = ; i < CCP_MAX_COM_ID; i++) {
if (s_fltobj[i] != NULL) {
IoDeleteDevice(s_fltobj[i]);
}
}
} NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) {
size_t i;
DbgPrint("过滤设备安装成功!"); // 所有分发函数都设置成一样的
for (i = ; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
driver->MajorFunction[i] = ccpDispatch;
} // 支持动态卸载
driver->DriverUnload = ccpUnload; // 绑定所有串口
ccpAttachAllComs(driver); // 直接返回成功即可
return STATUS_SUCCESS;
}

《Windows内核安全与驱动开发》 7.1&7.2&7.3 串口的过滤的更多相关文章

  1. Windows内核安全与驱动开发

    这篇是计算机中Windows Mobile/Symbian类的优质预售推荐<Windows内核安全与驱动开发>. 编辑推荐 本书适合计算机安全软件从业人员.计算机相关专业院校学生以及有一定 ...

  2. 《windows内核安全与驱动开发》ctrl2cap中的ObReferenceObjectByName疑问

    国内有关于windows内核驱动这块的书籍实在是甚少,不过好在<windows内核安全与驱动开发>这本书还算不错(内容方面),但是不得不说这本书在许多地方存在着一些细节上的问题.比如我今天 ...

  3. 《Windows内核安全与驱动开发》阅读笔记 -- 索引目录

    <Windows内核安全与驱动开发>阅读笔记 -- 索引目录 一.内核上机指导 二.内核编程环境及其特殊性 2.1 内核编程的环境 2.2 数据类型 2.3 重要的数据结构 2.4 函数调 ...

  4. 《Windows内核安全与驱动开发》 2.3 重要的数据结构

    <Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 2.3 重要的数据结构 一.驱动对象  Windows内核采用__的编程方式 ...

  5. 《Windows内核安全与驱动开发》 3.1 字符串操作

    <Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 3.1 字符串操作 一.字符串的初始化 1. 判断下列代码为什么会蓝屏? U ...

  6. 《Windows内核安全与驱动开发》 3.2 内存与链表

    <Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 3.2 内存与链表 1. 尝试生成一个链表头并将其初始化. 2. 尝试向内存 ...

  7. 《Windows内核安全与驱动开发》4.1 文件操作

    <Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发>4.1 文件操作 从 C:\a.txt 中读取一部分内容并利用 DbgPrin ...

  8. 《Windows内核安全与驱动开发》4.3 时间与定时器

    <Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发>4.3  时间与定时器 一.获取自系统启动以来的毫秒数 /* 函数作用:求自操 ...

  9. 《Windows内核安全与驱动开发》 4.4 线程与事件

    <Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 4.4 线程与事件 一.开辟一个线程,参数为(打印内容+打印次数),利用线程 ...

随机推荐

  1. CSPS模拟 48

    ??? 分数越来越低??? T1 String Master 题目过于毒瘤,以至于我都不想改 T2 Tourist Attractions 稍微转化题意是求无向图的三角形个数 由于坚信bitset不是 ...

  2. 关于GC(上):Apache的POI组件导致线上频繁FullGC问题排查及处理全过程

    某线上应用在进行查询结果导出Excel时,大概率出现持续的FullGC.解决这个问题时,记录了一下整个的流程,也可以作为一般性的FullGC问题排查指导. 1. 生成dump文件 为了定位FullGC ...

  3. 学习笔记之vim的使用

    很多刚学习linux编程的人总是对vim有一种恐惧,我自己就是这么回事的. 可是当你努力的去尝试学习使用后,才发现它的精髓所在. 在我看来,让vim变得好用的前提是要安装两个插件,ctags和tagl ...

  4. 深入理解@LoadBalanced注解的实现原理与客户端负载均衡

    前提 在阅读这篇博客之前,希望你对SpringCloud套件熟悉和理解,更希望关注下微服务开发平台 概述 在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate ...

  5. css3 svg路径蒙版动画

    css3 svg路径蒙版动画 具体看https://www.cnblogs.com/oubenruing/p/9568954.html 还有个更好控制的写法<pre><!DOCTYP ...

  6. nyoj 412 Same binary weight ()

    Same binary weight 时间限制:300 ms  |  内存限制:65535 KB 难度:3   描述 The binary weight of a positive  integer ...

  7. celery 启用worker ValueError: not enough values to unpack

    [2018-01-12 19:08:15,545: INFO/MainProcess] Received task: tasks.add[5d387722-5389-441b-9b01-a619b93 ...

  8. C语言作业|08

    问题 答案 这个作业的属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-2/homework/9977 我 ...

  9. error: (-215:Assertion failed) size.width>0 && size.height>0 in function 'cv::imshow'

    用Python打开图像始终提示错误 error: OpenCV(4.1.1) C:\projects\opencv-python\opencv\modules\highgui\src\window.c ...

  10. PHP的两种选择防止sql注入

    1.使用PDO: $stmt = $pdo->prepare('SELECT * FROM user WHERE name = :name'); $stmt->execute(array( ...