
Дифференциальный анализ вредоносного ПО в памяти
Инструмент анализа памяти с открытым исходным кодом, построенный на 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, образ памяти и список плагинов для выполнения (или '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)
По вопросам или комментариям: [email protected] Для сообщений об ошибках, пожалуйста, используйте трекер задач Github.
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
Будет:
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"/>
Чтобы использовать механизм различения, создайте 2 базы данных из 2 различных образов памяти, например, один до и один после выполнения вредоносной программы.```
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', имеют пометку 'New' в первом столбце ('Status').
* Результаты, изменившиеся между базами, имеют статус 'Changed', и, что важно, изменения, обнаруженные DAMM, обозначаются стрелкой '->': в последней строке вывода выше изменилось количество потоков.
### Управление уникальными идентификаторами <a name="unique-id"/>
Чтобы определить, какие процессы существуют в обеих дампах памяти, описанных выше, за кулисами используются определённые атрибуты процессов для создания уникального идентификатора каждого из них. Например, по умолчанию DAMM использует pid, ppid, имя и время запуска в качестве уникального идентификатора процесса. Это логично, поскольку эти параметры вряд ли изменятся (не должны? не могут?) за время жизни процесса, в отличие от таких атрибутов, как количество потоков и дескрипторов, которые меняются постоянно. Такой набор по умолчанию прекрасно работает для сравнения объектов из образов памяти, полученных при одной загрузке одной и той же машины (например, с использованием снимков ВМ), но что насчёт сравнения образов памяти, полученных при разных загрузках одной машины? Или даже на разных машинах? 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 использовать только process name, 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 теперь идентифицирует меньше процессов как 'New' (включая процесс вредоносного ПО), что позволяет исследователю сосредоточить свои усилия на этих процессах.
### Фильтрация <a name="filtering"/>
После запуска всех плагинов на небольшом образце памяти мы получаем ~14,000 объектов памяти: процессы, dll, модули и т.д. Что если мы уже идентифицировали какой-то процесс или строку, представляющую интерес? Grep может быть проблематичен, особенно при поиске pids, поэтому 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
### Warnings <a name="warnings"/>
В попытке сделать процесс триажа ещё проще, DAMM имеет экспериментальную систему предупреждений, встроенную для выявления признаков вредоносной активности, включая:
Для определённых процессов Windows:
* некорректные отношения родитель/потомок
* скрытые процессы
* некорректный путь к бинарному файлу
* некорректный приоритет по умолчанию
* некорректная сессия
Для всех процессов, а также загруженных DLL и модулей:
* загружены/запущены из временной директории
Для DLL:
* поддельные расширения
* скрытые DLL
И ещё!
* PE-заголовки во внедрениях
* SID, предоставляющие доступ к домену
* привилегии отладки
...```
python damm.py --db after_tdl3.db --warnings
Смотрите файл warnings.py для получения более подробной информации о том, что проверяет DAMM.
Спасибо команде Volatility за книгу Art of Memory Forensics, а также за шпаргалку Volatility, откуда взяты многие из этих предупреждений!