Monthly Archive for 12월, 2008

[Heap] Page Heap Enabled 환경

일반적으로 heap에 메모리를 할당하게 되면 _HEAP 과 _HEAP_ENTRY가 기본적으로 생성됩니다. 하지만 Page Heap Enabled 환경에는 그외에 몇가지 추가 정보들을 가지게 됩니다.

일반 환경의 Heap Allocation

  • Create Heap -> _HEAP 생성
  • Allocate Heap -> _HEAP_ENTRY 생성

Page Heap Enabled 환경의 Heap Allocation

  • Create Heap -> _DPH_HEAP_ROOT 생성, _HEAP 생성
  • Allocate Heap -> _DPH_HEAP_BLOCK 생성, _DPH_BLOCK_INFORMATION 생성, _HEAP_ENTRY 생성

_DPH로 시작하는 구조체는 각  Heap 생성과 Free 시에 Stack Trace 정보, Memory의 Size, 실제 할당된 Virtual Memory의 Page ( 0×2000 사이즈.. )의 Address 등의 정보를 가지게 됩니다.

0:001> !heap -p -all
_DPH_HEAP_ROOT @ a1000
Freed and decommitted blocks
DPH_HEAP_BLOCK : VirtAddr VirtSize
000a3bdc : 022da000 00004000
000a39ac : 02368000 00002000
000a3e34 : 022ee000 00002000
000a4a3c : 02300000 00002000
000a48ac : 0239a000 00004000
000a3de4 : 02310000 00002000
000a3c7c : 02322000 00002000
000a4884 : 0239e000 00004000
000a3aec : 02360000 00003000
000a48fc : 023a2000 00004000
000a14f4 : 02314000 00002000
000a345c : 000fa000 00002000
000a4604 : 022de000 00002000
000a3ac4 : 0237a000 00004000
000a3f24 : 02350000 00002000
000a4334 : 02354000 00002000
000a3a24 : 02394000 00004000
000a35ec : 0236a000 00002000
000a4794 : 0238c000 00002000
000a46f4 : 023b2000 00002000
000a4c1c : 023c6000 00002000
000a3ccc : 0237e000 00002000
000a4bf4 : 023c4000 00002000
000a4ba4 : 023c0000 00002000
000a3a4c : 02378000 00002000
000a4b7c : 023be000 00002000
000a4b54 : 023bc000 00002000
000a39fc : 02366000 00002000
000a4b2c : 023ba000 00002000
000a4adc : 023b6000 00002000
000a2f0c : 000f6000 00002000
000a43fc : 0235e000 00002000
000a4ab4 : 023b4000 00002000
000a4c44 : 023c8000 00002000
Busy allocations
DPH_HEAP_BLOCK : UserAddr UserSize - VirtAddr VirtSize
000a38bc : 023cefe8 00000018 - 023ce000 00002000
000a3e5c : 023b0f88 00000074 - 023b0000 00002000
000a3a9c : 023aefd8 00000024 - 023ae000 00002000
000a4a14 : 023acf88 00000074 - 023ac000 00002000
000a3b14 : 02302f88 00000074 - 02302000 00002000
000a4a8c : 022fef88 00000074 - 022fe000 00002000
000a4a64 : 0234ef88 00000074 - 0234e000 00002000
000a47e4 : 02320f88 00000074 - 02320000 00002000
000a4b04 : 023b8f88 00000074 - 023b8000 00002000
000a48d4 : 02398f88 00000074 - 02398000 00002000
000a43ac : 0235afb8 00000044 - 0235a000 00002000
MSCTF!CProxyITfLangBarItemSink::`vftable’
000a3eac : 0231afb8 00000044 - 0231a000 00002000
MSCTF!CProxyITfLangBarItemSink::`vftable’
000a467c : 02316fb8 00000044 - 02316000 00002000
MSCTF!CProxyITfLangBarItemSink::`vftable’
000a44ec : 022f4fb8 00000044 - 022f4000 00002000
MSCTF!CProxyITfLangBarItemSink::`vftable’
000a3664 : 02282fb8 00000044 - 02282000 00002000
MSCTF!CProxyITfLangBarItemSink::`vftable’
000a2d2c : 02238fb8 00000044 - 02238000 00002000
MSCTF!CProxyITfLangBarItemSink::`vftable’
000a3bb4 : 022e2fb8 00000044 - 022e2000 00002000
MSCTF!CProxyITfLangBarItemSink::`vftable’
000a318c : 022e0fb8 00000044 - 022e0000 00002000
MSCTF!CProxyITfLangBarItemSink::`vftable’
000a476c : 0238afc8 00000038 - 0238a000 00002000
MSCTF!CStubITfLangBarItemButton::`vftable’
000a462c : 02344fc8 00000038 - 02344000 00002000
MSCTF!CStubITfLangBarItemButton::`vftable’
000a3d94 : 0230cfc8 00000038 - 0230c000 00002000
MSCTF!CStubITfLangBarItemButton::`vftable’
000a4834 : 023a6fc8 00000038 - 023a6000 00002000
MSCTF!CStubITfLangBarItemButton::`vftable’
000a4744 : 02388ff8 00000004 - 02388000 00002000
000a46a4 : 02380fd8 00000024 - 02380000 00002000
MSCTF!CSharedBlockNT::`vftable’
000a45dc : 02376ff0 00000010 - 02376000 00002000
MSCTF!CPtrArray<SYSTHREAD>::`vftable’
000a40dc : 02336ff0 00000010 - 02336000 00002000
000a4014 : 0232cf78 00000084 - 0232c000 00002000
MFC42!AFX_MODULE_THREAD_STATE::`vftable’
000a3c54 : 022d4f70 00001090 - 022d4000 00003000
MFC42!_AFX_BASE_MODULE_STATE::`vftable’
000a471c : 000f4fe0 00000020 - 000f4000 00002000
000a395c : 02364f78 00000084 - 02364000 00002000
MFC42!AFX_MODULE_THREAD_STATE::`vftable’
000a3f4c : 022fcfe0 00000020 - 022fc000 00002000
000a47bc : 02392fe0 00000020 - 02392000 00002000
000a421c : 02390fe0 00000020 - 02390000 00002000
000a42e4 : 0238efe0 00000020 - 0238e000 00002000
000a46cc : 02386fe0 00000020 - 02386000 00002000
000a4474 : 02384fe0 00000020 - 02384000 00002000
000a449c : 02382fe0 00000020 - 02382000 00002000
000a453c : 02372fe0 00000020 - 02372000 00002000
000a444c : 02370fe0 00000020 - 02370000 00002000

Windbg에서는 이러한 Page Heap Enabled 환경에서의 정보를 좀더 쉽게 볼수 있도록 !heap Extension Option을 제공하고 있습니다. ( !heap Extension에 관해서는 나중에 기회가되면 좀 정리하여 올리도록 하겠습니다. ) !heap -p 를 통해서 _DPH_HEAP_ROOT와 _DPH_HEAP_BLOCK으로 실제 할당된 메모리와 해제된 메모리의 추적이 가능합니다. 일단 _DPH_HEAP_ROOT의 실제 구조체를 살펴보죠.

0:001> dt ntdll!_DPH_HEAP_ROOT a1000
+0x000 Signature : 0xffeeddcc
+0x004 HeapFlags : 2
+0x008 HeapCritSect : 0x000a5000 _RTL_CRITICAL_SECTION
+0x00c nRemoteLockAcquired : 0
+0x010 pVirtualStorageListHead : 0x000a3894 _DPH_HEAP_BLOCK
+0x014 pVirtualStorageListTail : 0x000a10bc _DPH_HEAP_BLOCK
+0x018 nVirtualStorageRanges : 3
+0x01c nVirtualStorageBytes : 0x300000
+0×020 pBusyAllocationListHead : 0×000a38bc _DPH_HEAP_BLOCK
+0×024 pBusyAllocationListTail : 0×000a115c _DPH_HEAP_BLOCK
+0×028 nBusyAllocations : 0×14f
+0×02c nBusyAllocationBytesCommitted : 0×29f000

+0×030 pFreeAllocationListHead : 0×000a3bdc _DPH_HEAP_BLOCK
+0×034 pFreeAllocationListTail : 0×000a4c44 _DPH_HEAP_BLOCK
+0×038 nFreeAllocations : 0×22
+0×03c nFreeAllocationBytesCommitted : 0×51000

+0×040 pAvailableAllocationListHead : 0×000a480c _DPH_HEAP_BLOCK
+0×044 pAvailableAllocationListTail : 0×000a39d4 _DPH_HEAP_BLOCK
+0×048 nAvailableAllocations : 3
+0×04c nAvailableAllocationBytesCommitted : 0xa000

+0×050 pUnusedNodeListHead : 0×000a3934 _DPH_HEAP_BLOCK
+0×054 pUnusedNodeListTail : 0×000a4fb4 _DPH_HEAP_BLOCK
+0×058 nUnusedNodes : 0×1d
+0×05c nBusyAllocationBytesAccessible : 0×150000
+0×060 pNodePoolListHead : 0×000a1094 _DPH_HEAP_BLOCK
+0×064 pNodePoolListTail : 0×000a1094 _DPH_HEAP_BLOCK
+0×068 nNodePools : 1
+0×06c nNodePoolBytes : 0×4000
+0×070 pNextHeapRoot : 0×002b1000 _DPH_HEAP_ROOT
+0×074 pPrevHeapRoot : (null)
+0×078 nUnProtectionReferenceCount : 1
+0×07c InsideAllocateNode : 0
+0×080 ExtraFlags : 3
+0×084 Seed : 0×42752766
+0×088 NormalHeap : 0×001a0000
+0×08c CreateStackTrace : (null)
+0×090 FirstThread : 0×00000938

_DPH_HEAP_ROOT 구조체를 보면 현재 Busy 한 Heap Block과 Free한 Heap Block을 Linked List로 가지고 있는 것을 확인 할 수 있습니다. 이 링크를 통해서 _DPH_HEAP_BLOCK를 추적해 보죠.

0:001> dl 000a38bc
000a38bc 000a3e5c 023ce000 00002000 00001000
000a3e5c 000a3a9c 023b0000 00002000 00001000
000a3a9c 000a4a14 023ae000 00002000 00001000
000a4a14 000a3b14 023ac000 00002000 00001000
000a3b14 000a4a8c 02302000 00002000 00001000
000a4a8c 000a4a64 022fe000 00002000 00001000
000a4a64 000a47e4 0234e000 00002000 00001000
000a47e4 000a4b04 02320000 00002000 00001000
000a4b04 000a48d4 023b8000 00002000 00001000
000a48d4 000a43ac 02398000 00002000 00001000
000a43ac 000a3eac 0235a000 00002000 00001000
000a3eac 000a467c 0231a000 00002000 00001000
000a467c 000a44ec 02316000 00002000 00001000
000a44ec 000a3664 022f4000 00002000 00001000
000a3664 000a2d2c 02282000 00002000 00001000
000a2d2c 000a3bb4 02238000 00002000 00001000
000a3bb4 000a318c 022e2000 00002000 00001000
000a318c 000a476c 022e0000 00002000 00001000
000a476c 000a462c 0238a000 00002000 00001000
000a462c 000a3d94 02344000 00002000 00001000
000a3d94 000a4834 0230c000 00002000 00001000
000a4834 000a4744 023a6000 00002000 00001000
000a4744 000a46a4 02388000 00002000 00001000
000a46a4 000a45dc 02380000 00002000 00001000
000a45dc 000a40dc 02376000 00002000 00001000
000a40dc 000a4014 02336000 00002000 00001000
000a4014 000a3c54 0232c000 00002000 00001000
000a3c54 000a471c 022d4000 00003000 00002000
000a471c 000a395c 000f4000 00002000 00001000
000a395c 000a3f4c 02364000 00002000 00001000
000a3f4c 000a47bc 022fc000 00002000 00001000
000a47bc 000a421c 02392000 00002000 00001000

ntdll!_DPH_HEAP_BLOCK
+0x000 pNextAlloc : 0x000a3e5c _DPH_HEAP_BLOCK
+0x004 pVirtualBlock : 0x023ce000 ""
+0x008 nVirtualBlockSize : 0x2000
+0x00c nVirtualAccessSize : 0x1000
+0x010 pUserAllocation : 0x023cefe8 "???"
+0x014 nUserRequestedSize : 0x18
+0x018 nUserActualSize : 0x18
+0x01c UserValue : (null)
+0x020 UserFlags : 0
+0×024 StackTrace : 0×023e4efc _RTL_TRACE_BLOCK

상당히 많은 Block 들이 Double Linked List로 연결되어 있는 것을 확인 할 수 있습니다. 실제 가장 디버깅에 많이 사용되는 Stack Trace와 UserAllocation 부분 그리고 _DPH_BLOCK_INFORMATION을 확인해 보도록 하죠.

0:001> dt _RTL_TRACE_BLOCK 0x023e4efc
ntdll!_RTL_TRACE_BLOCK
+0x000 Magic : 0xabcdaaaa
+0x004 Count : 2
+0x008 Size : 0x10
+0x00c UserCount : 1
+0x010 UserSize : 0x18
+0x014 UserContext : 0x000a1000
+0x018 Next : (null)
+0×01c Trace : 0×023e4f1c -> 0×7c97bea7
0:001> dps 0×023e4f1c
023e4f1c 7c97bea7 ntdll!RtlReAllocateHeap+0×1de
023e4f20 7c830998 kernel32!LocalReAlloc+0×1b6
023e4f24 746a13cb MSCTF!cicMemReAlloc+0×13
023e4f28 7469346c MSCTF!CVoidPtrArray::CompactSize+0×1f
023e4f2c 746661b5 MSCTF!CVoidPtrArray::Remove+0×4f
023e4f30 7467c9f7 MSCTF!FreeMarshaledStubOfItem+0xe9
023e4f34 7467cfb1 MSCTF!CLangBarItemMgr::RemoveItem+0xc5
023e4f38 7467d649 MSCTF!CLangBarItemMgr::RemoveItem+0×42
023e4f3c 4b54c950 imekr61!CToolBar::Terminate+0xee
023e4f40 4b54a535 imekr61!CToolBar::`scalar deleting destructor’+0×7a
023e4f44 4b54a9df imekr61!SetIndicator+0×4a
023e4f48 4b54b6bf imekr61!UIPopupMenu+0×5e3
023e4f4c 77cf8734 USER32!InternalCallWinProc+0×28
023e4f50 77cf8816 USER32!UserCallWinProcCheckWow+0×150
023e4f54 77d0927b USER32!SendMessageWorker+0×4a5
023e4f58 77d4b875 USER32!SendMessageToUI+0×52

실제로 이 Block이 할당한 Stack을 확인 할 수 있습니다. 그럼 UserAllocation 부분과 _DPH_BLOCK_INFORMATION을 통해서 Stack Trace를 확인해 보도록 하죠.

0:001> dd 0x023cefe8-0x20
023cefc8 abcdbbbb 000a1000 00000018 00001000
023cefd8 019203b0 01926cdf 023e4f5c dcbabbbb
023cefe8 0234afc8 023a6fc8 0230cfc8 02344fc8
023ceff8 0238afc8 0235efc8 ???????? ????????
023cf008 ???????? ???????? ???????? ????????
023cf018 ???????? ???????? ???????? ????????
023cf028 ???????? ???????? ???????? ????????
023cf038 ???????? ???????? ???????? ????????

0:001> dt _DPH_BLOCK_INFORMATION 0x023cefe8-0x20
ntdll!_DPH_BLOCK_INFORMATION
+0x000 StartStamp : 0xabcdbbbb
+0x004 Heap : 0x000a1000
+0x008 RequestedSize : 0x18
+0x00c ActualSize : 0x1000
+0x010 FreeQueue : _LIST_ENTRY [ 0x19203b0 - 0x1926cdf ]
+0×010 TraceIndex : 0×3b0
+0×018 StackTrace : 0×023e4f5c
+0×01c EndStamp : 0xdcbabbbb

0:001> dps 0×023e4f5c
023e4f5c abcdaaaa
023e4f60 00000001
023e4f64 00000010
023e4f68 00000000
023e4f6c 00000000
023e4f70 00000000
023e4f74 00000000
023e4f78 023e4f7c
023e4f7c 7c99d27f ntdll!RtlDebugReAllocateHeap+0×30
023e4f80 7c97bea7 ntdll!RtlReAllocateHeap+0×1de
023e4f84 7c830998 kernel32!LocalReAlloc+0×1b6
023e4f88 746a13cb MSCTF!cicMemReAlloc+0×13
023e4f8c 7469346c MSCTF!CVoidPtrArray::CompactSize+0×1f
023e4f90 746661b5 MSCTF!CVoidPtrArray::Remove+0×4f
023e4f94 7467c9f7 MSCTF!FreeMarshaledStubOfItem+0xe9
023e4f98 7467cfb1 MSCTF!CLangBarItemMgr::RemoveItem+0xc5
023e4f9c 7467d649 MSCTF!CLangBarItemMgr::RemoveItem+0×42
023e4fa0 4b54c950 imekr61!CToolBar::Terminate+0xee
023e4fa4 4b54a535 imekr61!CToolBar::`scalar deleting destructor’+0×7a
023e4fa8 4b54a9df imekr61!SetIndicator+0×4a
023e4fac 4b54b6bf imekr61!UIPopupMenu+0×5e3
023e4fb0 77cf8734 USER32!InternalCallWinProc+0×28
023e4fb4 77cf8816 USER32!UserCallWinProcCheckWow+0×150
023e4fb8 77d0927b USER32!SendMessageWorker+0×4a5

여기서 특징적인 부분이라하면 _DPH_HEAP_BLOCK에 나타나는 StackTrace의 위치와  _DPH_BLOCK_INFORMATION에 나타나는 StackTrace의 위치가 다르다는 점입니다. 물론 그 내용은 동일 합니다. 좀더 효율적인 디버깅을 위해서 _DPH_BLOCK_INFORMATION과 _DPH_HEAP_BLOCK에 Stack Trace 정보를 따로 저장한것으로 생각됩니다.  Page Heap Enabled 환경의 경우 이러한 정보를 통해서 좀더 효율적인 Memory Debugging이 가능합니다. 예를 들면 Memory Leak 이나 Heap Curruption을 추적 같은 경우죠.

멋지게 한번 활용해 보시길 … Enjoy Debugging..^^

IT EXPERT 윈도우 디바이스 드라이버

IT EXPERT 윈도우 디바이스 드라이버

IT EXPERT 윈도우 디바이스 드라이버

재홍군이 또한권의 책을 출판했습니다. 옆에서 항상 보는 친구 지만 정말 대단하내요. 나도 빨리 책한권 내야하는데 흑흑 …

yes24에서 예약 판매하고 있으니 많은 분들이 사보셨으면 합니다.

IT Expert 윈도우 디바이스 드라이버 Yse 24 링크

[x64] 64bit Vista 환경에서의 Inline Hook에 어려움 ( Relative Address의 압박 )

32bit 환경에서 API Inline Hooking을 할 경우 상위 5Byte 또는 6Byte를 교체하여 Jmp Code를 만들어주고 Trampoline Function을 통해서 원본 코드를 실행하여 동작하도록 많이 하고 있습니다. ( 보통은 Detour Library를 사용하지요.  ) 실제로 코드를 보면 Hooking에 사용되는 상위 Byte는 대부분 그 Function의 Prologue에 해당하는 부분이지요. 하지만 64bit환경에서는 얘기가 조금 다릅니다. 32bit환경과 달리 64bit 환경에서는 Function 상위에 Prologue가 존재하지 않기 때문입니다. 가장 큰 문제가 되는 부분은 Function의 상위에 Relative Address를 사용하는 Instruction이 존재할 수 있다는 점이죠. 간단한 예를 들어보죠

lkd> u nt!IofCallDriver
nt!IofCallDriver:
fffff800`01c595e0 4883ec28        sub     rsp,28h
fffff800`01c595e4 488b05f50c1a00  mov     rax,qword ptr [nt!pIofCallDriver (fffff800`01dfa2e0)]
fffff800`01c595eb 4885c0          test    rax,rax
fffff800`01c595ee 0f85d8090600    jne     nt! ?? ::FNODOBFM::`string’+0×11a60 (fffff800`01cb9fcc)
fffff800`01c595f4 804243ff        add     byte ptr [rdx+43h],0FFh
fffff800`01c595f8 384243          cmp     byte ptr [rdx+43h],al
fffff800`01c595fb 0f8ed7090600    jle     nt! ?? ::FNODOBFM::`string’+0×11a6c (fffff800`01cb9fd8)
fffff800`01c59601 488b82b8000000  mov     rax,qword ptr [rdx+0B8h]

가장 많이 사용하고 있는 IofCallDriver 함수 입니다. 특이한 점은 함수 상위에 Relative Address를 사용하는 Instruction이 있다는 것이죠 .  위와 같은 경우 일반적인 Inline Hooking을 했을때 Trampoline함수에서 문제가 발생할 수 있습니다.  이런 부분은 좀더 고민해서 64bit 환경 Hooking을 구현해야 할 것으로 생각됩니다. ( 물론 x64 Vista환경에서 Patch Guard때문에 IofCallDriver를 Hooking 못할 꺼라 생각 할 수 있지만 실제로 DPC 를 Hooking 해서 Patch Guard 관련 함수를 Disable 하도록 Kernel patch를 하면 가능하긴 합니다. )

참고로 Relative Address의 경우 RIP를 통해서 Address를 연산해 냅니다.
예 )  32bit Operland + RIP = Virtual Address
lkd> ? fffff800`01c595e4+001a0cf5+7
Evaluate expression: -8796061588768 = fffff800`01dfa2e0

[windbg] Virtual Address -> Physical Address

간혹 Virtual Address를 Physical Address로 변환해야할 일 이 있습니다.

windbg에서는 굉장히 간단한 방법으로 변환이 가능합니다.

start end module name
f7a0b000 f7a37980 NDIS (deferred)
Image path: NDIS.sys
Image name: NDIS.sys
Timestamp: Mon Apr 14 04:20:35 2008 (48025D03)
CheckSum: 0002E181
ImageSize: 0002C980
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4

lkd> !pte f7a0b000
VA f7a0b000
PDE at C0300F78 PTE at C03DE82C
contains 019E2963 contains 0A99A963
pfn 19e2 -G-DA–KWEV pfn a99a -G-DA–KWEV

Physical Memory의 상위 20 Bit는 a99a라는 것을 알 수 있습니다. 물론 하위 12bit는 Address의 Page Index를 나타내는 것이므로 그냥 더해주기만 하면 바로 VA를  PA로 변환할 수 있습니다.

lkd> dc f7a0b000
f7a0b000 00905a4d 00000003 00000004 0000ffff MZ..............
f7a0b010 000000b8 00000000 00000040 00000000 ........@.......
f7a0b020 00000000 00000000 00000000 00000000 ................
f7a0b030 00000000 00000000 00000000 000000e8 ................
f7a0b040 0eba1f0e cd09b400 4c01b821 685421cd ........!..L.!Th
f7a0b050 70207369 72676f72 63206d61 6f6e6e61 is program canno
f7a0b060 65622074 6e757220 206e6920 20534f44 t be run in DOS
f7a0b070 65646f6d 0a0d0d2e 00000024 00000000 mode....$.......
lkd> dc /p a99a000
0a99a000 00905a4d 00000003 00000004 0000ffff MZ..............
0a99a010 000000b8 00000000 00000040 00000000 ........@.......
0a99a020 00000000 00000000 00000000 00000000 ................
0a99a030 00000000 00000000 00000000 000000e8 ................
0a99a040 0eba1f0e cd09b400 4c01b821 685421cd ........!..L.!Th
0a99a050 70207369 72676f72 63206d61 6f6e6e61 is program canno
0a99a060 65622074 6e757220 206e6920 20534f44 t be run in DOS
0a99a070 65646f6d 0a0d0d2e 00000024 00000000 mode....$.......

간단하죠 ^ ^. 생각보다 유용하게 쓰일때가 있습니다.

Enjoy Debugging…

MDA 에서 가장 중요한 세가지

MDA를 계속 하고 있지만 개인적으로 무엇보다 중요하게 생각하는 것이 3가지 있습니다.

1. Analysis의 방향
2. Analysis에 필요한 정보 파악
3. 인내심과 끈기 !!

이 3가지에 대해서 모두 자신이 있다면 어떠한 상황을 만나도 겁나지 않겠죠 ..^ ^