虽然为了通俗易懂而使语句显得不那么“专业”,但是的确还是提到了重点。我就来补充一下好了。
结束进程,一般来说前提首先是NtOpenProcess(PsLookupProcessByProcessId->ObOpenObjectByPointer)得到有相应权限的进程句柄,只要得到句柄之后方法就多了,不一定用ZwTerminateProcess(冰刃1.22据说用的是PspTerminateProcess)结束进程,各种能使程序崩溃的方法包括内存清零等都能搞得出来。也不必非要NtOpenProcess,完全可以自己调用内核函数得到进程句柄。
以上是一般来说的,其实为了达到让目标进程崩溃的目的,甚至可以不要进程句柄。
比如内存清零或写入垃圾代码的方式,其实只要驱动下获得_EPROCESS结构中的DirectoryTableBase得到页目录物理地址,切换cr3就可以读写其他进程的虚拟内存空间了(没记错的话早有POC了吧),而对于获得_EPROCESS结构,任何在任务管理器中未被隐藏的进程,其_EPROCESS结构指针都可以非常容易得到的(PsLookupProcessByProcessId就可以直接得到,如果没有被做手脚的话。遍历ActiveProcessLinks双向链表也可以,既然任务管理器能看见进程说明这个链表相应项没有被摘链)。所以不要怀疑,只到POC层次的话,驱动下的确很容易实现,而且这方法你还很难有针对性地拦截和判断(把_EPROCESS给藏起来任务管理器里就看不见此进程了,用户不会答应;过程中的其他步骤则简单到你根本无从判断它的好坏)。当然以上的作法都是要有Ring0权限的。
双方都进了Ring0的话,本来就是endless war,只要对方研究了你的技术,就可以见招拆招,在这一点上安全软件和病毒rootkit没有什么区别,一般用户就是想不通这一点,才会老是纠缠在“冰刃能够结束瑞星”这种事情上。其实阻止冰刃结束瑞星即使在Ring0做也不难,但是由此带来的稳定性、兼容性、运行速度等等的影响却不能不考虑(比如PsLookupProcessByProcessId要是做掉的话,估计任务管理器对此进程的显示就会不正常的,这是用户不会接受的。ObOpenObjectByPointer打开的不仅仅是进程句柄,很多对象的访问都可以通过它,被调用的越频繁,HOOK掉之后就越会影响稳定性和响应速度,KiInsertQueueApc就更不用说了,看到号称不会被冰刃结束的安全软件们的inline hook,我都怕了)。
与其他安全工具做这种技术竞赛,吃亏的永远是瑞星这样的正规商业软件,因为说白了,很多在底层上做得很大胆的工具,基本都是免费工具,而且不是常驻内存的工具,既不必担心长期使用导致的稳定性等问题,也不必担心用户因此找他们的麻烦,而这些因素瑞星这样的商业软件却不得不考虑。用户电脑系统稳定性是第一位的,你保护做得再牛,如果系统因为稳定性原因而崩溃,也是得不偿失。
因此,呼吁杀软阻止冰刃,并最终导致这种技术上的无休止竞赛,从而使用安全软件稳定性兼容性隐患越来越大的话,最终吃亏的还是用户自己。
说了这么多,听起来Ring0级的驱动攻防对主动防御的形势好像很严峻,其实并不是这样的,我只是想说要在Ring0级搞破坏有多么容易。
一般用户提起这个问题时,也忽略了一个前提,即冰刃进Ring0这个前提。
用户根本忽略了杀毒软件主动防御的真正特性,就是利用高优先级启动的优势,抢先占领内核底层这个“制高点”,以拒绝后来的一切有害操作。实际操作中,如果冰刃是个病毒,它一加载驱动,瑞星拦截提示后,用户马上选择拒绝,冰刃就会初始化失败,就直接没戏了。所有谈论冰刃结束瑞星并因此担忧的用户,无一例外地都是直接允许了冰刃加载驱动,这本身就已经是自己无视了主动防御的作用,自己把这个问题带入了Ring0的endless war的范畴。而一旦进入了驱动攻防的状态,主动防御的优势就将丧失,不懂技术的用户根本就没有意识到这个问题。
同样的,担心有病毒利用冰刃的技术的用户,大可不用担心,这种病毒早就出现过了,在某些版本的机器狗驱动里就有这部分按照冰刃的结束进程原理进行操作的代码,但是这个版本根本没有大规模流行。原因正是基于上一段所讲的事实,机器狗的加载驱动方式是最传统的CreateService(或者通过替换beep.sys再启动其服务方式加载病毒驱动),在现今杀毒软件普遍拦截驱动加载的情况下,实际上已经没有了在防护完整的系统中继续肆虐的空间了。只要拦截并拒绝这种病毒加载驱动,这个问题就将不再存在。
因此,真正需要担心的不是这种传统的驱动型的Ring0级对抗,对于主动防御软件来说,这种对抗更多的只是一种技术层面的讨论,更应该引起注意的是通过Ring3级的代码就可以做到的对付杀毒软件包括结束瑞星的一些方法,以及时不时冒出来的可以被称为主动防御的恶梦的内核权限提升漏洞。
主动防御的机制看起来复杂,最终其实归结于三步:
拦截->判断->放行/拒绝
最难做的是哪一步?
是拦截吗?不是,只要插入系统底层,进占内核“制高点”,拥有了完全的权限之后,在POC级别上可以说只要病毒能做的,我们至少不会输,而从POC到实用软件,则是稳定性和兼容性的问题了(当然有时这个问题很难解决,以致于一些目前其实早已了解的技术因此根本无法在商业安全软件中采用)。
其实最难的是判断。主动防御软件被终结,往往并不是因为拦载不住某个操作,而是拦住了之后并没有把它当成恶意行为,于是又放行了。这种放行,当然有用户自己无法判断情况下自主放行,也有安全软件完全没有“意识”到其为危险操作而自动放行的。
举个例子,用NtOpenProcess获取不了句柄的话,就用ZwQuerySystemInformation->ZwDuplicateObject就好了,就如我之前在样本区看到一个Ring3下结束杀软的样本,都是早就公开了的代码了,害我逆了半天VB程序最后发现没有什么收获。这些API都是安全软件早已知道的,对其调用的拦截也是完全有拦截的,但是就是因为难以判断其操作的好坏,就放行了,因此造成了意料不到的结果。在主动防御时代,这种东西将越来越多,病毒不再是企图用直接冲进Ring0的方法来对占据“制高点”的杀软进行强攻,而是采取这种“不按常理出牌”的方式让安全软件措手不及。从这一点上看,至少瑞星如果把在csrss.exe进程中保存的自身进程的句柄抹掉,应该是有好处的。
另一种就是让人兴叹的内核权限提升漏洞了。如之前的win32k.sys的漏洞,一个SendMessage就可以触发,触发后可以添加GDT,然后就可以操作内核空间了,漏洞利用的POC当时放出来的时候任何主动防御软件都没能阻止。同样也并不是拦不到,一个SendMesage只要SSDT Shadow HOOK就行了嘛,早就有了,但是问题是当时安全软件还根本不“知道”这个看似普通的调用就是可以导致溢出的信号。
因此,从主动防御这个角度来看,规规矩矩加载驱动的软件,包括正常的安全工具,绝不是杀毒软件自我保护的大敌,没有必要对冰刃能结束瑞星耿耿于怀。
PS:说实在,现在驱动级技术的讨论,早就超越了冰刃的范畴,冰刃以前使用的那些手段,在驱动技术爱好者看来,已经变成早已被挖掘公开了的“科普”级技术了。但是为什么冰刃还在普通用户的手工杀毒操作中扮演着重要的角色?那是因为技术讨论中的POC是一回事,真正能够实用的成品又是另外一回事,实际出现的病毒所使用的技术,一般来说与真正的技术讨论者所讨论的技术,要有几年的差距。
因此,从普通用户的角度出发,我们不应该过份关注于这种技术层面的讨论,而更应该关注杀毒软件在实际使用中到底能不能发挥作用,这对于普通用户来说才是最实际的,也是杀毒软件最应该做好的。