Malware Analysis/PE

#2 PE - File Header

geunyeong 2021. 8. 1. 02:20

Abstract

PE 포맷의 DOS 헤더의 e_lfanew 멤버가 File Header의 위치를 가리킨다.  File Header에는 PE 파일이 실행될 수 있는 머신(32/64 비트) 종류를 포함해 OptionalHeader의 크기, 섹션 개수, PE 파일 속성 등을 포함한다.

File Header

IMAGE_FILE_HEADER structure

PE 헤더에서 File 헤더는 파일의 개략적인 속성을 나타낸다. PE32 파일인지 PE32+(64비트 프로그램)인지도 File 헤더를 통해 알 수 있다. File 헤더는 DOS 헤더가 e_lfanew 멤버를 통해 가리키던 NT 헤더의 멤버로 포함되어 있다. winnt.h를 통해 IMAGE_NT_HEADERS 구조체를 살펴보면 아래와 같다.

typedef struct _IMAGE_NT_HEADERS64 {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

32비트 프로그램으로 빌드할지 64비트 프로그램으로 컴파일할지에 따라 IMAGE_NT_HEADERS가 달라지지만 IMAGE_FILE_HEADER는 두 프로그램 모두 동일하다. IMAGE_FILE_HEADER는 아래와 같다.

//
// File header format.
//

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;

주요 멤버는 Machine, NumberOfSections, SizeOfOptionalHeader, Characteristics다.

Machine

실행파일이 실행될 수 있는 CPU 종류를 나타내는 값이다. Intel x86 계열(32비트 프로그램)은 14Ch라는 값을 가지고 AMD64(64비트 프로그램)은 8664h 값을 가진다. 이를 통해 실행 파일이 32비트 프로그램인지 64비트 프로그램인지 구별할 수 있다.

 

32비트와 64비트 PE 파일의 FileHeader.Machine 값

 

현재 winnt.h에 정의된 Machine 값들은 아래와 같다.

#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_TARGET_HOST       0x0001  // Useful for indicating we want to interact with the host and not a WoW guest.
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5               0x01a8  // SH5
#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2  // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT             0x01c4  // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33              0x01d3
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1
#define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE           0x0520  // Infineon
#define IMAGE_FILE_MACHINE_CEF               0x0CEF
#define IMAGE_FILE_MACHINE_EBC               0x0EBC  // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R              0x9041  // M32R little-endian
#define IMAGE_FILE_MACHINE_ARM64             0xAA64  // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE               0xC0EE

NumberOfSections

PE 파일이 가지는 섹션의 개수다. PE 파일을 패치할 때 섹션을 삭제하거나 늘리는 경우 섹션 헤더를 추가하고, 섹션 데이터를 삽입하는 것 외에도 File 헤더의 NumberOfSections 값을 조정해야 한다. 그렇지 않으면 정상적으로 실행되지 않는다. sample32.exe의 SizeOfSections는 4이며, 섹션 헤더를 보면 4개의 섹션이 있는 걸 볼 수 있다.

 

FileHeader.NumberOfSections
섹션 헤더들

 

SizeOfOptionalHeader

앞서 Machine 멤버 값을 보고 32/64비트를 구분할 수 있다고 했다. 하지만 SizeOfOptionalHeader 멤버 값으로도 구분이 가능하다. 14Ch나 8664h는 흔하기 때문에 바로 구별할 수 있지만 Machine은 CPU를 구별하는 값이기 때문에 두 값 외에 다른 값도 들어갈 수 있다. 일반적인 경우 32/64비트 sizeof(IMAGE_OPTIONAL_HEADERS)는 아래와 같은 값을 가진다.

  • 32비트: sizeof(IMAGE_OPTIONAL_HEADER32) == 224
  • 64비트: sizeof(IMAGE_OPTIONAL_HEADER64) == 240

32비트와 64비트 PE 파일의 FileHeader.SizeOfOptionalHeader 값

 

PE 헤더를 심하게 꼬아버리는 패커들은 SizeOfOptionalHeader 값도 바꿔치기 때문에 32비트와 64비트를 구별하는 가장 좋은 방법은 IMAGE_OPTIONAL_HEADER의 매직넘버 값을 보는 것이다.

Characteristics

PE 파일의 속성을 나타낸다. 실행 가능한 EXE 파일인지, 단독으론 실행이 불가능한 DLL 파일인지 등의 정보가 담긴다. 속성 값들은 OR 연산을 통해 하나 이상의 정보가 담긴다. EXE 파일은 2가, DLL 파일은 2000h 비트가 1로 설정된다.

#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved external references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Aggressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM                    0x1000  // System File.
#define IMAGE_FILE_DLL                       0x2000  // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.

32비트 프로그램의 Characteristics 값을 CFF Explorer로 살펴보면 EXE 파일이며, Relocation이 이루어지지 않고, 32비트 머신에서 동작하는 프로그램이란 걸 알려주고 있다. 빌드 시 ASLR 옵션을 끄고 빌드하면 IMAGE_FILE_RELOCS_STRIPPED 비트가 1로 설정되고 .reloc 섹션이 생성되지 않는다.

 

FileHeader.Characteristics 플래그

'Malware Analysis > PE' 카테고리의 다른 글

#6 PE - .reloc 섹션  (0) 2021.08.01
#5 PE - IAT  (0) 2021.08.01
#4 PE - Section Header  (0) 2021.08.01
#3 PE - Optional Header  (1) 2021.08.01
#1 PE - DOS Header  (0) 2021.07.31