StackFrame구성 - Stack Overflow
CallStack에 대한 이해를 돕고자 간단한 Quiz로 포스팅을 시작하겠습니다.
아래 와 같은 코드가 있습니다.
void Dummy() { printf("In Dummy Function()\n"); exit(0); } void SomFunction() { BYTE Buf[4]; printf("In SomFunction()\n"); return ; } int wmain(int argc, _TCHAR* argv[]) { printf("Before call SomFunction()\n"); SomFunction(); printf("After call SomFunction()\n"); return 0; } |
asm 코드를 쓰지 않고 SomFunction()을 수정하여 아래와 같은 결과를 출력한 후, 프로그램이 종료되도록 수정할 수 있을까요?
자. 감이 오지 않는 분들은 아래의 글을 먼저 읽고 오시기 바랍니다.
[디버깅을 위한 기초지식 #3] CallStack - 프로시저 호출에 따른 스택의 구성
이제 어느 정도 방향을 잡으셨나요?
아래와 같은 방법을 사용하면 위의 문제를 해결할 수 있을 것 같습니다.
1. Return Address가 저장되어 있는 Stack상의 Address를 구한다.
A. asm 코드를 사용하지 않으려면, 해당 주소를 구하기 위해 로컬변수 Buf의 address를 통해 구해야 할 것 같습니다.
2. 1에서 구한 Address에 Dummy() 함수의 Address를 Overwrite하게 되면, SomeFunction이 모든 처리를 마치고 리턴할 때 Dummy()가 실행되게 됩니다..
생각보다 복잡하지는 않군요.
그럼 한단계씩 따라가 보겠습니다.
1. SomeFunction이 복귀할 ReturnAddress가 저장된 Stack상의 주소 구하기
A. 스택 구성에 대한 링크된 포스트의 그림에 따르면 첫번째 로컬 변수의 위치는 ebp-0x4이므로, szBuf의 주소+0x4(szBuf사이즈)는 ebp의 주소가 됩니다.
B. Rerturn Address의 주소는 ebp+0x4이므로, [ Buf+0x4/*ebp*/+4/*ebp+4*/ ]로 계산이 되겠습니다.
void SomFunction() { BYTE Buf[8]; DWORD *pDw = (DWORD *)(Buf+0x8/*ebp*/+4/*ebp+4*/); *pDw = (DWORD)Dummy; printf("In SomFunction()\n"); return ; } |
2. 그럼 이제 구해진 주소에 Dummy()함수의 주소를 write해주기만 하면 되겠군요
*pDw = (DWORD)Dummy; |
혹시 위의 코드를 기반으로 혹은 코드를 작성해서 따라해 보신분…?
머야? 안돼잖아~ 하신분도 있으리라 생각됩니다.
저도 테스트를 하다 보니 CallStack내에서의 첫번째 로컬 변수의 주소가 항상 ebp – 0x4의 주소에 위치하지는 않더군요.
위의 테스트 코드는 아래의 환경하에서 정상 동작했습니다.
n VC++ 2008, Release모드, optimize off
n Optimize(최적화)옵션을 켜게 되면, SomFunction()함수의 코드가 wmain()함수 안에 삽입되어 버리거나, stack frame이 생략되는 등 실제 작성된 코드와는 많은 부분이 달라질 수 있습니다.
실제로 아래의 코드는 [ release mode: 최적화-속도 최대화 ]를 설정하여 컴파일한 코드로 SomFunction()의 코드가 wmain()함수 안쪽에 박혀(?)있습니다.
n 또한 링크된 포스트의 그림에서 설명한 대로라면 SomeFunction()안의 szBuf변수의 사이즈를 8로 잡을 경우, 첫 번째 로컬변수의 주소가 ebp-0x8로 할당될것으로 생각했으나, 실제로는 ebp-0xc위치로 할당되었습니다.(어떠한 다른 규칙이 있는 것인지 제가 잘못 이해한것인지? 답을 아시는 분은 좀 알려주세요~)
별 활용성은 없는 코드이 겠으나, 위의 내용을 완벽히 이해하시면 CallStack BackTrace라던지 함수 호출 흐름 분석에 꽤 도움이 되지 않을까 생각합니다.
'Windows Programming > 디버깅' 카테고리의 다른 글
Windbg 콘솔 출력 내용 파일로 저장 (0) | 2018.10.25 |
---|---|
VS2008 & VMWare7 원격디버깅 (0) | 2011.09.06 |
[디버깅을 위한 기초지식 #4] Calling Convention (0) | 2011.07.18 |
[디버깅을 위한 기초지식 #3] CallStack - 프로시저 호출에 따른 스택의 구성 (0) | 2011.07.18 |
[디버깅을 위한 기초지식 #2] 8086 명령어 (0) | 2011.07.18 |