Application Verifier를 이용하여 Heap Corruption(buffer overrun) 찾기
개발 과정에서 아래와 같은 유사한 실수가 자주 있습니다.
...
::GetSystemDirectory(buf, MAX_PATH);
...
이런 경우, 오류는 즉각적으로 보고되지 않으며 엉뚱한 위치에서 Crash가 발생하는 경우가 대다수 입니다.
그래서 정확한 오류 위치를 찾기가 생각보단 쉽지 않습니다.
그리고, 이런 경우 buffer overrun으로 인해 프로그램의 취약점에 포함되어, 해커의 공격대상이 되기도 합니다.
아래와 같은 샘플을 가지고 진행하겠습니다.
#include "stdafx.h" #include <WINDOWS.H> #include <CONIO.H> #include <TIME.H> #include <STDLIB.H> void heap_corrupt(IN LPTSTR lpszBuf) { _tprintf(TEXT("try to corrupt\r\n")); ::GetSystemDirectory(lpszBuf, MAX_PATH); _tprintf(TEXT("corruptted\r\n")); } int _tmain(int argc, _TCHAR* argv[]) { LPTSTR buf = NULL; buf = new TCHAR[10]; heap_corrupt(buf); int i = 0; srand(time(NULL)); _tprintf(TEXT("start\r\n")); for (i=0; i<100; i++) { LPBYTE p = new BYTE[rand() % 100 + 100]; LPBYTE p2 = new BYTE[rand() % 100 + 100]; _tprintf(TEXT("[%d] alloc\r\n"), i); delete [] p; delete [] p2; _tprintf(TEXT("[%d] free\r\n"), i); } _tprintf(TEXT("all done\r\n")); getche(); return 0; } |
위는 Source Code, Binary, 그리고 디버깅을 위한 pdb 파일이 포함되어 있습니다.
우선, Heap.exe를 실행하게 되면,
와 같이 오류가 발생하거나 혹은 경우에 따라 오류가 발생하지 않기도 합니다.
즉, 항상 문제가 재현되지 않기 때문에 개발자는 당황스럽기도 합니다.
개발자 입장에서는 Crash가 발생했기 때문에, windbg를 설치하여 해결하려고 할 것입니다.
일단,
"C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" -I |
그다음 Heap.exe를 실행하고, 만일 오류가 발생하게 된다면 windbg가 실행됩니다.
(만일 오류가 발생하지 않는 경우는 아래 내용은 해당되지 않습니다.)
windbg->File->Symbol File Path에
와 같이 하고, C:\corrupt에 heap.zip의 pbd 파일을 넣습니다.
그리고, command에,
0:000> .reload -i ********************************************************************* * Symbols can not be loaded because symbol path is not initialized. * * * * The Symbol Path can be set by: * * using the _NT_SYMBOL_PATH environment variable. * * using the -y <symbol_path> argument when starting the debugger. * * using .sympath and .sympath+ * ********************************************************************* |
그리고 통상적인 작업을 하면,
0:000> !analyze -v ... STACK_TEXT: WARNING: Stack unwind information not available. Following frames may be wrong. 0012ff2c 00402bf1 00390000 00000000 00000068 ntdll!wcsncpy+0x99f 0012ff4c 00401259 00000068 00310037 00000000 Heap!malloc+0x79 [f:\dd\vctools\crt_bld\self_x86\crt\src\malloc.c @ 163] 0012ff64 00401065 00000068 00310037 00350034 Heap!operator new+0x1f [f:\dd\vctools\crt_bld\self_x86\crt\src\new.cpp @ 59] 0012ff78 00401401 00000001 00393028 00393060 Heap!wmain+0x65 [e:\temp\work\heap\heap.cpp @ 35] 0012ffc0 7c817067 00310037 00350034 7ffd4000 Heap!__tmainCRTStartup+0xfa [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 266] 0012fff0 00000000 00401458 00000000 78746341 kernel32!RegisterWaitForInputIdle+0x49 ... |
윈도우 Web Symbol을 맞추는 일도 필요해 보입니다. 그래서,
앞선 symbol 설정을,
C:\corrupt;SRV*C:\websymbol*http://msdl.microsoft.com/download/symbols
와 같이 하여 다시 .reload -i 하면 다음과 같이 됩니다.
0:000> !analyze -v IMAGE_NAME: heap_corruption |
그래서 Application Verifier를 설치하고 진행하겠습니다. 자세한건 도움말이나 구굴링으로 확인하세요.
Application Verifier->File->Add Application
하고, Heap만 체크한뒤 Save를 합니다.
그리고, 다시 Heap.exe를 실행해 봅니다.
그럼 Application Verifier에 의해 강제 오류가 발생하게 되어, 무조건 WinDbg가 실행하게 됩니다. (포스트모텀으로 연결했다는 가정하에)
그럼 위 과정 처럼 .reload -i를 한 뒤, 통상적인 분석을 해보면 다음과 같이 보고됩니다.
0:000> !analyze -v FAULTING_SOURCE_CODE:
SYMBOL_NAME: Heap!wmain+25 FOLLOWUP_NAME: MachineOwner MODULE_NAME: Heap IMAGE_NAME: Heap.exe DEBUG_FLR_IMAGE_TIMESTAMP: 4fd1a3ac STACK_COMMAND: ~0s ; kb FAILURE_BUCKET_ID: STRING_DEREFERENCE_c0000005_Heap.exe!wmain BUCKET_ID: APPLICATION_FAULT_STRING_DEREFERENCE_INVALID_POINTER_WRITE_Heap!wmain+25 Followup: MachineOwner |
즉, Application Verifier로 인해 Heap을 Corrupt하는 위치를 알 수 있게 되었습니다.
경험삼아, 아래와 같은 경우 Application Verifier를 이용하면 효과를 볼 수 있습니다.
- Crash가 발생할 때도 있고, 안할 때도 있다.
- 문제의 제현 자체가 제약이 많다 (예를 들어, 특정 PC에서만 재현된다던지)
- Crash가 발생하나, !analyze -v한 위치가 매번 변경된다.
'프로그래밍 > Win32' 카테고리의 다른 글
실행가능한 DLL 제작 (편리한 DLL Test(DLL 테스트), DLL Debug(DLL 디버그), DLL Unit Test, 개발 방식 지원) (0) | 2013.04.29 |
---|---|
printf로 간단하게 디버깅하기 (0) | 2012.07.31 |
ATL의 A2W, W2A 버그를 수정한 손쉬운 String Encoding 함수 공유(smart pointer) (1) | 2012.06.01 |
"이 프로그램이 제대로 설치되지 않았을 수 있습니다." 대처 빌드 방법 (0) | 2011.11.24 |
VC9.0 + MFC + StaticLink 시, gdiplus.dll 오류 해결법 (0) | 2011.11.17 |