PE 바이너리 포맷 요약 정리
해당 파트에서는 PE 바이너리 포맷을 요약하여 정리한다.
3.1 MS-DOS Header와 MS-DOS Stub
3.1.1 MS-DOS Header
winnt.h에 정의되어 있는 _IMAGE_DOS_HEADER
//define winnt.h
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 words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
C
복사
해당 구조체에서는 e_magic과 e_lfanew가 중요한 포인트.
e_magic의 경우 무조건 MZ 값으로 고정되어 있으며
e_lfanew의 경우 PE Header를 가리킨다.
3.1.2 MS-DOS Stub
DOS 운영체제에서 실행 됐을 경우
"This program cannot be run in DOS mode" 라는 구문을 출력하는 프로그램이 포함되어 있다.
3.2 PE Signature, File Header, Optional Header
MS-DOS Header와 동일하게 winnt.h에 정의되어 있다.
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable; // not use now
DWORD NumberOfSymbols; // not use now
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
ULONGLONG 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;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
C
복사
3.2.1 IMAGE_NT_HEADER64
_IMAGE_NT_HEADER64 구조체는 Signature, FileHeader, OptionalHeader를 가지고 있는 구조체이다.
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
C
복사
Signature에는 앞의 2바이트가 PE 문자열, 뒤의 2바이트가 0으로 채워져 있다.
그리고 IMAGE_FILE_HEADER 구조체인 FileHeader와 IMAGE_OPTIONAL_HEADER64 구조체인 OptionalHeader가 존재한다.
3.2.2 IMAGE_FILE_HEADER
_IMAGE_FILE_HEADER 구조체는 파일의 일반 속성을 나타낸다.
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable; // not use now
DWORD NumberOfSymbols; // not use now
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
C
복사
1.
Machine 값의 경우 System Architecture를 명시한다.
2.
NumberOfSections 값은 Section의 갯수를 나타낸다.
3.
TimeDateStamp값은 해당 파일이 생성된(컴파일 된) 시간을 나타낸다.
4.
PointerToSymbolTable과 NumberOfSymbols는 현재는 사용되지 않는다.
5.
SizeOfOptionalHeader값은 OptionalHeader의 사이즈를 나타낸다.
6.
Chararcteristics의 경우 파일의 대략적인 속성을 나타낸다.
3.2.3 IMAGE_OPTIONAL_HEADER
_IMAGE_OPTIONAL_HEADER 구조체는 PE바이너리에서 필수적인 구조체이다.
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
ULONGLONG 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;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
C
복사
1.
Magic 멤버는 0x020b값으로 정해져 있다.
2.
MajorLinkerVersion, MinorLinkerVersion 멤버는 바이너리를 생성한 링커의 메이저 및 마이너 버전을 의미한다.
3.
Imagebase는 바이너리를 로드해야 할 주소 정보를 담고 있다.
4.
AddressOfEntryPoint 멤버는 EntryPoint의 RVA(Relative Virtual Address)을 가지고 있다.
•
RVA = Imagebase + BaseOfCode
5.
DataDirectory는 _IMAGE_DATA_DIRECTORY 구조체의 배열로써 각 배열마다 특정 정보에 대한 값을 담고 있다.
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
/*DataDirectory 배열의 이름, 배열 인덱스, 설명*/
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE
7
Architecture-specific data
IMAGE_DIRECTORY_ENTRY_BASERELOC
5
Base relocation table
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
11
Bound import directory
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
14
COM descriptor table
IMAGE_DIRECTORY_ENTRY_DEBUG
6
Debug directory
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
13
Delay import table
IMAGE_DIRECTORY_ENTRY_EXCEPTION
3
Exception directory
IMAGE_DIRECTORY_ENTRY_EXPORT
0
Export directory
IMAGE_DIRECTORY_ENTRY_GLOBALPTR
8
The relative virtual address of global pointer
IMAGE_DIRECTORY_ENTRY_IAT
12
Import address table
IMAGE_DIRECTORY_ENTRY_IMPORT
1
Import directory
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
10
Load configuration directory
IMAGE_DIRECTORY_ENTRY_RESOURCE
2
Resource directory
IMAGE_DIRECTORY_ENTRY_SECURITY
4
Security directory
IMAGE_DIRECTORY_ENTRY_TLS
9
Thread local storage directory
C
복사
3.3 섹션 헤더 테이블
winht.h 에 정의되어 있는 _IMAGE_SECTION_HEADER이다.
각 Section별로 Section Header Table을 가지고 있다
// Section header format.
//
#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;
C
복사
1.
VirtualSize, SizeOfRawData
•
메모리 상에서의 사이즈, 파일 상에서의 사이즈를 의미한다
2.
PointerOfRawData, VirtualAddress
•
파일 상에서의 오프셋, 메모리 상에서의 오프셋을 의미한다.
3.
Characteristic
•
해당 Section의 권한을 의미한다.
3.4 섹션
PE 파일의 섹션이다.
Sections:
Idx Name Size VMA LMA File off Algn
0 .textbss 00010000 00401000 00401000 00000000 2**2
ALLOC, LOAD, CODE
1 .text 000055b7 00411000 00411000 00000400 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .rdata 00002281 00417000 00417000 00005a00 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .data 00000200 0041a000 0041a000 00007e00 2**2
CONTENTS, ALLOC, LOAD, DATA
4 .idata 00000ade 0041b000 0041b000 00008000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .msvcjmc 00000104 0041c000 0041c000 00008c00 2**2
CONTENTS, ALLOC, LOAD, DATA
6 .00cfg 00000109 0041d000 0041d000 00008e00 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .rsrc 0000043c 0041e000 0041e000 00009000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .reloc 00000584 0041f000 0041f000 00009600 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
SYMBOL TABLE:
no symbols
C
복사
아래는 일반적인 섹션과 해당 섹션에서 가지고 있는 정보이다.
.bss //초기화 되지 않은 데이터 섹션
.data //초기화 된 데이터 섹션
.rdata //읽기 전용 데이터 섹션
.CRT //읽기 전용 C Runtime 데이터 섹션
.test // 코드 섹션
.testbss //증분 링크(incremetal link) 옵션이 설정된 경우 컴파일러에 의해 생성되는 섹션
.rsrc // Resource 섹션
.debug // 디버그 정보 섹션
.idata // Import Name Table Section
.didata // Delay Import Name Table
.edata // export Name Table
.reloc // 재배치 테이블 정보
.tls // Thread Local Storage 정보 섹션
.xdata // Exception handler table
C
복사
중분 링크 알아보기
아래는 IDA에서 추출한 Import Table Section이다
모두 외부 참조 extrn 함수이다.
.idata:0041B000 ; Section 5. (virtual address 0001B000)
.idata:0041B000 ; Virtual size : 00000ADE ( 2782.)
.idata:0041B000 ; Section size in file : 00000C00 ( 3072.)
.idata:0041B000 ; Offset to raw data for section: 00008000
.idata:0041B000 ; Flags 40000040: Data Readable
.idata:0041B000 ; Alignment : default
.idata:0041B000 ;
.idata:0041B000 ; Imports from KERNEL32.dll
.idata:0041B000 ;
.idata:0041B000 ; ===========================================================================
.idata:0041B000
.idata:0041B000 ; Segment type: Externs
.idata:0041B000 ; _idata
.idata:0041B000 ; LPVOID __stdcall HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes)
.idata:0041B000 ?? ?? ?? ?? extrn __imp__HeapAlloc@12:dword
.idata:0041B000 ; CODE XREF: _RTC_GetSrcLine(uchar *,wchar_t *,ulong,int *,wchar_t *,ulong)+2CE↑p
.idata:0041B000 ; DATA XREF: _RTC_GetSrcLine(uchar *,wchar_t *,ulong,int *,wchar_t *,ulong)+2CE↑r ...
.idata:0041B004 ; BOOL __stdcall IsDebuggerPresent()
.idata:0041B004 ?? ?? ?? ?? extrn __imp__IsDebuggerPresent@0:dword
.idata:0041B004 ; CODE XREF: failwithmessage+DF↑p
.idata:0041B004 ; ___scrt_fastfail+DB↑p
.idata:0041B004 ; DATA XREF: ...
.idata:0041B008 ; void __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR *lpArguments)
.idata:0041B008 ?? ?? ?? ?? extrn __imp__RaiseException@16:dword
.idata:0041B008 ; CODE XREF: notify_debugger+46↑p
.idata:0041B008 ; DATA XREF: notify_debugger+46↑r ...
.idata:0041B00C ; int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCCH lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
.idata:0041B00C ?? ?? ?? ?? extrn __imp__MultiByteToWideChar@24:dword
.idata:0041B00C ; CODE XREF: failwithmessage+61↑p
.idata:0041B00C ; failwithmessage+80↑p
.idata:0041B00C ; DATA XREF: ...
.idata:0041B010 ; int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar)
.idata:0041B010 ?? ?? ?? ?? extrn __imp__WideCharToMultiByte@32:dword
.idata:0041B010 ; CODE XREF: failwithmessage+173↑p
.idata:0041B010 ; failwithmessage+1A8↑p
.idata:0041B010 ; DATA XREF: ...
.idata:0041B014 ; BOOL __stdcall QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount)
.idata:0041B014 ?? ?? ?? ?? extrn __imp__QueryPerformanceCounter@4:dword
.idata:0041B014 ; CODE XREF: __get_entropy+43↑p
.idata:0041B014 ; DATA XREF: __get_entropy+43↑r ...
.idata:0041B018 ; DWORD __stdcall GetCurrentProcessId()
.idata:0041B018 ?? ?? ?? ?? extrn __imp__GetCurrentProcessId@0:dword
.idata:0041B018 ; CODE XREF: __get_entropy+33↑p
.idata:0041B018 ; DATA XREF: __get_entropy+33↑r ...
.idata:0041B01C ; void __stdcall GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
.idata:0041B01C ?? ?? ?? ?? extrn __imp__GetSystemTimeAsFileTime@4:dword
.idata:0041B01C ; CODE XREF: __get_entropy+12↑p
.idata:0041B01C ; DATA XREF: __get_entropy+12↑r ...
.idata:0041B020 ; BOOL __stdcall TerminateProcess(HANDLE hProcess, UINT uExitCode)
.idata:0041B020 ?? ?? ?? ?? extrn __imp__TerminateProcess@8:dword
.idata:0041B020 ; CODE XREF: ___raise_securityfailure+21↑p
.idata:0041B020 ; DATA XREF: ___raise_securityfailure+21↑r ...
.idata:0041B024 ; HANDLE __stdcall GetCurrentProcess()
.idata:0041B024 ?? ?? ?? ?? extrn __imp__GetCurrentProcess@0:dword
.idata:0041B024 ; CODE XREF: ___raise_securityfailure+1A↑p
.idata:0041B024 ; DATA XREF: ___raise_securityfailure+1A↑r ...
C
복사