|
Application이 Crash가 발생하거나 혹은, Hang 현상이 발생할 경우에, Application Logic 만 가지고 추측하여 문제가 발생하는 지점을 찾아 Fix하는 것은 쉽지 않다. 만일, 그게 가능하다면, 사실 개발단계에서 그런 문제점을 고려하지 못했던 것을 탓해야 할 것이지만, 그렇지 못하기 때문에 대부분의 문제는 Application 운영 중 예상치 못한 시점에 발생한다. 이 경우에 Application에 대한 Debugging은 어떻게 접근하는 것이 좋을 까. 무엇보다도 문제 시점에 데이타를 보는 것이 빠른 접근이 아닐까 한다. Application은 일반적으로 logic에 따라 데이터의 흐름으로써 처리가 되며 그 결과를 보여주는 형태이다. 그러므로, 예상치 못한 시점의 예상치 못한 결과, Crash나 Hang이 발생했다면, 그 시점에 존재하는 연관된 데이타들은 Programmer가 예상한 시나리오에서의 올바른 데이터가 아니거나 고려하지 못한 흐름이라고 볼 수 있으며, 데이터와 logic을 보면서 verify 함으로써, logic의 수정이나 피치 못할 예외처리라든가 여러 가지 Application을 안정화하는 code를 추가할 수 있게 된다. 그러므로, Debugging은 전반적인 Logic을 보는 과정에 앞서서 문제 시점의 데이타를 분석하는 것이 우선이고 중요하다. 메모리 덤프는 Application이 Crash가 발생하거나 Hang이 발생하는 시점에 Debugging Tool을 이용하여 Application이 사용하는 메모리를 그대로 file Drop시킨 것이다. 그러므로, 그 시점에 register, heap memory나 assembly code등을 windbg.exe와 같은 tool을 이용하여 살펴볼 수 있는데, 메모리 덤프를 이용하여 Debugging하는 경우, 데이터 분석 시 가장 익숙하지 않고 어려운 부분은 Assembly code에 숨어 있는 데이터구조를 이해하는 것이 아닐까 한다. 예를 들어, array와 같은 Data Structure, linked list 그리고 Class와 같은 것들이다. 그러므로, 이들이 Memory Dump에서 어떻게 보여지고 이를 어떻게 해석해야 하는 지를 조금 언급해 볼까 한다. 먼저, 살펴볼 것은 array 구조에 대한 assembly code이다. mov eax, DWORD PTR [ebp-20h] mov ecx, DWORD PTR [ebp+eax*8-24h] ebp-20h로부터 load 된 eax 값은 array의 index 값이고, ebp-24h 는 array의 base pointer이다. 여기서 *8 연산을 하는 것은 array의 저장된 item의 size(예를 들어, long 형)를 eax 즉, index에 곱해줘서 원하는 위치의 array item을 구하기 위한 offset 연산이 된다. 그리고, 동일하지만, shift 연산을 사용하는 다음과 같은 경우도 존재한다. mov eax, DWORD PTR [ebp-20h] shl eax, 2 mov ecx, DWORD PTR [ebp+eax-24h] 이러한 pattern은 array 연산의 대표적인 형태이다. 다음은 Linked List 데이터 구조의 경우인데, 하나의 node는 Item과 Next node pointer를 갖고 있는 형태로 assembly code에서는 다음과 같이 처리된다. mov eax,dword ptr [ebp+8] mov ecx,dword ptr [eax] mov edx,dword ptr [ecx] cmp edx,dword ptr [ebp+0Ch] 보면, ebp+8은 current node pointer이다. 그러므로, current node pointer를 ecx로 load 하고, 다시 해당 address를 edx로 load 한 후에 이를 ebp+0ch 값과 비교하는 것을 봐서 edx에 load된 값은 node structure의 첫 번째 item을 얻어 온 것이다. if ((*n)->data == i) { /* … */ } 그리고, 연계하여, mov eax,dword ptr [ebp+8] mov ecx,dword ptr [eax] add ecx,4 mov dword ptr [ebp+8],ecx 이것은 current node pointer인 ecx에 +4를 하는 것으로 보아 첫 번째 item은 int 와 같은 data type일 가능성이 있고, 4만큼 offset 이동하여 node struct의 두 번째 item을 얻어오는 것을 알 수 있다. 이는 Linked list 구조상 Next Pointer가 되는 데, 이를 current node pointer로 mov 하는 것이므로, Next node로 이동하는 다음과 같은 code 이다. n = &(*n)->next; 이러한 pattern이 대표적인 Linked List 구조이다. 그리고, 다음에 언급할 구조는 class 구조이다.
High Level Language에서는 상위의 그림처럼 작성이 되지만, 메모리 layout은 좀 차이가 있다. 예를 들어, 상위의 C2 class의 경우는 아래와 같은 메모리 layout을 갖는 다. 0:000> dt rvsTest!C2 +0x000 __VFN_table : Ptr32 +0x004 b_m : Int4B +0x008 c_m : Int4B +0x00c c2_m : Int4B 보면, Virtual Function Table과 public 하게 inherited 된 fields가 hierarchical 하게 메모리를 점유하고 있다. 그리고, Virtual function Table의 실제 memory layout을 살펴보면 다음과 같다. 0:000> dt rvsTest!C2 0x00235e38 +0x000 __VFN_table : 0x002e7768 +0x004 b_m : 1 +0x008 c_m : 2 +0x00c c2_m : 3 0:000> dds 002e7768 002e7768 002e120d rvsTest!ILT+520(?b_vf1CUAEXXZ) 002e776c 002e11f9 rvsTest!ILT+500(?b_vf2CUAEXXZ) 002e7770 002e1073 rvsTest!ILT+110(?c_vf1C2UAEXXZ) 002e7774 00000000 002e7778 002e86d0 rvsTest!C::`RTTI Complete Object Locator' 002e777c 002e120d rvsTest!ILT+520(?b_vf1CUAEXXZ) 002e7780 002e11f9 rvsTest!ILT+500(?b_vf2CUAEXXZ) 002e7784 002e1217 rvsTest!ILT+530(?c_vf1CUAEXXZ) 002e7788 00000000 002e778c 002e86e8 rvsTest!B::`RTTI Complete Object Locator' 002e7790 002e11b8 rvsTest!ILT+435(?b_vf1BUAEXXZ) 002e7794 002e11a9 rvsTest!ILT+420(?b_vf2BUAEXXZ) … 그러므로, 이러한 구조상에서 Virtual Function Call이 이뤄지게 된다. 다음의 assembly code를 보면,
mov eax,dword ptr [ebp-14h] mov edx,dword ptr [eax] mov esi,esp mov ecx,dword ptr [ebp-14h] mov eax,dword ptr [edx+8] call eax 일반적인 Virtual Function Calling의 형태이다. Ebp-14는 Class Object를 가리키고 있으며, edx는 상위에서 언급한 것처럼, Virtual Function Table의 Pointer이다. 그러므로, edx+8 은 002e7768+8=002e7770 즉, rvsTest!ILT+110(?c_vf1C2UAEXXZ)를 가리킨다. 그러므로, 다음은 Virtual Function의 disassembly code가 된다. 0:000> uf 002e1073 rvsTest!C2::c_vf1 [c:\codes\examples\rvstest\rvstest\rvstest.cpp @ 101]: 101 002e1c30 55 push ebp 101 002e1c31 8bec mov ebp,esp 101 002e1c33 81eccc000000 sub esp,0CCh 101 002e1c39 53 push ebx 101 002e1c3a 56 push esi 101 002e1c3b 57 push edi 101 002e1c3c 51 push ecx 101 002e1c3d 8dbd34ffffff lea edi,[ebp-0CCh] 101 002e1c43 b933000000 mov ecx,33h 101 002e1c48 b8cccccccc mov eax,0CCCCCCCCh 101 002e1c4d f3ab rep stos dword ptr es:[edi] 101 002e1c4f 59 pop ecx 101 002e1c50 894df8 mov dword ptr [ebp-8],ecx 102 002e1c53 8bf4 mov esi,esp 102 002e1c55 680c782e00 push offset rvsTest!`string' (002e780c) 102 002e1c5a ff15e4b22e00 call dword ptr [rvsTest!_imp__printf (002eb2e4)] 102 002e1c60 83c404 add esp,4 102 002e1c63 3bf4 cmp esi,esp 102 002e1c65 e821f5ffff call rvsTest!ILT+390(__RTC_CheckEsp) (002e118b) 103 002e1c6a 5f pop edi 103 002e1c6b 5e pop esi 103 002e1c6c 5b pop ebx 103 002e1c6d 81c4cc000000 add esp,0CCh 103 002e1c73 3bec cmp ebp,esp 103 002e1c75 e811f5ffff call rvsTest!ILT+390(__RTC_CheckEsp) (002e118b) 103 002e1c7a 8be5 mov esp,ebp 103 002e1c7c 5d pop ebp 103 002e1c7d c3 ret rvsTest!ILT+110(?c_vf1C2UAEXXZ): 002e1073 e9b80b0000 jmp rvsTest!C2::c_vf1 (002e1c30)
|
카테고리
이글루링크
최근 등록된 덧글
그러세요
by 강세윤 at 12/15 오늘 많이 헤매다..알게 .. by youna at 12/14 글 잘 읽었습니다 . 전 .. by 위시 at 11/26 어렷다 by klhk at 11/09 dhjjgbem by kl at 11/09 17번부터 어떻게 접는지.. by tykim0131 at 10/28 ATL이나 MFC를 이용하.. by 김명신 at 09/24 복원되었군요.. 제 RSS.. by 강세윤 at 09/24 허걱, 하고 있는 것으로.. by 강세윤 at 09/15 RSS 주소 서비스는 안 .. by 정성태 at 09/15 이글루 파인더
| |||