PE파일을 생성하는 과정 : 소스 파일 & 헤더 파일 -> 기계어 코드 (obj 파일) -> 링킹 (동적 라이브러리, 리소스 데이터, 임포트, 익스포트 테이블 처리 정보 어딘가에 적어둔다) -> PE 포맷의 파일

 

PE Header에는 실행 파일을 실행하기 위한 각종 정보가 기록돼 있어서 이 부분이 깨질 경우 파일 로딩 단계부터 실패하여 실행이 되지 않음.

 

PE의 구조

IMAGE_DOS_HEADER
IMAGE_NT_HEADER
IMAGE_FILE_HEADER
IMAGE_OPTIONAL_HEADER
IMAGE_SECTION_HEADER
IMAGE_IMPORT_HEADER
IMAGE_EXPORT_HEADER
IMAGE_IMPORT_BY_NAME
IMAGE_THUNK_DATA32

 

IMAGE_DOS_HEADER

typedef struct _IMAGE_DOS_HEADER {  // DOS .EXE header
    WORD e_magic;         // Magic number
    WORD e_cblp;          // Bytes 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;            // Initial SP value
    WORD e_csum;          // Checksum
    WORD e_ip;            // Initial 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 wordscal
    LONG   e_lfanew;        // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

e_magic : 0x5A4D (IMAGE_DOS_SIGNATURE)

e_lfanew : IMAGE_NT_HEADER의 구조체 위치

 

IMAGE_NT_HEADER

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

Signature : "PE\0\0"

참고 : _IMAGE_NT_HEADERS | Microsoft Docs

 

IMAGE_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 : 어떤 CPU에서 이 파일이 실행될 수 있는지 보여줌

NumberOfSections : 섹션의 개수 (섹선 : .text .data ....)

TimeDateStamp : 이 파일을 빌드한 날짜 (obj -> exe)

SizeOfOptionalHeader : IMAGE_OPTIONAL_HEADER32의 구조체 크기

Characteristics : 현재 파일의 형식 (DLL인지 EXE인지 구분하는데 많이 사용)

참고 : _IMAGE_FILE_HEADER | Microsoft Docs

IMAGE_OPTIONAL_HEADER

typedef struct _IMAGE_OPTIONAL_HEADER {
  // Standard fields.
  WORD                 Magic;
  BYTE                 MajorLinkerVersion;
  BYTE                 MinorLinkerVersion;
  DWORD                SizeOfCode;
  DWORD                SizeOfInitializedData;
  DWORD                SizeOfUninitializedData;
  DWORD                AddressOfEntryPoint;
  DWORD                BaseOfCode;
  DWORD                BaseOfData;
  // NT additional fields.
  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;

참고 : _IMAGE_OPTIONAL_HEADER | Microsoft Docs

Magic : 32비트에서는 0x10B, 64비트에서는 0x20B

SizeOfCode : 코드 양의 전체 크기

MajorLinkerVersion, MinorLinkerVersion : 컴파일러의 버전 정보

ImageBase : 해당 파일이 실행될때 가상메모리에 올라가는 번지

AddressOfEntryPoint : 실제 파일이 메모리에서 실행되는 시작 지점

BaseOfCode : 코드 영역이 시작되는 베이즈 주소 (ImageBase로부터 상대적인 값)

SectionAlignment, FileAlignment : 각 섹션의 정렬 단위 (실제 크기가 이보다 작으면 0x0으로 패딩)

SizeOfImage : 이 파일이 메모리에 로딩되었을때 전체 크기, 로더가 이 값을 보고 공간을 확보해놓음

SizeOfHeaders : PE헤더의 크기 (ms docs 참고)

Subsystem : 프로그램이 GUI(0x2)인지 콘솔(0x3)인지 알려준다(ms docs 참고)

DataDirectory : 첫번째 IMAGE_DATA_DIRECTORY 구조체를 가리키는 포인터

typedef struct _IMAGE_DATA_DIRECTORY {
  DWORD VirtualAddress;
  DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

IMAGE_NUMBEROF_DIRECTORY_ENTRIES는 16이고, 배열의 원소들은 다음과 같다.

#define PE_EXPORT_DIRECTORY 0
#define PE_IMPORT_DIRECTORY 1
#define PE_RESOURCE_DIRECTORY 2
#define PE_EXCEPTION_DIRECTORY 3
#define PE_SECURITY_DIRECTORY 4
#define PE_RELOCATION_DIRECTORY 5
#define PE_DEBUG_DIRECTORY 6
#define PE_DESCRIPTION_DIRECTORY 7
#define PE_SPECIAL_DIRECTORY 8
#define PE_THREAD_LOCAL_STORAGE_DIRECTORY 9
#define PE_LOAD_CONFIGURATION_DIRECTORY 10
#define PE_BOUND_IMPORT_DIRECTORY 11
#define PE_IMPORT_ADDRESS_TABLE_DIRECTORY 12
#define PE_DELAY_IMPORT_TABLE 13
#define PE_CLR_RUNTIME_DIRECTORY 14
#define PE_RESERVED_DIRECTORY 15

 

IMAGE_SECTION_HEADER

#define IMAGE_SIZEOF_SHORT_NAME        8

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;

참고 : _IMAGE_SECTION_HEADER | Microsoft Docs

각 섹션에 대한 이름, 시작 주소, 사이즈 등의 정보를 관리하는 구조체

※ IMAGE_FILE_HEADER에 NumberOfSections 값이 있다. 이를 이용하여 반복문을 통해 모든 섹션의 정보를 뽑아낼 수 있음.

 

Characteristics는 다음 값들이 OR 연산된 형태로 저장된다.

IMAGE_SCN_CNT_CODE
IMAGE_SCN_CNT_INITIALIZED_DATA
IMAGE_SCN_CNT_UNINITIALIZED_DATA
IMAGE_SCN_MEM_DISCARDABLE
IMAGE_SCN_MEM_NOT_CACHED
IMAGE_SCN_MEM_NOT_PAGED
IAMGE_SCN_MEM_SHARED
IMAGE_SCN_MEM_EXECUTE
IMAGE_SCN_MEM_READ
IMAGE_SCN_MEM_WRITE

 

IAT 관련

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
  union [
    DWORD Characteristics;
    DWORD OriginalFirstThunk;
  };
  DWORD TimeDateStamp;
  DWORD ForwarderChain;
  DWORD Name;
  DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_THUNK_DATA32 {
  union {
    DWORD ForwarderString;	// PBYTE
    DWORD Function;	// PDWORD
    DWORD Ordinal;
    DWORD AddressOfData;	// PIMAGE_IMPORT_BY_NAME
  } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32;

typedef struct _IMAGE_IMPORT_BY_NAME {
  WORD Hint;
  BYTE Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

import되는 dll 한개마다 IMAGE_IMPORT_DESCRIPTOR가 하나씩 생긴다. (Name에 그 이름이 적힘)

OriginalFirstThunk가 가리키는 위치로 가보면 그 DLL에서 import되는 함수에 대한 주소가 하나씩 적혀있고 각 주소는 IMAGE_THUNK_DATA32의 구조체로 이루어져있다. 거기에서 AddressOfData는 IMAGE_IMPORT_BY_NAME구조체를 가리키고 여기에 그 함수의 이름이 적혀있다.

'리버스 엔지니어링 바이블' 카테고리의 다른 글

07 MFC 리버싱  (0) 2018.11.11
06 흔히 사용하는 패턴  (0) 2018.11.10
04 DLL 분석  (0) 2018.10.17
03 C++ 클래스와 리버스 엔지니어링  (0) 2018.10.14
02 C 문법과 디스어셈블링  (0) 2018.10.14

+ Recent posts