string 메모리 구조


/*nothing*/
#include <string>
#include <iostream>

using namespace std;

int main() {
    string* test = new string();
    getline(cin, *test);
    return 0;
}

코드는 이렇게 짜놓고 대충 메모리 구조만 봤다.

이 상태에서 처음엔 값을 0x10이하의 길이로 주고 힙을 한 번 봤음.
(input : ipwnipwn\n)

pwndbg> x/24gx 0x613c10
0x613c10:   0x0000000000000000  0x0000000000000031
0x613c20:   0x0000000000613c30  0x0000000000000008
0x613c30:   0x6e7770696e777069  0x0000000000000000
0x613c40:   0x0000000000000000  0x0000000000000411
0x613c50:   0x6e7770696e777069  0x000000000000000a
0x613c60:   0x0000000000000000  0x0000000000000000
0x613c70:   0x0000000000000000  0x0000000000000000
0x613c80:   0x0000000000000000  0x0000000000000000
0x613c90:   0x0000000000000000  0x0000000000000000
0x613ca0:   0x0000000000000000  0x0000000000000000
0x613cb0:   0x0000000000000000  0x0000000000000000
0x613cc0:   0x0000000000000000  0x0000000000000000

이것만 봐도 많은 걸 알 수 있음

/*nothing*/
struct string {
    char *str;
    __int64 size;
    char buf[0x10];
}

대충 이런 구조로 이뤄져 있음. (객체의 메모리 구조를 따라서 struct로 표현한 것)
그리고 strbuf의 주소를 가리킨다는 것도 알 수 있음.

또 버퍼링 하기 위해서 입력받은 값도 힙 할당해서 거기에 받는다는 것도 알 수 있음. (뒤에 이어붙여진 힙을 보면 알 수 있다.)

이제 0x10보다 더 긴 값을 넣어줘보겠음.

당연히 원래 제 위치(buf)에 0x10보다 긴 값을 넣으면 bof가 발생하니까 그렇게 구현하진 않겠지?

(input : AAAAAAAAAAAAAAAAAAAAAAA...) 대충 때려박음

갑자기 왜 md 문법으로 메모리 보여주다가 사진을 쓰냐면 parseheap 기능 땜에 글자가 안 이쁘게 짤려서 그렇다.

여튼 parseheap 기능으로 힙을 보면 벌써부터 힙이 더럽다. 그 말은 즉 이래저래 여러 작업들을 거친다는 걸 알 수 있음.

이건 getline 함수 내부 구현을 봐야하는 거라 귀찮으므로 패스. 나중에 보자.

보면 size는 입력받은 크기만큼 제대로 변경 되어있는 걸 알 수 있고, str은 입력받은 값이 복사된 그 주소가 박힌다.

그리고 buf + 8쪽을 보면 일단 buf에 입력값을 쓰는 것 같긴 한데, 일련의 작업을 거쳐서 buf쪽에만 값을 어떤 값으로 초기화 해주는 것 같다.

결론


/*nothing*/
struct string {
    char *str;
    __int64 size;
    union{
        something...;
        char buf[0x10];
    }
}

위의 형태로 구현되어 있는듯~!