
メモリ内のマルウェアの差分分析
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)
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. db で 'processes' 出力を参照する
2. 'dlls' および 'modules' プラグインを実行する
3. 結果を表示する
4. 新しい結果を db に保存する
db にデータを保存したら、-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
次に、ベースラインのDB(ここでは、感染していないメモリイメージからの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' に新しく追加された結果、または両方の DB に存在するが 'before.db' から一部の属性が変更された結果のみが表示されます(ここでは出力を省略しています)。
* 'after.db' にのみ存在する結果は、最初の('Status')列に 'New' と表示されます。
* 両 DB 間で変更された結果には、'Status' が 'Changed' となり、重要な点として、DAMM が検出した変更は '->' で示されます: 上の出力の最後の行では、スレッド数が変更されています。
### 一意 ID の操作 <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
既定では、一意の識別子を作成するためにpidとppidを使用するため、すべてのプロセスが(Systemを除き)'New'としてタグ付けされることになります。
このため、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は現在、'New'として識別されるプロセス(マルウェアプロセスを含む)が少なくなり、調査担当者はこれらのプロセスに集中できます。
### フィルタリング <a name="filtering"/>
すべてのプラグインを小さなメモリサンプルに対して実行すると、プロセス、DLL、モジュールなど、約14,000個のメモリオブジェクトが得られます。すでに何らかのプロセスまたは対象の文字列を特定している場合はどうでしょうか?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感染前のメモリサンプルと感染後のサンプルがあります。感染前のdbで文字列'tdl'を検索すると約600件のヒットが得られます。感染後のdbでは約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 がチェックする内容の詳細が記載されています。
Art of Memory Forensics の書籍と、これらの警告アイデアの多くが生まれた Volatility チートシートについて、Volatility チームに感謝します。
質問やコメントはこちら: [email protected] バグ報告は、github の issue トラッカーをご利用ください。