오늘 새로운 도구를 소개해드립니다.
윈도우즈에서 물리 메모리를 덤프할 수 있는 'Fastdd v1.0'입니다.




win32dd를 역공학 분석하는 도중, 지금까지 외부에 알려지지 않았던 메모리 덤프 방식을 사용하는 것을 발견하여 이를 이용해 간단히 도구를 만들어 보았습니다.

자체 테스트 결과 win32dd보다 빠른 속도로 메모리를 수집할 수 있었습니다. 물리 메모리는 시간의 흐름에 따라 데이터의 변화량이 증가하기 때문에 수집 속도가 빠를 수록 메모리 분석에 유리합니다.

다운로드는 아래 링크를 참조해주세요.


<사용 방법>
"fastdd [덤프할 파일 이름]"


본 도구는 비영리적 목적에 한해 마음대로 사용하셔도 됩니다. 다만 소스코드는 제공해드리지 않습니다. 사실 별다른 기술이 들어가서 그런게 아니라.. 급하게 대충 만든거라 소스가 지저분해서요..ㅋㅋ 

x64 버젼도 개발하고 싶지만, 코드사이닝 문제로 비용이 발생하기 때문에 아마 무료로 푸는건 힘들 것 같고 내부적인 용도로만 사용할 것 같습니다. 사실 x64로 컴파일하는건 일도 아니긴 하죠. 

(수정) x64 버젼은 여기를 참조해주세요.


어찌되었든 차후에 시간이 되는대로 메모리 수집 도구들이 사용하는 방법들에 대해서 정리하여 포스팅하도록 하겠습니다. 그럼 이만.. :)

알림) fastdd32, 64의 실행파일 및 드라이버 바이너리의 디지털서명은 Four&Six Tech.의 지원을 받아 수행되었습니다. http://4n6tech.com



* 알림 : 본 포스트는 '2010 한국정보보호학회 동계학술대회'에 발표된 논문인 "A Study on Riskiness and Countermeasures of Personal Identifiable Information in Physical Memory"의 리뷰입니다.


물리 메모리에는 우리가 생각치 못한 많은 개인 정보들이 남아있습니다. 주민등록번호, 계좌번호, ID 및 패스워드 등이 그 대상입니다. 따라서 물리 메모리 포렌식의 가장 기본이 되는 분석 방법은 '문자열 검색'입니다. 너무나도 단순한 방법이고 어찌보면 수천만개씩이나 존재할지 모르는 문자열들 중에 중요한 정보를 찾는 것은 비효율적이기 때문에 old-fashioned method라고 치부될지 모르지만, 분명한 것은 어쨌든 중요한 정보가 '존재'한다는 것이고 이를 효율적으로 추출하는 것은 조사관의 몫이라는 것입니다.

이 논문은 물리 메모리 덤프에 존재하는 웹포털 사이트의 ID 및 패스워드를 추출하는 방법에 관한 논문입니다. 그 방법은 상당히 단순합니다. 물리 메모리 내에 존재하는 문자열 중 웹사이트로 전달하기 위한 POST Method와 관련한 문자열을 추출하고 이를 사이트 별 특징에 따라 정규표현식으로 ID와 패스워드를 추출하는 것입니다.

사실 누구나 생각해볼 수 있고 해외에서는 이와 같은 방식으로 웹사이트, 메신저 등의 계정 정보를 추출하는 방법에 대해 셀수 없이 논의되어 왔지만, 국내에서 자주 사용되는 웹사이트를 대상으로 하였을 때는 상당히 치명적이라는 사실이 와닿습니다.

메모리에 남아있는 모 사이트의 ID 및 패스워드
위와 같은 결과는 각 사이트들이 제공하는 보안로그인(일반적으로 1-3단계 제공)을 적용하더라도 똑같은 결과를 얻을 수 있습니다. 즉, 암호화하여 계정 정보를 전송한다고 하더라도 암호화되기 전의 데이터를 초기화 하지 않으면 메모리에 그대로 남아있게 된다는 것입니다.

물론 모든 사이트에 적용 가능한 방법은 아니며, 국내 모 포털사이트의 경우에는 보안로그인 여부와 관계없이 사용된 ID 및 패스워드를 초기화하여 관련 정보가 남지 않습니다. (하지만 불행하게도 90% 이상의 웹사이트는 위험 상태에 노출되어있습니다.)

Physical Memory Dump Explorer에 추가된 웹 패스워드 추출 기능

위 그림은 제가 만든 분석 도구인 Physical Memory Dump Explorer(a.k.a MEMA)에 새롭게 추가된 기능입니다. 실제 기능을 위한 모듈은 논문의 저자로부터 받아서 해결하였습니다. 결과를 통해 알 수 있듯이 상당히 많은 웹사이트들이 그 대상이 됨을 알 수 있습니다. 

간단히 논문 및 결과를 살펴보았습니다만, 모두가 메모리에 중요 정보가 남는다는 사실을 알면서도 "설마 누군가 들여다보겠어?"라는 생각으로 공용PC에서의 사용을 쉽게 생각하고 있는 것 같습니다. 참고로 실제 공용PC에서 메모리 덤프를 하여 프로그램을 돌려본 결과..... 역시 공용PC의 사용은 조심하시는게 좋겠습니다.




물리 메모리 분석을 위해서는 가상 주소를 물리 주소로의 변환이 필수적입니다. 당연하게도, 커널 혹은 유저 레벨에서의 모든 주소 표현은 가상 주소로 이루어집니다. 즉, 표현된 모든 주소를 물리 주소로 변환해야 물리 메모리 덤프에서의 오프셋을 구할 수 있습니다.

Non-PAE 환경에서의 가상-물리 주소 변환 과정
위의 그림은 Non-PAE(Physical Address Extension:물리주소확장)환경에서의 물리 주소 변환 과정을 나타냅니다. 그림을 통해 보면 생각보다 상당히 간단합니다. PAE는 XP 이상의 운영체제에서 일반적인 경우에 활성화 되므로 앞으로의 설명은 PAE 환경을 기준으로 하겠습니다.

PAE 환경에서의 가상-물리 주소 변환 과정
현재 사용되는 대부분의 운영체제는 메모리 사용의 효율성을 위해 페이징Paging 기법을 사용하며, 관리의 최소 단위로 페이지Page를 사용합니다. 일반적으로 페이지는 4096 바이트의 크기를 가지며, 일부의 경우 큰 페이지Large Page, 즉 2-4MB 이상의 크기를 가질 수 있습니다.

위의 그림을 참조해보면 가상 주소는 비트 단위로 2-4개로 나뉘어지며, 각 단위는 페이지 디렉토리Page Directory, 페이지 테이블Page Table, 혹은 실제 요구된 바이트 주소를 나타내면서 여러 단계를 거치게 됩니다. (PAE 환경의 경우 페이지 디렉토리 포인터 테이블Page-Directory-Pointer-Table을 추가로 거치게됩니다.)

우선 페이지 디렉토리(이하 PD) 혹은 페이지 디렉토리 포인터 테이블(이하 PDPT)을 가리키기 위해 CR3 레지스터가 사용됩니다. 이 값을 Directory Table Base라 부르는데, DTB는 _EPROCESS.Pcr.DirectoryTableBase 필드에도 존재합니다. (이와 관련한 내용은 다음에 정리해 포스팅합니다.)

CR3 레지스터의 DTB로 PDPT 또는 PD의 물리 주소를 가리키는데, PDPT, PD 혹은 PT는 8 바이트 단위의 엔트리Entry의 집합으로 표현됩니다. 이 엔트리의 구조는 아래 그림과 같습니다. 

Page Directory Entry, Page Table Entry의 구조
각 엔트리의 최하위비트는 다음 단계의 페이지가 메모리에 존재하는지를 나타내며, 1인 경우에만 물리 메모리 내의 주소로 변환할 수 있습니다. 또한 앞서 설명한 것과 같이, 페이지는 큰 페이지 크기를 가지는 경우가 존재하며, 이는 PDE의 7번째 비트(0부터 시작하는 인덱스)인 PS 플래그에 따라 구분됩니다. 31:12비트는 다음 단계의 페이지 프레임 넘버Page Frame Number를 표현합니다.

설명이 길어지면서 조금 난해하게 되었는데요, 실제로 가상 주소를 물리 주소로 변환하는 과정을 WinDbg를 통해 보여드리겠습니다. 변환할 주소는 커널 베이스 주소인 0x804d9000입니다.

----------------------------------------------------------------------------

0: kd> db 804d9000 
804d9000  4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00  MZ..............
804d9010  b8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00  ........@.......
804d9020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
804d9030  00 00 00 00 00 00 00 00-00 00 00 00 e0 00 00 00  ................
804d9040  0e 1f ba 0e 00 b4 09 cd-21 b8 01 4c cd 21 54 68  ........!..L.!Th
804d9050  69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f  is program canno
804d9060  74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20  t be run in DOS 
804d9070  6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00  mode....$.......

// 가상 주소 804d9000는 커널 베이스임을 나타내고 있습니다. DOS 헤더가 보이시죠?

0: kd> .formats 804d9000 
Evaluate expression:
  Hex:     804d9000
  Decimal: -2142400512
  Octal:   20023310000
  Binary:  10000000 01001101 10010000 00000000
  Chars:   .M..
  Time:    ***** Invalid
  Float:   low -7.12299e-039 high -1.#QNAN
  Double:  -1.#QNAN

// 가상 주소를 이진수로 변환하였습니다. 
// 이를 주소 변환에 쉽게 이용할 수 있도록 다시 나누어보았습니다.
// 10 000000010 011011001 000000000000
//  2         2        D9            0 
// PDPTE    PDE       PTE  Byte Offset

0: kd> r cr3
cr3=00b37000
0: kd> dd /p 00b37000 L8
00b37000  00b38001 00000000 00b39001 00000000
00b37010  00b3a001 00000000 00b3b001 00000000

// 앞서 구한 PDPTE Number가 2이기 때문에 00b3a001를 이용합니다. 
// 31:12 비트가 PD의 주소를 나타내기 때문에 00b3a000가 PD의 주소가 됩니다.

0: kd> dd /p 00b3a000+8*2 L2
00b3a010  004009e3 00000000
0: kd> .formats 004009e3 
Evaluate expression:
  Hex:     004009e3
  Decimal: 4196835
  Octal:   00020004743
  Binary:  00000000 01000000 00001001 11100011
  Chars:   .@..
  Time:    Wed Feb 18 22:47:15 1970
  Float:   low 5.88102e-039 high 0
  Double:  2.07351e-317

// 00b3a000에 엔트리 크기인 8과 PDE Number인 2을 곱한 값을 더하여 PDE를 구합니다.
// PDE를 보기 쉽게 나누면 다음과 같습니다.
// 00000000010000000000 100111100011
//                  400
//        Address of PT        Flags
// 최하위 비트가 1이기 때문에 Valid하며, PS 플래그가 1이기 때문에 큰 페이지입니다.
// 실제 페이지의 주소는 0x400에 페이지 기본 크기인 0x1000을 곱하여 구합니다.
// 아참, 큰 페이지이니 실제 요구된 바이트 주소를 다시 계산해야겠네요.
// 10 000000010 011011001000000000000
//  2         2                 D9000
// PDPTE    PDE           Byte Offset
// 이제 요구된 페이지의 주소인 0x400000에 0xD9000을 더하면 우리가 원하는 물리 주소가 됩니다.

0: kd> db /p 4d9000
004d9000  4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00  MZ..............
004d9010  b8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00  ........@.......
004d9020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
004d9030  00 00 00 00 00 00 00 00-00 00 00 00 e0 00 00 00  ................
004d9040  0e 1f ba 0e 00 b4 09 cd-21 b8 01 4c cd 21 54 68  ........!..L.!Th
004d9050  69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f  is program canno
004d9060  74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20  t be run in DOS 
004d9070  6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00  mode....$.......
0: kd> db 804d9000 
804d9000  4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00  MZ..............
804d9010  b8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00  ........@.......
804d9020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
804d9030  00 00 00 00 00 00 00 00-00 00 00 00 e0 00 00 00  ................
804d9040  0e 1f ba 0e 00 b4 09 cd-21 b8 01 4c cd 21 54 68  ........!..L.!Th
804d9050  69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f  is program canno
804d9060  74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20  t be run in DOS 
804d9070  6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00  mode....$.......

// 물리 주소와 가상 주소로 확인한 커널 베이스가 같음을 확인할 수 있습니다.




물리 메모리 이미지를 분석하기 이전에 가장 먼저 수행되어져야 할 작업은 바로 메모리 이미지의 OS(Windows) 및 버젼을 판별하는 것입니다. 사실 OS의 버젼 자체가 중요한 것이 아니라, OS의 버젼에 따라 커널 분석 방법 및 객체의 구조체 형태가 다르기 때문에 가장 먼저 고려되어져야만 합니다.

아래는 윈도우즈 물리 메모리 이미지의 버젼을 판별하는 방법들입니다.


1. 문자열 검색을 이용한 방법

OS 종류를 판별하기 위해 문자열을 검색해볼 수 있습니다. 아래 예제는 일부 윈도우즈 버젼과 관련한 문자열을 나타냅니다.

Windows XP: 5.1.2600

2546060:5.1.2600.0 (xpclient.010817-1148)
2546134:InternalName
2546160:HCAppRes.dll
2546194:LegalCopyright
2546226: Microsoft Corporation. All rights reserved.
2546322:OriginalFilename
2546356:HCAppRes.dll

Windows 7: 6.1.7600.16385 (win7_rtm.090713-1255)

1335896:6.1.7600.16385 (win7_rtm.090713-1255)
1335978:InternalName
1336004:BlbEvents.dll
1336038:LegalCopyright
1336070: Microsoft Corporation. All rights reserved.

만약 메모리 이미지가 x86 혹은 x64인지 확인하기 위해서는 PROCESSOR_ARCHITECTUREPROCESSOR_ARCHITEW6432와 같은 환경변수를 이용하면 됩니다.

PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 37 Stepping 5, GenuineIntel

PROCESSOR_ARCHITECTURE=AMD64
PROCESSOR_IDENTIFIER=Intel64

PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=AMD64

보다 자세한 관련 내용은 여기를 참조 바랍니다.


2. _DBGKD_DEBUG_DATA_HEADER64 구조체를 이용한 방법

위의 문자열 검색을 이용한 방법은 분석자의 눈으로 보기에는 괜찮은 방법이긴하나, 물리 메모리 분석을 자동화하는 경우에는 적합치않아 보입니다. 아래는 WinDbg 설치 후 볼 수 있는 'wdbgext.h'에 정의되어있는 _DBGKD_DEBUG_DATA_HEADER64 구조체를 나타냅니다.

typedef struct _DBGKD_DEBUG_DATA_HEADER64 {
LIST_ENTRY64 List;
ULONG OwnerTag; //"KDBG"
ULONG Size; //Different for each OS
} DBGKD_DEBUG_DATA_HEADER64, *PDBGKD_DEBUG_DATA_HEADER64;

보시다시피 OwnerTag 필드는 반드시 'KDBG'라는 4바이트의 문자열이 나타나야 합니다. 만약 시스템이 x86 기반일 경우, LIST_ENTRY64 구조체는 절반만 사용되기 때문에 뒤의 8바이트가 NULL로 나타나야합니다. 즉, 아래의 값을 _DBGKD_DEBUG_DATA_HEADER64 구조체의 시그니쳐와 같이 사용할 수 있습니다.

\x00\x00\x00\x00\x00\x00\x00\x00KDBG

_DBGKD_DEBUG_DATA_HEADER64에는 버젼을 구분할 수 있는 특징이 존재합니다. 바로 Size 필드가 윈도우 커널 버젼에 따라 다르다는 점입니다.

OS Size
Windows 2000 \x08\x02
XP \x90\x02
W2K3 \x18\x03
Vista \x28\x03
W2K8 \x30\x03
Windows 7 \x40\x03

참고로 아래는 메모리 이미지가 x64 기반인 경우에 나타내는 패턴입니다.


'\x00\xf8\xff\xffKDBG'

위의 설명된 경우를 모두 조합하면 각 OS 버젼별, CPU 아키텍쳐 별 시그니쳐를 만들 수 있습니다.


3. _DBGKD_GET_VERSION64 구조체를 이용한 방법

아래는 Windows XP SP3에서의 _DBGKD_GET_VERSION64 구조체를 나타냅니다.

kd> dt nt!_DBGKD_GET_VERSION64 0x8054f2b8
+0x000 MajorVersion : 0xf
+0x002 MinorVersion : 0xa28
+0x004 ProtocolVersion : 6
+0x006 Flags : 3
+0x008 MachineType : 0x14c
+0x00a MaxPacketType : 0xc ''
+0x00b MaxStateChange : 0x3 ''
+0x00c MaxManipulate : 0x2d '-'
+0x00d Simulation : 0 ''
+0x00e Unused : [1] 0
+0x010 KernBase : 0xffffffff`804d9000
+0x018 PsLoadedModuleList : 0xffffffff`8055f720
+0x020 DebuggerDataList : 0xffffffff`80687ff4

특이한 점은 MajorVersion 필드는 항상 0xf를 나타내고 있으며, MinorVersion 필드에 마이너 버젼이 아닌, 빌드넘버를 표현하고 있습니다. (각 필드에 우리가 원하는 값이 있다면 좋겠지만)

하지만 다행스럽게도 빌드넘버는 각 커널 버젼마다 중복되지 않기 때문에 이를 이용하여 윈도우즈 버젼을 파악할 수 있습니다. 아래는 각 윈도우즈 버젼 별 빌드 넘버입니다.


Title Revison Build Number
/Version Level
Windows 2000 RTM  5.0.2195
Windows 2000 SP1  5.0.2195 SP 1
Windows 2000 SP2  5.0.2195 SP 2
Windows 2000 SP3  5.0.2195 SP 3
Windows 2000 SP4  5.0.2195 SP 4
Windows XP RTM  5.1.2600
Windows XP SP1  5.1.2600.1106
Windows XP SP2  5.1.2600.2180
Windows XP SP3  5.1.2600.5512
Windows Server 2003 RTM  5.2.3790
Windows Server 2003 SP1  5.2.3790.1180
Windows Server 2003 SP2  5.2.3790.3959
Windows Server 2003 R2 SP1  5.2.3790.1180
Windows Fundamentals SP3 5.1.2600.5512
Windows Vista RTM 6.0.6000.16386
Windows Vista SP1 6.0.6001.18000
Windows Vista SP2 6.0.6002.18005
Windows Home Server 5.2.4500
Windows Server 2008 RTM/SP1 6.0.6001.18000
Windows Server 2008 SP2  6.0.6002.18005
Windows 7 RTM  6.1.7600.16385
Windows Server 2008 R2 RTM  6.1.7600.16385

앞선 이미지에서의 MinorVersion 필드의 값이 0xa28, 즉 빌드넘버가 2600이기 때문에 Windows XP라는 것을 확인할 수 있습니다.


* 알림 : 이 글은 'JS's stuff' 블로그의 'Identifying Memory Images'를 참고 인용 및 일부 개인적인 지식을 요약 정리한 것입니다.







윈도우즈 커널 디버깅을 하다보면 이것저것 번거로운 경우가 많습니다. 일반적으로 VMWare를 이용하여 pipe를 통해 시리얼포트를 설정하여 WinDBG를 연결하게 되는데요. 여러 버젼의 윈도우를 설치하는 경우에는 또 다시 각각의 가상머신마다 설정을 해줘야합니다. 게다가 가상이지만 시리얼포트를 이용하기 때문에 속도가 115,200 bps로 제한이 되어있어 답답해 속 터질정도로 느립니다.

제가 이번에 소개드릴 프로그램은 제목을 보시면 아시겠지만, 가상머신을 통해 커널 디버깅을 수행하는 경우 빠른 속도로 디버깅을 할 수 있도록 도와주는 프로그램인 VirtualKD입니다. 게다가 디버거와 디버기의 설정도 자동으로 이루어지기 때문에 상당히 편리하다는 장점을 가지고 있습니다.

프로그램을 다운로드를 받고 압축을 해제하면 여러개의 폴더와 파일이 보이는데요, 이 중 필요한 것은 vmmon.exe(vmmon64.exe)와 target 폴더입니다. 


압축 해제된 VirtualKD

사용법은 굉장히 간단합니다. 우선 디버기(게스트 PC)에 target 폴더를 복사하고 vminstall.exe를 실행합니다. 실행하고나면 두 가지 옵션을 선택할 수 있는 다이얼로그 박스가 뜨는데, 첫 번째 옵션은 부팅 시 커널 디버깅을 수행할 수 있는 새로운 부트엔트리를 작성하는 것이고, 두 번째 옵션은 현재 부트엔트리에 덮어쓰는 것입니다. 저는 개인적으로 첫 번째 옵션을 추천합니다.

vminstall.exe

원하시는 옵션을 선택한 후, Install 버튼을 누르면 부트엔트리가 작성이 되고 재부팅을 하시면 아래의 선택화면을 보실 수 있습니다. [VirtualKD]라 붙은 것을 선택하시면 VirtualKD를 통한 커널 디버깅을 수행하실 수 있습니다.
부트엔트리 선택 화면

다음은 디버거(호스트 PC)에서 해주셔야 할 부분입니다. 매우 간단합니다. 그냥 vmmon.exe를 실행시키시고 Debugger Path만 설정해주시면 끝입니다. 이후부터는 원하는 가상머신을 선택한 후 Run Debugger 버튼을 누르면 WinDBG가 실행되면서 커널 디버깅을 수행하실 수 있습니다.


vmmon.exe
WinDBG


Tip : 커널 디버깅을 하는 경우에는 VirtualKD가 편리합니다만, 유저모드 디버깅을 하기위해 WinDBG를 실행하면 심볼경로가 리셋이 되어 있습니다. 이때는 단축아이콘에 다음과 같은 옵션을 넣고 실행하면 됩니다.

C:\WinDDK\7600.16385.0\Debuggers\windbg.exe -y "srv*C:\WebSymbols*http://msdl.microsoft.com/download/symbols"




디지털 포렌식에 관련한 첫 글입니다. 최근들어 계속 진행해오던 윈도우즈 물리 메모리 분석과 관련해 지속적으로 포스팅할 계획입니다.

일반적으로 디지털 포렌식Digital forensics이라 하면 증거를 찾기 위한 하드디스크 복구 및 파일시스템 분석을 생각하실 듯 합니다. 물론 보조 저장장치로 가장 많이(대체할말한 것이?) 쓰이는 하드디스크 내에 중요 증거가 존재한다는 것은 명백한 사실입니다. 따라서 디지털 포렌식 분야에서 기술적, 법적으로 가장 많은 연구가 진행되어왔으며, 실제 민형사 사건 발생 시 하드디스크에서 발견된 디지털 데이터가 증거로서 채택이 된 경우가 많습니다.

제가 앞으로 떠들고자하는 물리 메모리 분석은 라이브 포렌식Live forensics의 일부로서, 시스템이 활성 상태로 구동 중일 때 휘발성 데이터를 수집하고 분석하는 방법 중 하나입니다. 일반적으로 하드디스크 분석을 위한 이미징 시, 디스크의 무결성을 보존하기 위해 시스템의 전원을 강제로 차단해버립니다(쉽게 말해 코드를 뽑아버리는 방법으로). 하지만 이러한 방법을 사용하는 경우, 시스템이 구동 중이던 시점의 프로세스나 네트워크 세션 등의 휘발성 데이터가 소멸되어 버립니다. 물론 회계 부정이나 기밀 문서 유출 사건과 같은 경우에는 하드디스크 내의 데이터가 가장 중요한 증거가 될 수 있겠습니다만, 최근 많이 발생하고 있는 웜, 트로얀 및 시스템 침해 사건의 경우에는 시스템이 구동 중이던 시점의 그 '상태'가 더 중요할 수 있습니다.

지금까지의 침해 사건의 경우, 이에 대응하기 위한 콘솔 명령어 도구, 이를 자동화하기 위한 쉘스크립트 및 로그 파일 수집, 분석을 하게 됩니다. 이러한 방법은 대부분의 경우 OS가 제공하는 API(시스템 콜)를 이용하게 되는데, 이는 악성코드의 커널-유저모드 후킹과 같은 기법에 의해 변조된 결과를 얻을 가능성이 있습니다. 바로 이러한 단점을 극복하기 위한 기법이 물리 메모리 분석입니다.


물리 메모리 분석은 소프트웨어 및 하드웨어 기반으로 현재 물리 메모리에 존재하는 데이터를 그대로(raw) 파일 형태로 덤프한 후 이를 분석하여, 프로세스 실행 상태, 로드된 모듈, 사용 중이었던 파일, 네트워크 세션 등의 정보를 복구해내는 기술입니다. 물리 메모리 분석은 2005년에 열린 DFRWS 로데오 챌린지Digital Forensics Research Conference Rodeo Challenge에서 당시 파일시스템 포렌식계의 거물(?)인 브라이언 캐리어Brian Carrier가 챌린지를 주최 및 그 중요성을 강조하면서 본격적인 연구가 시작되었습니다. 챌린지의 대상으로는 Windows 2000 SP4의 물리 메모리 이미지가 올라왔구요.

The results of memory analysis challenge

그 결과로 위의 두 개의 도구 memparser, kntlist가 개발되었습니다. 메모리 분석에 관심있으신 분들은 한 번쯤은 들어보시거나 직접 사용해보셨으리라 생각됩니다. 두 도구는 물리 메모리로부터 프로세스 목록 및 환경, 감사 로그 등의 정보를 추출하는 최초의 도구입니다. 이 이후에는 프로세스 및 쓰레드 객체의 구조체인 EPROCESS, ETHREAD를 카빙하는 도구인 ptfinder, 파이썬으로 제작되었고 사용자가 기능을 추가할 수 있도록 플러그인 개발을 지원하는 Volatility Framework 등의 유명한 도구들이 개발되었습니다.

하지만 앞서 설명드린 도구들은 콘솔 기반이기 때문에 분석의 결과를 시각적으로 보여주지 못한다는 단점을 보여줍니다. 또한 대부분 Windows 2000 및 XP만을 대상으로 하였기 때문에 최근 널리 쓰이고 있는 Vista 및 7, 그리고 서버 제품군을 지원하지 못하고 있습니다.


뭐 이러한 이유 때문은 아니지만.. 제가 최근에 물리 메모리 분석에 대해 공부하며 직접 분석 도구를 개발하였습니다. 아직 완벽하지는 않지만 상당부분에서 진행이 완료되어 쓸만하다고 생각됩니다. 우선 GUI 형태로 개발되어 보기도 좋고(?) 폭 넓은 윈도우즈 버젼을 지원한다는 것이 장점입니다.


Physical Memory Dump Explorer

보시면 아시겠지만, Sysinternals(http://technet.microsoft.com/en-us/sysinternals/default.aspx)의 Process Explorer와 비슷한 형태를 지니고 있습니다. 프로세스명, PID, 실행-종료 상태 등의 기본 정보 및 파일 핸들, 시스템 드라이버 및 DLL, 네트워크 세션 등의 정보가 출력되며, Processlibrary.com으로부터 얻어온 프로세스의 상세 정보 역시 출력됩니다. 또한 아래의 프로세스 속성, 메모리맵, 프로세스 주소 영역 덤프 및 문자열 추출 기능까지 지원하도록 개발되었습니다.


Image properties

Memory map

Strings

아직까지는 갈길이 멀긴하지만, 앞으로 관련 연구가 진행되는대로 기능이 추가될 예정입니다. 현재는 4n6tech(http://4n6tech.com)에서 MEMA라는 이름으로 판매되고 있지만(-_-;) 향후 오픈 소스 프로젝트로 새롭게 개발할까도 생각하고 있습니다. 실천이 될런지는 모르겠습니다만.. 물리 메모리 분석에 대해 관심있으신 분들의 지속적인 관심 및 격려를 부탁드리겠습니다 하하.

참고로 Mac OS X를 대상으로 한 오픈소스 프로젝트가 진행 중입니다. n0fate님의 Volafox(http://code.google.com/p/volafox/)이구요, 맥을 대상으로 한 물리 메모리 분석에서는 가장 진보한 형태라고 생각됩니다(사실 다른건 몰라서 ㅋㅋ). 유일한 맥을 대상으로 한 물리 메모리 분석 도구입니다. (n0fate님 지적 감사)


향후 본 블로그에 물리 메모리 분석과 관련한 글을 지속적으로 포스팅할 계획입니다. 사실 지금까지 해온 것들을 정리한다는 느낌이 크긴 하지만요. 제가 글을 잘 쓰는 편이 아니라 쉽게 이해가 되지 않으실지도 모르겠습니다만, 관심을 가져주시면 감사드리겠습니다.


일단 이번 포스팅은 여기에서 마무리 짓겠습니다. 두 번째 글은 아마도 가상-물리 주소 변환과 관련한 글이 될 것 같습니다.






블로그 첫 포스팅을 좋은 소식과 함께하게 되어 상당히 기쁩니다.

저희 팀인 DFRC가 미 국방부 산하의 DC3(DoD Cyber Crime Center)에서 주최한 '2010 DC3 Digital Forensics Challenge'(이하 DC3)에서 우승을 차지하였습니다. 이는 작년에 개최된 챌린지에 이어 2회 연속 우승입니다.

이번 대회에는 총 53개 국가의 1010개 팀이 참가하여 최종적으로 71개 팀만이 보고서를 제출하였습니다. 이는 작년에 44개 팀만이 최종 보고서를 제출한데 비해서 경쟁률이 올랐다는 것을 보여주네요.

시상은 총 11개 부문에 대해 이루어집니다. 우선 크게 International 부문과, U.S, 그리고 U.S. Academic으로 나뉘어집니다. 그리고 각 분류 내에서 미영주권자 여부 및 신분(Non-US, Commercial, Civilian 등)에 따라 세부 시상이 주어지는데요. 저희 DFRC는 미국 사람이 아닌 관계로(-_-;) 'Non-US Only'에게 주어지는 'Prize IMPACT'를 수상하였습니다. 물론 총점은 3,297점으로 가장 높기 때문에 'Grand Champion'도 수상하였습니다.

2010 DC3 Challenge Stats - Winner's Circle

위의 시상에 대해 재미있는 점은, 총점이 84점임에도 불구하고 세부적으로 나뉜 시상부문 덕분에 수상하게 된 사람들도 꽤 된다는 점입니다. 미군이라는 신분으로 88점을 획득하여 Prize ECC를 탄 사람도 있습니다.


어찌되었든 'South Korea'를 달고 세계무대에서 우승한다는 것은 상당히 기쁜 일입니다. 저보다는 저희 팀원들이 더 수고해주었지만 말이죠. :)

Challenges and Point Structure

위에 보이는 것이 각 문제 및 점수 배점표입니다. 작년과 크게 달라진 것이라면, 500점짜리 도구 개발 문제가 새롭게 상당 수 추가되었다는 점입니다. 아마 작년에 우승할 적에 저희 연구실에서 개발한 도구를 사용하여 문제를 풀었다는 것이 큰 영향을 끼치지 않았나 생각합니다만.. 100% 저만의 생각이니 믿진 마시길..

이번 DC3 챌린지로 인해 연구실 내에 학술적인 성과도 있었습니다. 아직까지 세계적으로 Shadow Volume Copy에 대한 연구가 진행된바가 없었습니다만, 연구실 박사과정 선배가 이 문제를 해결함으로해서 해당 연구가 어느정도 성공적으로 진행되었습니다. (아마 곧 논문으로 나올 듯 싶습니다. 나오는대로 리뷰를 포스팅할 계획입니다.)

다만 어이없는(?) 문제도 좀 보이는데요. 저만의 생각일지도 모릅니다만, BitLocker나 TPM 관련 문제는 풀라고 낸거 같아 보이지는 않네요. 물론 챌린지의 의도가 디지털 포렌식 커뮤니티에 새로운 도구, 기술 및 방법론에 대한 지식을 공유하자는 것이긴 하지만, 확실히 쉽게 해결될 문제들은 아닙니다. 아마 저 문제들은 각 2,000점씩 줘야 할 듯..하하

또 다른 불만도 있습니다. 일부 문제들이 정답을 바꾸지 않고 그대로 나왔다는 사실입니다. 도대체 그 문제들은 왜 '꾸준히' '그대로' 나오는지 의문입니다. 점수 줄려고 그러나.. 덕분에 저희도 좀 날로 먹은게 있지만 말이죠.


문제가 어찌되었든지간에, 앞으로 DC3 문제와 관련하여 이를 어떻게 해결했는지를 포스팅할 계획입니다. 그 중에는 완벽하게 해답을 찾지 못한 것도 일부 있습니다만, 혹시나 저의 포스팅을 보게 되실 분들께서 좋은 의견을 가지고 계신다면 문제 해결을 위한 의논도 해보고 싶습니다.

앞으로 이 블로그에 디지털 포렌식, 정보보호 및 기타 잡다한 개잡소리까지 열심히 포스팅할 계획이니 많이 찾아주시면 감사드리겠습니다.

그럼 이만 :)