[Reversing] 4. Windows Memory Layout

Wonder_Land🛕·2022년 8월 25일
0

[Reversing]

목록 보기
4/6
post-thumbnail

[Reference] : 위 글은 다음 내용을 제가 공부한 후, 인용∙참고∙정리하여 만들어진 게시글입니다.


  1. 서론
  2. 프로세스 메모리 구조
  3. Q&A
  4. 마치며

1. 서론

  • 메모리 레이아웃(Memory Layout)
    : 프로세스 가상 메모리(Virtual Memory)의 구성

프로그램을 실행하면 운영체제는 프로세스에게 사용 가능한 메모리 공간을 할당해 줍니다.

이 공간을 '가상 메모리(Virtual Mermoy)'라고 합니다.

운영체제는 프로그램의 정보를 참조하여, 프로그램에 저장된 데이터가 적절한 영역에 저장되게 합니다.

프로세스에게 할당한 가상 메모리 공간을 용도별로 구획하고, 프로세스가 사용하는 데이터를 적절한 구획에 저장합니다.
유사한 데이터를 모아놓기 때문에, 운영체제는 각 구획에 적절한 권한을 부여할 수 있으며, 개발자는 프로세스의 메모리를 더욱 직관적으로 이해할 수 있습니다.

소프트웨어 리버스 엔지니어링의 핵심은
⟪바이너리를 분석하여 바이너리의 동작을 이해하는 것⟫입니다.

하지만, 바이너리의 동작은 메모리와 굉장히 밀접한 관련이 있기 때문에,
바이너리의 동작을 자세히 이해하기 위해서는, 바이너리가 상호작용하는 메모리에 대한 이해가 필요합니다.


2. 프로세스 메모리 구조

1) 섹션

윈도우 PE 파일은 'PE헤더와 1개 이상의 섹션'으로 구성되어 있습니다.

  • 섹션
    : 유사한 용도로 사용되는 데이터가 모여있는 영역

예를 들어, ".text"섹션에는 PE의 코드가 적혀있고,
".data"에는 PE가 실행중에 참조하는 데이터가 적혀있습니다.

섹션에 대한 정보는 PE 헤더에 적혀있습니다.
PE 헤더에 저장되는 섹션과 관련된 데이터 중, 중요한 것은 다음과 같습니다.

  1. 섹션의 이름
  2. 섹션의 크기
  3. 섹션이 로드될 주소의 오프셋
  4. 섹션의 속성과 권한

윈도우는 PE를 실행할 때, 이 정보를 참조하여 PE의 각 섹션들을 가상 메모리의 적절한 세그먼트에 매핑합니다.

보통 ".text", ".data", ".rdata"섹션이 사용됩니다.

(1) .text

  • .text 섹션
    : 실행 가능한 기계 코드가 위치하는 영역

프로그램이 동작하기 위해서는 코드를 실행할 수 있어야 합니다.
따라서 이 세그먼트에는 읽기 권한과 실행 권한이 부여됩니다.

반면, 쓰기 권한이 있다면, 공격자가 악의적인 코드를 삽입할 수 있기 때문에,
대부분의 현대 운영체제에서는 쓰기 권한을 제거합니다.

int main() { ... }

위의 main함수가 컴파일 되면 어떤 기계 코드로 변환될 것입니다.
이 기계 코드가 코드 세그먼트에 위치하게 됩니다.

(2) .data

  • .data 섹션
    : 컴파일 시점에 값이 정해진 전역 변수들이 위치

CPU가 이 섹션의 데이터를 읽고 쓸 수 있어야 하므로,
읽기와 쓰기 권한이 부여됩니다.

(3) .rdata

  • .rdata 섹션
    : 컴파일 시점에 값이 정해진 전역 상수와 참조할 DLL 및 외부 함수들의 정보가 저장

CPU가 이 섹션의 데이터를 읽을 수 있어야 하므로,
읽기 권한이 부여됩니다.

const char data_rostr[] = "readonly_data";
char *str_ptr = "readonly";  // str_ptr은 .data, 문자열은 .rdata

2) 섹션이 아닌 메모리

윈도우의 가상 메모리 공간에는 섹션만 로드되는 것은 아닙니다.
프로그램 실행에 있어 필요한 '스택과 힙'도 같이 가상 메모리 공간에 로드됩니다.

(1) 스택(Stack)

윈도우 프로세스의 각 쓰레드( : 프로세스 내에서 실행되는 흐름의 단위)는 자신만의 스택 공간을 가지고 있습니다.

이 영역에는 보통 지역 변수나 함수의 리턴 주소가 저장됩니다.

이 영역은 자유롭게 읽고 쓸 수 있어야 하기 때문에 읽기 및 쓰기 권한이 부여됩니다.

스택에서는 "아래로 자란다"라는 표현을 사용하기도 하는데,
스택이 확장될 때, 기존 주소보다 낮은 주소로 확장되기 때문입니다.
(스택의 확장 방향 : 높은 주소값 → 낮은 주소값)

int main(){
	int var1 = 1;
    int var2 = 2;
    
    ...
}

위의 코드에서 사용된 지역변수 var1, var2가 스택에 저장됩니다.

(2) 힙(Heap)

힙은 프로그램이 여러 용도로 사용하기 위해 할당받는 공간으로, 모든 종류의 데이터가 저장될 수 있습니다.

스택에 비해서, 큰 데이터도 저장할 수 있으며 전역적으로 접근이 가능하도록 설계되었습니다.
또한, 동적으로 할당받는 점 역시 다릅니다.

보통은 데이터를 읽고 쓰기만 하기 때문에, 읽기 및 쓰기 권한이 부여되지만, 실행 권한을 가지는 경우도 있습니다.

int main(){
	int var3 = malloc(sizeof(*int));
	...
}

위의 코드에서, var3는 지역변수로 스택에 위치하며, malloc으로 할당된 힙 세그먼트의 주소를 가리키고 있습니다.


3. Q&A

-


4. 마치며

-

[Reference] : 위 글은 다음 내용을 제가 공부한 후, 인용∙참고∙정리하여 만들어진 게시글입니다.

profile
아무것도 모르는 컴공 학생의 Wonder_Land

0개의 댓글