内核呓语系列5 —— 系统调用Hook

2014-1-10 Nie.Meining Coding

上次写了一堆系统调用的相关东西,相信不少研究过rootkit或主动防御的朋友都是从SSDT/ShadowSSDT hook开始的,本篇就针对系统调用监控这方面展开讲讲。

主动防御技术一般通过拦截系统调用实现,在Windows中特别流行,Linux中比较少。除了Windows用户多,需求量大以外,还有一个原因是Linux中做系统调用监控其实不太方便提取上层行为,因为Linux把一切都的当作文件的理念导致你极有可能拦截到一大堆sys_read/sys_write,却很难知道样本究竟在干什么。尤其是一些以linux为内核的其它操作系统,往往在样本行为和系统调用之间还夹了一层虚拟机,例如Android的Dalvik。最初做Android监控时就遇到了这个问题,因此不得不采用了一些特别的手段。截图说明一下:

nhyy5_1.png

最初不管rk还是ark都爱在SSDT里一阵乱勾,这并不是一个很好的方案,比如容易被检测、hook点太分散、兼容性不好、动态增减hook不方便以及维护难度大……因此后来出现了一些技术上的进化。

进化的核心思想就是将分散的hook点尽可能地聚合在一起。这里先简单讲讲系统调用的过程,当应用层通过int 0x2e/sysenter进入系统内核后,KiSystemService/KiFastCallEntry作为“分发函数”被调用(KiSystemService和KiFastCallEntry最终会跳转到同一个函数KiSystemServiceRepeat,该函数分发根据服务号调用KTHREAD->ServiceTable里的实际函数,完成实际的分发工作)。

在这个过程中,有三个比较有意思的地方:

第一个地方是:对于Windows,系统调用往往参数复杂,直接复制到内核栈上即可,但Linux的系统调用比较短小精干,因此通过寄存器传递,寄存器不够用的话就在用一个寄存器直接指向参数所在的用户空间地址,相当高效;

第二个地方是:对于Windows,进程地址空间中有个神奇的地方,KeUserSharedData同时被映射到用户空间的0x7FFE0000处和内核空间的0xFFDF0000处,俗称“飞地”。这里不仅有TickCount等频繁使用的东西,还有SystemCall和SystemCallReturn两个函数指针,指向ntdll.dll中的syscall入口方法和出口方法,即int 2e或sysenter:

nhyy5_2.png

这样Windows在启动过程中就可以根据处理器是否支持快速系统调用(cpuid)来动态地选择syscall入口/出口,以及内核中的分发函数KiFastSystemCall/KiIntSystemCall,非常巧妙。具体可以看看WRK中的 PspInitializeSystemDll->PspLookupKernelUserEntryPoints,代码片段如下:

nhyy5_3.png

第三个有趣的地方是:每个线程都有自己的KTHREAD->ServiceTable,但是指向的其实是KeServiceDescriptorTable或KeServiceDescriptorTableShadow这两张全局表(取决于该线程是否是GUI线程,具体可以参考本系列之前讲Windows子系统的文章)。因此如果修改某线程的KTHREAD->ServiceTable指向某个伪造的调用表,似乎能实现一些意想不到的邪恶效果……

回到主动防御的问题上来。随着技术进步,360的hookport.sys很有代表性,这个驱动对分发过程进行了hook(在我的印象中应该是360最先这么做的)。当年大致逆向过hookport.sys,做过一些摘钩子的实验。360的hook采用两级跳的形式,第一跳有检测修复,因此摘第二跳比较科学。当时还仿照360的hook方案做了一个课程设计:Hook KiFastCallEntry监控系统调用(实际上,正确的说法应该是 Hook KiSystemServiceRepeat监控系统调用)

后来,360的这种hook分发函数的方式几乎成了主动防御的模板,金山卫士、腾讯管家啥的都是这么干的。具体可以参见我写的:QQ电脑管家中的TsFltMgr Hook框架分析》和《QQ电脑管家中的 Hook 过程分析》。该技术中的关键问题是,在hook过程中需要处理好多核同步(不要暴力关中断,提升IRQL要考虑到多核问题)、读写保护(不要暴力改cr0,映射MDL更好一些),以及一些低概率竞争问题(QQ管家中的3个nop做得很棒)。

逆向了一些主动防御产品后,自己也手痒,仿造这些产品做了一个主动防御的框架,发到了看雪上:《发一个主动防御的代码》,支持32位和64位。当然,支持64位纯粹为了练手,必须关闭PatchGuard……

个人感觉,在操作系统本身并不完善的年代,系统会允许(或依赖)第三方软件对其进行patch,因此各类主动防御产品蓬勃发展。但是随着系统本身的完善,无论ARK还是RK都将被一视同仁地看作内核完整性的威胁者(毕竟其技术原理是一样的),这也是PatchGuard出现的原因。因此,传统方式的主动防御也逐渐不适用了。那么主动防御新的推广方式是什么?1. 学习MSE,注册标准的回调方法,包括进程/线程/模块的创建/卸载回调函数、文件/网络等各种过滤驱动,以及新的对象钩子ObCallBack回调(检测方法可参见我写的《ObCallback 回调钩子检测》)等。2. 利用广大非技术用户不在电脑、手机等智能设备上装一个管家卫士啥的就浑身难受的心理!(开个玩笑,不过这确实是一个方面)

今天先到这里了,下一期准备写写中断和异常。

发表评论:

Powered by emlog