一款基于Volatility的开源内存分析工具,旨在为社区提供展示有趣新技术的试验场。这些技术试图通过数据精简和专家知识编码来加快调查过程。
NOTE: Most DAMM output looks better piped through 'less -S' (upper 'S') as in:
python damm.py -h usage: damm.py [-h] [-d DIR] [-p PLUGIN [PLUGIN ...]] [-f FILE] [-k KDBG] [--db DB] [--profile PROFILE] [--debug] [--info] [--tsv] [--grepable] [--filter FILTER] [--filtertype FILTERTYPE] [--diff BASELINE] [-u FIELD [FIELD ...]] [--warnings] [-q]
DAMM v1.0 Beta
optional arguments: -h, --help show this help message and exit -d DIR Path to additional plugin directory -p PLUGIN [PLUGIN ...] Plugin(s) to run. For a list of options use --info -f FILE Memory image file to run plugin on -k KDBG KDBG address for the images (in hex) --db DB SQLite db file, for efficient input/output --profile PROFILE Volatility profile for the images (e.g. WinXPSP2x86) --debug Print debugging statements --info Print available volatility profiles, plugins --tsv Print screen formatted output. --grepable Print in grepable text format --filter FILTER Filter results on name:value pair, e.g., pid:42 --filtertype FILTERTYPE Filter match type; either "exact" or "partial", defaults to partial --diff BASELINE Diff the imageFile|db with this db file as a baseline -u FIELD [FIELD ...] Use the specified fields to determine uniqueness of memobjs when diffing --warnings Look for suspicious objects. -q Query the supplied db (via --db).
### 支持的插件 <a name="plugins"/>
参见 #python damm.py --info
apihooks callbacks connections devicetree dlls evtlogs handles idt injections messagehooks mftentries modules mutants privileges processes services sids timers
### 示例 <a name="example"/>
提供一个类似于 Volatility 中的profile、内存镜像以及要运行的插件列表(或 'all')以获取终端输出:```
python damm.py --profile WinXPSP2x86 -f memory.dmp -p processes | less -S
(or python damm.py --profile WinXPSP2x86 -f memory.dmp -p processes dlls modules)
(or python damm.py --profile WinXPSP2x86 -f memory.dmp -p all)
processes
offset name pid ppid prio image_path_name create_time exit_time threads session_id handles is_wow64 pslist psscan thrdproc pspcid csrss session deskthrd command_line
0x25c8830 System 4 0 8 59 403 False True True True True False False False
0x225ada0 alg.exe 188 668 8 C:\WINDOWS\System32\alg.exe 2010-10-29 17:09:09 UTC+0000 6 0 107 False True True True True True True True C:\WINDOWS\System32\alg.exe
0x2114938 ipconfig.exe 304 968 8 2011-06-03 04:31:35 UTC+0000 2011-06-03 04:31:36 UTC+0000 0 0 False True True False True False False False
0x2086978 TSVNCache.exe 324 1196 8 C:\Program Files\TortoiseSVN\bin\TSVNCache.exe 2010-10-29 17:11:49 UTC+0000 7 0 54 False True True True True True True True "C:\Program Files\TortoiseSVN\bin\TSVNCache.exe"
0x22df020 smss.exe 376 4 11 \SystemRoot\System32\smss.exe 2010-10-29 17:08:53 UTC+0000 3 19 False True True True True False False False \SystemRoot\System32\smss.exe
...
要使这些结果持久化到SQLite数据库中,只需提供一个数据库文件名即可:``` python damm.py --profile WinXPSP2x86 -f memory.dmp -p processes --db my_results.db
这将把结果打印到终端,同时将它们存储在 'my_results.db' 中。
要再次查看结果:```
python damm.py -p processes --db my_results.db
(请注意,您不再需要内存映像或指定配置文件,并且无论原始处理耗时多长,列表都会几乎瞬间生成。)
如果您稍后想要查看进程和其他插件:``` python damm.py --profile WinXPSP2x86 -p processes dlls modules --db my_results.db
Will:
1. 从数据库中查询 'processes' 输出
2. 运行 'dlls' 和 'modules' 插件
3. 显示结果
4. 将新结果存入数据库
一旦你在数据库中存储了一些数据,你可以使用 -q 开关进行查询。```
python damm.py -q --db my_results.db
profile: WinXPSP2x86
memimg: WinXPSP2x86/stuxnet.vmem
COMPUTERNAME: JAN-DF663B3DBF1
plugins: processes dlls modules
插件具有属性,这些属性可以具有用于筛选的类型,例如对于进程:(使用 --info 查看所有插件属性)``` offset name : string pid : pid ppid : pid image_path_name : string command_line : string create_time exit_time threads session_id handles is_wow64 pslist psscan thrdproc pspcid csrss session deskthrd
这些属性和类型可以被DAMM的差异比较和过滤功能利用
### 差异比较 <a name="differencing"/>
要使用差异比较引擎,从两个不同的内存映像创建两个数据库,例如一个在恶意软件执行之前,一个在之后。```
python damm.py --profile WinXPSP2x86-f before.dmp -p processes --db before.db
python damm.py --profile WinXPSP2x86 -f after.dmp -p processes --db after.db
然后对基线数据库(此处为来自未感染内存映像的数据库)使用 --diff 选项。```
python damm.py -p processes --db after.db --diff before.db
processes Status offset name pid ppid prio image_path_name create_time exit_time threads session_id handles is_wow64 pslist psscan thrdproc pspcid csrss session deskthrd command_line New 0x17d22e0 pythonw.exe 1256 1940 8 2013-10-31 23:23:14 UTC+0000 2013-10-31 23:23:19 UTC+0000 0 -268370093 False False True False False False False False Changed 0x18b4d38 svchost.exe 1080 692 8 2013-10-31 17:21:26 UTC+0000 66->71 False False True False False False False False Changed 0x1915198 winlogon.exe 648 376 13 2013-10-31 17:21:25 UTC+0000 24->26 False False True False False False False False Changed 0x1900120 services.exe 692 648 9 2013-10-31 17:21:25 UTC+0000 16->18 False False True False False False False False Changed 0x18b0360 svchost.exe 1124 692 8 2013-10-31 17:21:26 UTC+0000 5->6 False False True False False False False False Changed 0x1875490 explorer.exe 1636 1596 8 2013-10-31 17:21:27 UTC+0000 13->14 False False True False False False False False ...
结果看起来类似于上面的'processes'插件输出,但存在一些差异:
* 仅显示在'after.db'中新增的结果,或者同时存在于两个数据库中但某些属性相对于'before.db'发生了变化的结果(此处输出已截断)。
* 仅存在于'after.db'中的结果在第一列('Status')中显示'New'。
* 在两个数据库之间发生变化的结果的状态为'Changed',并且重要的是,用'->'标识DAMM检测到的变化:在上述输出的最后一行中,线程数量发生了变化。
### 唯一标识符操作 <a name="unique-id"/>
为了确定哪些进程同时存在于上述两个内存捕获中,后台会使用某些进程属性为每个进程生成唯一标识符。例如,默认情况下,DAMM使用pid、ppid、名称和启动时间作为进程的唯一标识符。这很合理,因为这些属性在进程的生命周期内不太可能(不应该?不能?)发生变化,而线程数和句柄数等属性则会不断变化。这个默认集合对于比较同一台机器同一次启动的内存镜像中的对象(例如使用VM快照)来说效果很好,但如果比较机器不同次启动的内存镜像呢?甚至比较不同机器的内存镜像呢?pid和ppid很可能不相同,但名称、镜像路径和命令行应该是相同的。
比较一个原版XPSP2x86内存镜像与运行了某些恶意软件后的镜像:```
python damm.py -p processes --diff stock_WinXPSP2x86_processes.db --db after_malware.db
...
New 0x1874da0 explorer.exe 1636 1596 C:\WINDOWS\Explorer.EXE C:\WINDOWS\Explorer.EXE 2013-10-31 17:21:27 UTC+0000 None 12 0 316 False True False True True True True True
New 0x1983020 smss.exe 376 4 \SystemRoot\System32\smss.exe \SystemRoot\System32\smss.exe 2013-10-31 17:21:24 UTC+0000 None 3 19 False True False True True False False
New 0x182cda0 wpabaln.exe 1812 648 C:\WINDOWS\system32\wpabaln.exe C:\WINDOWS\system32\wpabaln.exe 2013-10-31 23:10:13 UTC+0000 None 1 0 58 False True False True True True True
New 0x1883308 spoolsv.exe 1500 692 C:\WINDOWS\system32\spoolsv.exe C:\WINDOWS\system32\spoolsv.exe 2013-10-31 17:21:27 UTC+0000 None 14 0 113 False True False True True True True
Changed 0x1bcc830->0x1bcc9c8 System 4 0 None None 60->71 209->266 False True True->False True True False False False
结果导致每个进程都被标记为 'New'(System 除外),因为默认情况下我们使用 pid 和 ppid 来生成唯一标识符。
因此,DAMM 允许用户指定某些对象的哪些属性可用于创建唯一标识符。如果我们告诉 DAMM 只使用进程名称、image_path_name 和 command_line,结果会更加合理:``` python damm.py -p processes --diff stock_WinXPSP2x86_processes.db --db after_malware.db -u name image_path_name command_line
Status offset name pid ppid image_path_name command_line create_time exit_time threads session_id handles is_wow64 pslist psscan thrdproc pspcid csrss session deskthrd
New 0x1860020 wuauclt.exe 548 1080 C:\WINDOWS\system32\wuauclt.exe "C:\WINDOWS\system32\wuauclt.exe" /RunStoreAsComServer Local[438]SUSDS109850d1d4659d4590c0302d99249922 2013-10-31 17:22:20 UTC+0000 None 7
New 0x1891da0 VBoxTray.exe 1932 1636 C:\WINDOWS\system32\VBoxTray.exe "C:\WINDOWS\system32\VBoxTray.exe" 2013-10-31 17:21:29 UTC+0000 None 7 0 65 False True False True True
New 0x195bbf0 pythonw.exe 1256 1940 C:\Python27\pythonw.exe C:\Python27\pythonw.exe C:\hkurkt\analyzer.py 2013-10-31 23:09:24 UTC+0000 None 5 0 114 False True False True True True
New 0x1877448 MagicDisc.exe 1960 1636 C:\Program Files\MagicDisc\MagicDisc.exe "C:\Program Files\MagicDisc\MagicDisc.exe" 2013-10-31 17:21:29 UTC+0000 None 1 0 24 False True False
New 0x182cda0 wpabaln.exe 1812 648 C:\WINDOWS\system32\wpabaln.exe C:\WINDOWS\system32\wpabaln.exe 2013-10-31 23:10:13 UTC+0000 None 1 0 58 False True False True True True True
New 0x1877940 pythonw.exe 1940 1636 C:\Python27\pythonw.exe "C:\Python27\pythonw.exe" "C:\Documents and Settings\jawauser\Start Menu\Programs\Startup\agent.pyw" 2013-10-31 17:21:29 UTC+0000 None 1 0
New 0x1875718 tdl3 1344 1256 C:\DOCUME1\jawauser\LOCALS1\Temp\tdl3 "C:\DOCUME1\jawauser\LOCALS1\Temp\tdl3" 2013-10-31 23:09:25 UTC+0000 None 1 0 37 False True False True True
New 0x18ee360 VBoxService.exe 860 692 C:\WINDOWS\system32\VBoxService.exe system32\VBoxService.exe 2013-10-31 17:21:26 UTC+0000 None 8 0 106 False True False True True True
Changed 0x1bcc830->0x1bcc9c8 System 4 0 None None 60->71 209->266 False True True->False True True False False False
Changed 0x18b7020->0x18b4648 svchost.exe 1076->1080 680->692 C:\WINDOWS\System32\svchost.exe C:\WINDOWS\System32\svchost.exe -k netsvcs 2011-09-26 01:33:36 UTC+0000->2013-10-31 17:21:26 UTC+0000 None 87->7
Changed 0x1994d08->0x18ffa30 services.exe 680->692 636->648 C:\WINDOWS\system32\services.exe C:\WINDOWS\system32\services.exe 2011-09-26 01:33:35 UTC+0000->2013-10-31 17:21:25 UTC+0000 None 15->1
Changed 0x16a2cd0->0x18fd648 lsass.exe 692->704 636->648 C:\WINDOWS\system32\lsass.exe C:\WINDOWS\system32\lsass.exe 2011-09-26 01:33:35 UTC+0000->2013-10-31 17:21:25 UTC+0000 None 24->22 0 356->
Changed 0x1aefda0->0x1983020 smss.exe 384->376 4 \SystemRoot\System32\smss.exe \SystemRoot\System32\smss.exe 2011-09-26 01:33:32 UTC+0000->2013-10-31 17:21:24 UTC+0000 None 3 19 False
Changed 0x189a1d0->0x18a7a60 svchost.exe 1336->1152 680->692 C:\WINDOWS\system32\svchost.exe C:\WINDOWS\system32\svchost.exe -k LocalService 2011-09-26 01:33:37 UTC+0000->2013-10-31 17:21:26 UTC+0000 None 14->1
Changed 0x16c9b40->0x1914aa8 winlogon.exe 636->648 384->376 ??\C:\WINDOWS\system32\winlogon.exe winlogon.exe 2011-09-26 01:33:35 UTC+0000->2013-10-31 17:21:25 UTC+0000 None 16->18 0 498->509
Changed 0x1ab5248->0x18c1020 svchost.exe 944->992 680->692 C:\WINDOWS\system32\svchost.exe C:\WINDOWS\system32\svchost -k rpcss 2011-09-26 01:33:36 UTC+0000->2013-10-31 17:21:26 UTC+0000 None 11->9 0
Changed 0x14b03e0->0x183e620 alg.exe 2272->1888 680->692 C:\WINDOWS\System32\alg.exe C:\WINDOWS\System32\alg.exe 2011-09-26 01:33:55 UTC+0000->2013-10-31 17:21:37 UTC+0000 None 7->6 0 112->105
Changed 0x1af5cd0->0x1874da0 explorer.exe 1752->1636 1696->1596 C:\WINDOWS\Explorer.EXE C:\WINDOWS\Explorer.EXE 2011-09-26 01:33:45 UTC+0000->2013-10-31 17:21:27 UTC+0000 None 32->12 0 680->316 False
Changed 0x1670020->0x18e4020 svchost.exe 868->904 680->692 C:\WINDOWS\system32\svchost.exe C:\WINDOWS\system32\svchost -k DcomLaunch 2011-09-26 01:33:35 UTC+0000->2013-10-31 17:21:26 UTC+0000 None 17
Changed 0x15685e0->0x1883308 spoolsv.exe 1516->1500 680->692 C:\WINDOWS\system32\spoolsv.exe C:\WINDOWS\system32\spoolsv.exe 2011-09-26 01:33:39 UTC+0000->2013-10-31 17:21:27 UTC+0000 None 14 0 159->
Changed 0x1816ab8->0x190c020 csrss.exe 612->624 384->376 ??\C:\WINDOWS\system32\csrss.exe C:\WINDOWS\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows S
Changed 0x19f7548->0x18afc70 svchost.exe 1200->1124 680->692 C:\WINDOWS\system32\svchost.exe C:\WINDOWS\system32\svchost.exe -k NetworkService 2011-09-26 01:33:37 UTC+0000->2013-10-31 17:21:26 UTC+0000 None
DAMM现在将更少的进程识别为'新'(包括恶意软件进程),从而使调查人员能够将精力集中在这些进程上。
### 过滤 <a name="filtering"/>
运行所有插件后,在一个小型内存样本中,我们得到约14,000个内存对象:进程、DLL、模块等。如果我们已经识别出某些感兴趣的进程或字符串呢?使用Grep可能会出现问题,尤其是在搜索PID时,因此DAMM包含一个简单的类型和过滤系统。要过滤具有特定pid属性值的对象:```
python damm.py -p processes dlls connections handles --db after_malware.db --filter pid:1344
processes
offset name pid ppid image_path_name command_line create_time exit_time threads session_id handles is_wow64 pslist psscan thrdproc pspcid csrss session deskthrd
0x1875718 tdl3 1344 1256 C:\DOCUME~1\jawauser\LOCALS~1\Temp\tdl3 "C:\DOCUME~1\jawauser\LOCALS~1\Temp\tdl3" 2013-10-31 23:09:25 UTC+0000 None 1 0 37 False True False True True TrueTrue True
dlls
proc_pid dll_base size_of_image load_count full_dll_name
1344 0x73000000 155648 0x1 C:\WINDOWS\system32\WINSPOOL.DRV
1344 0x400000 77824 0xffff C:\DOCUME~1\jawauser\LOCALS~1\Temp\tdl3
1344 0x77f10000 299008 0xffff C:\WINDOWS\system32\GDI32.dll
1344 0x7e410000 593920 0xffff C:\WINDOWS\system32\user32.dll
...
connections
offset pid local_ip local_port remote_ip remote_port allocated
0x1853580 1344 192.168.56.101 1035 192.168.43.171 2042 True
handles
offset pid handle_value granted_access object_type name
0xe1007ff0 1344 0x4 0xf0003 KeyedEvent CritSecOutOfMemoryEvent
0x81a43310 1344 0x3c 0x1f03ff Thread TID 384 PID 1344
0x81902878 1344 0x6c 0x1f01ff File \Device\Tcp
0x81902240 1344 0xc 0x100020 File \Device\HarddiskVolume1\DOCUME~1\jawauser\LOCALS~1\Temp
0x81906158 1344 0x38 0x1f0003 Semaphore shell.{A48F1A32-A340-11D1-BC6B-00A0C90312E1}
0x81a43310 1344 0x64 0x1f03ff Thread TID 384 PID 1344
0x81851900 1344 0x68 0x1f01ff File \Device\Afd\Endpoint
0x81953f78 1344 0x20 0xf01ff Desktop Default
0xe106b648 1344 0x44 0xf003f Key MACHINE\SYSTEM\CONTROLSET001\SERVICES\WINSOCK2\PARAMETERS\PROTOCOL_CATALOG9
0x81902950 1344 0x70 0x1f01ff File \Device\Tcp
0x81902cd0 1344 0x7c 0x100001 File \Device\KsecDD
0xe1aa0ca0 1344 0x80 0x2001f Key USER\S-1-5-21-1644491937-789336058-854245398-1003\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\INTERNET SETTINGS
(many lines removed for brevity)
这可以很好地概览与进程关联的对象。
更强大的是,diff 和过滤可以结合使用。我有一份 TDL3 感染前和感染后的内存样本。在感染前的数据库中搜索字符串 'tdl' 大约有 600 条结果。在感染后的数据库中,大约有 730 条结果。(注意 ntdll.dll 中包含字符串 tdl。)如下所示结合使用 diff 和过滤,结果仅约 180 条——显著减少。注意,对于字符串和 PID 过滤,DAMM 默认采用精确匹配。使用 --filtertype partial 选项可将过滤改为部分匹配。```
python damm.py -p all --diff before_tdl3.db --db after_tdl3.db --filter string:tdl --filtertype partial > string_tdl_diff.txt
### 警告 <a name="warnings"/>
为了进一步简化分类流程,DAMM 内置了一个实验性警告系统,用于嗅探恶意活动的迹象,包括:
针对特定 Windows 进程:
* 错误的父/子关系
* 隐藏进程
* 错误的二进制路径
* 错误的默认优先级
* 错误的会话
针对所有进程以及已加载的 DLL 和模块:
* 从临时目录加载/运行
针对 DLL:
* 虚假扩展名
* 隐藏的 DLL
更多内容!
* 注入中的 PE 头
* 提供域访问权限的 SID
* 调试权限
...```
python damm.py --db after_tdl3.db --warnings
参见 warnings.py 文件以了解 DAMM 检查的更多信息。
感谢 Volatility 团队撰写的《内存取证的艺术》以及 Volatility 速查表,许多告警思路即来源于此!
如有问题或意见,请联系:[email protected] 如报告错误,请使用 GitHub 问题跟踪器。