작성
·
219
0
// 스택 프레임 [ 지역변수 ] a가 함수가 종료되면서 없어지는데 함수 반환을 지역변수 a의 주소값으로 하고 있다.
int* TestPtr() {
int a = 3;
return &a;
}
// TestWrong() 함수가 호출되면서 다시 한번 스택프레임이 쌓이는데 이때 그전에 사용되고 반납됐던, TestPtr() 스택프레임 부분이 재사용되게 되고,
// a[0] ~ a[99] 까지 100개의 int(4byte)가 스택프레임 [지역변수] 에 쌓이고 [매개변수]로 받은 ptr이 가리키는 값을 다시한번 0x12341234로 수정한다.
void TestWrong(int* ptr) {
int a[100] = {};
a[99] = 0xAAAAAAAA;
*ptr = 0x12341234;
}
int main() {
// TestPtr() 스택프레임의 지역변수 a의 주소를 리턴받고
int* ptr = TestPtr();
// TestPtr 호출이 종료되면서 스택프레임에 있는 a의 주소 값이 유효하지 않게 되는데, 엄밀히 말하면 메모리 입장에서는 사라지는게 아니고 스택프레임 관리 차원에서 esp를 땡겨주는것이기 때문에
// ptr에 담긴 값을 수정할 수 있다. ( 이 자체만으로도 치명적인 문제! 하지만 디버깅에 문제없이 작동된다. )
*ptr = 123;
TestWrong(ptr);
return 0;
}
제가 이해가 안가는 부분은
*ptr = 0x12341234;
가 디버깅 단계에서 오류가 나는 부분입니다.
TestPtr() 이 사용했던 스택프레임을 재사용하다 운이 나빠 ptr의 주소가 TestWrong() 스택프레임의 지역변수 a배열 마지막 a[99] 다음인 ( a[99] + 1 ) 에 있다고 하더라도
그 ptr을 수정하는게 TestWrong() 스택프레임과 관련이 없는거 아닌가요?
마치 main 함수 내에서 유효하지 않더라도
*ptr = 123;
을 수정했던것처럼요.
제가 놓치고 있는 부분이 있을까요?
계속 고민해도 갈피가 잡히질 않네요..
답변 1
1
오염된 메모리를 고치는 순간,
사실 그 이후로는 무슨 일이든 일어날 수 있으니
크래시가 나지 않는다고 문제 없다고 판단하면 안 됩니다.
강의 예제에서 *ptr = 123;은 문제 없었고 그 다음 *ptr = 0x123124;가 터졌지만,
거꾸로 되더라도 전혀 이상하지 않습니다.
스택 메모리리는 여전히 유효한 공간이라 메모리를 고쳐쓸 수 있지만,
하필 그 위치가 ebp, ret 주소같이 매우 중요하고 치명적인 데이터가 있던 장소라거나,
디버깅 모드에서 0xCCCCC 쓰레기값으로 채워넣어 오버플로우 여부를 탐지하고 있던 장소라거나,
아니면 다른 포인터(주소)를 저장하고 있는 민감한 장소였다거나,
한다면 그 이후 진행에서 당연히 오동작 할테니 프로그램이 뻗는 것이죠.
드디어 이해가 갔습니다!!!
감사합니다 :)
제가 착각하고 있었습니다.
이미 사라진 스택프레임에 있던 ptr을 수정하는것도 문제지만 수정했는데 그게 하필 새롭게 생긴 스택프레임의 오버플로우 여부를 탐지하고 있던 장소와 같이 중요한 장소였으면 디버그 차원에서 프로그램이 뻗게 되는거군요.
다시한번 감사합니다~!
속 시원하게 다음 강의로 가보겠습니다 :)