본문 바로가기
분석의 묘미

PE File Format에 대해 알아보기

by Sweeny 2008. 7. 28.
반응형
※ 흐릿한 그림은 클릭(Click)하면 원본크기로 나옵니다.


PE파일을 언급하는 이유는 추후 있을 버퍼 오버플로우 기법과 바이러스 제작 강좌에 응용력을 키울수 있도록 하게끔 하는 것이 그 목적입니다. 스펙이라는 특성상 매우 지루할 내용이긴 하나 잘 이해만 해두신다면 시스템 프로그래머에 한발 더 앞서가는 일이 아닐까 합니다.

본론으로 넘어가서...

PE 파일 형식(Portable Exucutable File Format)이란?

파일에 담겨 다른 곳에 옮겨져도 실행될 수 있도록 규정한 형식이라는 뜻입니다.


PE 형식을 제대로 알지 못하면 윈도우 내부를 살펴보는데 많은 제약이 따르고 PE 형식은 단시간내에 마스터할 수 있는 내용은 아니기에 우선 형식이 어떤 것인지 프로그램 소스코드를 제공하며 유추해보도록 하겠습니다.

일단, 아래 예제를 작성하여 파일을 하나 만들어보도록 하지요.
 
#include <stdio.h>

int main(void)
{
          double  a;
          a = 3.14;
          printf("%The value of pi is %f. \n", a);

return 0;
}



위 예제를 실행파일로 만들때 과정은 아래와 같습니다.

사용자 삽입 이미지
<그림 1-2>



우선 stdio.h를 사용하기 때문에 컴파일러는 stdio.h와 hello.c를 한 개로 합친 후 컴파일 하여 기계어 코드를 만들어 냅니다.

컴파일 폴더로 가서 이 프로젝트 폴더의 obj 파일을 열어보면 아래창처럼 확인할 수 있습니다.


사용자 삽입 이미지
<그림 1-3>


빨간색 칸에 예제에서 입력한 "the value of pi is" 문자열 있습니다.

그러나 이 문자열만 갖고서 실행시킬수가 없습니다.
특정 행동을 하는 값을 우리가 입력 시켜야만 가능하고 우리가 입력 시킨값을 컴파일러가 CPU를 통해 기계어로 변환해줘야만 실행을 시킬수가 있지요.

그림 4-2의 hello.exe는 PE 파일이나 마찬가지라는 것 입니다.

일단 PE파일 형식으로 적힌 내용을 운영체제가 분석하기 전까지의 작업을 알아 본 후 PE 파일 형식을 구체적으로 알아보도록 하겠습니다.

모든 어플리케이션에 4GB를 부여한다?

사용자에 의해 프로그램 실행이 요청되면 컴퓨터는 우선적으로 실행 파일 앞에 붙어있는 헤더를 보고 내가 실행할 수 있는지 확인합니다. 예를 들어 ARM CPU 기반에서 동작하는 윈도우 CE에서 실행시키기 위해 컴파일 된 실행파일이라면 펜티엄에서는 동작시킬 수 없습니다. 이 테스트를 비록한 몇 가지 테스트에 모두 통과하면 운영체제는 이 프로그램에게 4G 바이트를 할당해 줍니다. 그런데 운영체제는 실제로 4G 바이트를 한 번에 다 주는게 아니라 주어진 4GB 중에 실제로 사용하려고 하는 시점에 메모리를 할당해 주는 것입니다.

Microsoft(이하 MS)의 운영체제인 Windows는 실행되는 모든 프로그램에 전부 2의 30승, 즉 4GB 라는 어마어마한 공간의 메모리를 줍니다. 보통 개인 컴퓨터에 일반적으로 256MB ~ 2GB을 장착하는 것을 생각해보면, 애당초 프로그램 하나에게도 4GB를 주지 못합니다. 그런데 Windows는 각 프로그램에 4GB씩 실제로 할당하고 있습니다.

할당하는 방식에는 크게 두 가지 방식이 있습니다.

한가지는 한번에 4GB를 다 할당해 주지 않고 당장 필요한 만큼만 주는 방식입니다. 보통 간단한 프로그램은 실제 동작하는데 있어서 수백 KB나 몇 MB정도의 메모리면 충분합니다.

다른 한가지는 많이들 알고 있는 방식인 하드디스크를 메모리처럼 사용하는 것입니다.
하드디스크는 DRAM보다 느려서 그렇지 읽고 쓰는데는 아무 문제가 없다는 점에서 하드디시크는 결국 메모리와 본질이 같습니다. 이 방법은 페이징이라는 테크닉으로 이루어지는데 매우 복잡한 문제이므로 페이징과 각 프로그램 당 메모리 할당 문제는 추후 다루도록 하겠습니다.

여기서 기억할 것은 Windows에서 실행되는 모든 프로그램은 각자 자기만의 4GB 메모리 공간을 할당 받는다는 것이라는 점!

자, 모든 프로그램에게 4GB 받았더라도 첫번째 방법처럼 사용하려고 하는 시점에 메모리를 할당해 주는 방식이라면 5만 바이트의 hello.exe를 메모리에 올려야 합니다. 왜냐면 CPU는 메모리에 올라온 것들만 읽거나 쓸 수 있기 때문입니다. 따라서 CPU는 프로그램이 올라오면 5만 바이트만큼의 메모리 공간을 달라고 메모리 관리자에게 요청하게 됩니다. 요청을 받은 메모리 관리자는 DRAM에 공간이 있는지 살펴보고 5만 바이트를 담을 수 있는 공간을 모아서 주게 됩니다.

아래 그림 1-4을 보면서 이해를 높이시길..

사용자 삽입 이미지
<그림 1-4>


이때, 가상 메모리 관리자는 메모리를 효율적으로 관리하기 위해 4KB 단위로 메모리를 관리하게 됩니다. 여기서 4KB를 1페이지(page)라고 합니다. 이 같이 프로그램이 메모리를 사용할 때 DRAM과 하드디스크에서 안 쓰는 공간을 페이지 단위로 취합해서 쓸 수 있도록 해주고, 프로그램이 종료되거나 프로그램이 일정 부분의 메모리를 더 이상 쓰지 않아 운영체제에 되돌려 줄 때 다른 프로그램이 사용할 수 있도록 할당한 메모리를 해제하는 역할을 하는 것이 바로 가상 메모리 관리자입니다.

이렇게 5만 바이트를 할당받아 hello.exe 전체를 할당받은 메모리에 전부 복사합니다.
그런데 복사한 5만 바이트 중에 현재 운영체제의 재정 상태와 건강 상태를 알맞게 실시간으로 고쳐 주어야 하는 값들이 있습니다. 이 값들을 채워주면 실행 준비 완료됩니다. 운영체제는 이 프로그램을 실행시키기 위해 CPU 컨텍스트를 한 개 준비 합니다.

CPU 컨텍스트는 동시에 여러 작업을 하기 위한 방법 중 멀티쓰레딩에 해당한다는 것을 기억하기 바랍니다.

CPU 컨텍스트 중에 실행할 명령어가 담긴 주소를 담는 레지스터가 IP(Instruction Pointer)라고 기억해 두길 바랍니다. 네트워크 용어인 IP Address의 IP가 아닙니다.
다만 요즘 CPU들은 64bit, 32bit이기 때문에 Extended를 붙여 EIP(Extended Instruction Pointer) 라고 부릅니다. EIP 라고 부르니 네트워크 용어와 좀 더 차별화되어 보이나요? 그렇담 헷갈리지 않을 것이니 다행이라 생각합니다.

PE 파일 형식에는 실제 컴파일해서 나온 기계어가 위치한 첫 번째 주소가 적혀 있는 지점이 있습니다. 이 값을 읽어 온 뒤에 EIP 레지스터에 집어넣고 실행 풀(Pool)에 CPU 컨텍스트를 올려놓으면 실행됩니다. 이 작업을 해 주는 것이 Windows에서 프로그램을 실행시키는 명령어인 CreateProcess입니다.

읽어주셔서 감사합니다.


참고 자료 - MSDN, An In-Depth Look info the Win32 PE File FOrmat - Part 1
참고 도서 - 해킹, 파괴의 광학(출판사 : 와이미디어, 김성우 저자)
반응형