[File Structure] PE파일(Portable Executable)
PE-COFF(Portable Executable Common Object File Format)
Windows 운영 체제에서 실행 파일(executable files)와 object 파일. 즉 윈도우즈에서 사용되는 실행 파일을 뜻한다. PE파일에는 exe, scr, com, dll, ocx, sys 등이 있다.
PE파일은 악성코드 분석이나 리버스 엔지니어링의 주요 대상이기때문에 보안을 공부하는 사람들이 반드시 공부해야 하는 것 중 하나라고 할 수 있다.
PE파일 구조
PE파일의 구조를 공부하기 위해 PE파일의 헤더에 대한 공부는 필수적이다. PE헤더에 파일이 실행되기 위해 필요한 모든 정보가 구조체 형식으로 적혀있기때문이다.
DOS Header
64bytes로 고정된 길이를 가지며 주요 구성요소는 e_magic(2bytes)와 e_lfanew(4bytes)다.
e_magic | 2bytes | 0x00 | MZ |
... | ... | ... | |
e_lfanew | 4bytes | 0x3C | NT header의 시작점 |
DOS Stub Code
길이가 가변적이고 Linker가 만들어서 삽입하는 부분이다. 윈도우가 아닌 DoS 환경에서 실행되었을 경우 실행되는 코드로 필수 구성요소가 아니다.
NT Header
120bytes 혹은 248bytes의 길이를 가지며 프로그램 실행에 필요한 요소를 가지고 있다.
NT header 구조체는 크게 Signature, FileHeader, OptionalHeader 3가지로 구성되어 있다.
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
Signature | 4bytes | 0x00 | PE(0x50450000) |
FILE_Header | 20bytes | 0x04 | |
Optional_Header | 96bytes, 224bytes | 0x18 |
- File Header
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;
Machine | 2bytes | 0x00 | IA32: 0x014c / IA64: 0x0200 / AMD64: 0x8664 |
NumberOfSections | 2bytes | 0x02 | 섹션 개수 |
TimeDateStamp | 4bytes | 0x04 | 파일의 빌드 시간 |
... | ... | ... | ... |
SizeOfOptionalHeader | 2bytes | 0x10 | Optional Header 크기. |
Characteristics | 2bytes | 0x12 | 파일 속성 |
Characteristics의 플래그는 다음과 같다.
(https://docs.microsoft.com/ko-kr/windows/win32/api/winnt/ns-winnt-image_file_header)
IMAGE_FILE_RELOCS_STRIPPED | 0x0001 | Relocation information was stripped from the file. The file must be loaded at its preferred base address. If the base address is not available, the loader reports an error. |
IMAGE_FILE_EXECUTABLE_IMAGE | 0x0002 | The file is executable (there are no unresolved external references). |
IMAGE_FILE_LINE_NUMS_STRIPPED | 0x0004 | COFF line numbers were stripped from the file. |
IMAGE_FILE_LOCAL_SYMS_STRIPPED | 0x0008 | COFF symbol table entries were stripped from file. |
IMAGE_FILE_AGGRESIVE_WS_TRIM | 0x0010 | Aggressively trim the working set. This value is obsolete. |
IMAGE_FILE_LARGE_ADDRESS_AWARE | 0x0020 | The application can handle addresses larger than 2 GB. |
IMAGE_FILE_BYTES_REVERSED_LO | 0x0080 | The bytes of the word are reversed. This flag is obsolete. |
IMAGE_FILE_32BIT_MACHINE | 0x0100 | The computer supports 32-bit words. |
IMAGE_FILE_DEBUG_STRIPPED | 0x0200 | Debugging information was removed and stored separately in another file. |
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP | 0x0400 | If the image is on removable media, copy it to and run it from the swap file. |
IMAGE_FILE_NET_RUN_FROM_SWAP | 0x0800 | If the image is on the network, copy it to and run it from the swap file. |
IMAGE_FILE_SYSTEM | 0x1000 | The image is a system file. |
IMAGE_FILE_DLL | 0x2000 | The image is a DLL file. While it is an executable file, it cannot be run directly. |
IMAGE_FILE_UP_SYSTEM_ONLY | 0x4000 | The file should be run only on a uniprocessor computer. |
IMAGE_FILE_BYTES_REVERSED_HI | 0x8000 | The bytes of the word are reversed. This flag is obsolete. |
- Optional Header
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;
Magic | 2bytes | 0x00 | Optional Header 시작, 0x010b(HDR32), 0x020b(HDR64) |
... | ... | ... | |
AddressOfEntrypoint | 4bytes | 0x10 | PE파일이 메모리에 로드된 후 처음 실행되어야하는 코드(EntryPoint) 주소 |
... | ... | ... | |
ImageBase | 4bytes | 0x1C | 메모리 내에서 PE 파일이 로딩(매핑)되는 시작 주소 일반적으로 exe - 0x4000000 dll-0x1000000 |
SectionAlignment | 4bytes | 0x20 | 메모리에서 섹션의 최소단위 |
FileAlignment | 4bytes | 0x24 | 파일에서 섹션의 최소단위 |
... | ... | ... | |
SizeOfImage | 4bytes | 0x38 | 메모리에 로드된 PE file 크기 |
... | ... | ||
DataDirectory | 128bytes | 0x60 |
Section Header
각 section의 속성을 정의한 부분으로 각 section 별 IMAGE_SECTION_HEADER 구조체의 배열로 구성된다.
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
Name | 8bytes | 0x00 | section 이름, 최대 8bytes |
... | .... | ||
VirtualAddress | 4bytes | 0x0C | section 시작주소 값(RVA) |
SizeOfRawData | 4bytes | 0x10 | 파일 상태에서의 section 크기 |
PointerToRawData | 4bytes | 0x14 | 파일 상태에서 section 시작 위치(RVA) |
... | ... | ||
Characteristics | 4bytes | 0x24 | section 속성 값 |
Section
프로그램의 실제 내용을 담고 있는 블록이다.
optional header 구조체의 file alignment가 0x0200이었으므로 200의 배수부터 text section이 시작되는데 200은 아직 section header가 있으므로 400부터 text section이 시작된다.
실행 파일 생성 과정
=> 소스코드 -(Compiler)->오브젝트파일-(Linker)->exe, elf
RVA
- 상대주소
- RVA = RAW - ImageBase
RAW
- 데이터가 쓰인 파일 내의 주소
- RAW = RVA+ImageBase
- RAW = RVA - VirtualAddress + PointerToRawData
참고
https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_nt_headers32