
메모리 내 악성코드의 차등 분석
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
Will:
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
Plugins have attributes that can have types for filtering, e.g., for processes: (use --info to see for all plugin attributes)``` 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개의 데이터베이스를 생성하십시오.```
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'에만 있는 결과는 첫 번째 ('상태') 열에 '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를 사용하기 때문입니다.
이 때문에 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은 특히 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와 filtering을 함께 사용할 수 있습니다. tdl3 감염 전 메모리 샘플과 감염 후 메모리 샘플이 있습니다. 감염 전 db에서 'tdl' 문자열을 검색하면 약 600개의 결과가 나옵니다. 감염 후 db에서는 약 730개의 결과가 있습니다. (참고: ntdll.dll에는 tdl 문자열이 포함되어 있습니다.) 아래와 같이 diff와 filtering을 함께 사용하면 약 180개의 결과만 나옵니다 - 상당한 감소입니다. 문자열 및 pid 필터링의 경우, DAMM은 기본적으로 정확히 일치(exact matching)를 사용합니다. --filtertype partial 옵션을 사용하면 필터링이 부분 일치(partial matching)로 변경됩니다.``` 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"/>
트라이지(triage) 프로세스를 더 쉽게 만들기 위해 DAMM은 악성 활동의 징후를 탐지하는 실험적 경고 시스템을 내장하고 있습니다:
특정 Windows 프로세스의 경우:
* 잘못된 부모/자식 관계
* 숨겨진 프로세스
* 잘못된 바이너리 경로
* 잘못된 기본 우선순위
* 잘못된 세션
모든 프로세스 및 로드된 DLL과 모듈의 경우:
* 임시 디렉토리에서 로드/실행됨
DLL의 경우:
* 가짜 확장자
* 숨겨진 DLL
그 외에도 더 있습니다!
* 인젝션 내 PE 헤더
* 도메인 접근을 부여하는 SID
* 디버그 권한
...```
python damm.py --db after_tdl3.db --warnings
DAMM이 확인하는 내용에 대한 자세한 정보는 warnings.py 파일을 참조하세요.
이러한 경고 아이디어의 대부분이 나온 Volatility 치트 시트와 Art of Memory Forensics 책을 제공한 Volatility 팀에게 감사드립니다!
질문이나 의견: [email protected] 버그 신고는 github 이슈 트래커를 사용해 주세요.