=> PE file format을 만들 당시 널리 사용되던 DOS파일에 대해 하위호환성을 고려해서 만들었음.
그 결과로 인해 PE 헤더의 제일 앞부분에 기존 DOS EXE Header를 확장시킨 IMAGE_DOS_HEADER 구조체가 존재.
그렇다면 구조체 내용을 보자!
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; /* 00: MZ Header signature */
WORD e_cblp; /* 02: Bytes on last page of file */
WORD e_cp; /* 04: Pages in file */
WORD e_crlc; /* 06: Relocations */
WORD e_cparhdr; /* 08: Size of header in paragraphs */
WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */
WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */
WORD e_ss; /* 0e: Initial (relative) SS value */
WORD e_sp; /* 10: Initial SP value */
WORD e_csum; /* 12: Checksum */
WORD e_ip; /* 14: Initial IP value */
WORD e_cs; /* 16: Initial (relative) CS value */
WORD e_lfarlc; /* 18: File address of relocation table */
WORD e_ovno; /* 1a: Overlay number */
WORD e_res[4]; /* 1c: Reserved words */
WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */
WORD e_oeminfo; /* 26: OEM information; e_oemid specific */
WORD e_res2[10]; /* 28: Reserved words */
DWORD e_lfanew; /* 3c: Offset to extended header */
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
크기는 총 40이다. 여기서 일단 살펴볼껀 2가지를 살펴보자.
- e_magic
- e_lfanew
e_magic : DOS signature 4D5A를 나타낸다. ('MZ')
MZ 보이시죠 헤헿
PE의 스펙에 맞게 '4D5A'의 2바이트로 시작하며 'MZ'가 보입니다. 그 다음으로
e_lfanew : NT Header의 offset을 나타낸다.
빨간네모박스가 e_lfanew 값입니다. 000000D8 입니다. (리틀 엔디언)
실제 000000D8에 'PE'가 보이네요 [NT Header 시작부분]
이 값들은 PE header이기 때문에 변조하면 정상 실행되지 않습니다.
DoS Stub
다음으로 DoS Stub 입니다.
DoS Header와 NT Header 사이가 그렇다면 DoS Stub이 되겠죠 ??
이 부분입니다!
DOS Stub의 존재여부는 옵션이며 크기도 일정하지 않습니다. (없어도 파일실행과 상관없음!)
이 멤버는 그 섹션의 개수를 나타낸다고 합니다. 이 값은 반드시 0보다 커야하며 정의된 섹션 개수와 실제 섹션이 다르면 실행 에러가 발생합니다.
위 그림에서 4개의 섹션을 가지고 있다고 합니다. PEview를 통해서 확인해볼까요?
놀랍군요! ㅋㅋㅋㅋㅋ
#3. SizeofOptionalHeader
IMAGE_NT_HEADERS 구조체체의 마지막 멤버는 IMAGE_OPTIONAL_HEADER32 입니다.
이 멤버는 바로 IMAGE_OPTIONAL_HEADER32 구조체의 크기를 나타냅니다.
PE32+의 경우에는 IMAGE_OPTIONAL_HEADER64 구조체를 활용합니다. (두개의 구조체 크기는 다름)
=> 이렇게 구조체의 범위를 미리 잡아놓고 그만큼의 데이터를 파일의 정보로 받아들임 ㅋ.
#4. Characteristics
파일의 속성을 나타내는 값으로, 실행 가능한 형태인지 혹은 DLL파일인지의 정보들이 bit OR 형식으로 조합됨
ex) '0102' = '0100' + '0002'
=> PE 파일이 어떤 속성을 가지고 있는지 조합된 숫자로 파악한다!
0002와 2000은 기억하도록 하자(실행가능과 DLL)
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable
// (i.e. no unresolved externel references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Agressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from
// file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media,
// copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net,
// copy and run from the swap file.
#define IMAGE_FILE_SYSTEM 0x1000 // System File.
#define IMAGE_FILE_DLL 0x2000 // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.