写在前边

六、DLL清单
在本系列文章中,我们已经看到了使用DLL实现恶意功能的恶意软件的例子。因此,除了调查进程之外可能还希望检查已加载的库列表。要列出加载的模块(可执行和dll),可以使用Volatility的dlllist插件。dlllist插件会显示与进程相关的完整路径。
下面让我们以一个名为Ghost RAT的恶意软件为例,它以服务DLL的形式实现恶意功能,因此,该恶意DLL通过svchost.exe进程加载。
下面是dlllist的输出,在这里我们可以看到一个由svchost.exe进程(pid 800)加载的带有非标准扩展名(.ddf)的可疑模块。第一列Base指定Base地址,也就是加载模块的内存中的地址:
python vol.py -f ghost.vmem --profile=Win7SP1x86 dlllist -p 880 Volatility Foundation Volatility Framework 2.6 ****************************************************************** svchost.exe pid: 880
Command line : C:Windowssystem32svchost.exe -k netsvcs
Base Size LoadCount Path
-------- --------- --------------------------------
0x00f30000 0x8000 0xffff
0x76f60000 0x13c000 0xffff
0x75530000 0xd4000 0xffff
0x75160000 0x4a000 0xffff
0x75480000 0xac000 0xffff
0x77170000 0x19000 0xffff
0x76700000 0x15c000 0x62
0x76c30000 0x4e000 0x19c
0x770a0000 0xc9000 0x1cd
[REMOVED]
C:Windowssystem32svchost.exe
C:WindowsSYSTEM32ntdll.dll
C:Windowssystem32kernel32.dll
C:Windowssystem32KERNELBASE.dll
C:Windowssystem32msvcrt.dll
C:WindowsSYSTEM32sechost.dll
C:Windowssystem32ole32.dll
C:Windowssystem32GDI32.dll
C:Windowssystem32USER32.dll
0x74fe0000 0x4b000 0xffff
0x6bbb0000 0xf000 0x1
0x10000000 0x26000 0x1
dataacdsystemsacdseeimageik.ddf
0x71200000 0x32000 0x3 C:Windowssystem32WINMM.dll
*左右滑动查看更多
|
dlllist插件从一个名为进程环境块(PEB)的结构中获取所加载模块的信息。回想一下我们先前的系列文章代码注入和钩子,当谈到进程内存组件时有提到过PEB结构驻留在进程内存中(在用户空间中)。PEB包含关于可执行进程在何处加载的元数据信息、它在磁盘上的完整路径以及关于加载的模块(可执行和dll)的信息。dlllist插件查找每个进程的PEB结构并获取上述信息。
那么问题来了,如何找到PEB的结构?EPROCESS结构有一个名为Peb的字段,该字段包含指向Peb的指针。这意味着一旦插件找到EPROCESS结构,它就可以找到PEB。需要记住的一点是,_EPROCESS驻留在内核内存(内核空间)中,而PEB驻留在进程内存(用户空间)中。
要在调试器中获得PEB的地址,可以使用!process扩展命令,它显示EPROCESS结构的地址,它还指定PEB的地址。从下面的输出中,我们可以看到explorer.exe进程的PEB在它的进程内存地址7ffd3000,它的EPROCESS结构在0x877ced28(在它的内核内存中):
!process 0 0
NT ACTIVE PROCESS DUMP ****
.........
PROCESS 877cb4a8 SessionId: 1 Cid: 05f0 Peb: 7ffdd000 ParentCid: 0360
DirBase: beb47300 ObjectTable: 99e54a08 HandleCount: 70.
Image: dwm.exe
PROCESS 877ced28 SessionId: 1 Cid: 0600 Peb: 7ffd3000 ParentCid: 05e8
DirBase: beb47320 ObjectTable: 99ee5890 HandleCount: 766.
Image: explorer.exe
*左右滑动查看更多
另一种确定PEB地址的方法是使用display type (dt)命令。可以通过检查EPROCESS结构中的PEB字段找到explorer.exe进程的PEB地址,如下所示:
kd> dt nt!_EPROCESS 877ced28 [REMOVED]
+0x168 Session : 0x8f44e000 Void
+0x16c ImageFileName : [15] "explorer.exe" [REMOVED]
+0x1a8 Peb : 0x7ffd3000 _PEB
+0x1ac PrefetchTrace : _EX_FAST_REF
*左右滑动查看更多
现在我们知道了如何找到PEB,那么现在,让我们试着理解PEB包含什么样的信息。要获得给定流程的可读PEB摘要,首先需要切换到要检查其PEB的流程的上下文,这可以使用.process扩展名命令来完成。这个命令接受_EPROCESS结构的地址。下面的命令将当前进程的上下文设置为explorer.exe进程:
.process 877ced28
Implicit process is now 877ced28
然后,我们可以使用!peb扩展命令后跟peb地址。在下面的输出中,为了简洁起见,部分信息被截断。ImageBaseAddress字段指定在内存中加载进程可执行文件(explorer.exe)的地址。
PEB还包含另一个称为Ldr结构(类型为_PEB_LDR_DATA)的结构,它维护三个双链接列表,它们分别是InLoadOrderModuleList、InMemoryOrderModuleList以及InInitializationOrderModuleList。这三个双链接列表中的每一个都包含关于模块(进程可执行文件和dll)的信息。通过遍历这些双链接的模块,可以获得关于模块的信息列表。
InLoadOrderModuleList按模块的顺序组织模块,InMemoryOrderModuleList按照它们在进程内存中的顺序组织模块,而InInitializationOrderModule
List按照它们的DllMain函数执行的顺序组织模块:
kd> !peb 0x7ffd3000 PEB at 7ffd3000
InheritedAddressSpace: No ReadImageFileExecOptions: No BeingDebugged: No ImageBaseAddress: 000b0000
Ldr 77dc8880
Ldr.Initialized: Yes Ldr.InInitializationOrderModuleList: 00531f98 . 03d3b558 Ldr.InLoadOrderModuleList: 00531f08 . 03d3b548 Ldr.InMemoryOrderModuleList: 00531f10 . 03d3b550 [REMOVED]
*左右滑动查看更多
换句话说,所有三个PEB列表都包含关于已加载模块的信息,比如基址、大小、与模块关联的完整路径等。要记住的重要一点是,InInitializationOrderModuleList将不包含关于进程可执行文件的信息,因为与dll相比,可执行文件的初始化是不同的。
为了帮助您更好地理解,下面的图表以Explorer.exe为例(该概念也类似于其他进程)。当Explorer.exe被执行时,它的进程可执行文件被加载到进程内存中的某个地址(比方说0xb0000),带有PAGE_EXECUTE_
WRITECOPY (WCX)保护。相关的dll也被加载到进程内存中。
进程内存还包括PEB结构,它包含了explorer.exe在内存中的加载位置(基址)的元数据信息。PEB中的Ldr结构维持着三个双链表;每个元素都是一个结构(类型为_LDR_DATA_TABLE_ENTRY),它包含关于加载模块的信息(基址、完整路径等)。dlllist插件依赖于遍历InLoadOrderModuleList来获取模块的信息:
从这三个PEB列表中获取模块信息的问题是,它们容易受到DKOM攻击。所有三个PEB列表都驻留在用户空间中,这意味着攻击者可以将恶意DLL加载到进程的地址空间中,并可以从一个或所有PEB列表中断开恶意DLL的链接,以隐藏依赖于遍历这些列表的工具。为了克服这个问题,我们可以使用另一个名为ldrmodules的插件。
6.1 使用ldrmodule检测隐藏的DLL
ldrmodules插件将来自三个PEB列表(在进程内存中)的模块信息与来自内核内存中称为VADs(虚拟地址描述符)的数据结构的信息进行比较。内存管理器使用vad跟踪进程内存中保留(或空闲)的虚拟地址。
VAD是一种二叉树结构,它存储关于进程内存中几乎连续的内存区域的信息。对于每个进程,内存管理器维护一组VAD,每个VAD节点描述一个几乎连续的内存区域。如果进程内存区域包含一个内存映射文件(如可执行文件、DLL),那么VAD节点存储有关其基址、文件路径和内存保护的信息。下面的示例将有助于我们理解这个概念。
在下面的截图中,内核空间中的一个VAD节点描述了关于进程可执行文件(explorer.exe)加载位置、它的完整路径和内存保护的信息。类似地,其他VAD节点将描述进程的内存范围,包括那些包含映射的可执行映像,如dll:
为了获得模块的信息,ldrmodules插件枚举所有包含映射可执行镜像的VAD节点,并将结果与三个PEB列表进行比较,以确定是否存在差异。
下面是感染了TDSS rootkit(我们在前面看到的)的内存映像进程的模块列表。你可以看到ldrmodules插件能够识别一个名为TDSSoiqh.dll的恶意DLL,它隐藏了所有三个PEB列表(InLoad, InInit和InMem)。svchost.exe的InInit值设置为False,但其是可执行的,如前所述:
$ python vol.py -f tdl3.vmem --profile=WinXPSP3x86 ldrmodules -p 880 Volatility Foundation Volatility Framework 2.6
Pid Process Base InLoad InInit InMem MappedPath
--- ----------- -------- ----- ------- ----- ---------------------------- 880 svchost.exe 0x10000000 False False False WINDOWSsystem32TDSSoiqh.dll 880 svchost.exe 0x01000000 True False True WINDOWSsystem32svchost.exe 880 svchost.exe 0x76d30000 True True True WINDOWSsystem32wmi.dll
880 svchost.exe 0x76f60000 True True True WINDOWSsystem32wldap32.dll
[REMOVED]
*左右滑动查看更多

七、转储可执行文件和DLL柄
在识别出恶意进程或DLL之后,我们可能希望转储它以便进一步调查(例如提取字符串、运行yara规则、反汇编或使用杀毒软件进行扫描)。要将进程可执行文件从内存转储到磁盘,可以使用procdump插件。要转储进程可执行文件,您需要知道它的进程ID或物理偏移量。
在下面的例子中,一个内存镜像感染了Perseus恶意软件(之前在讨论pslist插件时提到),procdump插件用于转储其恶意进程的可执行文件svchost.exe (pid 3832)。使用-D(——dump-dir)选项,可以指定要转储可执行文件的目录名称。转储文件以进程的pid命名,如executable.PID.exe:
python vol.py -f perseus.vmem --profile=Win7SP1x86 procdump -p 3832 -D dump/
Volatility Foundation Volatility Framework 2.6
Process(V) ImageBase Name Result
---------- ---------- ------------ -----------------------
0x8503f0e8 0x00b90000 svchost..exe OK: executable.3832.exe
cd dump
file executable.3832.exe
executable.3832.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows
*左右滑动查看更多
要转储具有物理偏移量的进程,可以使用-o(——offset)选项,如果希望从内存转储隐藏进程,该选项很有用。
在下面的例子中,一个内存映像感染了prolaco恶意软件(在前面讨论时已经讨论过了psscan插件),隐藏进程使用其物理偏移量转储。物理偏移量由psscan插件确定,你也可以从psxview插件获取物理偏移量。当使用procdump插件时,如果你没有指定-p(——pid)或-o(——offset)选项,那么它将转储系统上运行的所有活动进程的进程可执行文件:
$ python vol.py -f infected.vmem --profile=WinXPSP3x86 psscan Volatility Foundation Volatility Framework 2.6
Offset(P) Name PID PPID PDB Time created ------------------ ------- ---- ---- ---------- -------------------- [REMOVED]
0x00000000016ba360 nvid.exe 1700 1660 0x08440320 2014-10-17 09:16:10
$ python vol.py -f infected.vmem --profile=WinXPSP3x86 procdump -o 0x00000000016ba360 -D dump/
Volatility Foundation Volatility Framework 2.6
Process(V) ImageBase Name Result
---------- ---------- -------- -----------------------
0x814ba360 0x00400000 nvid.exe OK: executable.1700.exe
*左右滑动查看更多
类似于进程可执行文件,您可以使用dlldump插件将恶意DLL转储到磁盘。要转储DLL,您需要指定加载DLL的进程的进程ID (-p选项),以及DLL的base地址,使用-b(——base)选项。您可以从dlllist或ldrmodules输出中获得DLL的基址。
在下面这个例子中,一个被Ghost RAT病毒感染的内存映像(我们在讨论dlllist插件时提到过),通过使用dlldump插件来转储svchos.exe (pid 880)进程加载的恶意DLL:
$ python vol.py -f ghost.vmem --profile=Win7SP1x86 dlllist -p 880 Volatility Foundation Volatility Framework 2.6 ************************************************************************ svchost.exe pid: 880
Command line : C:Windowssystem32svchost.exe -k netsvcs
Base Size LoadCount Path
---------- ------ -------- ------
[REMOVED]
0x10000000 0x26000 0x1 c:userstestapplication dataacd systemsacdseeimageik.ddf
$ python vol.py -f ghost.vmem --profile=Win7SP1x86 dlldump -p 880 -b 0x10000000 -D dump/
Volatility Foundation Volatility Framework 2.6
Name Module Base Module Name Result
---------- ------------ ---------------- --------------------------
svchost.exe 0x010000000 imageik.ddf module.880.ea13030.10000000.dll
*左右滑动查看更多
(未完待续)
往期回顾
原文始发于微信公众号(安恒信息安全服务):九维团队-青队(处置)| 使用内存取证狩猎恶意软件(四)