이번에는 짧은 글을 작성해보려 합니다.
그냥 제가 리버싱이나 포너블 공부를 하다가 거의 안그렇지만 가끔씩 헷갈리는거라서...
익숙해지면 뭐 안 그러겠죠 ㅋㅋ...
프로그램에서 메모리 구조를 따질 때 보통 위의 그림과 같이 구성됩니다.
뭐 다른 방법도 있겠지만 보오통은 이렇습니다.
가장 낮은 주소 0x00000000 에서 시작해서 곧바로 코드가 나오지 않을 가능성이 많지만,
일단 설명하기로는 프로그램 코드, 전역변수와 정적변수, 동적할당, 지역변수와 매개변수 순서로 메모리에 배치되게 됩니다.
프로그램 코드와 전역변수, 정적변수는 컴파일 시에 메모리에 배치되어 공간이 할당되어 있고,
힙 영역, 스택 영역은 프로그램 구동을 하면서 메모리에 배치되기 때문에 미리 공간이 할당되어있지는 않습니다.
여기서 다른건 다 치워두고 스택만 살펴볼게요...
스택은 메모리의 가장 아래쪽(가장 높은 주소)부터 쌓이게 됩니다. 힙 영역이랑 겹칠 가능성을 줄이기 위해서라고 생각되네요.
0xFFFFFFFF에서 스택을 만들 때마다 ebp와 esp를 새로 설정해주어 사용할 부분을 설정해주게 되는데요...
여기서 알아야할점은 여러 스택이 쌓여있을 때 맨 위에 스택에 있는 메모리만 사용할 수 있는 것입니다. 자료구조에서와 다르게 모양만 흉내낸것이라 할 수 있죠. (말하려던 내용이랑 상관이 없지만 알면 좋을 것 같아서...)
스택은 가장 가장 아래(가장 높은 주소)부터 쌓이기 시작하지만 데이터를 입력할 때에는 리틀 엔디안 방식으로 스택의 esp를 기준으로 낮은 주소에서 높은 주소로 순차적으로 입력되게 됩니다.
이 부분이 제가 헷갈렸던 부분이에요 ㅠㅜ...
스택이 구성될 때에는 아래부터 쌓이지만 스택 내에서 데이터를 입력할 때에는 esp를 기준으로 위에서부터 쌓인다는 점이죠...
이게 왜 헷갈릴까 생각하실 수도 있는데, 스택이 쌓이는 위치와 리틀 엔디안과 데이터 입력 방식이 환상의 콜라보를 이뤄서 저에겐 헷갈렸습니다. ㅋㅅㅋ...
데이터가 입력되는 방식은 제가 알기에는 다음과 같습니다.
1. 함수가 호출되면 Stack을 생성하기 위해 esp와 ebp의 값을 새로이 조정한다.
2. 변수가 선언되었을 때, 선언된 변수의 크기에 맞추어 esp의 주소값을 다시 설정하여 ebp와의 거리를 벌린다.
3. 변수에 데이터를 입력할 때 esp를 기준으로 위치를 잡아서 입력한다.
와 같은 방식이 아닐까요.... 제가 지금까지 공부할 때까지는 이렇게 생각해도 문제는 없었던거 같습니다.
저 방식에서 제가 또 헷갈렸던 점은 변수 선언 순서에 따라서 스택에 입력되는 위치가 달라진다는 점입니다.
변수가 선언될 때마다 esp의 값을 새로이 조정하여 ebp와의 거리를 벌리기 때문에 먼저 선언된 변수는 나중에 선언된 변수와 비교했을 때 상대적으로 아래(높은 주소)에 쌓이게 됩니다. 따라서 오버플로우에 대한 대비책이 없다고 가정했을 때, 나중에 선언된 변수의 데이터 입력을 통해 먼저 선언된 변수나 그 전에 생성되었던 스택의 변수에도 접근할 수 있습니다.
그냥 머릿속에 있는 말을 꺼내다보니까 횡성수설하고 아무 말 한거같은데... 나중에 한번 더 보고 좀 고쳐보도록 하겠습니다 ㅠㅜ
'Hacking-기초 > 알쓸신잡_해킹' 카테고리의 다른 글
Assembly 문법? 조금 정리 (0) | 2020.09.02 |
---|---|
어셈블리 operand 사용하는 방식 정리 (0) | 2020.09.02 |
리틀 엔디안, 빅 엔디안 (0) | 2020.08.31 |