오늘은 제가 어떤 익스텐션 DLL 을 만들었는지 소개합니다.
목적은 "커널덤프 파일에서 파일 옵젝트를 가지고 커널덤프에 존재하는 파일데이터를 모아서 실제 파일로 만드는 것" 입니다.
먼저 익스텐션 DLL 작성에는 두가지가 있다는 점을 알아두셔야 합니다.
1. DbgEng extension DLL
2. WdbgExts estension DLL
1번은 dbgeng.h 에 있는 Debugger Engine API 를 사용하여 익스텐션 DLL 을 만드는 것을 말합니다. Debugger Engine API 는 디버거를 만들 수 있을 정도의 기능을 가졌다고 합니다. 막강하다는 느낌과 함께 복잡할 것 같다는 생각이 드네요. ^^
2번은 wdbgexts.h 에 있는 WdbgExts API 를 사용하여 익스텐션 DLL 을 만드는 것을 말합니다. Old style extension DLL 이라고도 하네요. Old style 이라 그런지 처음 배우기는 이게 훨씬 쉬운 것 같아 이걸 선택했습니다. ^^
지난번에 소개했던 sdk\samples\simplext 가 바로 Old style extension DLL 예제입니다.
소스는 다음 두개입니다.
exts.c - WdbgExts extension DLL 기본골격
simple.c - 예제 command 들
exts.c 는 전혀 수정하지 않고 simple.c 만 myext.c 로 이름을 바꾸고 여기에 제가 원하는 명령 ef (extract file) 를 작성했습니다. 물론 SOURCE 파일도 수정해서 myext.dll 이 만들어지도록 했습니다.
그리고 ntddk.h 를 포함할 수가 없어서 nttype.h 를 별도로 만들어서 NT 커널 구조체를 사용합니다.
myext.dll 이 빌드되면 역시 WinDbg 설치폴더 밑의 winext 폴더로 복사하고 명령할 땐 다음과 같이 합니다. 먼저 help 를 보지요.
kd> !myext.help
Help for extension dll myext.dll
help - Shows this help
ef <fileobject address> <filename> - It extracts file from shared section
ef 명령은 FileObject 주소를 하나 골라서 넣어야 합니다. 만들어질 파일 이름하구요.
kd> !myext.ef 85f636e0 C:\temp\test.file
Creating "C:\temp\test.file" with file object(85f636e0)
SHARED_CACHE_MAP
================
FileSize : 12671
FileSize(Hex) : 0x317f
InitialVacbs[0] : 0x86792fa0
InitialVacbs[1] : 0x0
InitialVacbs[2] : 0x0
InitialVacbs[3] : 0x0
Vacbs : 0x85f04638
FileObject : 0x85f636e0
.Done!
출력에서 짐작하시겠지만 FileObject 로부터 SectionObjectPointer, SharedCacheMap, Vacb를 따라가서 시스템 캐쉬의 메모리를 가져오고 이것들을 모아서 파일로 만드는 것입니다. 현재는 DataSectionObject 나 ImageSectionObject 는 따라가지 않습니다. SharedCacheMap 만을 따라가서 파일을 만듭니다.
따라서 SectionObjectPointer 나 SharedCacheMap 이 NULL 이면 시스템캐쉬에 파일이 올라와 있지 않다는 뜻이고 이런 FileObject 에 대해서는 파일을 만들어내지 못합니다. 생각보다 이런 경우가 많습니다. 이 익스텐션 명령이 모든 FileObject 를 파일로 만들어 줄거라는 환상은 갖지 마시라는 뜻입니다. ^^
SharedCacheMap 이 존재하더라도 파일이 한번이라도 읽힌 적이 있어서 캐쉬에 있을 경우에만 유효한 데이터를 가져옵니다. 파일의 특정영역이 읽힌적이 없어서 캐쉬에 없다면 파일을 만들 때 이 영역은 0으로 채워서 만듭니다. 즉, 불완전한 파일이 만들어지게 됩니다. 이점도 반드시 기억해 주시구요.
이 과정은 "Windows 구조와 원리 그리고 Codes", "Windows Internals" 를 참고해서 만들었습니다. 여러분도 책을 참고해서 구현하실 수 있을 겁니다.
이제부터 구현한 내용을 약간 기술적으로 설명해 봅니다.
머리 아프신분들은 안보셔도 됩니다. ^^
!fileobj 명령을 사용하면 !ef 명령 안에서 하는 모든 동작을 하고 정보를 보여줍니다.
다만 파일로 만들어 주지만 않을 뿐이죠.
kd> !fileobj 85f636e0
\TestProj\DbgExt\myext\sample.txt
Device Object: 0x867b4900 \Driver\Ftdisk
Vpb: 0x8676e530
Access: Read SharedRead
Flags: 0x44042
Synchronous IO
Cache Supported
Cleanup Complete
Handle Created
File Object is currently busy and has 0 waiters.
FsContext: 0xe170dd90 FsContext2: 0xe170dee8
CurrentByteOffset: 317f
Cache Data:
Section Object Pointers: 866131dc
Shared Cache Map: 85f04608 File Offset: 317f in VACB number 0
Vacb: 86792fa0
Your data is at: cf08317f
데이터가 존재하는 메모리 주소까지 보여줍니다. !ef 명령에서는 저 메모리 주소를 따라가서 파일로 저장해 주는 과정을 수행합니다.
FileObject 부터 따라가는 과정을 보면
kd> dt _FILE_OBJECT 85f636e0
ntdll!_FILE_OBJECT
+0x000 Type : 5
+0x002 Size : 112
+0x004 DeviceObject : 0x867b4900 _DEVICE_OBJECT
+0x008 Vpb : 0x8676e530 _VPB
+0x00c FsContext : 0xe170dd90
+0x010 FsContext2 : 0xe170dee8
+0x014 SectionObjectPointer : 0x866131dc _SECTION_OBJECT_POINTERS
...
kd> dt 0x866131dc _SECTION_OBJECT_POINTERS
ntdll!_SECTION_OBJECT_POINTERS
+0x000 DataSectionObject : 0x86613260
+0x004 SharedCacheMap : 0x85f04608
+0x008 ImageSectionObject : (null)
kd> dt _SHARED_CACHE_MAP 0x85f04608
nt!_SHARED_CACHE_MAP
+0x000 NodeTypeCode : 767
+0x002 NodeByteSize : 304
+0x004 OpenCount : 0
+0x008 FileSize : _LARGE_INTEGER 0x317f
+0x010 BcbList : _LIST_ENTRY [ 0x85f04618 - 0x85f04618 ]
+0x018 SectionSize : _LARGE_INTEGER 0x40000
+0x020 ValidDataLength : _LARGE_INTEGER 0x317f
+0x028 ValidDataGoal : _LARGE_INTEGER 0x317f
+0x030 InitialVacbs : [4] 0x86792fa0 _VACB
+0x040 Vacbs : 0x85f04638 -> 0x86792fa0 _VACB
+0x044 FileObject : 0x85f636e0 _FILE_OBJECT
...
kd> dt _VACB 0x86792fa0
nt!_VACB
+0x000 BaseAddress : 0xcf080000
+0x004 SharedCacheMap : 0x85f04608 _SHARED_CACHE_MAP
+0x008 Overlay : __unnamed
+0x010 LruList : _LIST_ENTRY [ 0x805587e0 - 0x86793538 ]
kd> db 0xcf080000
cf080000 3b 3b 3b 20 54 72 69 6e-69 74 79 20 54 6f 74 61 ;;; Trinity Tota
cf080010 6c 20 53 65 63 75 72 69-74 79 0d 0a 3b 3b 3b 20 l Security..;;;
cf080020 54 68 69 73 20 66 69 6c-65 20 63 6f 6e 74 61 69 This file contai
cf080030 6e 73 20 61 6c 6c 20 63-6f 6d 6d 6f 6e 20 73 74 ns all common st
cf080040 72 69 6e 67 73 20 64 65-66 69 6e 65 64 20 69 6e rings defined in
cf080050 20 55 73 65 72 20 49 6e-74 65 72 66 61 63 65 20 User Interface
cf080060 50 72 6f 74 6f 74 79 70-65 20 0d 0a 0d 0a 3b 3b Prototype ....;;
cf080070 3b 20 49 44 20 4e 61 6d-69 6e 67 20 43 6f 6e 76 ; ID Naming Conv
이렇게 따라와서 메모리의 내용을 파일로 쓰는 겁니다.
파일이 1MB 이하일 땐 InitialVacbs 가 사용되고 1MB 초과일 땐 Vacbs 가 사용된다는 둥 VACB 는 256KB 블럭을 가리킨다는 둥 고려할 내용이 몇가지 있지만 책을 통해서 공부해 보시는게 좋을 것 같습니다.
익스텐션 DLL 소스와 바이너리를 첨부합니다.
맘대로 수정해서 사용하셔도 되구요 버그 발견해서 보고해 주시거나 수정해 주시는 것은 더욱 환영입니다. ^^
http://www.driveronline.org/bbs/view.asp?tb=tipbbs&GotoPage=1&s_bulu=&s_key=&no=98