欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

驱动程序学习笔记(四)

驱动程序学习笔记(四)

终于来到我们将要看到的过滤了,刚刚起步感觉辛苦。其时内核编程真的有点难,难得不是编,而是自己如何挖掘
想要的知识,挖掘深藏在里面的知识。书是大牛写的,大牛写书时虽然考虑到我们小菜学内核的情况,但是写书时他
们都小有成就了,思维方式也和我们存在差距了,这节我们就以小菜的想法来切实完成这个串口过滤的驱动吧。这章
我先从头仔细看了一遍,没有动手去写代码,现在大概了解整个过程,自己一步一步实现这个过滤驱动吧。写过滤驱
动前首先要了解下面几点:
1:什么是过滤?--个人理解(当然是看了书之后的理解了),就是在上层设备与下层设备之间再加上一层过滤网,过滤
出我们喜欢的东西,不喜欢的就让它继续走。比如家里电饭锅淘米一样,滤除渣滓,留下上等大米,哈哈,想起大米
就饿了。
2:为什么要过滤?--这不废话吗,呵呵,当然个人用途不同了,杀毒软件监视这端口,不放过每一位从端口流过的数
据,他能怎么办呢,过滤呗,那些黑客呢,自然不是等闲之辈了,他们想从端口获得他们感兴趣的东西,密码?或是
截获他老婆跟比人的聊天记录?无聊……这里纯属自娱自乐,不然长时间对着电脑就没兴趣啦O(∩_∩)O~~
3:怎么样去过滤?--重点来了,过滤嘛,能有多难?不就是在上下层设备之间加一个过滤设备嘛,既不影响上层,也
不影响下层。说来说去就是这么个过程,首先创建一个设备(用于过滤)--将这个设备附加到指定的设备栈上--找到你
要绑定的串口--写出自
己的请求分发函数--不想过滤时就把驱动拆了,把设备从链子上摘下来便是。其中一个问题就是如何找到你要过滤的
指定设备传送的请求呢,下面一一道来。
**************第一步:生成设备,并绑定到指定的设备栈上,生成设备用到IoCreateDevice,而绑定设备则是用到
IoAttachDevice
ToDeviceStack,函数都很简单,看看DDK上的说明吧,
NTSTATUS 
  IoCreateDevice(
    IN PDRIVER_OBJECT  DriverObject,--本驱动对象
    IN ULONG  DeviceExtensionSize,--这里不使用,为NULL即可
    IN PUNICODE_STRING  DeviceName  OPTIONAL,--可选的名字,过滤设备不要名称
    IN DEVICE_TYPE  DeviceType,--和要绑定的设备类型一致
    IN ULONG  DeviceCharacteristics,--书上凭经验设为O
    IN BOOLEAN  Exclusive,--保留为系统使用,直接定位false即可
    OUT PDEVICE_OBJECT  *DeviceObject--OUT宏指定为输出参数,即返回值,返回本过滤设备指针
    );
IoCreateDevice:下面一段英文解释
IoCreateDevice creates a device object and returns a pointer to the object. The caller is responsible 
for deleting the object when it is no longer needed by calling IoDeleteDevice.
IoCreateDevice can only be used to create an unnamed device object, or a named device object for which
a security descriptor is set by an INF file. Otherwise, drivers must use IoCreateDeviceSecure to 
create
named device objects. For more information, see Creating a Device Object. The caller is responsible 
for
setting certain members of the returned device object. For more information, see Initializing a Device 
Object and the device-type-specific documentation for your device. 
Be careful to specify the DeviceType and DeviceCharacteristics values in the correct parameters. Both
parameters use system-defined FILE_XXX constants and some driver writers specify the values in the 
wrong
parameters by mistake.
Device objects for disks, tapes, CD-ROMs, and RAM disks are given a Volume Parameter Block (VPB) that 
is
initialized to indicate that the volume has never been mounted on the device.
If a driver's call to IoCreateDevice returns an error, the driver should release any resources that it
allocated for that device. 
Callers of IoCreateDevice must be running at IRQL <= APC_LEVEL.
捡主要的讲,意思是该函数创建一个设备对象并返回这个对象的指针,当你不再需要这个设备时请调IoDeleteDevice
去删除它,这样我们又学到了这个函数。而且IoCreateDevice只能创建没有名字的设备,若想创建命名的设备,则使
用函数IoCreateDeviceSecure。另外这里提到是小心使用这两个参数,DeviceType,DeviceCharacteristics,他们
都是被定义成FILE_XXX 这样的结构,如果该函数调用失败,那么请释放之前所有用到的资源。最后这个函数运行在
APC_LEVEL级别以下。
而我们要创建的是过滤设备,最后我们这个设备什么事也不干,为了不影响串口功能的使用,还是把这个设备类型设
置成和原来那个设备一样的吧,即这个参数使用原来设备的类型,另外要注意的是,创建设备成功后,把这个设备相
关标志设置成和要过滤的设备标志一样。oldobj为要过滤的设备对象,fltobj为本过滤设备对象
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;
一切设置好以后,就可以开始绑定了,
IoAttachDeviceToDeviceStack(*fltobj,oldobj); returns a pointer to the device object to which the 
SourceDevice
 was attached。返回一个被过滤设备绑定后的设备指针,其实这里有点疑问?这个返回的不就是要被绑定的设备么
,这个设
备现在存在于最上层了,等待我后面验证。***********验证**********
默认情况下,绑定设备之后设备并没有启动,书上给出这么一句,
(*fltobj)->Flags = (*fltobj)->Flags & ~DO_DEVICE_INITIALIZING;
我在DDK帮助上找到这样一句,
Function and filter drivers must clear the DO_DEVICE_INITIALIZING flag. 这样就可以理解了,清除相应的
标志位就可以了,意思是不需要初始化,直接启动即可,因为他和要绑定的设备是同样的。

****************第二步:根据相应串口ID,设法找到串口设备的指针,这样才能提供给人家绑定啊,连串口设备的
指针都没有
你叫人家啥啊,书上说是打开串口,可我觉得整个过程根本就没有没碰到打开串口这个东西啊,我把它叫做获得串口
设备对象指针函数吧。假设这个设备有名字的话,可以用函数IoGetDeviceObjectPionter来得到对象指针。
DDK中有这样的评论:
This routine also returns a pointer to the corresponding file object. When unloading, a driver can 
dereference
the file object as a means of indirectly dereferencing the device object. To do so, the driver calls 
ObDereferenceObject
from its Unload routine, passing the file object pointer returned by IoGetDeviceObjectPointer. 
这个例程同样返回一个文件对象指针,当卸载的时候这个驱动必须解除这个文件对象指针的引用。不管怎么样,一定
记得解除引用。一般地,串口在在设备中总是以固定形式的名字出现的,如\device\serial0,\device\serial1之类
的,那么可变的就是一个序号而已。在此引入内核中的一个格式化字符的函数,同sprintf有异曲同工之处。
即RtlStringCchPrintf,参数没什么好解释的,看DDK上微软的一个范例就OK了,
WCHAR pszDest[30]; 
size_t cchDest = 30;
LPCWSTR pszFormat = L"%s %d + %d = %d.";
WCHAR* pszTxt = L"The answer is";
NTSTATUS status = 
    RtlStringCchPrintfW(pszDest, cchDest, pszFormat, pszTxt, 1, 2, 3);
The resultant string is "The answer is 1 + 2 = 3." It is contained in the buffer at pszDest。
照葫芦画瓢,把传进来的串口ID转换成\device\serial0这种类型即可,看代码。
  UNICODE_STRING name_str;
  static WCHAR name[32] = { 0 };
  PFILE_OBJECT fileobj = NULL;
  PDEVICE_OBJECT devobj = NULL;
  // 输入字符串。
  memset(name,0,sizeof(WCHAR)*32);
  RtlStringCchPrintfW(name,32,L"\\Device\\Serial%d",id);
  RtlInitUnicodeString(&name_str,name);
然后获得该设备对象的指针,
*status=IoGetDeviceObjectPointer(&name_str, FILE_ALL_ACCESS, &fileobj, &devobj);
记得上面所说的用过之后要调用ObDereferenceObject解除文件对象的引用哦。
这里是获得一个串口设备对象的指针,但是一个系统里有多少个串口我们并不晓得,我也没什么办法去列举出那些串
口,书上是假设最多有32个串口,不知正确与否。不过我可以提出一种思路,遍历所有的设备对象,然后匹配Serial%d
这个字符串,但是显然比作者的那个麻烦多了,图省事,直接假设吧,一般也没有那么串口。
那么构造一个循环,获得所有的串口设备对象的指针不难吧,就是不断传入相应的串口ID,然后调用获得串口设备对
象指针这个函数,接着再依次绑定这些串口,这里因为不知道有多少,所以干脆全部都绑定了,管他有多少呢,一个
都不能少是吧。相应的代码逻辑简单,就不列出了,代码传在附件中。

上传的附件 comcap.rar

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功