阅读:2065回复:7
初学驱动,关于文件过滤驱动程序的几个问题
我刚学windows驱动程序开发,想尝试在sfilter基础上设计一个实现文件加密解密的驱动程序,有几个问题:
1)sfilter没有处理IRP_MJ_READ和IRP_MJ_WRITE,而是使用了fastio回调函数,我应该在IRP_MJ_READ和IRP_MJ_WRITE的处理函数中完成数据的加密解密还是在FastIORead和FastIOWrite函数中完成加密、解密? 2)在FastIORead、FastIOWrite函数中我需要判断读写文件的进程是否是指定进程(比如WINWORD.exe),如果是就进行加密解密,否则不做处理。如何获得读写文件的进程名字? 3)我想用3DES或者AES之类的加密算法,是以8字节或者16字节分组完成加密解密的,对于长度不是16整数倍的文件,需要补齐到整数倍字节,不知道我的设想是否正确。 4)对于读文件的操作,如果应用程序要求读文件的offset不是16的整数倍,我可以要求底层文件系统驱动多读几个字节,解密后从正确的偏移量开始给应用程序正确长度的数据;但是对于写文件加密,如果应用程序写的内容是文件中间的几个字节,是不是我还得把数据从文件中读出来,把相应内容的数据修改,再加密,再写回文件? 5)问题4)中描述的写加密的实现方式,对于以前是明文保存,用受控软件打开后再保存的文件,可能会存在部分内容加密了,部分内容未加密的情况,这样就麻烦了。不知道这时应该怎么处理? 初学驱动程序,不懂的问题很多,希望大拿们不吝赐教!先谢谢啦! |
|
沙发#
发布于:2009-03-22 14:20
![]() |
|
板凳#
发布于:2009-03-22 17:40
楚狂人的回复(他只回答了4个问题):
(1)中的“不是”“而是”是错误的。sfilter没有处理irp_mj_read和irp_mj_write,是因为所有的read和write都被默认的分发函数处理了。默认分发函数的功能就是直接下发。 fast io read write也是直接下发。只是因为每个fast io函数原型不同,无法写出一个通用的处理函数,所以你才以为每个fast io都“处理了”。要加密解密必须自己增加对read,write的分发函数,取代默认的分发函数。 (2)获取进程的名字不是一件简单的事情,我拷贝代码给你。但是切记:请勿向我索要任何代码或者发送代码让我帮你找bug。这是业内的大忌。(楼主注:俺没有向他要代码,也没有让他帮忙找bug,不知楚狂人何出此言) // 这个函数必须在DriverEntry中调用,否则cfCurProcName将不起作用。 static size_t s_cf_proc_name_offset = 0; void cfCurProcNameInit() { ULONG i; PEPROCESS curproc; curproc = PsGetCurrentProcess(); // 搜索KPEB结构,在其中找到字符串 for(i=0;i<3*4*1024;i++) { if(!strncmp("System",(PCHAR)curproc+i,strlen("System"))) { s_cf_proc_name_offset = i; break; } } } // 以下函数可以获得进程名。返回获得的长度。 ULONG cfCurProcName(PUNICODE_STRING name) { PEPROCESS curproc; ULONG i,need_len; ANSI_STRING ansi_name; if(s_cf_proc_name_offset == 0) return 0; // 获得当前进程PEB,然后移动一个偏移得到进程名所在位置。 curproc = PsGetCurrentProcess(); // 这个名字是ansi字符串,现在转化为unicode字符串。 RtlInitAnsiString(&ansi_name,((PCHAR)curproc + s_cf_proc_name_offset)); need_len = RtlAnsiStringToUnicodeSize(&ansi_name); if(need_len > name->MaximumLength) { return RtlAnsiStringToUnicodeSize(&ansi_name); } RtlAnsiStringToUnicodeString(name,&ansi_name,FALSE); return need_len; } (3)你的想法是对的。 (4)所以需要加密标识。加密标识可以保存在文件头也可以保存在文件尾,必须对应用程序隐藏。保存在文件尾比较容易实现。 |
|
地板#
发布于:2009-03-22 19:31
关于第五个问题的答案:
我看了tooflat的sfilter程序,是这样处理的: 对于任何一个新打开的文件,根据规则判断这个文件以前是否加密了,现在是否需要加密,然后根据要求更新整个文件:以前没加密现在需要加密的,全部读出来,加密后再写回去(在sfWrite完成),以前加密了的,现在需要不加密的,全部读出来,解密(在sfRead()中完成),再写回去。 这样,就可以保证文件在打开之后处于正确的加密状态。 |
|
地下室#
发布于:2009-04-12 19:37
|
|
5楼#
发布于:2009-04-12 22:07
把readLen = iopb->Parameters.Read.Length以及ByteOffset设置成你想读的值,然后向底层驱动发送IRP读就行了。
如果用minifilter,在preread中设置参数后调用FltSetCallbackDataDirty()就行了。 注意Offet和length的长度需要满足底层驱动的要求。 |
|
6楼#
发布于:2009-04-15 15:21
回 5楼(zzbwang) 的帖子
Read的部份我瞭解了! 谢谢!但是现在疑问是在 pre-write时,每次进来的iopb->Parameters.Write.Length都不一样不知道如何让它进来就是固定的size. 如:4096 |
|
7楼#
发布于:2009-04-15 19:43
如果你的驱动只过滤Paging io,那么长度都是4096,这是一个簇的大小。如果还要处理cached io,进来的数据长度可以是任意值,你只能先把数据读出来,用新数据部分覆盖后再写回去。
|
|