리버스 엔지니어링-006 PE-01

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 파일은 구조화되어 있습니다. 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