0. 들어가며
- PE (Portable Executable) 파일은 Windows 운영체제에 사용되는 실행파일 형식
- 32비트의 경우 PE32 / 64비트의 경우 PE+ 혹은 PE32+ 라고부르며 PE파일의 확장 형태
1. PE File Format
1) PE 파일 종류
종류 주요 확장자
실행 계열 | EXE, SCR |
라이브러리 계열 | DLL, OCX, CPL, DRV |
드라이버 계열 | SYS, VXD |
오브젝트 파일 계열 | OBJ |
- OBJ 파일을 제외한 모든 것은 실행 가능한 파일
- DLL, SYS는 쉘에서 직접 실행은 불가능하지만 다른 형태의 방법으로 실행 가능
(1) 기본 구조
- 메모장은 일반적인 pe파일의 기본구조로 구성
- Dos header부터 Section header 까지 = PE 헤더
- 그 밑 부분의 Section = PE 바디
- 파일에서는 offset / 메모리에서는 VA로 위치를 표시
- 메모리에 로딩되면 모양이 변경되어 보여짐
- NULL padding 존재 = 처리 효율을 높이기위해 최소 기본 단위 사용
- → 남은 빈 부분을 NULL로 채움
(2) VA&RVA
- VA : 프로세스 가상 메모리의 절대주소
- RVA : 기준 위치로부터의 상대주소
- RVA + ImageBAse = VA
- PE헤더 내의 정보는 RVA 형태가 많음 → 다른 PE 파일과 충돌이 일어나지 않게 재배치 시 액세스가 가능하도록 RVA 사용
3) PE Header
(1) DOS Header
- PE 파일 포맷을 만들 당시 DOS 파일에 대한 호환성을 고려하여 만들어짐
- PE헤더의 앞부분에는 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;
- 구조체의 크기는 40이며, e_magic과 e_lfanew를 꼭 알아두자
- 첫 번째 필드 e_magic : DOS Signature ( MZ ⇒ ASCII 0x5A4D) 리틀 엔디안으로 4D 5A 형식으로 보여짐
#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
- 마지막 필드 e_lfanew : NT header의 옵셋 표시 해당 값이 가리키는 위치에 NT header의 구조체가 존재
→ NT header의 시작이 100인것을 마지막 필드를 통해 확인 가능
(2) DOS Stub
- DOS Stub의 존재 여부는 옵션
- 메모장의 경우 16비트에서 사용되는 DOS용 코드가 DOS Stub에 존재
- 이 특성을 활용하여 하나의 실행 파일에 두 환경에서 모두 실행 가능한 파일을 생성 가능
(3) NT Header
typedef struct _IMAGE_NT_HEADERS
{
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADER32, *PIMAGE_NT_HEADER32;
- 첫 번째 멤버 : Signature → 해당 파일의 구조가 PE인것을 확인 가능
- 두 번째 멤버 : File_Header
- 세 번쩨 멤버 : Optional_Header
(4) NT Header - 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;
#1 Machine
- cpu별로 고유한 값
#2 NumberOfSections
- pe파일이 가지고 있는 섹션의 개수를 나타내며 반드시 0보다는 커야함
#3 SizeOfOptionalHeader
- 32비트와 64비트의 optional header 구조체의 크기가 다르므로 크기를 명시
#4 Characteristics
- 파일의 속성을 나타내는 값
사진에 나와있는 것을 통해 파일의 속성이 무엇인지 확인 가능
(5) - 1 / NT Header - IMAGE_OPTIONAL_HEADER32
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;
#1 Machine
- 32비트의 경우 10B, 64비트의 경우 20B
#2 AddressOfEntryPoint
- Entry Point의 RVA값을 가지고 있음 (프로그램에서 최초로 실행되는 코드의 주소)
#3 ImageBase
- pe파일이 로딩되는 시작 주소를 나타내며
- 메모리 로딩 후 EIP값을 ImageBase + AddressOfEntryPoint 값을 세팅
#4 SectionAlignment, FileAlignment
- 파일/섹션의 최소단위를 나타내는 것
- 해당 최소 단위의 배수로 크기를 가져야함
#5 SizeOfImage
- pe파일이 메모리에 로딩되었을때 가상 메모리에서 PE Image가 차지하는 크기
#6 SizeOfHeader
- PE 헤더의 전체 크기를 나타내며, FileAlignment의 배수임
#7 Subsystem
- 일반 실행 파일인지 시스템 드라이버인지 구분
#8 NumberOfRvaAndSizes
- 마지막 멤버인 DataDirectory의 배열 개수
#9 DataDirectoy
- 각 항목마다 정의된 값을 가짐
(5) - 2 / NT Header - IMAGE_OPTIONAL_HEADER64
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;
- IMAGE_OPTIONAL_HEADER32 큰 차이를 보이지는 않음
- 해당하는 PE파일의 비트를 통해 파악 가능
- 현재 분석하는 메모장은 64비트 형식 사용
- 첫 멤버인 Magic이 20B = 64비트
(6) Section Header - IMAGE_SECTION_HEADER
- 각 섹션의 속성을 정의
- code, data, resource 등 각각의 섹션 표현
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;
#1 주요멤버
#2 Name
- pe 파일에서의 어떠한 명시적 규칙x
- 참고용으로 적어놓는 것
- 총 7개의 섹션으로 이루어져있음
'Security > Reversing' 카테고리의 다른 글
실행 압축 & UPX 패킹 (1) | 2023.07.23 |
---|---|
리버싱 / 악성코드 분석을 위한 Windows 10 Defender 비활성화 (0) | 2023.07.11 |
Calling Convention (함수 호출 규약) (0) | 2023.07.06 |
스택프레임 (0) | 2023.07.05 |
PE파일 (1) | 2023.07.03 |