PE 파일 내부에는 가상 주소로 매핑하기 위한 Base 주소를 저장해 두는 부분이 있다. 이 부분은 IMAGE_OPTIONAL_HEADER 구초제의 ImageBase 필드에 지정되어 있는데, NT일 경우 EXE는 디폴트로 0x04000000번지에 이미지의 시작부인 "MZ~"를 로드한다. 시작 주소를 알았으므로 이제 RVA + ImageBase를 해 주면 VA를 구할 수 있다.

 거창하게 식으로 나타내면

VA = RVA + ImageBase

쯤 되겠다.

 이는 메모리에 매핑되는 가상 주소이며 실제 메모리의 주소는 아니다. 이렇게 매핑되는 메모리를 '가상 주소 공간(Virtual Address Space)'이라고 부르며,  한 프로세스당 32비트 시스템에서 4GB, 64비트 시스템에서는 16EB의 가상 주소 공간을 가지게 된다. 그리고 이렇게 매핑된 가상 메모리를 실제 물리적인 기억 장치와 연결시켜 주는 것이 가상 메모리 관리자(Virtual Memory Manager)이다. 줄여서 VMM이라고 부르는데, 여기서 물리적인 기억 장치라 함은 휘발성 메모리인 RAM 뿐만 아니라 하드 디스크의 특정 파일, 디폴트로 논리적 디스크의 루트에 존재하는 PageFile.sys를 포함한다.


 페이징 파일과 RAM, VAS는 VMM에 의해 관리되면서 각각의 프로세스에게는 독립적인 4GB(32비트 기준)의 선형 주소 공간을 가진 것처럼 착각하게 만든다. 하지만 이는 사실 가상의 주소일 뿐으로, 프로세스에 속한 스레드가 가상 주소 공간 내의 특정 번지에 액세스할 경우 VMM은 해당 번지의 페이징 파일과 그 주소를 매핑시켜 준다. 따라서 특정 가상 공간에 읽거나 쓰는 행위는 결국 해당 페이징 파일의 특정 페이지에 동일한 행위를 하는 것이 된다.


결국 매핑이라 함은 가상 주소 공간과 페이징 파일 사이의 페이지 단위의 대응을 의미한다. 이렇게 매핑된 페이지는 접근 가능한 상태가 되며, 이런 페이지를 COMMIT된 페이지라고 한다.

이런 매핑은 굳이 PageFile.sys 파일이 아닌 일반 파일에도 적용이 가능하다.

 특정 파일을 메모리에 매핑시켜 PageFile.sys의 역할을 대신하는 경우를 메모리에 매핑된 파일(MMF : Memory Mapped File)이라고 한다. 이렇게 메모리에 특정 파일을 매핑하기 위해서 API를 주로 사용하는데, 우선 CreateFile 함수를 이용해 파일을 열고, 해당 핸들을 인자로 CreateFileMapping 함수를 통해 MMF 커널 객체의 핸들을 반환받는다. 마지막으로 MapViewOfFile 함수를 이용해 리턴 값으로 해당 파일과 매핑된 메모리 번지를 가져올 수 있다. 이렇게 가져온 번지를 이용해 읽거나 쓰는 내용은 모두 VMM에 의해 실제 파일과 연동이 된다.

 이렇게 매핑을 할 때 디폴트로 사용되는 MMF는 PageFile.sys이지만, 로더는 EXE나 DLL을 로드할 때 PageFile.sys를 사용하지 않는다. PE파일 자체를 MMF로 사용함으로써 로드 시간을 절약하는 것이다. 물론 여기에서는 가상 공간 상의 PE에 무엇을 쓴다는 것이 바로 PE 파일 자체에 대한 변경을 의미하지는 않는다. 메모리의 페이지 속성에 따라 즉각 반영되는 경우도 있고 그렇지 않은 경우도 있는데, 메모리에 매핑된 PE는 "실행 가능" 속성을 지니기 때문에 "Copy-On-Write"라는 매커니즘을 통해 디스크 상의 해당 PE로의 즉각적인 반영은 이루어지지 않는다.


'Knowledge' 카테고리의 다른 글

마이크로/모놀리식 커널 (Micro/Monolithic Kernel)  (0) 2016.04.02
libcapstone-dev 설치 방법  (0) 2016.03.12
PE 파일과 Memory-Mapped File  (0) 2015.12.24
Wireshark로 인증서 추출하기  (0) 2015.11.02
제한적 ASLR 해제 방법  (0) 2015.10.22
RTL Chaining의 원리  (0) 2015.10.18
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요