Sh4n3e
Reversing[3] - PE(1) 본문
오늘은 PE(Portable Executable) 파일 구조에 대해 설명해 보겠습니다.
우선은 구조에 들어가기 앞서 간단한 정의를 집어보고 넘어가겠습니다.
PE 파일이란? Portable Executable 파일의 약자로 명령(Operation Codes, OP Codes)에 따라 지시된 작업을 수행하도록 작성된 파일로 실행코드, 전역데이터, Import/Export 함수정보, 리소스 데이터 등을 포함하고 있는 파일이라고 할 수 있습니다. 이 파일은 여러 개의 구조체로 엮여 있으며, 윈도우 커널의 PE로더를 통해 실행가능한 파일로 판단되었을 때, 메모리에 프로그램을 올림으로써 실행할 수 있게 됩니다.
이 구조를 가지고있는 파일의 종류로는 실행파일(EXE), 라이브러리(DLL, LIB), 드라이버(SYS), 오브젝트(OBJ) 등의 파일이 있습니다.
PE_Format_Layout.pdf
다음의 첨부 파일은 PE 구조에 대한 큰 그림을 구조체로써 보여주는 파일로 참고하시면 좋을 것같아 공유합니다.
이제 PE구조에 대해서 조금 더 자세히 살펴보도록 하겠습니다.
첫째로 PE 구조는 다소 생소할 수 있는 3 가지의 주소표현방식을 사용하고 있습니다. 3가지를 살펴보자면 아래와 같습니다.
- VA(Virtual Address) : 가상 메모리상의 절대주소, VA = ImageBase(메모리상에서 기준이 되는 주소) + RVA
- RVA(Relative Virtual Address) : 기준(ImageBase) 위치에서의 상대주소, PE 파일 내부데이터는 RVA 형식으로 메모리 위치가 지정된다.
- RAW : PE 파일내에서의 오프셋(offset)
PE구조는 크게 DOS Header, PE Header, Section Table, 각 Section들로 구성되어 있습니다.
DOS Header는 다음의 그림과 같습니다.
여기서 중요한 부분은 e_magic와 e_lfanew입니다. e_magic는 PE파일의 시그니쳐인 MZ를 나타내주고 있으며, e_lfanew는 IMAGE_NT_HEADER의 시작 위치를 알려줍니다. 직접 바이너리를 통해 설명드리겠습니다. 바이너리를 읽는 방법은 Little-Endian 방식으로써 거꾸로 읽어야 합니다. e_lfanew를 보시면 값이 0xE8000000 이지만 Little-Endian 방식으로 읽게되면 오른쪽->왼쪽 방향으로 읽게 됩니다. 따라서 e_lfanew의 값은 0x000000E8인 것 입니다.
현재 보이는 부분은 IMAGE_DOS_HEADER, DOS_STUB, IMAGE_NT_HEADERS를 보여주고 있습니다.
IMAGE_DOS_HEADER->e_lfanew를 통해서 IMAGE_NT_HEADERS로 넘어갈 수 있습니다. 이때 IMAGE_NT_HEADERS는 IMAGE_FILE_HEADER과 IMAGE_OPTIONAL_HEADER로 나뉠 수 있는데, 위의 0x100부터 IMAGE_OPTIONAL_HEADER가 시작됩니다. 중요한 부분은 빨간 BOX와 이름을 명시해 놓았으니 참고하시기 바랍니다. 조금만 더 상세히 중요한 부분이 무엇을 의미하는지 말씀드리겠습니다.
1) Number of Section : Section의 수 (현재는 0x05 : 5개의 섹션 존재)
2) Size of Optional Header : Optional Header의 크기 (현재는 0xE0 : 0xE0 크기 만큼의 Optional Header)
3) Magic : 0x10B : 32bit, 0x20B 64bit
4) Size of code : 실행 코드가 포함된 섹션의 크기 (보통 .text 영역, 현재는 0x30000)
5) Address of Entry Point : 프로그램 시작점(Entry Point)의 RVA (현재는 0x8370)
6) Image Base : 메모리(가상 주소 공간) 내에 PE 파일이 로딩되는 시작 주소
=> exe기본 Image Base : 0x400000
=> dll기본 Image Base : 0x100000
다음은 IMAGE_SECTION_HEADER입니다. 해당 섹션은 IMAGE_OPTIONAL_HEADER 이후에 SECTION의 개수 만큼 해당 SECTION의 정보를 담고 있는 HEADER입니다. 위의 초록색 박스로 되어있는 Number of Section의 개수만큼 SECTION이 존재합니다. 각 섹션은 0x28만큼의 크기를 가지고 있습니다.
여기서 중요한 부분은 Name과 VirtualSize, VirtualAddress, SizeOfRawData, PointerToRawData, Characteristics입니다. 다음 그림을 통해 좀더 자세히 보도록 하겠습니다.
현재 빨간색 Box로 표시된 부분은 .text Section에 해당되는 헤더입니다. 각각 명칭별로 무슨의미를 가지고 있는 것인지 알아보겠습니다.
1) Name : 섹션 이름(최대 8바이트)
2) Virtual Size : 섹션 데이터의 실제 바이트 수
3) Virtual Address : 메모리에서 해당 섹션이 시작하는 주소(RVA) (현재 0x1000)
4) Size Of Raw Data : 파일에서 섹션이 차지하는 크기 (현재 0x30000)
5) Pointer to Raw Data : 파일에서 섹션의 시작 위치 (현재 0x1000)
6) Characteristics : 섹션의 속성(해당 속성의 읽기 권한이 부여되어있는지, 쓰기, 실행 권한이 있는지의 속성)
우리는 PE파일을 분석하면서 RVA(가상메모리주소)와 RAW(파일오프셋)을 매핑할 줄 알아야 합니다. 이 방법은 RAW = RVA - VirtualAddress + PointerToRawData의 계산을 이용해서 실제 파일에 위치를 따라갑니다. 이 부분은 Section내에서 사용하는 것이기 때문에 추후에 어떻게 사용되는지 보여드리겠습니다.
다음으로는 Section의 종류에 대해서 한번 알아보겠습니다.
Section |
Description |
.text |
실행 코드가 포함되는 섹션 |
.rdata |
읽기 전용 데이터가 저장되는 섹션 |
.data |
초기화된 전역 변수를 담고 있는 섹션 (읽기, 쓰기 가능) |
.idata |
IAT(Import Address Table) 관련 정보가 존재하는 섹션 |
.edata |
EAT(Export Address Table) 관련 정보가 존재하는 섹션 |
.pdata |
64bit 실행 파일에만 포함되며, 예외 처리와 관련된 정보가 저장됨 |
.rsrc |
리소스 데이터가 포함되는 섹션 |
.reloc |
라이브러리 파일들의 재배치(relocation) 정보를 담고 있는 섹션 |
다음 시간에는 Import Table에 대한 설명과 함께, Import Table 분석 및 수정에 대해서 알아보도록 하겠습니다.
'System Hacking > Reverse Engineering' 카테고리의 다른 글
Debugger 단축키 (0) | 2017.06.16 |
---|---|
DLL 작성 및 로딩 방법 (0) | 2015.12.24 |
Reversing[4] - PE(2) (0) | 2015.10.08 |
Reversing[2] (0) | 2015.10.06 |
Reversing[1] (0) | 2015.10.06 |