본문 바로가기

리버스 엔지니어링

NT 헤더 -2

HT Header-optional Header


PE 헤더 구조체 중에서 가장 크기가 큰 IMAGE_OPTIONAL_HEADER32이다.


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; 



IMAGE_OPTIONAL_HEADER32 구조체에서 주목할 맴버에 대해 살펴보자.



1. Magic

 Magic 넘버는 IMAGE_OPTIONAL_HEADER32 구조체인 경우 10B,  IMAGE_OPTIONAL_HEADER64 구조체인 경우 20B를 가진다.



2. AddressOfEntryPoint

 AdressOfEntryPoint는 EP(EntryPoint)의 RVA(Relative Virtual Address)값을 가지고 있다. 이 값은 프로그램에서 최초로 실행되는 코드의 주소로 매우 중요한 값이다.


3. ImageBase

 프로세스의 가상 메모리는 0~FFFFFFFFF 범위이다.(32bit인 경우) ImageBase는 이렇게 광활한 메모리에서 PE 파일이 로딩되는 시작 주소를 나타낸다.

 EXE,DLL 파일은 user memory 영역인 0~7FFFFFFFF 범위에 로딩되고 SYS 파일은 kernel memory 영역인 80000000~FFFFFFFFF 범위에 로딩된다. 일반적으로 개발도구들이 만들어내는 EXE 파일의 Image Base 값은 00400000이고 DLL 파일의 ImageBase 값은 10000000이다. PE로더는 PE파일을 실행시키기 위해 프로세스를 생성하고 파일을 메모리에 로딩한 후 EIP 레지스터 값을 ImageBase + AddressOfEntryPoint 값으로 세팅한다.


4. SectionAlignment, FileAlignment

PE 파일의 Body 부분은 섹션으로 나뉘어져있다, 파일에서 섹션의 최소 단위를 나타내는 것이 FileAlignment이고 메모리에서 센셕의 최소 단위를 나타내는 것이 SectionAlignment이다. (하나의 파일에서 FileAliignment 와 SectionAlignment는 다를수 있다.) 파일/메모리 섹션의 크기는 반드시 각각 SectionAlignment/FileAlignment의 배수가 되어야 한다.


5. SizeOfImage

SizeOfImage는 PE 파일이 메모리에 로딩되었을 때 가상 메모리에서 PE Image가 차지하는 크기를 나타낸다. 일반적으로 파일의 크기와 메모리에 로딩된 크기는 다르다.


6. SizeOfHeader

SizeOfHeader는  PE헤더의 전체 크기를 나타낸다. 이 값 역시 FileAliignment의 배수여야 한다.


7. SubSystem

이 SubSystem의 값을 보고 시스템 드라이버 파일(*.sys)인지 일반 실행파일(*.exe, *.dll)인지 구분 할 수 있다.  

1 : Driver file (*.sys)

2 : GUI (Graphic User Interface) 파일 -> notepad.exe 와 같은 윈도우 기반 어플리케이션

3 : CUI (Console User Interface) 파일 -> cmd.exe 와 같은 콘솔 기반 어플리케이션


8. NumberOfRvaAndSizes

NumberOfRvaAndSizes는 IMAGE_OPTIONAL_HEADER32 구조체의 마지막 맴버인 DataDirecroty 배열의 개수를 나타낸다. 구조체의정의에 분명히 배열 개수가 IMAGE_NUMBEROF_DIRECTORY_ENTRIES (16)라고 명시되어있지만 PE 로더는 .NumberOfRvaAndSizes의 값을 보고 배열의 크기를 인식합니다. 즉 16이 아닐수도 있다는 뜻.


9. DataDirectory

DataDirectory는 IMAGE_DATA_DIRECTORY 구조체 배열로 배열긔 각 항목마다 정의 된 값을 가진다.   

'리버스 엔지니어링' 카테고리의 다른 글

RVA to RAW  (0) 2018.01.18
섹션 헤더  (0) 2018.01.16
PE 헤더 -1  (0) 2018.01.11
PE File Format -1  (0) 2018.01.10
함수 호출 규약  (0) 2018.01.10