PE구조 정리
PE파일
마이크로소프트가 만든 실행파일의 형식, 운영체제간의 이식성을 높히기 위하여 만든 파일 포멧입니다. PE구조로 되어 있는 파일은
종류 |
확장자 |
실행파일 |
exe, scr |
드라이버 |
sys, vxd |
라이브러리 |
dll, ocx, cpl, drv |
오브젝트파일 |
obj |
이 있으며 exe는 직접적으로 실행가능하고 obj를 제외한 나머지파일은 간접적으로 실행이 가능합니다.
PE파일 구조
PE헤더
DOS Header부터 Section Table[Section Header]까지를 포함하여 PE헤더라고 부르며 위의 sections은 PE Body라고 합니다. 이 부분에는 코드 및 데이터 영역의 위치와 크기, 운영체제, 초기 스택 크기 등 여러 중요한 정보가 들어갑니다.
1) DOS Header
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 {
WORD e_magic; // DOS signature : 4D5A ("MZ")
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
LONG e_lfanew; // offset to NT header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; |
cs |
모두 다 알기는 어렵기 때문에 중요한것만 고르자면 e_magic과 e_lfanew입니다. [중요한건 텍스트를 진하게 해둘께요.]
1. e_magic : DOS signature로 PE파일의 시그니처가 저장됩니다.
2. e_lfanew : NT Header의 시작주소를 저장합니다.[옵셋값]
2) DOS Stub
DOS Header다음에 있는 코드로 크기가 정해져 있지 않는 부분입니다.
DOS에서 돌아가는 16bit 어셈블리어로 작성되어 있습니다.
32bit이상 윈도우에선 실행되지않고 무시되기 때문에 있든없든 상관없습니다.
(대부분 32bit로 프로그래밍된 프로그래밍이 16bit도스모드로 실행됬을때 여기선 돌릴 수 없다 라는 텍스트를 출력하는 용도로 사용하더군요.)
3)NT Header
1
2
3
4
5
6 |
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; // PE Signature : 50450000 ("PE"00)
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; |
cs |
총 3개의 멤버로 구성되어 있습니다.
1. Signature : NT코드의 시작을 알리는데 고정적으로 50450000(아스키코드로 PE00)값이 들어 있습니다.
2. FileHeader : 구조체
1
2
3
4
5
6
7
8
9 |
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; |
cs |
1. Machine : 동작가능한 cpu의 종류를 코드로 담고 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 |
#define IMAGE_FILE_MACHINE_UNKNOWN 0
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
#define IMAGE_FILE_MACHINE_AM33 0x01d3
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
#define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian
#define IMAGE_FILE_MACHINE_CEE 0xC0EE |
cs |
2. NumberOfSections : 파일이 가지고 있는 Section의 개수를 의미합니다.
3. TimeDateStamp : 파일이 빌드된 시간을 나타냅니다.
4. SizeOfOptionalHeader : NT Header의 3번째 멤버인 OptionalHeader의 크기를 나타냅니다.
5. Characteristics : 파일의 속성에 대한 정보가 담겨있습니다. [리눅스의 rwx와 비슷한것 같네요.]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 |
#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. |
cs |
3. OpticalHeader : 구조체
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 |
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; |
cs |
1. Magic : 구조체가 32bit용이면 10Bh, 64bit용이면 20Bh값을 가집니다.
2. AddressOfEntryPoint : EP[프로그램의 시작점]주소를 가지고 있습니다.
3. ImageBase : PE파일이 매핑되는 시작주소를 나타냅니다.
4. SectionAlignment : 메모리에서의 섹션의 최소단위를 나타냅니다.
5. FileAlignment : 파일에서 섹션의 최소단위를 나타냅니다.
6. SizeOfimage : 파일이 메모리에 로딩되었을때 가상 메모리에서 PE파일이 차지하는 크기를 나타냅니다.
7. SizeOfHeader : PE헤더의 전체크기를 나타냅니다.
8. SubSystem : 파일을 실행하기위한 기본 환경을 나타냅니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 |
#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 // image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 // Image runs in the Windows CE subsystem.
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 //
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 //
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 //
#define IMAGE_SUBSYSTEM_EFI_ROM 13
#define IMAGE_SUBSYSTEM_XBOX 14
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16 |
cs |
9. NumberOfRvaAndSizes : 10번인 DataDirectory구조체의 배열 크기를 정합니다.
10. DataDirectory : 파일이 어떤 라이브러리를 제공하고, 필요한지를 정의한 테이블의 위치와 크기가 들어있습니다.
1
2
3
4 |
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; |
cs |
이런형식으로 들어있는데 배열마다의 역할이 다릅니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 |
Data Directory[0] = Export Directory
Data Directory[1] = Import Directory
Data Directory[2] = RESOURCE Directory
Data Directory[3] = EXCEPTION Directory
Data Directory[4] = SECURITY Directory
Data Directory[5] = BASERELOC Directory
Data Directory[6] = DEBUG Directory
Data Directory[7] = COPYRIGHT Directory
Data Directory[8] = GLOBALPTR Directory
Data Directory[9] = TLS Directory
Data Directory[10] = LOAD_CONFIG Directory
Data Directory[11] = BOUND_IMPORT Directory
Data Directory[12] = IAT Directory
Data Directory[13] = DELAY_IMPORT Directory
Data Directory[14] = COM_DESCRIPTOR Directory
Data Directory[15] = Reserved Directory |
cs |
4) SectionTable[Section Header]
이곳에서는 Section을 나누고, Section들의 시작위치, 크기, 속성값등을 정합니다.
1. VirtualSize : 메모리에서의 Section의 크기가 저장되어 있습니다.
cs
2. VirtualAddress : 메모리에서 Section이 시작되는 주소가 저장되어 있습니다.[RVA형식으로 저장]
3. SizeOfRawData : 파일에서 Section이 차지하는 크기를 저장하고 있습니다.
4. PointerToRawData : 파일에서 Section이 시작하는 위치를 저장하고 있습니다.
5. Characteristics : NT헤더의 Characteristics랑 같은 역할을 합니다.
1
2
3
4
5
6 |
define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data.
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable.
#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable.
#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. |
cs |