반응형
  • NT Header

NT Header 부분에는 IMAGE_NT_HEADERS 구조체가 존재 하고, 구조체의 크기는 F8 이다.

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, FileHeader, Optionalheader 이 3개의 멤버로 되어 있는데,

 

NT Header의 첫번째 멤버는 Signature로 50450000 ("PE"00)의 값을 가진다.

NT Header 시작부분

50 45으로 되어있는 오프셋부터 NT Header의 시작이다.


NT Header의 두번째 멤버는 FileHeader로 구조체 형식으로 되어 있다

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;

FileHeader의 구조체 멤버들 중에서는 이 1 ~ 4 멤버가 제일 중요하다. 5는 그냥 번외다 알면 좋은

  1. Machine
  2. NumberOfSections
  3. SizeOfOptionalHeader
  4. Characteristics
  5. TimeDateStamp

 

1. Machine은 CPU별로 고유한 값이며 Machine 안에는 CPU마다 다른 값들이 들어간다.

이 정보들은 winnt.h 헤더 파일에 정의 되어 있다.

0x8464가 들어있는 모습.

 

 

2. PE파일은 코드, 데이터, 리소스 등이 각각의 섹션에 나뉘어서 저장되는데, NumberOfSections 이 섹션의 개수를 나타낸다 반드시 0보다 커야한다.

0x0007이 들어있는 모습.
Die로 확인해도 섹션에 7이 들어있다.

 

 

3. SizeOfOptionalHeader는 (Optionalheader가 미리 나오는데), NT Header의 마지막에 있는 Optionalheader의 구조체 인 IMAGE_OPTIONAL_HEADER32 의  크기를 나타낸다. C언어의 구조체라 크기가 이미 결정되어 있지만, PE로더는 이것을 보고 Optionalheader의 구조체 크기를 인식한다.

Optionalheader의 크기는 0x00F0이다.

 

   SizeOfOptionalHeader와 e_lfanew멤버의 범위를 이상하게 지정하면 꽈배기 PE파일을 만들 수 있다.

 

   32비트 PE는 IMAGE_OPTIONAL_HEADER32

   64비트 PE는 IMAGE_OPTIONAL_HEADER64

 

 

 

4. Characteristics는 처음 말했던 파일의 속성을 나타내는 값으로 이 파일이 실행 가능한 형태인지, DLL파일인지 등의    정보들이 bit OR 형식으로 조합된다. 이 정보들도 winnt.h 헤더 파일에 정의 되어있다.

#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  
#define IMAGE_FILE_DLL                       0x2000  // File is a DLL.

이런 식으로 값을 조합하여 Characteristics안에 들어가게 된다.

0x0022로 된 파일의 속성.

 

5. TimeDateStamp는 실행에 영향을 미치지 않으며 파일의 빌드 시간을 나타낸 값이다.

0x4178AED3의 값을 가지는 빌드 시간.


NT Header의 세번째 멤버로 Optionalheader 는 IMAGE_OPTIONAL_HEADER32라는 구조체를 가진다.

(아까 나왔던) IMAGE_FILE_HEADER의 SizeOfOptionalHeader옵션이 이 구조체의 크기를 나타내는 것이다.

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_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은 이 구조체가 32bit용이라면 0x10B의 값을,64bit용이라면 0x20B의 값을 가지게 된다.

 

2. AddressOfEntryPointEP(Entry Point) 의 RVA(Relative Virtual Address) 값을 가지고 있다.

  • RVA값이기 때문에 실제 EP의 VA(실제 주소)는 AddressOfEntryPoint+ImageBase이다.
  • PE로더는 파일을 메모리에 올리고 EIP를 AddressOfEntryPoint+ImageBase로 설정한다.

 

3. ImageBase는 PE파일이 메모리에 로딩되는 시작 주소를 나타낸다.

 

4. SectionAlignment, FileAlignment들은 하나씩 보면

  • 파일에서 섹션의 최소 단위를 나타내는것이 FileAlignment이다.
  • 메모리에서 섹션 최소 단위를 나타내는것이 SectionAlignment이다.
  • 그렇기 때문에 파일/메모리의 섹션 크기는 반드시 각각 FileAlignment/SectionAlignment 의 배수가 되어야 한다.

 

5. SizeOflmagePE파일이 메모리에 로딩됐을 때 가상 메모리(VA)에서 PE Image(PE구조)가 차지하는 크기를 나타낸다.

 

6. SizeOfHeaderPE header 의 전체 크기를 나타냅니다.

  • 이 값 역시 FileAlignment 의 배수 이어야 한다.
  • 파일 시작에서 SizeOfHeader 옵셋만큼 떨어진 위치에 첫번째 섹션이 위치한다. 
  • PE header 다음에는 PE body니까 첫번째 섹션이 오게 되는거다.

 

7. Subsystem은 이 값을 보고 무슨 파일인지 알 수 있다.

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

 

8. NumberOfRvaAndSizes는 바로 밑에 있는 IMAGE_DATA_DIRECTORY 구조체의 배열의 크기를 정합니다.

  • 구조체에 #define으로 16이라고 크기가 정해져있지만 windows에서는 이 값을 보고 구조체 배열의 크기를 정한다.

 

9. DataDirectory는 바로 위에 있던 멤버가 크기를 가르키던 IMAGE_DATA_DIRECTORY 구조체의 배열로써, 배열의 각 항목마다 정의된 값을 가지게 된다.

DataDirectory[0] = EXPORT Directory        
DataDirectory[1] = IMPORT Directory        
DataDirectory[2] = RESOURCE Directory     
DataDirectory[9] = TLS Directory

일부만 가져왔는데, 빨간색으로 표시한 EXPORT, IMPORT, RESOURCE, TLS Directory 이 4개가 중요하고,
특히 IMPORT 와 EXPORT Directory 구조는 PE header 에서 매우 중요하다고 한다. (책 뒤에 나온다고 한다.)

이것들을 이미지로 확인해보면,

IMAGE_OPTIONAL_HEADER32

Magic : 020B (64bit)

AddressOfEntryPoint : 00024050

Imagebase : 00000001

SectionAlignment : 00001000

FileAlignment : 00000200

SizeOfImage : 03800000

SizeOfHeader : 04000000

Subsystem : 0200

NumberOfRvaAndSizes : 00000010 (0x10 == 16)

 

 

NT_header 끝

 

 

 

 

 

다음에는 Section Header 하겠습니다.

반응형

'윈도우 > PE 구조' 카테고리의 다른 글

PE 구조 (6) - IAT  (0) 2022.04.19
PE 구조 (5) - (RVA to RAW) 예제 포함  (0) 2022.04.05
PE 구조 (4) - (Section Header)  (0) 2022.04.02
PE구조 (2) - (DOS Header, DOS Stub)  (0) 2022.03.30
PE 구조 (1) - (PE File Format, VA & RVA)  (0) 2022.03.29