aben1223
驱动小牛
驱动小牛
  • 注册日期2004-11-29
  • 最后登录2007-06-01
  • 粉丝1
  • 关注0
  • 积分1000分
  • 威望201点
  • 贡献值0点
  • 好评度192点
  • 原创分2分
  • 专家分0分
阅读:3767回复:1

心得--内核驱动与文件创建读写

楼主#
更多 发布于:2007-04-23 10:41
  内核驱动与文件创建读写
目的:
在内核驱动中创建文件,并进行读写。用于保存驱动运行中的信息。

方式:
    可以用两种方式实现该操作。
1、    在应用程序中创建文件,驱动运用IOCTL将信息传给应用层,应用程序对文件进行读写。Tdi_fw就是利用这种方式来记录驱动过滤信息,Tdi_fw的应用程序创建一个线程,循环利用IOCTL来读取驱动信息,并保存到文件。
2、    在驱动中完成所有的这些操作。在这里我们主要讨论这种方式。

实现:
    利用ZwCreateFile创建磁盘文件,利用ZwReadFile、ZwWriteFile读写文件。
创建文件代码如下:
RtlInitUnicodeString  (&usname,L"\\SystemRoot\\System32\\LogFiles\\passthru.log");
InitializeObjectAttributes(&oa, &usname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwCreateFile(&hfile, GENERIC_WRITE, &oa, &iostatus, NULL,
        FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);

写文件的代码如下:
ZwWriteFile(hfile, NULL, NULL, NULL, &iostatus, PrintContent, count, NULL, NULL);

这些代码倒是不难,网上找一些例子就搞定了。
注意两点:
1、    记得要在结束时,ZwClose(hFile)。
2、    系统刚启动时,最好将文件创建于C:,或者系统文件下。否则会创建文件失败。
真正的问题在下面,这些Zw函数都只能运行在PASSIVE_LEVEL上。在DISPATCH_LEVEL上调用这几个函数会出现BSOD。这时问题就来了,我们在PtReceive函数里面也需要保存一些运行的信息,而PtReceive处于DISPATCH_LEVEL的级别。这个问题需要解决。

这里有两种方式:
1.运用工作队列WorkItem,WorkItem能排队注册的回调函数。当例程处于DISPATCH_LEVEL级别时将回调函数塞入队列,当进程降低到PASSIVE_LEVEL时,这些队列中的回调函数将会被系统调用。
2.运用PsCreateSystemThread方式注册一个线程,在注册一个事件,申请一段内存。
在我们有信息写入文件的时候,先将信息写入内存,然后Set这个事件。在这个线程中循环KeWaitForSingleObject这个Event。然后在调用ZwWriteFile将信息写入文件。这里要注意一点的是文件读写的同步问题。我实现的就是这种方案。




4月20日补充:
1、可以用用RtlStringCbPrintfA代替sprintf函数,对内存进行字符串初始化。例子如下:

#include "ntstrsafe.h"

CHAR pszDest[30];
ULONG cbDest = 30;
LPCSTR pszFormat = "%s %d + %d = %d.";
CHAR* pszTxt = "The answer is";

RtlStringCbPrintfA(pszDest, cbDest, pszFormat, pszTxt, 1, 2, 3);
KdPrint(("%s",pszDest));
    需要注意的是这个函数还有另一个版本RtlStringCbPrintfW,专门用来对UNICODE进行超作。其他可能对我们比较有用的函数是RtlStringCbCopyA和RtlStringCbCatA用于拷贝和连接。操作都很简单,它们本身就是驱动下的sprintf的替代版本。

2、发现一个问题,就是安装完驱动重启后,在DriverEntry调用那个ZwCreateFile函数会返回失败。而在系统启动以后安装Passthru,就不会出现这个问题。原因是在操作系统启动时,系统初始化Passthru,调用我们的DriverEntry函数。这时候磁盘还没完全初始化好无法访问磁盘。
    这个问题其实对我们来说没有什么影响,我们需要记录信息的时候,一定是在应用程序客户端已经开启后的事情了。这时候磁盘早已启动好了,我们不用担心。
这里的解决方法是,在应用程序一启动,打开驱动设备的时候,才ZwCreateFile。这样一定是可以的。

3、    运用WorkItem进行系统回调函数排队的方法也不难。在NDIS下可以使用NdisInitializeWorkItem和NdisScheduleWorkItem函数来排队我们在高irql下的不能执行的动作。等到进程下降到passive_level时,这些已经排队了的回调函数就会Dequeue。
这个方法我今天试过了,可以使用。但是从效率来讲,并没有什么突出的地方。而且根据CSDN的介绍,工作队列有两个需要注意的地方。一是不能执行太长的操作,会死锁。2是在排队工作项之前,最好释放所有的mutex、lock、semaphore,否则很容易死锁。反正这两种操作都不错(另一种线程的方法参见前面文档)。随便选一个用用就行了。

最新喜欢:

linshierlinshi...
周维彬
cppdev
驱动牛犊
驱动牛犊
  • 注册日期2006-11-26
  • 最后登录2009-01-11
  • 粉丝0
  • 关注0
  • 积分300分
  • 威望43点
  • 贡献值0点
  • 好评度42点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-04-29 17:23
xiexie xieixie  
游客

返回顶部