基于文件过滤驱动的透明加密那点事儿

  文件透明加密这点事儿,从2001年开始出现基于API HOOK的方式开始到现在,已经十几年了,有细心人按技术实现的方式将其细分为4代,分别是基于API HOOK的第一代技术、基于文件过滤驱动(加清缓存)的第二代技术、使用Layerfsd的双缓冲第三代技术和基于微软新一代minifilter框架的Layerfsd双缓冲第四代技术。第一代和第二代的技术划分基本上没有异议,所谓的第四代很多人并不认同,认为使用minifilter框架算不上是技术突破,其技术实现仍然是基于Layerfsd的双缓冲技术,没有新意。
        我们从2009年开始研究并实现了基于Layerfsd的双缓冲技术,并应用于自己的产品中,这些本来都是老生长谈,只是最近几天根据用户反馈修改了几个BUG,忽然觉得还可以说道说道。Layerfsd的双缓冲技术最早出现在驱网论坛上的时候,讨论可谓是热烈,随着一些开发者逐步从理论到实践,完成了具体的实现之后,就开始了有意无意的技术封锁,一些技术理论和部分公开的源代码都无影无踪,不过从侧面也可以看出来,这个技术其实还是有一定的门槛的。其门槛并不在于技术有多难,关键在于细节和稳定性,根据理论做出一个实现不难,网上很多号称出售Layerfsd的双缓冲技术实现源代码的,叫价8-40万的都有,不过都只能算是一个理论研究系统,稳定性都很难保证,更不用说实用性了。
        为了了解同行的技术成熟度,我们经常找来同行的产品进行测试,今年上半年测试了两个驱动,一个驱动是对Visual Studio不兼容,每次保存文件后都会提示文件被外部修改,需要再确认一次,都是做这个的,我们当然清楚这个是layerfsd层的文件时间没有处理好,不过用VC编译一个加密的工程源代码时,总是蓝屏,这个应该就是实现者的技术实力问题了,还有对NTFS分区还马马虎虎,但是只要操作FAT分区的文件系统就没有反应,根据我们的经验应该是内部有死锁产生。还有一个驱动是不支持动态磁盘系统和可卸载的媒体(比如U盘),用WORD打开的文档,在编辑状态时居然可以从资源管理器中删除,这个是致命的layerfsd层文件权限管理失败,和作者沟通这个问题,作者认为这是双缓冲驱动实现的特征,只要是使用双缓冲技术实现的驱动都有这个问题,对此我们不敢苟同。
        这样的实现买回去也没办法用,想做出实用的商业软件至少还要2-3年的时间开发功能并做好稳定性。如果有钱,可以直接购买OSR的DMK,稳定性有一定的保证,但是要在上面做二次开发实现自己的功能。pfp也公开过一份源代码,是个半成品系统(现在驱网所有的下载链接都失效了),但是距离实现还有很远的距离,当然还是有很多人的实现都是基于这个源代码做的,这个一测试就能感觉出来。
        使用第二代技术实现的商业应用很多,只要能做稳定,基本都有市场,但是这个技术有几个致命的问题,就是文件操作效率低下,容易损坏文件,并且和反病毒软件不兼容。文件操作效率低下的原因在于为了防止非授信进程访问文件系统缓存的文件明文,每次打开和关闭文件时都要清理文件缓存。这对相当于屏蔽了系统文件缓存带来的性能优化,对大文件的操作影响尤其明显。我们测试过一个使用这种技术实现的商业软件,用word打开一个100多M的大文件后,用另一个非授信进程每隔15-30秒钟只读访问一次这个文件(这会促使驱动实现每隔15-30秒钟就清一次缓存),结果卡的基本上没办法操作这个word文档,如果是双缓冲,就没有这个问题。损坏文件的原因主要是对于延迟写入的缓冲文件,用户的写入操作是写入了缓存,但是负责延迟写入的system进程还没有将其写入文件,此时如果有非授信进程打开文件,会导致缓存被清除,这导致用户的修改没有写入,很多情况下都会造成文件数据丢失或文件格式损坏,与杀毒软件不兼容也基本上是这个原因。
        第二代技术的实现,在处理加密文件标识的问题上也很棘手,我们测试过的很多实现都是使用影子文件的方式,所谓影子文件,就是构造一个文件名与加密文件有一定的关联的影子文件,比如在原始文件名前增加一个固定标识的前缀,或后缀,或使用一个特殊的文件扩展名。当打开一个文件时,加密驱动首先看看是否存在影子文件,如果是就说明是一个加密文件,需要做解密处理。影子文件的管理也是一个很麻烦的地方,需要在驱动中对IRP_MJ_DIRECTORY_CONTROL进行过滤处理,对上层应用过滤掉这些文件名,使得用户在资源管理器中看不到这些影子文件,感觉不到他们的存在。但是只要用户停止驱动,这些文件就原型毕露,一些安全软件,比如冰刃,可以绕过驱动直接删除影子文件,会带来一些不稳定因素。此外,文件的复制和删除都要考虑影子文件,维护上也挺麻烦的。也有一些商业实现将影子文件集中在某个系统目录中进行管理,但是也要解决同名的问题,也不是完美的方案。
        从理论上所,使用双缓冲技术可以回避上面提到的清缓存问题,同时,双缓冲也可以解决文件加密标识的存放问题。双缓冲技术可以将加密信息构造成一个特殊的数据块直接存放在文件中,至于是放在文件头部还是文件尾部(从理论上说,也可以放在文件中间某个位置,不过是自找麻烦),不同意见还是很多的,各有各的理论依据,有人认为放在文件头部容易破坏文件,不过这是没有根据的,如果驱动实现不成熟,这块信息放在什么地方都可能破坏文件。倾向于将这块信息放在文件尾部的人觉得文件完成最后的写入,关闭之前补上一块加密信息是顺理成章的事情,倾向于将这块信息放在文件头部的人则是秉承传统的思想,毕竟很多文件格式都是将文件的特殊信息构造成一个特殊的文件头存放的,不过就实现而言,这二者没有优劣之分。
        双缓冲技术需要在一个layerfsd层访问真实文件,这就带来一个驱动的(IRP_MJ_CREATE)重入问题,这个解决不好就直接递归到栈溢出了。防止重入有多重方法,使用minifilter框架的有个优势,就是可以直接使用FltCreateFile系列函数绕开驱动直接打开和读写文件,这个后面再说。如果不使用minifilter框架,常用的两种方法就是构造影子卷进行文件访问,或直接构造IRP进行文件操作。构造影子卷的原理就是通过影子卷重定向文件的访问,因为过滤驱动不会attach影子卷,因此就规避了重入问题。使用影子卷的好处是可以使用ZwCreateFile等内核API直接操作文件,方便、安全。但是attach物理卷的时候要避开影子卷,一旦不小心attach了影子卷就会死的很惨。直接构造IRP进行文件操作应该是一个很优雅的方案,但是实现起来需要考虑比较多的细节,网上也有一些现成的源代码实现,不过或多或少都有一些问题,需要修改一下才能用。关于这方面的资料首先是OSR的“Rolling Your Own - Building IRPs to Perform I/O”一文,此外,还有baiyuanfan的“Windows平台内核级文件访问”一文也有很不错的介绍。
        minifilter是微软引入的一个轻量级微过滤驱动模型,简化了文件过滤驱动的实现细节,使得微过滤驱动可以忽略一些细枝末节的东西,将注意力集中在业务实现上。这比采用遗留驱动模型的sfilter框架有一定的优势,但是就透明加密驱动而言,并没有进步到说使用minifilter框架就比sfilter技术先进的程度,要知道,第二代透明加密技术的驱动也可以用minifilter框架实现,所以鼓吹minifilter+layerfsd更先进是没有依据的,重要的还是谁的驱动更稳定,毕竟动不动就蓝屏,或者损坏文件是用户最不能接受的。
        最后要说一些细节问题,比如双缓冲,所谓的双缓冲就是对同一个文件的访问形成两个cache缓存,对于授信进程,可以使用解密数据的明文cache,对于非授信进程,则使用密文的cache,二者共存且互相不干扰。使用双缓冲对系统内存的使用肯定是会增加的,但是带来的安全性和文件访问效率的提升是不言而喻的。至于cache的实现方式,可以使用windows的文件缓存系统,也可以自己实现文件缓存系统,据我所知,很多数据库软件就没有使用windows的文件缓存系统,而是根据需求自己实现的缓存系统。极端的说,你甚至可以不实现缓存,所有加密文件的读写都是实时操作实际文件,不支持一切缓存读写和fastio,我们在测试时遇到过这样的实现,也号称是支持layerfsd的双缓冲技术,虽然没有双缓冲的文件访问效率,但是也算是回避了第二代驱动技术的几个难题。还有比如授信进程的识别问题,简单地根据程序文件名称进行识别是非常幼稚的做法,对程序改个名字就可以欺骗加密驱动得到解密后的明文。还有授信进程的识别问题,对于有的应用程序,通常是一个图形的前端加上几个没有界面的后台程序配合工作,如果授信进程只有前端的UI进程,还是无法访问加密文件,对这种情况也要做进程父子关系的识别和处理。当然还有经典的线程注入问题,通过远程线程注入,可以在授信进程中启动一个线程访问加密文件,并将解密的明文通过共享内存或socket接口传递给另一个非授信进程。解决之道就是阻止线程注入,内核和应用层都可以做,当然也会对正常需要线程注入的程序产生影响,比如本人的TabSiPlus外挂插件,需要注入到Source Insight进程内部启动一个tab标签栏,就因为这个原因与加密软件产生冲突。对于一些支持插件的软件,比如office,还需要对插件进行识别和屏蔽,方法也很多,方式也很流氓,经常弄得用户莫名其妙。我的建议是对这种支持插件的软件不要做特殊处理,安全性由用户自己管理,用户有时候并不是那么傻,不要什么事情都替用户做了。

你可能感兴趣的:(文件)