写在前边
8.3 识别内联内核钩子
攻击者可以使用jmp指令修改现有内核驱动程序中的一个或多个内核函数,从而将执行流重定向到恶意代码,而不是替换SSDT中的指针(这使其易于识别)。正如本章前面提到的,我们可以使用apihooks插件来检测内核空间中的内联挂接。通过指定-P参数,我们可以告诉apihooks插件只扫描内核空间中的钩子。
在下面这个TDL3 rootkit的例子中,apihook检测内核函数IofCallDriver和IofCompleteRequest中的钩子。被钩子连接的API函数被重定向到名称未知的恶意模块中的0xb878dfb2和0xb878e6bb地址(可能是因为它通过解除KLDR_DATA_TABLE_ENTRY结构的链接来隐藏):
|
$ python vol.py -f tdl3.vmem --profile=WinXPSP3x86 apihooks -P Volatility Foundation Volatility Framework 2.6 ************************************************************************ Hook mode: Kernelmode
Hook type: Inline/Trampoline
Victim module: ntoskrnl.exe (0x804d7000 - 0x806cf580) Function: ntoskrnl.exe!IofCallDriver at 0x804ee120 Hook address: 0xb878dfb2
Hooking module: <unknown>
Disassembly(0):
0x804ee120 ff2500c25480 JMP DWORD [0x8054c200] 0x804ee126 cc INT 3
0x804ee127 cc INT 3
[REMOVED]
************************************************************************
Hook mode: Kernelmode
Hook type: Inline/Trampoline
Victim module: ntoskrnl.exe (0x804d7000 - 0x806cf580)
Function: ntoskrnl.exe!IofCompleteRequest at 0x804ee1b0 Hook address: 0xb878e6bb
Hooking module: <unknown>
Disassembly(0):
0x804ee1b0 ff2504c25480 JMP DWORD [0x8054c204] 0x804ee1b6 cc INT 3
0x804ee1b7 cc INT 3
[REMOVED]
*左右滑动查看更多
即使钩子模块的名称未知,仍然有可能检测到恶意的内核模块。在这种情况下,我们知道在恶意模块中API函数被重定向到以0xb87开头的地址,这意味着恶意模块必须位于以0xb87开头的某个地址。运行modules插件不会检测到该地址范围内的任何模块(因为它是隐藏的),而modscan插件检测到一个名为TDSSserv的内核模块。
Sys在基址0xb878c000加载,大小为0x11000。换句话说,内核模块TDSSserv的起始地址。Sys为0xb878c000,结束地址为0xb879d000 (0xb878c000+0x11000)。我们可以清楚地看到钩子地址0xb878dfb2和0xb878e6bb在tdssserver.sys的地址范围内。至此,我们已经成功识别了恶意驱动程序。现在你可以将驱动程序转储到磁盘上进行进一步分析:
python vol.py -f tdl3.vmem --profile=WinXPSP3x86 modules | grep -i 0xb878
Volatility Foundation Volatility Framework 2.6
python vol.py -f tdl3.vmem --profile=WinXPSP3x86 modscan | grep -i 0xb878 Volatility Foundation Volatility Framework 2.6
0x0000000009773c98 TDSSserv.sys 0xb878c000 0x11000 systemrootsystem32driversTDSSserv.sys
*左右滑动查看更多
8.4 检测IRP函数钩子
rootkit可以修改主函数表(调度例程数组)中的条目,以指向恶意模块中的例程,而不是与内核API函数挂钩。例如,rootkit可以通过覆盖驱动主函数表中IRP_MJ_WRITE对应的地址来检查写入磁盘或网络的数据缓冲区。下面的图表说明了这个概念:
通常,IRP处理程序在它们自己的模块中运行驱动程序点。例如,与null的IRP_MJ_WRITE相关联的例程。Sys指向一个空地址。然而,有时一个驱动程序会将处理函数转发给另一个驱动程序。下面是磁盘驱动程序转发处理程序函数到CLASSPNP.SYS的示例(存储类设备驱动):
|
python vol.py -f win7_clean.vmem --profile=Win7SP1x64 driverirp -r disk Volatility Foundation Volatility Framework 2.6 --------------------------------------------------
DriverName: Disk
DriverStart: 0xfffff88001962000
DriverSize: 0x16000
DriverStartIo: 0x0
0 IRP_MJ_CREATE
1 IRP_MJ_CREATE_NAMED_PIPE
2 IRP_MJ_CLOSE
3 IRP_MJ_READ
4 IRP_MJ_WRITE
5 IRP_MJ_QUERY_INFORMATION [REMOVED]
0xfffff88001979700 CLASSPNP.SYS
0xfffff8000286d65c ntoskrnl.exe
0xfffff88001979700 CLASSPNP.SYS 0xfffff88001979700 CLASSPNP.SYS 0xfffff88001979700 CLASSPNP.SYS 0xfffff8000286d65c ntoskrnl.exe
*左右滑动查看更多
要检测IRP钩子,我们可以关注指向另一个驱动程序的IRP处理程序函数,由于该驱动程序可以将IRP处理程序转发给另一个驱动程序,需要进一步研究它以确认钩子。如果我们正在实验室设置中分析rootkit,那么就可以从一个干净的内存映像中列出所有驱动程序的IRP函数,并将它们与受感染的内存映像中的IRP函数进行比较,以便进行任何修改。
在下面的例子中,ZeroAccess rootkit钩子磁盘驱动的IRP函数,并将它们重定向到地址未知的恶意模块中的函数(因为模块是隐藏的):
DriverName: Disk
DriverStart: 0xba8f8000
DriverSize: 0x8e00
DriverStartIo: 0x0
0 IRP_MJ_CREATE
1 IRP_MJ_CREATE_NAMED_PIPE 2 IRP_MJ_CLOSE
3 IRP_MJ_READ
4 IRP_MJ_WRITE
5 IRP_MJ_QUERY_INFORMATION [REMOVED]
0xbabe2bde Unknown
0xbabe2bde Unknown
0xbabe2bde Unknown
0xbabe2bde Unknown
0xbabe2bde Unknown
0xbabe2bde Unknown
|
modscan的以下输出显示了与ZeroAccess相关的恶意驱动程序(具有一个可疑的名称)和它在内存中加载的base地址(可以用来将驱动程序转储到磁盘):
python vol.py -f zaccess_maxplus.vmem --profile=WinXPSP3x86 modscan | grep -i 0xbabe
Volatility Foundation Volatility Framework 2.6
0x0000000009aabf18 * 0xbabe0000 0x8000 *
*左右滑动查看更多
一些rootkit使用间接的IRP挂钩来避免怀疑。在下面的例子中,Gapz Bootkit钩子null.sys的IRP_MJ_DEVICE_CONTROL。乍一看,似乎一切正常,因为IRP_MJ_DEVICE_CONTROL对应的IRP处理程序地址指向null.sys内。
仔细一看,就会发现不符之处:在一个干净的系统上,IRP_MJ_DEVICE_CONTROL指向ntoskrnl.exe (nt!IopInvalidDeviceRequest)中的地址,在这里,它是指向到null.sys中的0x880ee040。在拆卸地址0x880ee040(使用volshell插件),我们可以看到跳转到0x8518cad9的地址,这是在null.sys范围之外:
python vol.py -f gapz.vmem --profile=Win7SP1x86 driverirp -r null Volatility Foundation Volatility Framework 2.6 --------------------------------------------------
DriverName: Null
DriverStart: 0x880eb000
DriverSize: 0x7000
DriverStartIo: 0x0
0 IRP_MJ_CREATE
1 IRP_MJ_CREATE_NAMED_PIPE
2 IRP_MJ_CLOSE
3 IRP_MJ_READ
4 IRP_MJ_WRITE
5 IRP_MJ_QUERY_INFORMATION
[REMOVED]
13 IRP_MJ_FILE_SYSTEM_CONTROL
14 IRP_MJ_DEVICE_CONTROL
15 IRP_MJ_INTERNAL_DEVICE_CONTROL 0x828ee437 ntoskrnl.exe
python vol.py -f gapz.vmem --profile=Win7SP1x86 volshell [REMOVED]
dis(0x880ee040)
0x880ee040 8bff MOV EDI, EDI
0x880ee042 e992ea09fd JMP 0x8518cad9 0x880ee047 6818e10e88 PUSH DWORD 0x880ee118
As discussed so far, detecting standard hooking techniques is fairly straightforward. For instance, you can look for signs such as SSDT entries not pointing to ntoskrnl.exe/win32k.sys or IRP functions pointing to somewhere else, or jump instructions at the start of the function. To avoid such detections, an attacker can implement hooks while keeping call table entries within the range, or place the jump instructions deep inside the code. To do this, they need to rely on patching the system modules or third-party drivers. The problem with patching system modules is that Windows Kernel Patch Protection (PatchGuard) prevents patching call tables (such as SSDT or IDT) and the core system modules on 64-bit systems. For these reasons, attackers either use techniques that rely on bypassing these protection mechanisms (such as installing a Bootkit/exploiting kernel-mode vulnerabilities) or they use supported ways (which also work on 64-bit systems) to execute their malicious code to blend in with other legitimate drivers and reduce the risk of detection. In the next section, we will look at some of the supported techniques used by the rootkits.
465 ]
0x880ee07c Null.SYS
0x828ee437 ntoskrnl.exe
0x880ee07c Null.SYS
0x880ee07c Null.SYS
0x880ee07c Null.SYS
0x880ee07c Null.SYS
0x828ee437 ntoskrnl.exe
0x880ee040 Null.SYS
*左右滑动查看更多
|
关于Gapz Bootkit所使用的隐形技术的详细信息,可参阅题为“注意Gapz:有史以来分析过的最复杂的Bootkit”的白皮书,由Eugene Rodionov和Aleksandr Matrosov撰写。
白皮书网址:
https://www.welivesecurity.com/wp-content/uploads/2013/04/Gapz-Bootkit-whitepaper.pdf
*左右滑动查看更多
如上所述,检测标准挂钩技术相当简单。例如,我们可以查找诸如SSDT条目没有指向ntoskrnl.exe/win32k.sys这样的迹象或IRP函数指向其他地方,或在函数开始处跳转指令。为了避免这种检测,攻击者可以实现钩子,同时将调用表条目保持在范围内,或者将跳转指令放置在代码深处。
要做到这一点,他们需要依赖于给系统模块或第三方驱动程序打补丁。打补丁系统模块的问题是,Windows内核补丁保护(PatchGuard)阻止对64位系统上的调用表(如SSDT或IDT)和核心系统模块打补丁。
由于这些原因,攻击者使用技术,依靠绕过这些保护机制(如安装Bootkit/利用内核漏洞)或者他们支持的方式(也在64位系统上工作)来执行他们的恶意代码融入其他合法司机和降低检测的风险。在下一节中,我们将研究rootkit所使用的一些受支持的技术。
(未完待续)
往期回顾
原文始发于微信公众号(安恒信息安全服务):九维团队-青队(处置)| 使用内存取证检测高级恶意软件(七)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论