구글링해보면 정말 많은 PE 구조에 대한 글이 있지만 이걸 적어두는 이유는 오롯이 나를 위해 ㅎ
00. PE 개요
00. PE란
- PE: Portable Executable
- Windows 운영체제에서 실행 가능한 파일의 형태
- 64bit는 PE+로 표기
01. PE 파일 확장자
- 실행: exe, scr
- 라이브러리: dll, ocx, cpl, drv
- 드라이버: sys, vxd
- 오브젝트 파일: dbj
02. PE 구조
크게 Header와 Body로 구성
- Header
- 파일이 실행되기 위한 파일 구성에 관련된 전반적인 정보.
- PE Header + Section Header
- 모든 Windows PE 파일은 PE Header에서 공통적으로 IMAGE_DOS_HEADER, MS_DOS Stub Program, IMAGE_NT_HEADERS를 가지고 있음
- Section Header는 PE 파일마다 내용과 형태가 다르고, 최소 1개 이상의 Section Header를 가짐
- Body
- 실제 코드, 데이터, 리소스 등이 존재. 헤더에 있는 규칙에 따라 실행되는 기계어(코드)가 저장 되어 있음
- Section Data 영역이라고도 하며, 최소 1개 이상의 Section Data 영역을 가짐
01. Header
00. IMAGE_DOS_HEADER
DOS 운영체제에서 Windows용 PE 파일을 실행했을 때의 호환성을 위해
실제 Windows용 PE 헤더 위치를 가리키는 필드가 있음
typedef struct _IMAGE_DOS_HEADER
{
WORD e_magic; // magic number(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; // RVA address
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
- e_magic
- DOS Signature
- 모든 PE 파일은 0x4D5A, 아스키로 MZ 값을 가짐
- e_lfanew
- NT Header의 시작 Offset(RVA 주소값)
01. MS_DOS Stub Program
DOS 환경에서 32bit PE 파일을 실행할 때 오류 메시지 출력
현재 사용하지 않는 필드(위와 마찬가지로 호환성을 위해 존재)
02. IMAGE_NT_HEADERS
PE 파일의 세부 사항이 저장되는 기본 위치로 이 헤더의 Offset을 IMAGE_DOS_HEADER의 e_lfanew 필드로 확인할 수 있음
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
// 64bit도 동일한 형태로, 구조체의 이름만 IMAGE_NT_HEADER64로 다름
- Signature
- 4 byte로 PE 파일 식별자
- \x4550, 아스키로 PE00
- IMAGE_FILE_HEADER
- Machine: 컴퓨터의 아키텍처
- IMAGE_FILE_MACHINE_I386: 32bit, 0x014C
- IMAGE_FILE_MACHINE_IA64: Intel Itanium, 0x0200
- IMAGE_FILE_MACHINE_AMD64: 64bit, 0x8664
- NuberOfSections: 섹션 개수. 헤더 바로 다음에 섹션 테이블이 나오는데, 그 섹션 테이블의 크기이며 96개까지만 가능.
- TimeDateStamp: 타임스탬프의 하위 4byte.
- PointerToSymbolTable: Symbol Table 오프셋이며 COFF symbol table이 없으면 0.
- NumberOfSymbols: Symbol Table에 있는 심볼의 개수
- SizeOfOptionalHeader: Optional Header의 크기(byte 단위). 파일이 오브젝트 파일이라면 이 값이 0이여야 함.
- Characteristics: 이미지의 특성
- Machine: 컴퓨터의 아키텍처
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;
- IMAGE_OPTIONAL_HEADER
- PE 구조에서 중요한 역할
- 링커 버전, 코드 및 데이터의 크기/주소 정보 등 다양한 정보를 담고 있음
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;
// 64bit도 동일한 필드
- Magic: 시그니처. 0x10B(32bit), 0x20B(64bit)
- AddressOfEntryPoint: 실제 프로그램이 메모리에서 실행되는 시작 지점이며 RVA임
- 첫 EIP 값이 ImageBase+AddressOfEntryPoint
- BaseOfCode: Code Section의 시작 포인터(RVA)
- ImageBase: 메모리에 PE 파일이 로드된 시작 주소
- 0x00400000가 기본
- dll의 경우에는 0x10000000가 기본
- NumberOfRvaAndSize: DataDirectory 배열 개수
- DataDirectory[]: 실행 파일 내의 중요한 위치에 대한 주소. 총 16개의 값을 가짐
- DataDirectory[0]: Export table
- DataDirectory[1]: Import table
- DataDirectory[2]: Resource Table
- DataDirectory[3]: Exception table
- DataDirectory[4]: Certificate table
- DataDirectory[5]: Base relocation table
- DataDirectory[6]: Debugging information
- DataDirectory[7]: Architecture-specific data
- DataDirectory[8]: Global pointer register relative virtual address
- DataDirectory[9]: Thread local storage (TLS) table
- DataDirectory[10]: Load configuration table
- DataDirectory[11]: Bound import table
- DataDirectory[12]: Import address table
- DataDirectory[13]: Delay import descriptor
- DataDirectory[14]: The CLR header
- DataDirectory[15]: Reserved
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; // RVA of the data
DWORD Size; // Size of the data
};
03. Section Header
IMAGE_NT_HEADERS 바로 다음에 Section Table이 존재하며, IMAGE_SECTION_HEADER 구조체 배열임. 각 섹션에 대한 속성을 정의
IMAGE_SECTION_HEADER 구조체 개수는 IMAGE_NT_HEADERS.FileHeader.NumberOfSecions 필드 개수로 확인 가능함
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: .text .rdata 등 섹션의 이름(8byte가 최대)
- VirtualAddress: 메모리에서의 섹션 시작 주소(RVA)
- SizeOfRawData: 파일자체에서 섹션이 차지하는 크기
- Characteristics: 섹션의 속성
- IMAGE_SCN_MEM_EXECUTE The section can be executed as code.
- IMAGE_SCN_MEM_READ The section can be read.
- IMAGE_SCN_MEM_SHARED The section can be shared in memory.
- IMAGE_SCN_MEM_WRITE The section can be written to.
- IMAGE_SCN_CNT_CODE The section contains executable code.
- IMAGE_SCN_MEM_NOT_CACHED The section cannot be cached.
- IMAGE_SCN_MEM_NOT_PAGED The section cannot be paged.
- IMAGE_SCN_CNT_INITIALIZED_DATA The section contains initialized data.
- IMAGE_SCN_CNT_UNINITIALIZED_DATA The section contains uninitialized data.
- File Offset = RVA-VirtualAddress+PointerToRawData
02. References
'Reversing' 카테고리의 다른 글
PE Structure - EAT (0) | 2021.12.04 |
---|---|
PE Structure - IAT (0) | 2021.11.30 |