덤프 파일을 통한 사후 디버깅 실용 테크닉 NDC2012

17,982 views

Published on

Published in: Technology
2 Comments
140 Likes
Statistics
Notes
No Downloads
Views
Total views
17,982
On SlideShare
0
From Embeds
0
Number of Embeds
627
Actions
Shares
0
Downloads
506
Comments
2
Likes
140
Embeds 0
No embeds

No notes for slide

덤프 파일을 통한 사후 디버깅 실용 테크닉 NDC2012

  1. 1. 덤프 파일을 통한 사후 디버깅실용 테크닉김이선veblush@[nexon|gmail]
  2. 2. 버블파이터 BNB 카트라이더 프로토타입 에버플래닛 던전엔파이터 GTR프로그래머 리드 프로그래머 리드 프로그래머 리드 프로그래머 테크니컬 디렉터 프로그래머 게임 프로그래밍 11년차
  3. 3. 개발은 곧 디버깅배포전 배포후 디버깅디버깅
  4. 4. 개발은 곧 디버깅배포전 배포후 배포후 디버깅디버깅 디버깅
  5. 5. 도입
  6. 6. 덤프 파일특정 상황에서 프로세스의 상태 를디버깅을 목적으로 파일로 남긴 것
  7. 7. Exception System프로세스 상태 Thread 아니오 Module Full- Memory Dump? … 예
  8. 8. 6 KB4804 KB
  9. 9. 덤프 파일의 정보를 보기 >dat i A.dmp
  10. 10. Exception System Module MemoryTheadId: 1956 Processor/CPU Modules(0) addr: 0012fedc,Code: 80000003 Arch: 0 Name: Tests.exe size: 00000124Flags: 00000000 Level: 6 Base: 00400000 addr: 0040114f,Record: 00000000 Revision: 5894 Size: 00006000 size: 00000100Address: 004011cf VendorId: Intel CheckSum: 00006722 addr: 0040114f, Version: 00010676 Stamp: 4f926cc4 size: 00000100 Feature: bfebfbff CV_GUID: 244b5515- addr: 00501000, Thread Extended: 6d960e89 CV_AGE: 43 size: 00010000Thread(id:1956) OS CV_Path: Tests.pdb addr: 00520000, SCount: 0 Version: 6.1 Modules(1) size: 00021000 PClass: 32 Build: 7601 Name: ntdll.dll … Priority: 0 Platform: 2 Base: 777e0000 Stack: 1244892 CSD: SP1 Size: 0013c000 EIP: 004011cf CheckSum: 00141016 EBP: 0012ff40 Stamp: 4ec49b60Thread(id:2910) CV_GUID: 93d2cd7- … CV_AGE: 2 CV_Path: ntdll.pdb …
  11. 11. VS IDE 가온라인 디버깅처럼 보여줌
  12. 12. 미니덤프를 남기고 수집해서VS IDE 로 디버깅하는 시스템은 필수
  13. 13. 편하다!그런데?
  14. 14. 병원에서 디버깅하는 내용을 다룬 드라마
  15. 15. 까다로운 경우의 사후 디버깅을해결하기 위해 했던 작업 소개
  16. 16. 덤프 파일과 PDB 연결 여러 개의 덤프 파일 분석 콜스택 힙 메모리
  17. 17. 덤프 파일과 PDB 파일의 키
  18. 18. EXE K 컴파일러소스 링커 PDB K
  19. 19. MinidumpEXE DMP K K
  20. 20. PDB PathAge (UTF-8)
  21. 21. 덤프 파일에 맞는 PDB 파일 찾기
  22. 22. K KK
  23. 23. Symbol K K ServerM L L ? M M
  24. 24. 심볼 서버를 사용하고 있지 않다면 바로 도입하는 것을 추천!
  25. 25. 어? 잘 되잖아? 뭐가 문제?
  26. 26. 실행파일 보안 솔루션!Themida, ASProtect, …
  27. 27. K K
  28. 28. 보안 MinidumpEXE EXE DMP K K !
  29. 29. Name: Tests.exe Name: Tests.exeBase: 00400000 Base: 00400000Size: 00005000 Size: 00173000CheckSum: 0000fdf1 CheckSum: 000b1076Stamp: 4f936fe3 Stamp: 4f936fe3CV_GUID: 152589ac- CV_GUID:CV_AGE:CV_Path: 1 Tests.pdb 보안 Minidump CV_AGE: CV_Path: EXE EXE DMP K K !
  30. 30. 이를 해결하기 위해DMP 파일에 원본 EXE 키를 연결하자! EXE DMP K ! K
  31. 31. EXE EXE DMP K K ! 수집 K DMP dat DMP K !
  32. 32. DMP → EXE, PDB 연결을 만들어줌 >dat l -m A.exe A.dmp
  33. 33. ? EXE DMP K !수집된 DMP 가 어떤 EXE 랑 연결되는지?클라이언트 버전 or 빌드 타임을 사용!
  34. 34. EXE EXE DMP T K T K T !EXE T T’ L 수집EXE K T” M DMP dat DMP T K T !
  35. 35. 클라이언트 덤프 수집 단계에올바른 PDB 연결 단계를 꼭 넣자!
  36. 36. 덤프 파일과 PDB 연결여러 개의 덤프 파일 분석 콜스택 힙 메모리
  37. 37. 적합한 기준!
  38. 38. 게임 내용에 맞춰문제 시점의 맵, 스킬, 장비, …
  39. 39. 대부분 역할을 잘 해줌 그런데…
  40. 40. 그런데 외부 모듈이나절대 발생할 수 없는 로직에서 문제가 나타난다면?혹은 에러를 내는 양상이 매번 바뀐다면?
  41. 41. 클라이언트의 경우 실행 환경이 통제되지 않는데 H/W 결함 바이러스 악성유저 Driver 결함 악성코드
  42. 42. 외부 요인인지 아닌지잘 판단하는 것이 중요!
  43. 43. EIP 차트 OS CPU GPU
  44. 44. EIP 차트 OS CPU GPU
  45. 45. 환경 편재에 주목!외부 요인을 추정할 수 있다!
  46. 46. OS 윈도우 9X : OS + 드라이버 불안 OS Heap 차이, ?CPU CPU 자체 보다는 메인 보드인 경우가 더 많음GPU 그래픽 카드 드라이버!!!
  47. 47. 모듈 외부 프로그램에 의한 영향 메신저, 보안 솔루션 등의 DLL 이 게임 프로세스에 연결됨. 악성 프로그램 DLL 도 마찬가지
  48. 48. CASE STUDY[던전엔 파이터]
  49. 49. 2011 년 상반기Visual Studio 2003 → 2008 Migration
  50. 50. 2003 덤프, 클레임 재배포 아니요 2003 2008개발 배포 괜찮나? 2008 예 아싸!
  51. 51. VS2008 빌드 버전: 유저의 클레임“채널을 선택하면 클라이언트가 종료됩니다”
  52. 52. VS2008 빌드 버전: 덤프 리포트HeapAlloc, HeapFree 수행 중 크래시가 늘어남
  53. 53. HeapAlloc, HeapFree 중에 크래시가 나는 것은 십중팔구 힙 깨짐
  54. 54. 힙 깨짐에 중점을 두고코드 리뷰 + 트랩 코드 패치
  55. 55. 해당 문제를 유발 하는 코드가 없음!
  56. 56. 악성 프로그램이 문제의 원인!문제의 덤프 파일들로부터 모듈 편재 확인
  57. 57. 악성DLL 악성DLL 힙깨짐 크래시
  58. 58. 덤프 보고의 환경 편재를 잘 살펴서 외부 요인을 잡아내자!
  59. 59. 덤프 파일과 PDB 연결여러 개의 덤프 파일 분석 콜스택 힙 메모리
  60. 60. 콜스택은?쓰레드의 현재 함수 호출 상태를 보여줌
  61. 61. Visual Studio 는어떻게 콜스택을 보여줄까?
  62. 62. 코드 스택 ADDR VALUE DESC400h int Func(int x, int y) { 104h 10 a403h int a = x * y;40Bh return a; 108h 118h EBP411h } 10Ch 435h EIP 110h 2420h void Test() { 114h 5423h Func(2, 5); 118h 12Ch EBP435h } 11Ch 470h EIP
  63. 63. STACK … EBP EIP … EBP EIP … EBP EIP …
  64. 64. ADDR VALUE EIP:010E2E130020fa58 0020fa64 EBP:0020FA580020fa5c 010e2e290020fa60 004b2ff80020fa64 0020fa740020fa68 010e2e4d0020fa6c 000000050020fa70 004b2ff80020fa74 0020fa880020fa78 010e2e6d0020fa7c 000000020020fa80 00000005
  65. 65. ADDR VALUE EIP:010E2E130020fa58 0020fa64 EBP:0020FA580020fa5c 010e2e290020fa60 004b2ff80020fa64 0020fa740020fa68 010e2e4d0020fa6c 000000050020fa70 004b2ff80020fa74 0020fa880020fa78 010e2e6d0020fa7c 000000020020fa80 00000005
  66. 66. 콜스택 구성에 필요한 것: 스택 메모리, EBP, EIP그 중에 하나만이라도 깨지면?
  67. 67. ADDR VALUE0020fa58 0020fa64 EBP:0020FA5c0020fa5c 010e2e290020fa60 004b2ff80020fa64 0020fa740020fa68 010e2e4d0020fa6c 000000050020fa70 004b2ff80020fa74 0020fa880020fa78 010e2e6d0020fa7c 000000020020fa80 00000005
  68. 68. ADDR VALUE 0020fa58 0020fa64EBP:002BFE64 0020fa5c 010e2e29 0020fa60 004b2ff8 0020fa64 0020fa74 0020fa68 010e2e4d 0020fa6c 00000005 0020fa70 004b2ff8 0020fa74 0020fa88 0020fa78 010e2e6d 0020fa7c 00000002 0020fa80 00000005
  69. 69. ADDR VALUE 0020fa58 0020fa64EBP:002BFE64 0020fa5c 010e2e29 0020fa60 004b2ff8 0020fa64 0020fa74 0020fa68 010e2e4d 0020fa6c 00000005 0020fa70 004b2ff8 0020fa74 0020fa88 0020fa78 010e2e6d 0020fa7c 00000002 0020fa80 00000005
  70. 70. 보통의 콜 스택 재구성은스택, EBP 가 정상일 때만 동작!
  71. 71. 스택, EBP 깨졌을 수도 있을 때는 다른 방법을 사용해보자!
  72. 72. ADDR VALUE0020fa58 0020fa64 Func20020fa5c 010e2e29 1. 스택 메모리에서0020fa60 004b2ff8 코드 주소 추리기0020fa64 0020fa74 Func10020fa68 010e2e4d0020fa6c 000000050020fa70 004b2ff80020fa74 0020fa880020fa78 010e2e6d0020fa7c 00000002 Test40020fa80 00000005
  73. 73. ADDR VALUE0020fa58 0020fa640020fa5c 010e2e29 2. 스택 메모리에서0020fa60 004b2ff8 스택 주소 영역 추리기0020fa64 0020fa740020fa68 010e2e4d0020fa6c 000000050020fa70 004b2ff80020fa74 0020fa880020fa78 010e2e6d0020fa7c 000000020020fa80 00000005
  74. 74. ADDR VALUE0020fa58 0020fa640020fa5c 010e2e29 +Func2 3. 콜 스택 추정0020fa60 004b2ff80020fa64 0020fa740020fa68 010e2e4d +Func10020fa6c 000000050020fa70 004b2ff80020fa74 0020fa880020fa78 010e2e6d +Test40020fa7c 000000020020fa80 00000005
  75. 75. 예외 쓰레드 콜스택 강제 재구성 >dat c A.dmp
  76. 76. 함수 재구성에 프로그래머의 해석이 필요하지만 스택 파괴에도 최대한 정보를 제공!
  77. 77. <팁>함수 스택에 디버그 변수 저장하기
  78. 78. struct Item { int id; int count;};int GetCount(const vector<Item>& items) { int count = 0; for (i in items) { VERIFY(i->count > 0); count += i->count; } return count;}
  79. 79. int GetCount(const vector<Item>& items) { int count = 0; for (i in items) { int item_id = item.id; int item_count = item.count; VERIFY(i->count > 0); count += i->count; } return count;}
  80. 80. 그냥 Trace 쓰지 왜?간단히 덤프 파일로 볼 수 있다면 더 간편해서!재귀함수 등 콜 스택의 여러 변수를 봐야 한다!
  81. 81. #define DEBUG_VAR(T, var) volatile T& var = *(T*)_alloca(sizeof(T));
  82. 82. int GetCount(const vector<Item>& items) { DEBUG_VAR(int, item_id); DEBUG_VAR(int, item_count); int count = 0; for (i in items) { item_id = item.id; item_count = item.count; VERIFY(i->count > 0); count += i->count; } return count;}
  83. 83. DEBUG_VAR(int, item_id);DEBUG_VAR(int, item_count);
  84. 84. 스택 할당은 비용이 거의 없으므로 간편하게 써보자! (다만 스택 오버플로우는 조심)
  85. 85. 덤프 파일과 PDB 연결여러 개의 덤프 파일 분석 콜스택 힙 메모리
  86. 86. 덤프에 힙 메모리를 넣으면디버깅에 많은 도움을 줌
  87. 87. 몬스터class Monster : public Object{ int id; int ai_state; int more_over; virtual ~Monster();};
  88. 88. 사용void Move(Monster* m){ if (m->ai_state == 0) m->ai_state = 1; verify(Route(m));}
  89. 89. 일반 < 1MB힙포함 프로세스메모리 용량
  90. 90. 용량이 크지만 디버깅이 무척 편함개발버전 클라이언트, 서버, 툴은 적극 사용! 배포 클라이언트의 경우 선택적으로 사용
  91. 91. 풀 덤프만 있으면이제 이 버그는 제겁니다!
  92. 92. 사용void OnAttack(Monster* m, Player* p){ SetAttackTarget(m, p); log(“M:%d – P:%d”, m->id, p->id); verify(p->valid()); 로그} M:1500 – P:5 M:1901 – P:5
  93. 93. 모든 객체에 쉽게 접근할 수 없다. 콜스택 지역 변수에 남았거나, 전역변수 (싱글턴 등) 로부터!
  94. 94. 덤프 파일에 힙 메모리 내용이 다 있으니 어떻게 해볼 수 있지 않을까?
  95. 95. 1500 이 나오는 메모리 주소를 찾아 Watch 로 살펴보자! (Monster*)(0x043BD14-4)
  96. 96. 메모리를 다 뒤져서 전부 찾아서 Watch!
  97. 97. 덤프 메모리에서 32bit 1500 모두 찾기 >dat m –f i1500 A.dmp
  98. 98. 무식하지만 작동하는 방법! 좀 더 나아가 보자!
  99. 99. 잘못된 주소 올바른 주소
  100. 100. 메모리에 있는 객체를 찾아보자?
  101. 101. Object vftbl COL Type vftbl &LOC signature vftbl id &::~dtor offset dataai_state … cdOffset name[0]more_over pTypeDesc … … pClassDesc
  102. 102. 메모리에서 모든 객체를 찾아 vftbl 이 주소를 출력한다. 있는 객체 Monster 의vfptr: 0x4102c4 Monster* 타입?
  103. 103. 메모리의 모든 Monster 객체를 출력 >dat o –t Monster A.dmp
  104. 104. 찾은 Monster 객체에 대해 sizeof(T) 안에서 1500 숫자를 가지고 있는 객체만 출력 Monster 의vfptr: 0x4102c4
  105. 105. 메모리의 모든 Monster 객체 중32bit 1500 을 가지고 있는 것들 출력>dat o –t Monster –s 16 –f i1500 A.dmp
  106. 106. 힙 메모리에서 객체 찾기 응용
  107. 107. 플레이어class Player : public Object{ string name; int ip_addr; int cid; virtual ~Player();};
  108. 108. 문자열class string{ 길이가 15 int len; 이하면 여기에 char buf[16]; char* ptr; 16 이상이면}; 동적할당
  109. 109. 힙 메모리에서이름이 test_player_9000 인 Player 객체 찾기
  110. 110. 길이가 16 이니 string 이 문자열 포인터를 가리킴.먼저 문자열 주소를 찾자.문자열 주소 0x00391840 을 포함하고 있는 Player객체를 찾자.
  111. 111. 길이가 16 이니 string 이 문자열 포인터를 가리킴.먼저 문자열 주소를 찾자.문자열 주소 0x00391840 을 포함하고 있는 Player객체를 찾자.
  112. 112. 이제 모든 객체를 찾을 수 있어요! (vftbl 은 있어야 겠지만…)
  113. 113. 정리
  114. 114. 덤프는 프로그래머의 친구! 좀 더 많이 사용해보자!
  115. 115. 덤프 분석툴도틈틈이 만들어 보자! >dat
  116. 116. 감사합니다!
  117. 117. http://code.google.com/p/dump-analysis-tool/

×