阅读:3896回复:1
心得--内核驱动与文件创建读写
内核驱动与文件创建读写
目的: 在内核驱动中创建文件,并进行读写。用于保存驱动运行中的信息。 方式: 可以用两种方式实现该操作。 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,否则很容易死锁。反正这两种操作都不错(另一种线程的方法参见前面文档)。随便选一个用用就行了。 |
|
最新喜欢:linshi...
|
沙发#
发布于:2007-04-29 17:23
xiexie xieixie
|
|