PE(Portable Executable)파일은 말 그대로 옮겨다니면서 실행시킬수 있는 파일을 말합니다.
실행 계열 : EXE, SCR | 드라이버 계열 : SYS, VXD |
라이브러리 계열 : DLL, OCX, CPL, DRV | 오브젝트 파일 계열 : OBJ |
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;
여기서 중요한 값은 e_magic,e_lfanew 이렇게 2개가 있습니다.
여기서 e_magic의 값은 DOS signature로 MZ라는 문자열입니다.
(MZ는 Mark Zbikowski라고 DOS실행파일을 설계한 사람의 이니셜입니다.)
또한 e_lfanew의 값은 NT header의 RVA형태의 주소값을 가지고있습니다.
(이 값은 꼭 40이상의 크기를 가질 필요는 없습니다.)
실제로 계산기를 HxD로 열어보니 이렇게 나오네요.
2) DOS stub
DOS 에서 돌아갈 명령어가 16bit명령어 형태로 있습니다.
이 부분은 없어도 상관없고 크기도 정해져있지 않습니다.
여러 프로그램들을 분석해보았을때 보통 프로그램들은 This program cannot be run in DOS mode를 출력하고 꺼지게 만듭니다.
실제로 계산기도 그렇게 표시되고 꺼지게 되있네요.
3) 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;
NT header 구조체는 이렇게 크게 3개로 구분되 있습니다.
맨 첫번째 로는 Signature인데 이것은 PE라는 문자를 나타냅니다.
DOS signature과 마찬가지로 이 문자를 보면 아 이부분이 NT header의 시작이구나 하고 넘어갑시다.
실제로도 이렇게 나오는데 여기서 부터 NT header구조체의 시작이구나 하면서 판별을 합시다.
2번째 로는 IMAGE_FILE_HEADER 구조체 입니다.
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
IMAGE_FILE_HEADER구조체 에서는 바로 색칠된 4개의 값이 중요하다고 합니다.
1. Machine
Machine은 CPU별로 고유한 값을 가지면서 IA-32 호환 CPU는 14Ch의 값을, IA-64 호환 CPU는 200h의 값을 가집니다.
2. NumberOfSections
이 값은 이 다음에 나오는 Section들의 갯수입니다.
최소 1개 이상이여야 됩니다.
3. SizeOfOptionalHeader
이 값은 IMAGE_NT_HEADERS구조체의 마지막구조체 IMAGE_OPTIONAL_HEADER32의 구조체의 크기를 나타냅니다.
( 이 값과 e_lfanew값의 범위를 이상하게 지정할 수 있다는 것 때문에 변종 PE를 만들어 낼 수 있습니다.)
4. Characteristics
이 값은 드디어 맨처음부터 말한 이 파일의 속성에 대한 부분입니다.
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable
// (i.e. no unresolved externel 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 // Agressively 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.
실제로는 이렇게 나오며 여기있는 부분을 해석하면
Machine : 014C (=IA-32호환)
NumberOfSections : 4 (text,data,rsrc,reloc)
SizeOfOptionalHeader : 00E0
Characteristics : 0102 (IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE)
이렇게 파일들에 대한 정보를 얻어 낼 수 있습니다.
이 다음에는 마지막 구조체인 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;
이 구조체에서는 이렇게 색칠된 값이 중요하다고 합니다.
1. Magic
이 구조체가 32bit용이라면 10Bh의 값을,64bit용이라면 20Bh의 값을 가지게 됩니다.
2. AddressOfEntryPoint
EP의 RVA 주소값이 들어있습니다.
물론 RVA값이니까 실제 EP는 AddressOfEntryPoint+ImageBase이겠죠
3. ImageBase
PE파일이 맵핑되는 시작 주소를 가리킵니다.
4. SectionAlignment
메모리에서의 섹션의 최소단위를 나타냅니다.
5. FileAlignment
파일에서의 섹션의 최소단위를 나타냅니다.
4,5번의 최소단위를 맞추기 위해서 PE구조에서 각 section들이 끝나면 NULL값을 집어넣는 NULL padding이란 기술을 사용합니다.
6. SizeOfImage
메모리에서의 PE구조의 크기를 나타냅니다.
7. SizeOfHeader
PE header의 크기를 나타냅니다.
8. Subsystem
1의 값을 가지면 드라이버 파일(SYS, VXD)파일이란 뜻입니다.
2의 값을 가지면 GUI파일이란 뜻입니다.
3의 값을 가지면 CUI파일이란 뜻입니다.
9. NumberOfRvaAndSizes
바로 밑에 있는 IMAGE_DATA_DIRECTORY구조체의 배열의 크기를 정합니다.
(맨 처음에 #define으로 16이라고 크기가 정해져있지만
windows에서는 이 값을 보고 구조체 배열의 크기를 정합니다.)
실제 IMAGE_OPTIONAL_HEADER32 구조체 입니다.
분석을 해보면
Magic : 010B (=32bit)
Address of Entry point : 00012D6C
Imagebase : 01000000
Section Alignment : 1000
File Alignment : 200
Size of Image : 0C0000
Size of Headers : 400
Subsystem : 2
Number of Directoris : 10
이렇게 값이 나오는 것을 알 수 있습니다.
(Number of Directoris 왜 10이냐고 16이 아니냐고 하면 10h 는 16입니다.)
일단 이정도로 PE 구조 정리-1 을 끝내겠습니다.
읽어주셔서 감사합니다.
'리버스엔지니어링' 카테고리의 다른 글
간단한 리버싱 워게임-1 (0) | 2014.04.11 |
---|---|
reversing.kr 44위 달성! (0) | 2014.01.27 |
PE 구조 정리-2 (0) | 2013.07.21 |
레지스터 정리 (2) | 2013.07.11 |