0%

PE 구조 이해하기 - IMAGE_DOS_HEADER 구조

windows 시스템 실행파일의 구조와 원리 책 내용을 요약 및 정리 하는 포스팅이에요.

PE파일의 맨 앞부분에 해당하는 DOS 스텁에 대한 내용을 알아볼 거에요.


DOS 스텁의 시작

PE 파일은 몇십 바이트의 MS-DOS 스텁으로 시작 하고, MS-DOS 스텁은 예전의 MS-DOS 시절때의 MZ 포맷으로 PE 포맷에서는 큰 의미가 없다고 해요.

MS-DOS 스텁은 PE 파일을 도스 환경에서 실행 시킬 때 “This program cannot be run in DOS mode” 라는 문장을 출력하기 위한 조그마한 16비트 도스용 응용 프로그램에 불과해요.
그리고 DOS 스텁은 40바이트의 IMAGE_DOS_HEADER 구조체와 해당 프로그램 코드로 이루어져 있어요.


IMAGE_DOS_HEADER 구조체

IMAGE_DOS_HEADER 구조체는 “WinNT.h” 헤더 파일에 정의되어 있다고 해요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct _IMAGE_DOS_HEADER // DOS .EXE header
{
WORD e_magic; // Magic number
WORD e_cblp; // Byte on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Checksum
WORD e_ip; // Initital IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

IMAGE_DOS_HEADER 구조체는 64바이트로 구성되어 있어요.
PE 파일에서 0x0000003F 까지가 IMAGE_DOS_HEADER 구조체에요.
이 구조체에서 실제로 쓸모가 있는 것은 첫 번쨰 필드인 e_magic과 마지막 필드인 e_lfanew 이에요. 그 이외에 나머지는 사용되지 않아요.


첫 번째 필드인 e_magic

모든 PE 파일은 IMAGE_DOS_HEADER로 시작해요.
이때 e_magic은 ASCII “MZ” 로 고정되어 있어요. 위 구조체에서는 e_magic WORD 형으로 되어 있는데, “MZ”을 워드로 읽게 되면 0x5A4D가 되요.

여기서 0x5A=’Z’, 0x4D=’M’ 에 해당해요.
인텔 cpu 같은 경우에는 리틀 엔디번 방식으로 메모리를 정렬하기 때문에 0x5A4D로 값을 저장하게 되요.

이러한 “MZ”도 “WinNT.h” 헤더 파일에 매크로로 정의되어 있어요.

1
#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ

마지막 필드인 e_lfanew

IMAGE_DOS_HEADER 구조체에서 e_flanew 필드에는 실제 PE 파일의 시작이라고 할 수 있는 IMAGE_NT_HEADER 시작 오프셋 값을 가진다고 해요.

예를 들어서 DWORD 형으로 정의된 e_flanew의 값이 0x000000F0 이라면, 실제 PE 파일의 시작은 0x000000F0 이고, 여기서 PE 파일의 시그니쳐인 “PE”를 볼 수 있어요.


마지막으로…

IMAGE_DOS_HEADER 와 DOS 스텁은 MS-DOS 시절의 유산물이에요. 우리는 여기서 PE 파일내에서 사용하지 않는 부분이 있다는 것을 알았어요. 앞으로도 PE 파일내에서 사용하지 않는 부분이 존재할거에요. 그리고 이러한 부분들을 이용해서 패커 같은 것을 구현해서 PE 파일의 크기를 줄이고, 리버싱을 하기 어렵게 만들었다고 해요!!

우리가 IMAGE_DOS_HEADER에서 e_magic의 값이 0x5A4D 이어야지 PE 파일이라는 것을 알 수 있다는 사실과 e_lfanew의 값에 따라서 IMAGE_NT_HEADER의 시작 오프셋 값을 알 수 있다는 것만 알면 되요.