[WinDbg] Stack Overrun

/GS 플래그가 지정되었을때 함수 호출부와 함수 끝부분에서 쿠키값을 비교.
비교결과 틀리게 되면 해당 함수부의 지역변수의 영역을 넘어섰음을 의미한다.

따라서 특정 함수의 마지막부분을 가리키면서 해당 오류코드를 뱉어낸다면
함수 부분에서 지역변수를 넘어설 수 있는 지점을 하나씩 주석처리해 가면서 찾는다.
좋은 습관은 방어코딩이다.

나의 경우는 다음과 같은 것이었다.
filepath[512];
wcscpy( filepath, objectName.Buffer, objectName.Length / 2 ); <-- objectName.Length/2가 항상 512보다 작다는 것을 보장할 수 있나? 보장할 수 없기 때문에 최악의 경우 넘어서지 않도록 조치를 해줘야 한다. wcscpy_s류 같은 것들을 쓰자

gflags.exe를 이용한 디버깅 방법
 
일단 OS한테 특정 process에 대해서 user stack trace을 설정해 줘야 한다. 두가지 방법이 있는데
첫째는) gflags.exe를 이용하는 거고
둘째는) 커맨드 창에서 gflags.exe /i TestProgram.exe +ust 입력

결국, gflags.exe가 위의 명령의 결과로 다음의 레지스트리에 키값을 생성해 준다.
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution
키값 TestProgram.exe
GlobalFlag RGB_SZ 0x1000

위처럼 OS flag를 설정한 후에 process 를 시작해야 하는 거고
이후에 windbg를 기동한 후에 해당 process 를 attach 한다.

테스트 프로그램1) Heap Block을 넘어선 Free
---------------------------------------
char* p1 = (char*)malloc( 0x10 );
char* p2 = (char*)malloc( 0x20 );

sprintf( p1, "%s", "0123456789ABCDE0123456789ABCDE" );
OutputDebugStringA( p1 );

SAFE_FREE(p1);
---------------------------------------
위와 같이 되어 있는 상태에서 
gflags.exe 설정없이 Windbg로 실행하고 나면 windbg는 명령창에 다음을 출력해 준다.

Heap block at 00B35918 modified at 00B35930 past requested size of 10

Heap block의 처음 8바이트는 힙 메타데이터이고(00B35918)
그 이후부터가 우리한테 할당된 부분이기 때문에 00B35920부터가 우리가 볼수 있는 영역이다. 그리고 명령에서 0x10바이트를 할당했기 때문에 00B35930-1까지가 접근할 수 있는 영역이다.
위에서 그런 내용을 표시해 주고 있는 거다.
 (WINDBG를 attach해서 실행하는 것 만으로도 어느정도는 보여주고 있다)
00b35918  86 45 13 67 62 f0 00 18-30 31 32 33 34 35 36 37  .E.gb...01234567
00b35928  38 39 41 42 43 44 45 30-31 32 33 34 35 36 37 38  89ABCDE012345678
00b35938  39 41 42 43 44 45

테스트 프로그램2) Stack Overrun / Heap Overrun
---------------------------------------

WCHAR* pw = L"012345678901234567890123456789";
wprintf(L"Press any key to start\n");
_getch();
HelperFunction(pw); <- Stack Overrun
DupString(pw); <- 

VOID HelperFunction(WCHAR* psz)
{
WCHAR pszCopy[30];
wcscpy(pszCopy, psz);
OutputDebugStringW(pszCopy);
}
BOOL DupString(WCHAR* psz)
{
    BOOL bRet=FALSE;
    
    if(psz!=NULL)
    {
        DWORD dwBytes = 10 * sizeof(WCHAR);
        pszCopy = (WCHAR*) HeapAlloc(GetProcessHeap(), 0, dwBytes);
        if(pszCopy)
        {
            wcscpy(pszCopy, psz);
            wprintf(L"Copy of string: %s", pszCopy);
            HeapFree(GetProcessHeap(), 0, pszCopy);
            bRet=TRUE;
        }
    }
    return bRet;
}
---------------------------------------
마찬가지로 위와 같이 되어 있는 상태에서 Windbg로 실행하기만 하면 아래와 같은 정보를 준다. HelperFunction()을 호출하는 경우는 아래 (Stack 상의 유효 범위를 오버해 버린 경우)
STATUS_STACK_BUFFER_OVERRUN encountered

DupString()을 호출하는 경우은 아래( Heap 상의 유효 범위를 오버해 버린 경우)

Heap block at 004D36E0 modified at 004D36FC past requested size of 14
총 2바이트짜리 10개니깐, 0x14 바이트가 유효 범위이다.
우리가 볼수 있는 영역은 004D36E8부터 이고 004D36E8+0x14-1(004D36FB) 까지이다.
Windbg가 친절하게도 004D36FC를 넘었다고 해주고 있고, 요청된 사이즈도 0x14바이트라는 것을 알려주고 있다.

여기까지는 명시적으로 Stack과 Heap에 대해서 overrun 혹은 free시 Windbg가 영리하게 detect를 해줌을 확인할 수가 있다

댓글

이 블로그의 인기 게시물

[WinAPI] 모달리스 다이얼로그 설명

[WinDbg] Debugging a stack overflow

[WinDbg] first-chance, second-chance Exception