-
PE 구조 (5) - 계산기의 PE 구조 / NT HEADER - IMAGE OPTIONAL HEADER 분석Knowledge/Reversing 2019. 9. 25. 02:11
오늘은 계산기의 NT Header에서 IMAGE OPTIONAL HEADER에대해서 분석하려고 한다.
꽤나 중요한 녀석임으로 차근차근히 분석을 시작해보자.
우선 복습을 위하여 몇 가지 저번에 배운 내용을 확인해보자.
이것이 calc.exe의 NT header 영역이다.
그리고 NT header 구조체는
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;로 정의되어 있고 지난 포스터에서 FileHeader 부분을 알아봤었다.
https://shineild-security.tistory.com/73
오늘 알아볼 구조체는 IMAGE_OPTIONAL_HEADER이다.
일단 정의된 구조를 확인해보자.
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;가장 마지막 변수를 보면 IMAGE_DATA_DIRECTORY 라는 구조체 배열이 나온다.
IMAGE_NUMBEROF_DIRECTORY_ENTRIES는 16으로 정의되어 있다.
그리고 IMAGE_DATA_DIRECTORY 구조체의 구조를 보면
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;로 정의되어 있는 것을 확인 할수 있다.
정의된 구조체의 크기를 계산해보면 1 * 2 + 2 * 9 + 4 * 19 + 8 * 16 = 224 (0xE0)으로 앞서서 IMAGE FILE HEADER에 정의되있던 크기인 E0과 같은 것을 확인 할 수 있다.
여러 변수들이 선언되어있는데 우리가 알아봐야할 것은 일부분이다.
Magic : 32 & 64 bit 표현
AddressOfEntryPoint : 프로그램의 시작주소
ImageBase + AddressOfEntryPoint = 상대적 시작 주소
BaseOfCode : code 영역의 시작 주소
BaseOfData : data 영역의 시작 주소
SectionAlignment : 메모리 상의 최소 단위
FileAlignment : 파일 상의 최소 단위
SizeOfImage : PE 파일이 메모리에 load되어 있는 상태의 크기
SizeOfHeader : PE 헤더의 전체 크기
Subsystem : 1 - Driver, 2 - GUI, 3 - CUI
NumberOfRavAndSizes : IMAGE_DATA_DIRECTORY DataDirectory의 배열 길이DataDirectory : 각 항목별로 정의된 값이 존재한다.
// Directory Entries
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor#define IMAGE_DIRECTORY_ENTRY_RESERVED 15 // Reserved Directory
우리는 여기서 EXPORT(0), IMPORT(1), RESOURCE(2), TLS(9)만 집중해서 보면 된다.
그럼 이제 하나하나 값을 확인해보자!
MAGIC : 0B 01 (10B)
10B : 32 bit
20B : 64 bit
AddressOfEntryPoint : 75 24 01 00 (12475)
Entry Point의 RVA 값을 갖고 있다.
즉 프로그램이 시작되면 최초로 실행되는 코드의 시작 주소이다.
한번 확인해보자.
올리디버거를 키면 12475부터 시작하는 것을 확인할 수 있다!
BaseOfCode : 00 10 (10 00)
code 영역의 시작 주소이다.
밑에 언급한 imagebase의 주소의 값과 더한 1001000에 코드영역이 시작되는지 확인해 보자.
BaseOfData : 00 40 01 (14000)
아까 위에 사진을 보면 ASCII dump 칸을 보면 01014000에서부터 시작하는 것을 확인할 수가 있다!
ImageBase : 00 00 00 01 (1000000)
프로세스 가상메모리의 값으로 프로그램이 로드될때 eip는 imagebase값과 AddressOfEntry point 값을 더해서 로딩이 된다.
앞서 baseofcode와 baseofdata를 보면 알겠지만 실제 메모리에 맵핑될 때 더해지는 값이다.
SectionAlignment : 00 01 (100)
메로리상의 최소 단위로 100(h) 단위로 패딩된다.
FileAlignment : 00 02 (200)
파일 상의 최소 단위가 200으로 패딩된다.
SizeOfImage : 00 F0 01 (1F000)
PE 파일이 메모리에 로딩되엇을 때 가상 메모리에서 PE Image가 차지하는 크기가 1F000이라는 뜻이다.
SizeOfHeader : 00 04 (400)
PE header의 전체 크기로 이전글들에서
똥꼬쇼하며 구했던 녀석이 여기 있다...Subsystem : 02
1 : Driver file = 시스템 드라이버 (ex: ntfs.sys)
2: GUI file = 창 기반 애플리케이션 (ex: notepad.exe)
3: CUI file = 콘솔 기반 애플리케이션 (ex: cmd.exe)
NumberOfRvaAndSizes : 10
가끔 16이 아닐 경우도 있으니 확인을 꼭 해주자!
지금 같은 경우는 정의된 경우와 같이 16값을 나타내고 있다.
대망에 DataDirectory부분이다.
4바이트 변수 2개를 갖고 있는 구조체 배열로 하나당 8bytes씩 보면 된다.
첫번째는 가상주소 값이고 두번째는 사이즈를 표시한다.
[0]에는 값이 없으므로 넘어가고 [1]인 Import값을 확인해 보자.
80 2B 01이 주소로 적혀있다. 확인해보자.
12B80은 RVA의 값으로 offset값을 계산해야하는데 이건 섹션별 주소를 알때 계산이 쉽다.
고로 이 부분은 섹션 헤더를 정리한 후에 따로 작성하도록 하겠다.
절대 졸려서 그만 쓰는거 아닙니다.'Knowledge > Reversing' 카테고리의 다른 글
PE 구조 (7) RVA to RAW 변환 방법 (2) 2019.09.28 PE 구조 (6) - 계산기의 PE 구조 / SECTION Header (0) 2019.09.26 PE 구조 (4) - 계산기의 PE 구조 / NT HEADER - IMAGE FILE HEADER 분석 (0) 2019.09.20 PE 구조 (3) - 계산기의 PE 구조 / PE offset 확인하는 법 (2) 2019.09.18 PE 구조 (2) - PE의 기본 구조 (0) 2019.05.16