PE 헤더(PE 헤더)
PE(Portable Executalbe File Format)
- Windows 실행 파일 형식을 의미합니다.
- 실행 파일 목록: EXE, SCR(화면 보호기)
- 라이브러리 유형: DLL, OCX(Active X)
- 드라이버 제품군: SYS
- 개체 파일 패밀리: OBJ
- Windows 환경에 따라 32비트(PE32) 또는 64비트(PE+ 또는 PE32+)라고 합니다.
- PE 파일을 통해 프로그램이 사용하는 API나 DLL, 로드된 메모리 주소 등 다양한 정보를 확인할 수 있습니다.
- Linux 또는 UNIX 환경에서 ELF(Executable and Linkable Format) 파일은 PE 파일과 유사한 형식으로 존재합니다.
빌드 프로세스
- obj 파일 -> (c/cpp) 파일 짓다그런 다음 컴파일러는 (c/cpp)의 모든 헤더 파일과 소스 파일을 병합합니다. 기계어 파일만든다
- 연결 작업 -> OS에서 파일을 실행하려면 링커~이다 동적 라이브러리, 다양한 리소스 데이터, 가져오기 및 내보내기 테이블을 처리할 수 있는 정보를 저장합니다.하다
- PE 형식 -> Windows에서 실행 및 배포용으로 생성된 파일 형식
소스 코드 작성 -> 컴파일바이너리 파일로 OBJ -> 필수 라이브러리 연동 -> exe 파일
PE 파일 구조
※ PE 파일은 구조화되어 있습니다. PE 구조를 보면 굉장히 복잡하지만 억지로 외우기보다는 많이 보고 익숙해지는 것이 중요합니다!!
IMAGE_DOS_HEADER(4D 5A)
- IMAGE_DOS_HEADER의 내용은 WinNT.H 헤더 파일의 구조 형식으로 설정됩니다.
- 이 구조에서 확인할 필드는 첫 번째 필드 e_magic과 마지막 필드 e_lfanew입니다.
- e_magic: 파일이 PE 구조인지 확인하기 위해 사용(4D 5A: MZ)
- 프로그램이 실행되면 먼저 2바이트(WORD)를 읽고 PE 구조가 올바른지 확인합니다.
- e_lfanew: 다음 IMAGE_NT_HEADER의 시작 주소 저장, 파일에 따라 다른 값
- 주소 값을 저장할 때 Little Endian 표기법을 사용하세요!!
typedef struct _IMAGE_DOS_HEADER{ // DOS의 .EXE HEADER
WORD e_magic; // ★ Magic Number (4D 5A : MZ)
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; // Maxmum 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 identigier (for e_ominfo)
WORD e_ominfo; // OEM information; e_oemid specific
WORD e_res2(10); // Reserved words
WORD e_lfanew; // ★ File addrs of new exe Header ->
// IMAGE_NT_HEADER 구조체 위치를 알아내는 데 사용!!
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
IMAGE_NT_HEADER(50 45 00 00 : PE\0\0)
- 파일 실행에 필요한 정보 저장
- WinNT.H의 구조체에서 e_lfanew에 저장된 주소 값이 이 부분을 가리킨다.
- 서명: 파일에 PE 구조가 있음을 나타내는 4바이트 공간 ASCII 코드 50 45 00 00(PE\0\0).
- File_Header: 운영 CPU, 섹션 수, 생성 시간 등 파일에 대한 일반 정보를 저장합니다.
- optional_header : 파일 실행에 필요한 중요 정보 저장
typedef struct _IMAGE_NT_HEADERS{
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HJEADERS32, *PIMAGE_NT_HEADERS32;
- 서명은 바이러스 생산자가 값을 표시하는 데 자주 사용되었습니다. 50 45 00 00이 아니면 악성코드에 감염되었음을 나타내기 위해 자주 사용된다.
IMAGE_FILE_HEADER
- 파일을 실행하기 위한 가장 기본적인 데이터를 담고 있는 구조체
typedf struct _IMAGE_FILE_HEADER{
WORD Machine;
WROD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWROD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FIEL_HEADER, *PIMAGE_FILE_HEADER;
- Machine: 이 파일을 실행할 수 있는 CPU를 나타냅니다.
- ★NumberOfSections: 얼마나 많은 섹션이 있는지 나타냅니다. 4개의 섹션이 있습니다: .text, .rdata, .data, .rsrc
- 값은 4로 표시됩니다. 패킹이나 보호로 인해 단면 수가 증가하면 이 값도 증가합니다!!
- TimeDataStamp: 이 파일이 빌드된 날짜를 표시합니다. 컴파일을 통해 obj 파일이 EXE로 생성된 시간
- 변조의 가능성이 있으므로 X를 완전히 신뢰하고 델파이의 경우 이 값을 정상적으로 저장 X -> 1992로 표시
- SizeOfOptionalHeader : IMAGE_OPTINAL_HEADER32의 구조 크기
- 특징: DLL인지 EXE인지 구별하기 위해 사용
이미지 선택사항_헤더
- PE 구조 중에서 가장 가중치가 많이 포함된 구조!!
typedef struct _IMAGE_OPTIONAL_HEADER{
// Standard Fileds
WORD Magic; // ★
BYTE MajorLinkerVersion; // ★
BYTE MinorLinkerVersion; // ★
DWORD SizeOfCode; // ★
DOWRD SizeOfInitializedData;
DOWRD SizeOFUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
// NT Additional Filedes
DWORD ImageBase; // ★
DOWRD 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;
IMAGE_DATA_DIRECTORY DataDirectory(IMAGE_NUMBEROF_DIRECTORY_ENTRIES); // ★
}IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32
- 매직: 32비트용 비트 마크 0x10B, 64비트용 0x20B
- SizeOfCOde: 코드 양의 총 크기입니다. 맬웨어는 이 필드를 읽고 자신의 코드를 복사할 위치를 결정합니다.
- MajorLinkerVersion 및 MajorLinkerVersion: 빌드된 컴파일러 버전을 알려줍니다.
- ImageBase: 파일이 실행될 때 가상 메모리에 실제로 업로드되는 주소를 가리킴(exe: 0x400000, dll: 0x10000000)
- AddressOfEntry: 메모리에서 실제 파일이 실행되는 시작점, Entry Point
- 포장을 풀 때 OEP(Original Entry Pointer)를 찾으면 바로 여기를 가리킵니다.
- BaseOfCode: 코드가 실제로 실행되는 주소
- ImageBase는 전체 PE 파일의 시작 주소이며 코드 영역이 시작되는 기준 주소는 BaseOfCode를 추가한 값입니다.
- SectionAlignment, FileAlignment: 섹션별 정렬을 위한 저장 단위
- SizeOfImage: EXE/DLL이 메모리에 로드될 때 총 크기
- SizeOfHeaders: PE 헤더의 크기를 알려주는 필드
- 하위 시스템: 이 프로그램이 CLI인지 GUI인지 알려주는 필드
- DataDirectory: IMAGE_DATA_DIRECTORY의 구조, VirtualAddress 및 Size라는 필드 포함
- 이 필드를 통해 각 내보내기 디렉토리, 가져오기 디렉토리, 자원 디렉토리 및 IAT의 가상 주소 및 크기를 확인하십시오.
typedef struct _IMAGE_DATA_DIRECTORY{
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
IMAGE_NUMBEROF_DIRECTORY_ENTERIES가 숫자 16으로 정의된 경우 각각에 대한 배열은 아래와 같습니다.
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // ★Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // ★Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // ★Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTRUE 7
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
#define IMAGE_DIRECTORY_ENTRY_TLS 9 //★ TLS Direcotry
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
#define IMAGE_DIRECTORY_ENTRY_IAT //★ Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
#define IMAGE_DIRECTORY_ENTRY_C0M_DESCRIPTOR