학사 나부랭이

Reversing - Portable Executable - PE header - Section header 본문

Dot-Gabi/Reversing

Reversing - Portable Executable - PE header - Section header

태양왕 해킹 (14세) 2021. 6. 4. 23:58

PE header - Section header

 섹션은 실제 파일의 내용이 존재하는 부분으로, 각 섹션의 속성을 정의한 것이에요.

PE 파일을 여러 섹션으로 나누었을 때 장점은, 프로그램의 안정성을 확보할 수 있다는 점인데요. 코드와 데이터가 하나의 섹션으로 되어있고, 섞여있다면, 구현이 가능하긴 하지만 복잡성은 둘째 치더라도 데이터에 값을 쓰다가 오버플로우로 인해 코드를 오염시켜 뻗어버리는 등 안정성에 문제가 생길 수 있어요. 그래서 각각 성격(특징, 액세스 권한)에 따라 나누게 되었죠.

1. 코드 - 실행, 읽기 권한

 .text: 파일을 열었을 때, 실행될 코드 저장

2. 데이터 - 비실행, 읽기, 쓰기 권한

 .data: 초기화된 전역 변수, static 변수 저장

 .rdata: const 변수, 문자열 상수 저장

 .bss: 초기화되지 않은 전역 변수, static 변수, 문자열, 기타 상수 저장, 초기화 시, data 영역으로 이동

 .edata: EAT와 관련된 정보 저장

 .idata: IAT와 관련된 정보 저장

3. 리소스 - 비실행, 읽기 권한

 .rsrc: 리소스 저장

이렇게 PE 파일 포맷 설계자들은 비슷한 성격의 자료를 섹션이라 명명한 곳에 각각 모아두고 그 섹션의 성격을 섹션 헤더에 적어놓았어요.

 

Section header는 각 섹션 별로 IMAGE_SECTION_HEADER이라는 구조체의 배열로 이루어져 있어요.

이 구조체에서 잘 사용되지 않는 멤버를 제외한 주요 멤버는 아래와 같아요.

PE header - Section header - Name

 섹션의 이름, 여기서 값은, ".text"이며, 코드를 저장하는 섹션이라고 알려주네요.

그런데 이름을 짓는데 명시적인 규칙이 없기에 ".purachina"나 심지어 NULL로 넣어도 돼요. 그리고 개발 도구에 따라 섹션의 이름/개수도 달라지고요. 그러니 섹션의 Name은 어디까지나 참고용이에요.

PE header - Section header - VirtualSize, SizeOfRawData

 각각 메모리/파일에서 섹션이 차지하는 크기, 여기서는 ⓑ, ⓓ이며, 각각 071108h, 071200h이네요.

당연히 이전에 설명한 OptionalHeader의 SectionAlignment, FileAlignment의 배수이죠.

PE header - Section header - VirtualAddress, PointerToRawData

 각각 메모리(RVA)/파일에서 섹션이 시작하는 위치, 여기서 ⓒ, ⓔ이며, ImageBase가 0이었으니 메모리에서 실제 주소는 VA와 동일하겠죠?

마찬가지로 OptionalHeader의 SectionAlignment, FileAlignment에 맞춰 결정되죠.

PE header - Section header - Characteristics

 FileHeader의 Characteristics와 비슷한 기능(bit OR 조합)을 해요. 섹션이 읽기, 쓰기, 실행 가능한지, 초기화 된 섹션인지 등을 나타내죠. 여기서는 , 60500060h 그러니까 40000000h(읽기 가능한) + 20000000h(실행 가능한) + 500000h(기본 정렬) + 40h(초기화된 데이터 포함) + 20h(코드 포함)이죠.

 

현재까지 프로그램 요약

이름 용도 현재 프로그램에서 값
DOS header PE 구조 사용 여부 5A4Dh (MZ)
DOS stub DOS 시스템에서 실행할 때 동작 WriteString() ("This program cannot...")
Exit()
NT header
Machine 프로그램이 동작될 CPU 8664h (AMD64)
NumberOfSections 섹션의 수 0x11h (17개)
TimeDataStamp 만들어진 시간 약 2021/02/14
PointerToSymbolTable,
NumberOfSymbols
COFF 심벌 테이블이 있을 때, 이를 향한 포인터
해당 테이블에 있는 심벌의 개수
 
SizeOfOptionalHeader OptionalHeader의 크기 0xF0h (240바이트)
Characteristics 파일의 속성 0x27 (64비트 실행파일)
OptionalHeader
Magic OptionalHeader의 종류 020Bh (64비트)
SizeOfCode 코드 섹션의 크기 0x071200h
AddressOfEntryPoint 처음 실행되는 코드의 주소 0x1500h + ImageBase
BaseOfCode 코드 섹션의 주소 0x1000h + ImageBase
ImageBase RVA의 기준점 0
SectionAlignment,
FileAlignment
섹션의 메모리/파일에서 단위 0x1000h
0x2000h
SizeOfImage 메모리에 매핑되었을 때 크기 0x100000h
SizeOfHeader 파일에서 PE 헤더의 총 크기 0x0600h
SubSystem 파일의 종류 0x03h (CLI)
NumberOfRvaAndSizes DataDirectory 배열의 개수 0x10h (16개)
DataDirectory IMAGE_DATA_DIRECTORY 구조체의 배열  
SectionHeader(e.g. .text section header)
Name 섹션의 종류 0x747865742E (.text)
VirtualSize,
SizeOfRawData
섹션의 메모리/파일에서 크기 071108h + ImageBase
071200h
VirtualAddress
PointerToRawData
섹션의 메모리/파일에서 시작 위치 0x1000h + ImageBase
0x0600h
Characteristics 섹션의 속성 0500060h (읽기, 실행 가능, 기본 정렬, 초기화된 데이터, 코드 포함)

 

RVA to RAW

PE 파일이 메모리를 할당받을 때, 각 섹션에 있는 메모리의 주소(RVA)와 파일 오프셋을 잘 매핑할 수 있어야 해요. 이런 매핑 방식을 RVA to RAW라고 하는데, 방법은 아래와 같아요.

1. RVA가 속해 있는 섹션을 찾아요.

2. 간단한 비례식을 사용해 파일 오프셋(RAW)을 계산해요.

IMAGE_SECTION_HEADER 구조체에 의하면 비례식은 다음과 같아요.

RAW - PointerToRawData = RVA - VirtualAddress

RAW = RVA - VirtualAddress  + PointerToRawData

Comments