ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 13 PE File Format(2) - PE 헤더(DOS Header, NT Header,섹션 헤더)
    리버싱 엔지니어링/리버싱 핵심 원리 2022. 3. 23. 15:03

     PE 헤더 

    : PE 헤더는 많은 구조체로 이루어짐

     

     DOS Header 

    : 당시 사용되던 DOS 파일에 대한 하위 호한성을 고려해서 제작됨 

    • PE 헤더 제일 앞부분에 IMAGE_DOS_HEADER 구조체가 존재
    typedef struct _IMAGE_DOS_HEADER {
          WORD e_magic;        //DOS signature : 4D5A("MZ")
          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;         // offset to NT header 
    } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
    • 구조체 크기 : 40
    • 중요 멤버 : e_magic, eIfanew

    e_magic : DOS signature (4D5A => ASCII 값 "MZ")

    e_Ifanew : NT header의 옵셋을 표시(파일에 따라 가변적인 값을 가짐)

    • 모든 PE파일은 시작부분에 DOS signature("MZ")가 존재하고, e_Ifanew 값이 가리키는 위치에 NT Header 구조체가 존재해야 함

     

    hex editor로 IMAGE_DOS_HEADER 구조체 확인해보기

    notepad.exe

    • 파일 시작 2바이트 : 4D5A
    • e_Ifanew = 000000E0 (리틀엔디언 표기법, E0000000 X)

     

     DOS stub 

    : DOS Header 밑에 존재. DOS Stub 존재 여부는 옵션이며, 크기도 일정하지 않음

     

    • DOS Stub는 코드와 데이터의 혼합으로 이루어짐

     

    hex editor로  DOS Stub 확인해보기

    notepad.exe

    •  파일 옵셋 40~4D 영역은 16비트 어셈블리 명령어, 따라서 32비트,64 비트에서는 실행되지 않음
    • Dos 용 디버거를 이용해서 실행하면 "This is program cannot be run in DOS mode"를 출력할 수 있다.

     

    DOS 환경에서 실행하기

    * Windows XP 환경에서만 가능 

     

    ① 커맨드 창에 debug C:\Windows\notepad.exe 입력

    ② 'u' 명령어(Unassemble) 입력 -> 16비트 어셈블리 명령어가 나타남

    ③ 화면에 "This is program cannot be run in DOS mode" 출력 후 종료

     

     

     NT Header  

    • NT header 구조체 IMAGE_NT_HEADERS
    typedef struct _IMAGE_NT_HEADERS {
      DWORD                   Signature;  // PE Signature : 50450000 ("PE"00)
      IMAGE_FILE_HEADER       FileHeader;
      IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

    멤버

    • Signature : 5045000h ("PE"00)
    • FileHeader
    • Optional Header

     

    hex ditor로 IMAGE_NT_HEADERS 살펴보기

    • IMAGE_NT_HEADERS 구조체의 크기 : F8

     

     NT Header  - File Header

    : 파일의 개략적인 속성을 나타냄  

     

    • 구조체 IMAGE_FILE_HEADERS
    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

    : Machine 넘버는 CPU별로 고유한 값이며 32비트 Intel x86호환 칩은 14C의 값을 가짐

     

    • 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

     

    #2 NumberOfSections

    : 섹션의 개수

    • 반드시 0보다 커야함

     

     

    #3 SizeOfOptionalHeader

    : IMAGE_OPTIONAL_HEADER32 구조체의 크기

    • C언어의 구조체이기 때문에 이미 크기가 결정되어있으나, Windows PE 로더는 해당 값을 보고 크기를 인식함
    • PE32+  형태의 파일인 경우 IMAGE_OPTIONAL_HEADER64 구조체 사용
      • 32와 구조체 크기가 다름. 따라서, SizeOfOptionalHeader 멤버에 크기 명시

     

     

    #4 Characteristics

    : 파일의 속성을 나타내는 값.

    • 실행이 가능한 형태인지(executalble or not) 혹은 DLL 인지 등의 정보들을 bit OR 형식으로 조합

     

    • winnt.h 파일에 정의된 Cahracteristics(0002h, 2000h 기억)
    #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.
    • 0002h가 없는 경우(not executable) : *.obg와 같은 object 파일 및 resource DLL 같은 파일

    기타 멤버 : TimeDate Stamp

    : 해당 파일의 빌드 시간을 나타낸 값

    • 파일 실행에 영향을 미치지 않음
    • 개발 도구에 따라 이 값을 세팅해주는 도구(VB, VC++)가 있고, 그렇지 않은 도구(Delphi)가 있다. 

    hex editor로 IMAGE_FILE_HEADER 구조체 확인하기

    • 위 사진을 알아보기 쉽게 구조체 멤버로 표현 (안보고 작성해보기 ↓)

     

    [ IMAGE_FILE_HEADER ] - notepad.exe

    offset value description
    ------------------------------------------------------------------------------------------------------------------------
    000000E4 014C machine
    000000E6 0003 number of sections
    000000E8 48025287 TimeDateStamp
    000000EC 00000000 pointer to symboltable
    000000F0 00000000 number of symbols
    000000F4 00E0 size of optional header
    000000F6 010F characteristics
             IMAGE_FILE_RELOCS_STRIPPED
         IMAGE_FILE_EXECUTABLE_IMAGE
         IMAGE_FILE_LINE_NUMS_STRIPPED
         IMAGE_FILE_LOCAL_SYMS_STRIPPED
         IMAGE_FILE_32BIT_MACHINE


     NT Header  -  Optional Header  

    • (PE헤더 구조체 중 크기가 가장 큰) IMAGE_OPTIONAL_HEADERS 구조체
    typedef struct _IMAGE_DATA_DIRECTORY {
      DWORD                VirtualAddresss;
      DWORD                Size;
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY
    
    #define IMAGE_NUMBEROF_DIRECTIRY_ENTRIES 16
    
    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 Magic

    : Magic 넘버는 IMAGE_OPTIONAL_HEADER32 구조체인 경우 10B, IMAGE_OPTIONAL_HEADER64 구조체인 경우 20B 값을 가짐

     

     

    #2 AddressOfEntryPoint

    : EP의 RVA값, 프로그램에서 최초로 실행되는 코드의 시작 주소 

     

     

    #3 ImageBase

    : 메모리에서 PE파일이 로딩되는 시작 주소 

    • 32비트의 경우, 프로세스의 가상 메모리는 0~FFFFFFFF
      • EXE, DLL 파일은 user memory 영역인 0~7FFFFFFF 범위에 로딩-   일반적으로 개발 도구(VB/VC++/Delphi)들이 만들어내는 EXE 파일의 Image Base 값은 00400000, DLL 파일의 ImageBase 값은 10000000  
      • SYS 파일은 kernel memory 영역인 80000000~FFFFFFFF 범위에 로딩
    • PE 로더는 PE 파일을 실행시키기 위해 프로세스를 생성하고 파일을 메모리에 로딩 후 EIP 레지스터 값을 ImageBase + AddressOfEntryPoint 값으로 세팅

     

     

    #4 SectionAlignment, FileAlignment

    : PE 파일의 Body는 섹션으로 나누어져 있음. 이 섹션의 최소단위

    • FileAlignment : 파일에서 섹션의 최소 단위
    • SectionAlignment : 메모리에서  섹션의 최소 단위
    • 파일/메모리의 섹션 크기는 각각 FileAlignment/SectionAlignment의 배수가 되어야함.

     

     

    #5 SizeOfImage

    : PE 파일이 메모리에 로딩되었을 때 가상 메모리에서 PE Image가 차지하는 크기

    • 일반적으로 파일의 크기와 메모리에 로딩된 크기는 다름

     

     

    #6 SizeOfHeader

    : PE 헤더의 전체 크기

    • FileAlignment의 배수여야 함.
    • 파일 시작에서 SizeOfHeader 옵셋만큼 떨어진 위치에 첫 번째 섹션이 위치함. 

     

     

    #7 Subsystem

    : 시스템 드라이버(*.sys) 파일인지, 일반 실행 파일(*.exe, *dll)인지 구분

     

    • Subsystem 멤버
    의미 비고
    1 Driver file 시스템 드라이버(예 : ntfs.sys)
    2 GUI(Graphic User Interface) 창 기반 애플리케이션(예 : notepad.exe)
    3 CUI(Console User Interface) 콘솔 기반 애플리케이션(예 : cmd.exe)

     

     

    #8 NumberOfRvaAndSizes

    : IMAGE_OPTIONALHEADER32 구조체의 마지막 멤버인 DataDirectory 배열의 개수를 나타냄

    • 구조채 정의에 IMAGE_NUMBEROF_DIRECTORY_ENTRIES(16)이라고 명시되어 있지만, PE 로더는 NumberOfRvaAndSizes의 값을 보고 배열의 크기를 인식함

     

     

    #9 DataDirectory

    : IMAGE_DATA_DIRECTORY 구조체의 배열

     

    • DataDirectory 구조체 배열
    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_DESCRIPTOR Directory 
    DataDirectory[F] = Reserved Directory
    • EXPORT, IMPORT, RESOURCE, TLS Directory

     

    hex ditor로 IMAGE_OPTIONAL_HEADER 구조체 확인하기

    notepad.exe

     

     섹션 헤더 

    : 각 섹션의 속성(property)

     

    • PE 파일이 code, data, resource 등을 각각의 섹션으로 나누어 저장했을 때 좋은 점 : 프로그램의 안전성 
      • 만약, data에 값을 쓰다 overflow가 발생했을 때 바로 다음의 code를 그대로 덮어써버린다면 프로그램 오류 발생
      • 따라서, 비슷한 성격의 자료를 모으고 각 섹션의 속성을 기술할 섹션 헤더가 필요해진 것
    • 섹션의 속성 : file/memory에서의 시작 위치, 크기, 엑세스 권한 등
    • 메모리 속성별 액세스 권한
    종류 액세스 권한
    code 실행, 읽기 권한
    data 비실행, 읽기, 쓰기 권한
    resource 비실행, 읽기 권한

     

    IMAGE_SECTION_HEADER

    • IMAGE_SECTION_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;
      DWORD SizeOfRawData;
      DWORD PointerToRawData;
      DWORD PointerToRelocations;
      DWORD PointerToLinenumbers;
      WORD  NumberOfRelocations;
      WORD  NumberOfLinenumbers;
      DWORD Characteristics;
    } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

    중요 멤버

    항목 의미
    VirtualSize 메모리에서 섹션이 차지하는 크기
    VirtualAddress 메모리에서 섹션의 시작 주소(RVA)
    SizeOfRawData 파일에서 섹션이 차지하는 크기
    PointerToRawData 파일에서 섹션의 시작 위치
    Characteristics 섹션의 속성(bit OR)
    • VirtualAddress와 PointerToRawData는 SectionAlignment와 FileAlignment에 맞게 결정됨
    • VirtualSize와 SizeOfRawData는 일반적으로 서로 다른 값을 가짐 → 파일에서의 섹션 크기와 메모리에 로딩된 섹션의 크기는 다름
    • Characteristics는 아래 코드에 표시된 값들의 조합(bit OR)으로 이루어짐
    #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 writeable.

    Name 멤버

    • C언어의 문자열처럼 NULL로 끝나지 않고 ASCII 값만 와야한다는 제한도 없음
    • 어떠한 명시적 규칙이 없어 NULL로 채워도 됨. 즉, 참고용

     

    hex ditor로 IMAGE_OPTIONAL_HEADER 구조체 확인하기

     

     

    댓글

Designed by Tistory.