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 |