2020. 4. 2. 21:25ㆍ보안/리버싱
내용 : Windows 운영체제의 PE File Format에 대해 공부한다. Windows 운영체제의 가장 핵심적인 부분인 Process, Memory, DLL 등에 대한 내용을 정리한다.
PE File Format
기본 구조
PE 헤더 -> DOS 헤더, DOS Stup, NT 헤더, Section 헤더
DOS 헤더
제작 당시 DOS 파일에 대한 하위 호환성을 고려하여 제작함 / 가장 먼저 나오는 부분.
IMAGE_DOS_HEADER 구조체가 존재함
typedef struct _IMAGE_DOS_HEADER
{
WORD e_magic; //DOS signature {4D5A}
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
LONG e_lfanew; // NT header의 옵셋을 표시 (파일에 따라 가변적임)
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
DOS stup
파일에 따라 존재여부가 달라짐, Windows Os에서는 실행되지 않음.(PE 파일이라 인식하기 떄문임.)
DOS 모드에서 실행가능
NT Header
FileHeader / OptionalHeader을 가짐
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; //4
IMAGE_FILE_HEADER FIleHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} Image_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
IMAGE_FILE_HEADER
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; // CPU 별 고유 값을 가짐 | (X86 : 0X14C, X64 : 0X8664)
WORD NumberOfSections; //섹션의 개수 0보다 큰 값을 가짐, 정의된 값과 실제 값이 다르면 에러
DWORD TimeDateStamp; // 빌드 시간
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader; //IMAGE_OPTIONAL_HEADER32의 크기를 나타낸다
// PE32+ 형태 파일의 경우 IMAGE_OPTIONAL_HEADER64 구조체 사용 -> 두 구조체의 크기가 다르기 때문에
// 구조체 크기를 명시함
WORD Characteristics; // 파일의 속성을 나타냄, 실행가능한 형태인지 bit OR 방식으로 조합
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
IMAGE_OPTIONAL_HEADER
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic; //IMAGE_OPTIONAL_HEADER32 구조체 : 10B, "64 구조체 : 20B값을 가짐
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint; //EP의 RVA값을 가지고 있음, 프로그램 실행시 최초로 실행되는 코드의 시작 주소
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
// 프로세스의 가상 메모리 주소(X86) : 0 ~ FFFFFFFF
// EXE | DLL 로딩 주소 : 0 ~ 7FFFFFFF -> USER MEMORY SECTOR
// SYS 로딩주소 : 80000000 ~ FFFFFFFF -> KERNEL SECTOR
// 개발도구가 만들어내는 EXE의 IMAGE BASE : 00400000
// DLL 파일의 IMAGEBASE : 10000000
// PE 로더는 PE 파일 실행을 위해 EIP값을 IMAGEBASE + AddressOfEntryPoint 값으로 세팅
DWORD SectionAlignment; //메모리에서 섹션의 최소단위를 나타내는것
DWORD FileAlignment; // 파일에서 섹션의 최소 단위를 나타내는것
// * 파일에서 SectionAlignment와 FileAlignment의 값은 같거나 다를수 있음
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage; //PE 파일이 로딩되었을 때, 가상메모리에서 PE Image가 차지하는 크기
DWORD SizeOfHeaders; //PE 헤더의 전체 크기
DWORD CheckSum; //64
WORD Subsystem;
//시스템 드라이버(.sys)인지 일반 실행파일(.exe | .dll)인지 구분할 수 있음
// 1. Driver file - 시스템 드라이버
// 2. GUI file - 창 기반 에플리케이션
// 3. CUI file - 콘솔 기반 에플리케이션
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
//IMAGE_OOPTIONAL_HEADER32 구조체의 마지막 멤버인 DataDirectory 배열의 개수를 나타냄.
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
//구조체의 배열로, 각 배열 항목을 나열함
//아래에 구조체 배열 첨부
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
파일 실행에 필수적이어서, 잘못 세팅되면 파일이 정상실행이 되지 않는다.
/* DATA DICTIONARY */
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_RESCRIPTOR Directory
DataDirectory[F] = Reserved Directory
Export, Import, resource, TLS Dictionary 눈여겨보기
특히, IMPORT, EXPORT Dictionary는 중요한 역할을 함
PE 바디 -> Section (text, data, rsrc)
IMAGE_OPTIONAL_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; // 메모리에서 섹션의 시작주소 (RVA)
DWORD SizeOfRawData; // 파일에서 섹션이 차지하는 크기
DWORD PointerToRawData; //파일에서 섹션의 시작 위치
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics; // 섹션의 속성 (bit OR)
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
VirtualAddress와 PointerToRawData는 각각 IMAGE_OPTIONAL_HEADER32에 정의된 SectionAlignment와 FileAlignment에 맞게 결정된다.
VirtualSize와 SizeOfRawData는 일반적으로 서로 다른 값을 가진다.
(파일에서 섹션 크기와, 메모리에 로딩된 섹션의 크기는 다름.)
#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0X00000040 // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data.
#define IMAGE_SCN_MEM_EXECUTE 0X20000000 // Section is executable.
#define IMAGE_SCN_MEM_READ 0x40000000 //Section is readable.
#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writable.
위 코드는 Characteristics 파일의 형식이다.
#PE파일이 메모리에 로딩될 때 파일이 그대로 올라가는것이 아니라, 섹션 헤더에 정의된 대로 시작주소, 섹션 크기 등에 맞춰서 올라가게 된다. 따라서 파일에서의 PE와 메모리에서의 PE는 서로 다른 모양을 가진다.
이를 구별하기 위해서 메모리에 로딩된 상태를 이미지라는 용어를 사용하여 구별한다.
RVA to RAW
PE파일이 메모리에 로딩되었을 때 각 섹션에서 메모리의 주소(RVA)와 파일 옵셋을 매핑할 수 있어야 한다.
이러한 매핑 방법을 RVA to RAW라고 한다.
=======================================
1. RVA가 속해있는 섹션을 찾는다.
2. 간단한 비례식을 사용하여 파일 옵셋(RAW)을 계산한다.
=======================================
IMAGE_SECTION_HEADER에 따르면 비례식은
RAW - PointerToRawData = RVA - VirtualAddress
RAW = RVA - VirtualAddress + PointerToRawData
#해당 내용은 리버싱 작업에서 가장 기본이 되는 내용이므로 꼭 숙지하기!
'보안 > 리버싱' 카테고리의 다른 글
[Reversing] 리버싱 핵심원리 [11]. abex' Crack Me 4 풀이 (0) | 2020.03.15 |
---|---|
[Reversing] 리버싱 핵심원리 [10]. abex' Crack Me 3 풀이 (0) | 2020.03.15 |
[Reversing] 리버싱 핵심원리 [9]. Lena's Reversing for Newbies 1 (1) | 2020.03.12 |
[Reversing] 리버싱 핵심원리 [8]. 함수 호출 규약 (0) | 2020.03.03 |
[Reversing] 리버싱 핵심원리 [7 - 2]. abex' 2nd crackme 풀이 - 시리얼코드 생성 함수 분석 (0) | 2020.03.02 |