앞에서 살펴본 FILE HEADER에 이어서 이번에는 Optional Header에 대해서 알아보자.
Optional Header는 좀 길어서 2개로 나누어 볼까 한다.
data directory와 그 앞부분으로 말이다.
Optional Header의 크기는 앞에서 살펴본 File Header의 SizeOfOptionalHeader 필드에 정의 되어 있다.
그럼 1차 분석을 시작해보자.!
=========================================================================================
우선 WinNT.h에 정의된 구조체를 봐보자 ^__^
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;//
// NT additional fields.
//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;
아고 길다.. ^^;;
Optional Header는 3부분으로 쪼갤 수 있다.
Standard fields와 Nt additional fields, 그리고 DataDirectory이다.
우선 Standard fields 부분의 필드들을 살펴보자.
Standard fields는 실행에 필요한 정보들을 가지고 있다.
차근차근 하나 씩 짚어보자.
Magic : 이미지 파일의 타입을 명시한다. 기본적인 PE 파일이라면 0x10B의 값을 가진다.
PE32+ 포맷이라면 0x20B의 값이고, 롬 이미지일 경우 0x107의 값을 가진다.
MajorLinkerVersion
MinorLinkerVersion : 링커의 버전을 알려준다.
SizeOfCode : Code 섹션의 크기를 명시한다.
SizeOfInitializedData : 초기화된 데이터 섹션의 크기를 명시한다.
SizeOfUninitializedData : 초기화되지 않은 데이터 섹션의 크기를 명시한다.
AddressOfEntryPoint : 파일이 메모리에 로드된 후 엔트리 포인트 주소를 명시한다.
이 주소 값은 base address부터의 RVA이다.
* RVA는 Relative Virture Address의 약자로 어떤 기준점으로부터의 오프셋을 기준으로 하는 주소이다. VA와는 다른다.
BaseOfCode : Code 섹션의 시작 오프셋을 명시한다.
BaseOfCode : Data 섹션의 시작 오프셋을 명시한다.
여기까지가 Standard fields에 해당하는 부분이다. 음. AddressOfEntryPoint 필드 값은 쓸만할 거 같기도 하지만 실제로 사용해볼 용도가 없었기 때문에 잘 모르겠다 ^^;
다음은 NT additional fields를 알아보자.
ImageBase : 로드되었을 때 파일의 base address를 명시한다.
기본적으로 0x00400000의 값을 가지고, DLL의 경우 0x10000000의 값을 가진다.
이 주소를 사용하지 못 할 경우 File Header의 Chararicteristic 필드 값에 따라
행동이 달라진다. 하지만 기본적으로 Windows는 VA이기 때문에 정상적으로
로드될 것이다.
SectionAlignment : 메모리에 로드되었을 때 섹션의 정렬 값이다.
바이트 단위로 명시된다. 기본적으로 이 값은 Page 값과 같다.
FileAlignment 값보다는 크거나 같아야 한다. 일반적으로는 같다.
FileAlignment : 파일이 하드 드라이버에 저장될 때 쪼개지는 기본 단위이다.
SectionAlignment와 마찬가지로 바이트 단위로 명시된다.
기본 값은 512이지만 512에서 64K 사이의 수 중 2의 배수를 가질 수 있다.
MajorOperatingSystemVersion
MinorOperatingSystemVersion : 필요한 OS의 버전 정보를 명시한다.
MajorImageVersion
MinorImageVersion : 이미지의 버전을 명시한다.
사용자가 /VERSION 옵션으로 임의로 지정할 수 있다.
MajorSubsystemVersion
MinorSubsystemVersion : 사용하는 서브시스템의 버전을 명시한다.
Win32VersionValue : VC++ 6.0까지는 예약된 공간이였으며 7.0에 와서 필드명이 개조되었다.
하지만 여전히 사용되지 않는 것 같다.
SizeOfImage : 이미지의 크기로써 로드될 때 확보해야 할 메모리 공간의 크기이기도 하다.
파일의 실제 크기와 같을 수도 있지만 SectionAlignment 값에 따라 커지기도
한다.
SizeOfHeader : MS-DOS 스텁, PE 헤더(시그니처, File Header, Optional Header),
섹션 헤더의 크기를 합친 값으로 FileAlignment 필드 값의 배수이다.
CheckSum : 이미지가 로드되면서 검사할 때 사용하는 값이다.
무결성을 검사한다.
Subsystem : 사용하는 서브시스템을 명시한다.
기본적으로 가장 많이 명시되는 것이 1, 2, 3이다.
1은 IMAGE_SUBSYSTEM_NATIVE로 드라이버처럼 따로 서브시스템을
사용하지 않는 경우 사용한다.
2는 IMAGE_SUBSYSTEM_WINDOWS_GUI로 Windows 그래픽 환경(GUI)을
사용한다.
3은 IMAGE_SUBSYSTEM_WINDOWS_CUI로 Windows의 콘솔 환경(CUI)를
사용한다.
그 외 더 자세한 내용은 WinNT.h를 참조하여라.
DLL Characteristics : 몇 개 안되서 정리는 하지만 이해가 안되는 부분이 있다.
조금 더 공부를 해보아야 할 거 같다.
파일이 DLL일 경우에 지정된다.
IMAGE_DLLCHARACTERISTICS_NO_BIND
-> 로드되었을 때 바인딩하지 않는다. <- 무슨 의미인지 잘..
IMAGE_DLLCHARACTERISTICS_WDM_DRIVER
-> 드라이버가 WDM 형식을 따랐음을 명시한다.
IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
-> 터미널 서버가 이미지를 인식할 수 있다.
즉, 터미널 어플리케이션이 알 수 없는 이미지를 서버가 실행
할 수 있도록 실행에 필요한 파일들을 같이 로드 한다.
LoaderFlags : 현재 사용되지 않는 필드이다.
NumberOfRvaAndSize : DataDirectory의 개수를 명시한다.
16으로 고정되었다고 할 수 있다.
여기까지가 NT additional fields라고 볼 수 있다.
이 분에서 필요한 정보라고 한다면 ImageBase정도가 되겠다.
정보를 명시할 뿐 뭔가 딱히 결정적인 역활을 하지는 않는 듯하다. ^^;;