물먹는산세베리아

PE 파일 구조 : PE 헤더 본문

Waregame & CTF/Reversing

PE 파일 구조 : PE 헤더

suntall 2021. 9. 28. 00:33

PE 파일은 DOS header ~ Section header까지는 PE 헤더, 그 아래의 Sections들은 PE 바디로 구성되어 있다.

먼저, PE 헤더에 대해 살펴보자.

참고로, 파일은 일반적인 PE 파일의 기본 구조를 갖고 있는 윈도우의 notepad.exe 파일을 사용했다.

 

1. DOS Header

PEViewer에서 notepad.exe 열어봄

 

PE 헤더의 맨 앞에는 IMAGE_DOS_HEADER 구조체가 있다.

IMAGE_DOS_HEADER

typedef struct _IMAGE_DOS_HEADER // DOS .EXE header
{
    WORD e_magic;       // Magic number
    WORD e_cblp;        // Byte on last page of file
    WORD e_cp;          // Pages in file
    WORD e_crlc;        // Relocations
    WORD e_cparhdr;     // Size of header in paragraphs
    WORD e_minalloc;    // Minimum extra paragraphs needed
    WORD e_maxalloc;    // Maximum extra paragraphs needed
    WORD e_ss;          // Initial (relative) SS value
    WORD e_sp;          // Checksum
    WORD e_ip;          // Initital IP value
    WORD e_cs;          // Initial (relative) CS value
    WORD e_lfarlc;      // File address of relocation table
    WORD e_ovno;        // Overlay number
    WORD e_res[4];      // Reserved words
    WORD e_oemid;       // OEM identifier (for e_oeminfo)
    WORD e_oeminfo;     // OEM information; e_oemid specific
    WORD e_res2[10];    // Reserved words
    LONG e_lfanew;      // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

* microsoft docs winnt.h 에서 구조체 찾아봤는데 안나옴.. 

크기는 64바이트이며, 0x0000003F까지 해당 구조체에 속한다. 이 중 주목할 만한 건 e_magic과 e_lfanew이다.

  • e_magic: PE 파일 구조, DOS signature (4D 5A, 워드로 읽으면 0x5A4D)
  • e_lfanew: NT header 오프셋 표시 (000000F8), 파일에 따라 가변적인 값을 갖는다. IMAGE_NT_HEADER 시작주소 *리틀엔디언 표기법

* windows/notepad.exe는 000000F8, windodws/system32/notepad.exe는 00001000 이던데 그래서 그런가..? 또 다른 곳에서는 000000e0이다. 

2. DOS Stub

DOS Header 밑에 존재 하나 옵션이기 때문에 크기도 일정하지 않고, 없다고 해도 실행에 문제 되지 않는다.

notepad.exe MS-DOS Stub Program

notepad.exe 파일은 MS-DOS 호환 모드를 갖고 있기 때문에 DOS 환경에서 실행 할 경우 DOS EXE 코드가 동작하면서 "This is program cannot be run in DOS Mode" 문장을 출력한다. 즉, 하나의 실행 파일로 DOS, Windows 모두 사용 가능한 파일을 만들 수 있다는 뜻이다.

 

3. NT Header

typedef struct _IMAGE_NT_HEADERS {
  DWORD                   Signature;
  IMAGE_FILE_HEADER       FileHeader;
  IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

3.1. Signature

첫번째 멤버 Signature은 '00004550' 값은 갖는다. IMAGE_NT_SIGNATURE PE

좀 전의 IMAGE_DOCS_HEADER에서 e_Ifanew의 값이 IMAGE_NT_HEADER 시작주소라고 했었는데 '000000F8'로 값이 같음을 확인할 수 있다.

3.2. 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

  • Machine 넘버는 CPU 별로 고유한 값을 갖는다. 
  • 0x8664는 AMD64(K8)

 

NumberOfSections

  • PE 파일은 코드, 데이터, 리소스 등이 각각의 섹션에 나뉘어 저장됨
  • 이때 섹션의 개수
  • 반드시 0보다 커야 함
  • 정의된 섹션 개수와 실제 섹션이 다르면 실행 에러 발생
  • 0x0007

 

TimeDateStamp

  • 0xF57E80D4 → 4,118,708,436 →130년 220일 5시간 40분 36초 → 1970년 1월 1일 0시에 더 하면 엥 말이 안된다.

SizeOfOptionalHeader

  • IMAGE_NT_HEADERS 구조체의 마지막 멤버는 IMAGE_OPTIONAL HEADER32구조체
  • IMAGE_OPTIONAL_HEADER32 구조체의 크기를 나타냄
  • PE32+ 형태의 파일인 경우 IMAGE_OPTIONAL_HEADER64 구조체 사용
  • 0xF0은 64bit
  • 0xE0(32bit), 0x00(obj)

 

Characteristics

  • 실행 가능한 파일인지, DLL파일인지 등 파일의 속성 정보가 OR 형식으로 조합됨
  • 0x0002 IMAGE_FILE_EXECUTABLE_IMAGE(파일 실행 가능 여부)
  • 0x0020 IMAGE_FILE_LARGE_ADDRESS_AWARE(2GB 이상의 메모리 사용이 가능한지)

3.3. 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 0x10B(IMAGE_OPTIONAL_HEADER32),
0x20B(IMAGE_OPTIONAL_HEADER64)
AddressOfEntryPoint 프로그램에서 최초로 실행되는 코드의 시작 주소인 RVA 값을 갖고 있음
ImageBase PE 파일이 로딩되는 시작 주소
SectionAligment 메모리에서 섹션의 최소단위를 나타냄
FileAligment 파일에서 섹션의 최소단위를 나타냄
SizeOfImage PE 파일이 메모리에 로딩됐을 때 가상 메모리에서 PE Image가 차지하는 크기
SIzeOfHeader PE 헤더의 전체 크기, 파일의 시작에서 SizeOfHeader 오프셋만큼 떨어진 곳에 첫번째 섹션 위치
Subsystem 1: Driver file 2: GUI 파일(창 기반 ex.notepad.exe) 3: CUI 파일(콘솔 기반 ex.cmd.exe)
NumberOfRvaAndSizes DataDirectory 배열의 개수 (IMAGE_OPTIONAL_HEADER32 구조체의 마지막 멤버)
DataDirectory IMAGE_DATA_DIRECTORY 구조체의 배열, 배열 각 항목마다 정의된 값을 가짐

 

4. Section Header

각 섹션의 속성을 정의한 것

프로그램의 안전성을 위해 code, data, resource가 각각 다른 특성, 접근 권한을 가져야 한다.

종류 엑세스 권한
code 실행, 읽기 
data 비실행, 읽기, 쓰기
resource 비실행, 읽기

4.1. 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;
항목 의미
VirtualSize 메모리에서 섹션이 차지하는 크기
VirtualAddress 메모리에서 섹션의 시작 주소(RVA)
SizeOfRawData 파일에서 섹션이 차지하는 크기
PointerToRawData 파일에서 섹션의 시작 위치
Characteristics 섹션의 속성(bit OR)

여기서 VirtualAddress와 PointerToRawData는 각각 IMAGE_OPTIONAL_HEADER32에 정의된 SEctionAlignment, FileAlignmnet에 맞에 결정된다. 또, 파일에서의 섹션 크기와 메모리에서 로딩된 섹션 크기는 다르다. (일반적으로 VirtualSize != SizeOfRawData)

 

 

 

 

참고

https://777bareman777.github.io/2019/09/17/UnderstandPE/

 

PE 구조 이해하기 - IMAGE_DOS_HEADER 구조

windows 시스템 실행파일의 구조와 원리 책 내용을 요약 및 정리 하는 포스팅이에요. PE파일의 맨 앞부분에 해당하는 DOS 스텁에 대한 내용을 알아볼 거에요. DOS 스텁의 시작PE 파일은 몇십 바이트의

777bareman777.github.io

리버싱 핵심원리, 이승원 저

https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32

 

IMAGE_OPTIONAL_HEADER32 (winnt.h) - Win32 apps

Represents the optional header format.

docs.microsoft.com

https://blog.kimtae.xyz/8

 

PE구조

    1. PE 구조 개요 Microsoft의 운영 체제 Windows 3.1부터 지원되는 실행파일의 구조를 말한다. 다양한 운영 체제에서의 이식성을 보여준다는 뜻에서 이식이 가능한 실행 형식(Portable Executable)이라

blog.kimtae.xyz

https://t-okk.tistory.com/37

 

[PE 파일] 구조(2) - PE 파일 헤더(DOS_HEADER, DOS Stud Code)

기초 정적 분석_PE 파일 notepad.exe(ver. Win 10) Notepad.exe [IMAGE_DOS_HEADER] 첫번째 주소(5A4D): 앞에서 4D5A로 표현되어 있는데 이것을 보고 리틀엔디안인지 빅엔디안인지 알 수 있다. Window System에서..

t-okk.tistory.com

 

 

'Waregame & CTF > Reversing' 카테고리의 다른 글

[dreamkack.io] rev-basic-4  (0) 2021.10.02
32bit IAT, EAT 로딩 과정  (0) 2021.10.02
어셈블리 명령어 모음  (0) 2021.09.26
64bit 레지스터 / 32bit, 64bit 함수호출규약  (0) 2021.09.11
[dreamhack.io]rev-basic-1  (0) 2021.09.11