티스토리 뷰

Reversing/ETC

[Reversing] IMAGE_NT_HEADER

정뚱띵 2019. 2. 11. 20:23
728x90
반응형

[Reversing] IMAGE_NT_HEADER



  1. IMAGE_NT_HEADER
typedef struct _IMAGE_NT_HEADERS {



DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;



} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;


위 그림은 IMAGE_NT_HEADER 구조체입니다. 해당 구조체는 4byte 크기의 Signature 그리고 IMAGE_FILE_HEADER, IMAGE_OPTIONAL_HEADER32이 있습니다.


1.1 Signature

가장 먼저 Signature입니다. 

IMAGE_NT_HEADER 구조체의 시작부분인 Signature는 실행파일이 시작하는 부분입니다. 

여기에는 항상 'PE\0\0'라는 데이터가 고정으로 들어있습니다.

헥사코드로는 '0x50450000'라는 값이 들어있습니다. 'PE\0\0'입니다.


1.2 IMAGE_FILE_HEADER

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.2.1. Machine

먼저 가장 처음에 자리잡은 Machine 필드입니다.

https://docs.microsoft.com/ko-kr/windows/desktop/api/winnt/ns-winnt-_image_file_header

링크에서 보듯 Machine 필드의 값에 따른 의미를 설명하고 있습니다.


 0x014c

인텔 아키텍쳐 32비트 환경에서 동작한다는 의미입니다. 

 0x0200

인텔 아키텍쳐 64비트 환경에서 동작하다는 의미입니다.

 0x8664

 AMD 계열 64비트를 의미하는 것으로 알고있습니다.


해당 필드는 리틀인디언 방식으로 데이터가 쓰이며, 64비트 환경에서 동작하는 실행파일이라는 것을 알 수 있습니다.


1.2.2. NumberOfSections

NumberOfSections 해당 필드는 해당 파일이 가지고 있는 섹션의 수를 나타냅니다.

해당 필드 역시 리틀 인디언 방식으로 저장되는 값입니다.


1.2.3. SizeOptionalHeader

IMAGE_OPTIONAL_HEADER 구조체의 크기에 대한 정보를 가지고 있습니다.



IMAGE_OPTIONAL_HEADER 구조체의 크기는 '0x00E0' = 224byte 크기를 갖는 걸 확인 할 수 있습니다.


1.2.4. Characteristics

각 특성별로 부여된 헥사코드가 있습니다

 0x0001

파일에 대한 재배치 정보가 없으므로, 기본 주소에 로드 되어야한다는 의미입니다.

 0x0002

확인되지 않은 외부참조가 없고, 파일이 실행가능하다는 의미입니다.

 0x0004

COFF 라인 번호가 파일에서 삭제되었다는 의미입니다.

 0x0008

COFF 라인 번호가 파일에서 삭제되었다는 의미입니다.

 0x0010

적극적으로 워킹 셋을 정리해야한다는 의미입니다

 0x0020

응용 프로그램이 2GB보다 큰 주소를 처리할 수 있다는 의미입니다.

 0x0080

단어의 바이트가 반대로 되어있다는 의미입니다.

 0x0100

 32비트 단어를 지원한다는 의미입니다.

 0x0200

 디버깅 정보가 해당 파일에 없고 다른 파일에 저장되어있다는 의미입니다.

 0x0400

 파일이 이동식 미디어에 있는경우, 그것을 복사하여 스왑파일에서 실행한다는 의미입니다.

 0x0800

 파일이 네트워크상에 있는 경우, 그것을 복사하여 스왑파일에서 실행한다는 의미입니다.

 0x1000

 파일이 시스템 파일임을 의미합니다.

 0x2000

 파일이 DLL 파일이며, 이것이 실행파일이지만 직접 실행할 수는 없다는 의미입니다.

 0x4000

 파일이 단일 프로세서 컴퓨터에서만 실행되어야 한다는 의미입니다.

 0x8000

 단어의 바이트가 반대로 되어있다는 의미입니다.


파일의 특성에 따라 해당하는 헥사코드들을 더한 값을 Characteristics 필드에 저장합니다.


1.3 IMAGE_OPTIONAL_HEADER

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.3.1 Magic

이전의 IMAGE_DOS_HEADER 구조체에서 e_magic이라는 필드와 같이 IMAGE_OPTIONAL_HEADER의 Magic 필드 역시 해당 구조체의 시작을 알려주는 특정 값으로 고정이 되어있습니다.


 32비트

0x10B 

 64비트

0x20B 


헥사에디터에서는 리틀인디언 방식으로 확인 할 수 있습니다.


1.3.2 AddressOfEntrypoint

해당 필드는 EP 즉, EntryPoint라고 하는 주소값을 가지고 있습니다.

EntryPoint의 RVA 값이 저장되어 있습니다.

EntryPoint란 로더에 의해 PE파일이 로딩되고나서 가장 먼저 시작되는 소스코드의 시작점입니다.(제일 먼저 시작되는 소스코드의 시작점)


PEiD와 같은 툴을 통해 확인 해보겠습니다.

위 그림은 PEiD를 이용하여 notepad.exe를 확인하였습니다.

확인 시 AddressOfEntrypoint 필드에 저장되어 있던 값과 동일한 값이 표시되어 있을 것 입니다.


1.3.3 ImageBase

이 ImageBase 필드에 저장되어 있는 값은 PE파일이 로드되는 위치 입니다.

해당 값이 링커에 의해서 설정이 되며, 일반적으로 0x00400000 입니다.

지만, DLL 파일의 경우에는 일반적으로 해당 값이 0x10000000 입니다.

이 값들은 절대적인 값들이 아니라고 합니다. 일반적인 값이지..


파일을 실행하게 되면 프로세스의 어디엔 존재하는 가상 메모리 주소 공간에 올라갑니다.(mapping)

이 과정을 통해 가상 메모리 주소 공간에 자리를 잡는데 그게 ImageBase를 가르킵니다. 

즉, 시작주소를 알려주는 부분입니다


다음으로 VA(실제 메모리에 로딩되는 주소)를 구하고자 한다면 Image Base주소와 RVA주소를 더하면 됩니다.


1.3.4 SectionAlignment

섹션이라는 것은 실제 프로그램을 구성하는 코드 내에서 선언하는 전역변수나 static변수 등을 담고 있는 것 입니다.

그러면 Alignment란?

얼라이먼트라는 작업은 '일정하게 정렬한다'는 것을 의미합니다.

그러면 SectionAlignment는 뭘까요?
SectionAlignment는 메모리 상에서 섹션을 정렬하는 단위라고 합니다.

PEView를 통해 SectionAlignment 필드의 값을 보면 0x00001000 입니다. (4096byte)

즉, 이값을 기준으로 섹션들이 정렬된다는 것입니다.


예를 들어 .text 섹션(512byte)과 .data 섹션(5632byte)이 연속되어 나열된 섹션이라고 할때, 

.text 섹션의 데이터의 크기가 작아 빈공간이 생기더라도 섹션의 절대 단위인 4096byte를 할당합니다. .text 섹션시 끝나고 3584byte 빈공간이 지나고 나서야 .data 섹션이 시작합니다.

그럼 .data는 총 8192byte를 할당 받겠죠?


이런 섹션의 단위를 설정하는 필드가 SectionAlignment 필드 입니다.


1.3.5 FileAlignment

FileAlignment 필드 역시 절대 단위를 설정하는 값을 저장하는 필드입니다.

하지만 SectionAlignment 필드는 메모리상에서의 섹션 단위를 설정하였고, FileAlignment 필드는 디스크 상에서 섹션 절대 단위를 설정합니다.


Peview를 통해 확인해보세요

SectionAlignment 필드 값과 같다면 디스크 상에서와 메모리 상에서의 PE 파일의 모습이 같다고 생각하시면 됩니다.


1.3.6 SizeOfImage

SizeOfImage 필드는 메모리 상에 로그된 PE 파일의 전체 크기입니다.(SectionAlignment 필드 섹션의 절대 단위의 배수)


1.3.7 SizeOfHeader

SizeOfHeader 필드는 PE 헤더의 크기값을 저장합니다.

400h 부터 첫번째 섹션이 시작한다는 걸 확인 할 수 있습니다.

다음을 확인 해보면 400h 앞까지는 빈공간입니다. 이것은 위에서 설명한 Alignment에서의 절대 단위와 같은 개념이라 생각하시면 됩니다.


1.3.8 Subsystem

해당 필드는 GUI 기반인지 드라이버 파일인지 등의 설정값을 가지고 있습니다.

 0x01

.sys 확장자를 갖는 드라이버 파일 

 0x02

GUI 기반

 0x03

CLI 기반



728x90
반응형

'Reversing > ETC' 카테고리의 다른 글

[Reversing] IMAGE_SECTION_HEADER  (0) 2019.02.12
[Reversing] PE 포맷(Portable Executable)  (0) 2019.02.12
[Reversing] IMAGE_DOS_HEADER  (0) 2019.02.08
[Reversing] PE 파일 구조 찾기  (0) 2019.01.31
[Reversing] PE 파일 구조  (0) 2019.01.30
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
250x250