PE File Format 이란?
PE(Portable Executable) 파일은 Windows 운영체제에서 사용되는 실행파일 형식
PE 파일 종류
- 실행 계열 : EXE, SCR
- 드라이버 계열 : SYS, VXD
- 라이브러리 계열 : DLL, OCX, CPL, DRV
- 오브젝트 파일 계열 : OBJ
* 참고
OBJ 파일 자체로는 어떠한 형태의 실행도 불가능하므로 리버싱
에서는 크게 관심X
PE 파일 기본 구조
PE Header : DOS Header ~ Section Header
PE Body : PE Header 이후의 Section들
파일에서는 offset으로, 메모리에서는 VA(Virtual Address, 절대주소)로 위치를 표현
파일의 내용은 보통 코드(.txt), 데이터(.data), 리소스(.rsrc) 섹션으로 나뉘어 저장된다
파일/메모리에서 섹션의 시작 위치는 각 파일/메모리의 최소 기본 단위의 배수에 해당하는 위치여야 하고, 빈 공간은 NULL로 채움
VA(Virtual Address) & RVA(Relative Virtual Address)
VA는 프로세스 가상 메모리의 절대주소를 말하며, RVA는 어느 기준 위치에서부터의 상대주소를 말한다
RVA + ImageBase(기준 위치) = VA
PE 헤더
DOS Header
PE 헤더 가장 앞부분에는 IMAGE_DOS_HEADER 구조체가 존재하는데 크기는 40이고, 이 구조체에서 e_magic과 e_lfanew를 알아야한다
e_magic : DOS signature (4D5A -> ASCII값 "MZ")
e_lfanew : NT Header의 옵셋을 표시(파일에 따라 가변적인 값을 가짐)
모든 PE 파일의 시작부분(e_magic)에는 DOS signature ("MZ")가 존재하고, e_lfanew 값이 가리키는 위치에 NT Header 구조체가 존재한다
DOS Stub
DOS Stub의 존재 여부는 옵션이며 크기도 일정하지 않다
코드와 데이터의 혼합으로 이루어졌다
NT Header
IMAGE_NT_HEADERS 구조체는 3개의 멤버로 되어 있는데, 우선 Signature로 50450000h("PE"00)값을 가짐
그리고 File Header와 Optional Header 구조체 멤버가 있다
IMAGE_NT_HEADERS 구조체의 크기는 F8이다
NT Header -File Header
IMAGE_FILE_HEADER 구조체
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOptionalHeaders;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
#1. Machine
Machine 넘버는 CPU별로 고유한 값(파일의 CPU 아키텍처를 나타냄)이며 32비트 Intel x86 호환 칩은 014C의 값을 가진다
winnt.h 파일에 Machine 넘버의 값들이 정의되어 있다
#2. NumberOfSections
PE 파일은 코드, 데이터, 리소스 등이 각각의 섹션에 나뉘어서 저장되는데 NumberOfSections는 그 섹션이 개수를 나타냄
#3. SizeOfOptionalHeader
IMAGE_OPTIONAL_HEADER 구조체의 크기를 나타낸다
#4. Characteristics
실행이 가능한 형태인지 또는 DLL 파일인지 등의 정보들이 bit OR 형식으로 조합된다
winnt.h 파일에 정의된 Characteristcs 값들 중에 0002h, 2000h 값은 중요
#define IMAGE_FILE_EXCUTABLE_IMAGE 0x0002 // File is executable
// (i.e. on unresolved externel references).
#define IMAGE_FILE_DLL 0x2000 // File is a DLL.
Characteristics 값에 0002h가 없는 경우(not executable)는 *.obj와 같은 object 파일 및 resourceDLL 같은 파일이 있다
NT Header - Optional Header
IMAGE_OPTIONAL_HEADER32 구조체
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
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; // PE 파일이 로딩되는 시작주소
DWORD SectionAlignment; // 메모리의 섹션 최소단위
DWORD FileAlignment; // 파일의 섹션 최소단위
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion; <-- NT 추가 필드 : 윈도우 링커(로더)가 요구하는 정보
DWORD Win32VersionValue;
DWORD SizeOfImage; // 메모리 로딩 시 차지하는 PE 파일 크기
DWORD SizeOfHeaders; // PE 헤더의 전체 크기
DWORD CheckSum;
WORD Subsystem; // 파일종류(드라이버 / 실행파일)
WORD DllCharacteristics; // ASLR, DEP, SEH, Signing(메모리 보호) 관련 속성
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes; // DataDirectory 배열의 갯수
=====================================
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; <-- DataDirectory 배열
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
#1. Magic
Magic 넘버는 IMAGE_OPTIONAL_HEADER32 구조체인 경우 10B
IMAGE_OPTIONAL_HEADER64 구조체인 경우 20B의 값을 가짐
#2. AddressOfEntryPoint
EP의 RVA값을 가지고 있다. 프로그램에서 최초로 실행되는 코드의 시작주소
#3. ImageBase
PE 파일이 로딩되는 시작 주소를 나타낸다
EXE, DLL 파일은 user memory 영역인 0 ~ 7FFFFFFF 범위에 로딩되고,
SYS 파일은 kernel memory 영역인 80000000 ~ FFFFFFFF 범위에 로딩된다
PE 로더는 PE 파일을 실행시키기 위해 프로세스를 생성하고 파일을 메모리에 로딩한 후 EIP 레지스터 값을 ImageBase + AddressOfEntryPoint 값으로 셋팅
#4. SectionAlignment ,FileAlignment
PE 파일의 Body 부분은 섹션으로 나뉘어져 있는데 파일에서 섹션의 최소단위를 나타내는 것은 FileAlignment이고,
메모리에서 섹션의 최소단위를 나타내는 것은 SectionAlignment이다
#5. SizeOfImage
SizeOfImage는 PE 파일이 메모리에 로딩되었을 때 가상 메모리에서 PE Image가 차지하는 크기를 나타낸다
#6. SizeOfHeader
PE 헤더의 전체 크기를 나타내는데 FileAlignment의 배수여야 한다
#7. Subsystem
Subsystem의 값을 보고 시스템 드라이버 파일(*.sys)인지, 일반 실행 파일(*.exe, *.dll)인지 구분할 수 있다
#8. NumberOfRvaAndSizes
DataDirectory 배열의 갯수를 나타낸다 위에 IMAGE_NUMBEROF_DIRECTORY_ENTRIES (16)이라고 명시되어 있으나
PE 로더는 NumberOfRvaAndSizes의 값을 보고 배열의 크기를 인식하므로 값이 일치하지 않을 수 있다
#9. DataDirectory
DataDirectory 구조체 배열
DataDirectory[0] = EXPORT Directory (*)
DataDirectory[1] = IMPORT Directory (*)
DataDirectory[2] = RESOURCE Directory (*)
DataDirectory[3] = EXCEPTION Directory
DataDirectory[4] = SECURITY Directory
DataDirectory[5] = BASERELOC Directory
DataDirectory[6] = DEBUG Directory
DataDirectory[7] = COPYRIGHT Directory
DataDirectory[8] = GLOBALPTR Directory
DataDirectory[9] = TLS Directory (*)
DataDirectory[A] = LOAD_CONFIG Directory
DataDirectory[B] = BOUND_IMPORT Directory
DataDirectory[C] = IAT Directory
DataDirectory[D] = DELAY_IMPORT Directory
DataDirectory[E] = COM_DESCRIPTOR Directory
DataDirectory[F] = Reserved Directory
'리버싱 > 리버싱핵심원리' 카테고리의 다른 글
PE File Format(EAT) (0) | 2019.12.01 |
---|---|
PE File Format(IAT) (0) | 2019.11.29 |
Process Explorer, 함수 호출 규약 (0) | 2019.08.25 |
3, 4장 요약(바이트 오더링, IA-32 Register) (0) | 2019.08.24 |
1, 2장 요약 (0) | 2019.08.24 |