본문 바로가기

C++

buffer overflow 사례1

[1. 개요]

버퍼 오버플로우를 유발 할 수 있는 사례들을 정리한다.

 

포인터를 전달할 때, 실제 메모리는 해당 포인터 타입에 해당하는 크기만큼의 공간이 할당되어 있어야 한다.

아래와 같은 타입 캐스팅은 가급적 하지 않는 것이 좋다.

  • int value = 0x1234;
  • long long *ptr = reinterpret_cast<int*>(&value);

왜 그런가, ptr 을 대상으로 발생하는 연산은 ptr 이 가리키는 공간이 8byte 만큼 할당되어 있다고 판단하고

연산을 진행한다.

그러나, 실제 메모리 공간은 4바이트 이므로 할당된 메모리 공간을 넘어서는 문제가 발생할 수 있다.

 

아래 코드를 보면, func() 에는 변수 a 의 주소만 넘기는데, b 의 값이 변경되어 버린다.

#include <iostream>

void func(unsigned long *ptr)
{
        *ptr = 0x1234567887654321;
}

int main()
{
        unsigned int a = 0x1111;
        unsigned int b = 0x2222;

        std::cout << "a: 0x" << std::hex << a << std::endl;
        std::cout << "b: 0x" << std::hex << b << std::endl;


        func(reinterpret_cast<unsigned long*>(&a));

        std::cout << "a: 0x" << std::hex << a << std::endl;
        std::cout << "b: 0x" << std::hex << b << std::endl;

        std::cout << "addr(a): 0x" << std::hex << &a << std::endl;
        std::cout << "addr(b): 0x" << std::hex << &b << std::endl;

        return 0;
}

// output
// a: 0x1111
// b: 0x2222
// a: 0x87654321
// b: 0x12345678
// addr(a): 0x0x7fffa9210740
// addr(b): 0x0x7fffa9210744

 

여기서 변수 b 를 const 선언하면, 그 값이 바뀌지 않을 수 도 있다.

  • 반드시 바뀌지 않는다고 보장 할 수 없다.
  • 테스트 시에는 바뀌지 않았다.
    # 경우에 따라, 변수 b를 스택이 아닌 레지스터에 저장한다거나
    # 변수를 재배치하여 주소가 연속되지 않게 한다거나..
    # 결국, 작성자가 예측할 수 없으므로 어찌되었든 문제가 된다.
  • 그러나 이러한 코드자체가 undefined behavior 이므로, 권장하지 않는다.

정리하면,  포인터 형변환은 반드시 신중히해야 한다.

  • reinterpret_cast 의 사용을 자제하는 편이 좋아 보임
  • 포인터 변수를 선언하는 편이 더 좋아 보임. (컴파일 오류를 유발하도록 하여, 수정 할 수 있도록)

'C++' 카테고리의 다른 글

Segmentation fault 사례5  (0) 2025.06.24
Placement new  (0) 2025.05.28
wchar_t 사용에 관하여 [2]  (0) 2025.05.13
wchar_t 사용과 관련하여.  (0) 2025.05.12
std::bind  (0) 2025.04.28