[CSAPP 3장 완전 정복] 3.10 기계 수준 프로그램에서 제어와 데이터는 어떻게 결합될까?

2025. 4. 9. 15:43·크래프톤 정글/컴퓨터구조(CSAPP)

기계 수준 프로그램에서 제어와 데이터는 어떻게 결합될까?

이번 3.10절에서는 포인터의 정확한 이해부터 실제 해킹에 악용되는 버퍼 오버플로우, 그리고 이를 방어하기 위한 현대적인 기술에 이르기까지 기계 수준에서 제어와 데이터가 어떻게 결합되는지를 다룹니다.

 

 

포인터(Pointer)에 대한 올바른 이해

포인터는 많은 초보자에게 어려운 개념이지만, 기계 수준에서는 매우 기본적이고 중요한 역할을 하는데요. 아래 몇가지 특징들을 보면서 같이 살펴보겠습니다.

  • 포인터는 주소를 저장하는 변수이다.
  • C 언어의 포인터는 타입 정보를 가지고 있지만, 어셈블리 수준에서는 단순한 주소 값일 뿐이다.
  • * 연산자, & 연산자, 배열 인덱스 접근 등은 모두 주소 계산과 메모리 참조로 구현된다.
  • 함수 포인터처럼 코드의 주소를 참조하는 것도 가능하다.

이러한 포인터 연산은 어셈블리에서는 mov, leaq, load/store 형태로 나타납니다.

 

 

GDB 디버거를 활용한 실행 시점 분석

GDB는 기계 수준에서 프로그램의 실행 흐름을 살펴볼 수 있는 중요한 도구인데요. GDB의 몇 가지 특징을 살펴보면 다음과 같습니다.

  • breakpoint 설정으로 특정 지점에서 실행을 멈출 수 있다.
  • stepi / nexti로 어셈블리 단위에서 한 줄씩 실행할 수 있다.
  • register, memory, stack 상태를 직접 관찰할 수 있다.

이러한 기능은 함수 호출, 스택 프레임 확인, 포인터 값 추적에 매우 유용합니다.

 

 

버퍼 오버플로우(Buffer Overflow)와 보안 이슈

C 언어는 배열 범위 초과에 대한 검사(bound checking)를 하지 않습니다. 그 결과, 로컬 배열을 벗어나서 스택의 다른 영역을 덮어쓸 수 있는데, 이를 버퍼 오버플로우라고 합니다.

 

이를 예시 코드로 보면 다음과 같습니다.

void echo() {
    char buf[8];
    gets(buf);   // 위험한 함수
    puts(buf);
}

이 경우 8바이트 이상의 문자열을 입력하면, buf 다음에 있는 리턴 주소(return address)를 덮어쓸 수 있습니다. 이렇게 조작된 리턴 주소는 공격자가 삽입한 exploit(악성) 코드를 실행하게 만들 수 있으며, 실제로 많은 해킹 기술들이 이 방법을 이용합니다.

 

 

버퍼 오버플로우에 대한 방어 기법들

그래서 현대 운영체제와 컴파일러는 다음과 같은 기법들을 통해 버퍼 오버플로우 공격을 막으려고 합니다.

Stack Randomization (스택 랜덤화)

프로그램 실행 시마다 스택의 시작 주소를 무작위로 변경해, 공격자가 정확한 주소를 예측하지 못하게 하는 보안 기법입니다. 이는 전체 주소 공간 배치를 무작위화하는 ASLR(Address Space Layout Randomization) 기법의 일부입니다.

Stack Canary (스택 손상 검출)

버퍼와 리턴 주소 사이에 무작위로 생성된 특수 값(canary)을 삽입하고, 함수가 리턴하기 직전에 이 값이 변조되었는지 검사합니다. 만약 값이 달라졌다면 버퍼 오버플로우 공격을 탐지한 것으로 간주하고, 프로그램은 즉시 종료됩니다.

NX Bit (Non-eXecutable Stack, 실행 코드 영역 제한)

스택이 위치한 메모리 페이지에 실행 권한을 제거(NX: No eXecute)함으로써, 그 영역에 있는 데이터가 기계어 코드로 실행되는 것을 차단합니다. 이로 인해 공격자가 스택에 exploit 코드를 심더라도 CPU가 실행 자체를 거부하게 됩니다.

 

 

가변 크기 스택 프레임(Variable-Size Stack Frames)

지금까지 본 함수들은 대부분 스택 프레임의 크기가 고정되어 있었는데요. 일부 함수들은 실행 시점에 크기를 동적으로 결정해야 하는 경우가 있습니다.

long vframe(long n, long idx, long *q) {
    long i;
    long *p[n];   // 실행 시 결정되는 크기
    ...
}

이 경우 컴파일러는 정적인 오프셋 계산이 불가능하기 때문에, 기준 포인터 %rbp를 고정시켜 참조 기준으로 삼고, 변수 크기 할당은 %rsp를 이용해 조절합니다.

 

이러한 구조는 alloca 함수, 또는 변수 길이 배열(VLA)에서도 자주 등장합니다.

 

 

마치면서

이번 절에서는 C의 제어 구조와 데이터 구조가 기계 수준에서 어떻게 긴밀하게 엮여 있는지를 살펴봤습니다. 포인터, 디버거, 공격 기법, 방어 전략, 가변 크기 스택 프레임까지 이어지는 이 흐름은 실제 시스템 프로그래밍, 보안, 디버깅의 중요한 기반이 됩니다.

 

이제 다음 절에서는 부동소수점 연산이 기계 수준에서 어떻게 처리되는지를 이어서 살펴보겠습니다.

저작자표시 비영리 변경금지 (새창열림)

'크래프톤 정글 > 컴퓨터구조(CSAPP)' 카테고리의 다른 글

[CSAPP 7장 완전 정복] 7.1~7.2 컴파일러 드라이버와 정적 링킹  (0) 2025.04.17
[CSAPP 3장 완전 정복] 3.11 부동소수점 연산은 어떻게 이루어질까?  (0) 2025.04.09
[CSAPP 3장 완전 정복] 3.9 구조체는 메모리에서 어떻게 저장될까?  (0) 2025.04.08
[CSAPP 3장 완전 정복] 3.6 – 조건문, 반복문, 분기 흐름을 어셈블리로 해석해보자  (0) 2025.04.08
[CSAPP 3장 완전 정복] 3.8.5 동적 배열(VLA), 주소 계산은 어떻게 달라질까?  (0) 2025.04.08
'크래프톤 정글/컴퓨터구조(CSAPP)' 카테고리의 다른 글
  • [CSAPP 7장 완전 정복] 7.1~7.2 컴파일러 드라이버와 정적 링킹
  • [CSAPP 3장 완전 정복] 3.11 부동소수점 연산은 어떻게 이루어질까?
  • [CSAPP 3장 완전 정복] 3.9 구조체는 메모리에서 어떻게 저장될까?
  • [CSAPP 3장 완전 정복] 3.6 – 조건문, 반복문, 분기 흐름을 어셈블리로 해석해보자
그냥사람_
그냥사람_
IT 관련 포스팅을 합니다. 크래프톤 정글 8기 정경호
  • 그냥사람_
    그냥코딩
    그냥사람_
  • 전체
    오늘
    어제
    • 글 전체보기
      • 크래프톤 정글
        • 로드 투 정글(입학시험)
        • CS기초(키워드, 개념정리)
        • 컴퓨터구조(CSAPP)
        • Code 정글(C언어)
        • Equipped in 정글(나만무)
        • 마이 정글(WIL, 에세이)
      • 자료구조&알고리즘
        • 자료구조
        • 알고리즘
      • 일상
  • 블로그 메뉴

    • 홈
  • 링크

    • Github
  • hELLO· Designed By정상우.v4.10.3
그냥사람_
[CSAPP 3장 완전 정복] 3.10 기계 수준 프로그램에서 제어와 데이터는 어떻게 결합될까?
상단으로

티스토리툴바