=> 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')
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.