2016. 1. 14. 04:39

Chapter 16. Base Relocation Table


16.1 PE 재배치

1) 개념 : PE파일이 ImageBase에 로딩되지 못하고 다른 주소에 로딩될 때 수행되는 작업

- PE파일이 프로세스 가상 메모리에 로딩될 때 PE헤더의 ImageBase주소에 로딩됨

- DLL의 경우 ImageBase위치에 이미 다른 DLL파일이 로딩되어 있다면 다른 비어있는 주소 공간에 로딩됨


2) SDK(Software Development Kit) / Visual C++ 로 생성된 PE파일

- EXE의 ImageBase = 00400000

- DLL의 ImageBase = 10000000


3) DDK(Driver Development Kit)로 생성된 SYS파일

- SYS의 ImageBase = 10000

  


16.1.1. DLL/SYS


위 그림은 TEST.EXE 프로세스에 A.DLL이 10000000주소에 로딩되어 있는 상태를 나타낸다. 이후 B.DLL이 같은 주소(10000000)에 로딩을 시도하면 PE로더는 비어있는 주소에 B.DLL을 로딩시킨다. 



16.1.2. EXE

1) 프로세스가 생성될 때, EXE파일이 가장 먼저 메모리에 로딩되므로 EXE는 재배치를 고려할 필요가 없었음

2) Windows Vista 이후부터는 ASLR(Address Space Layout Randomization)기능으로 인해 EXE파일이 실행 때마다 임의의 주소로 로딩됨 (ASLR은 41장 참고)




16.2 PE 재배치 발생시 수행되는 작업

* Windows7의 notepad.exe 프로그램으로 PE 재배치 확인

1) PEView를 이용한 notepad.exe의 ImageBase 확인 (ImageBase = 01000000)


2) OllyDbg로 nodepad.exe 실행


위 그림은 notepad.exe의 EP코드 부분이다. 앞서 언급한 바와 같이 Windows Vista 이후 버전에서는 보안기능인 ASLR로 인하여 실행될 때마다 주소값이 매번 변경된다. 우선 각 박스 표시된 부분을 살펴보자. Instruction 박스 표시에는 프로세스 메모리 주소가 하드코딩이 되어있음을 알 수 있다.

- B210FC, B21100는 .text 섹션의 IAT 영역

- B2C0A4주소는 .data 섹션의 전역변수

상기 부분은 올리디버거에서 notepad.exe를 재실행할 때마다 로딩 주소에 맞게 수시로 변경된다. 이렇듯 프로그램상에 하드코딩된 메모리주소를 현재 로딩된 메모리주소에 맞게 변경해주는 작업을 "PE재배치"라 한다.


3) HxD를 이용하여 EP영역 확인

파일(ImageBase : 01000000) 

프로세스 메모리 (로딩주소 : 00B20000) 

 010010FC

B210FC 

 01001100

B21100

 0100C0A4

B2C0A4 

notepad.exe 파일이 빌드될 때, 실제 어느 주소에 로딩이 될지 예측할 수 없으므로 ImageBase기준으로 하드코딩 주소를 적었다. 그러나 실행되는 순간에 PE재배치 과정을 거치면서 이 주소들은 모두 로딩 주소 기준으로 변경된다.




16.3 PE 재배치 동작 원리

* PE재배치 작업의 기본 동작 원리

- 프로그램에서 하드코딩된 주소 위치를 찾는다.

- 값을 읽은 후 ImageBase만큼 뺀다(VA → RVA).

- 실제 로딩 주소를 더한다(RVA→VA)


16.3.1. Base Relocation Table

Base Relocation Table 주소는 PE헤더에서 DataDirectory배열의 여섯 번째 항목에 있다.

(IMAAGE_NT_HEADERS \ IMAGE_OPTIONAL_HEADER \ IMAGE_DATA_DIRECTORY[5])


PEView에서 notepad.exe의 Base Relocation Table 주소는 아래 그림과 같다.

Base Relocation Table의 주소는 RVA 2F000이며, 이 주소를 통해 아래 그림과 같이 하드코딩 주소들의 Offset을 파악할 수 있다.



16.3.2. IMAGE_BASE_RELOCATION 구조체

Base Relocation Table은 IMAGE_BASE_RELOCATION 구조체 배열이다. IMAGE_BASE_RELOCATION구조체 정의는 다음과 같다.

typedef struct _IMAGE_BASE_RELOCATION {

DWORD VirtualAddress; // Base Address (RVA 값)

DWORD SizeOfBlock;   // 각 단위 블록의 크기

// WORD TypeOffset[l];

} lMAGE_BASE_RELOCATION;

typedef lMAGE_BASE_RELOCATION UNALIGNED * PlMAGE_BASE_RELOCATION;



16.3.3. Base Relocation Table 해석방법

다음 표는 Base Relocation Table의 일부를 표현한 것이다. 

- Virtual Address (시작 주소) : 1000

- Size of Block (블록의 전체크기 ) : 150

- TypeOffset (= Type + Offset)

→ Type(4bit) : PE파일에서 일반적으로 3(IMAGE_REL_BASED_HIGHLOW)

 : PE+파일에서 일반적으로 A(IMAGE_REL_BASED_DIR64)

→ Offset(12bit) : 실제 사용되는 위치

- VirtualSize + Offset = RVA


(예시) 0002F008주소의 3420의 경우 3 + 420으로 분류할 수 있다. 따라서 시작주소와 Offset값을 더하면 1420이 된다. 실제 VA를 구하기 위해서는 RVA + ImageBase(로딩주소)를 계산해야하므로, 앞선 예제의 ImageBase(00B20000)를 이용한다면, VA = 00B21420이 된다. 이 주소에는 IAT주소가 저장되어 있다.


16.3.4. 실습

앞서 언급한 환경을 기준으로 설명한다.

1) 프로그램에서 하드코딩된 주소 위치를 찾는다.

앞서 구한 RVA 1420을 이용한다. PEView를 통해 실제 RVA 1420 주소의 내용은 다음 그림과 같다.

RVA 1420에는 프로그램의 하드코딩된 주소 0100010C4 값이 들어있다.


2) 값을 읽은 후 ImageBase만큼 뺀다. (VA  RVA)  ** RVA + imageBase = VA

010010C4 - 01000000 = 000010C4


3) 실제 로딩 주소를 더한다. (RVA  VA)

000010C4 + 00B20000 = 00B210C4


PE로더는 프로그램 내에 하드코딩된 주소를 위와 같은 과정을 거쳐서 실제 로딩된 메모리 주소에 맞게 보정을 한 겂을 같은 위치에 덮어쓴다.






Chapter 17. 실행파일에서 .reloc 섹션 제거하기


17.1 .reloc 섹션

EXE형식의 PE파일에서 Base Relocation Table항목은 실행에 큰 영향을 미치지 않는다. 실제로 이 부분을 제거한 후 실행을 시켜도 정상적인 동작을 수행한다. 다만, EXE와 다르게 DLL, SYS의 경우 Base Relocation Table이 반드시 필요하다.

VC++에서 생성된 PE파일의 Relocation 섹션 이름은 ".reloc"이다. 이 .reloc 섹션이 제거되면 PE파일의 크기가 줄어든다. 보통 이 섹션은 마지막에 위치한다.


17.2. reloc.exe

.reloc을 제거하기 위해서는 다음과 같은 네 단계의 작업을 수행해야 한다.

- 1단계 : .reloc 섹션 헤더 정리

- 2단계 : .reloc 섹션 제거

- 3단계 : IMAGE_FILE_HEADER 수정

- 4단계 : IMAGE_OPTIONAL_HEADER 수정


17.2.1. .reloc 섹션 헤더 정리

- File Offset : 270

- Header Size : 28

- Range : [270, 297] <헤더의 마지막 부분을 참고>

해당 범위 부분을 0으로 덮어 쓴다(HxD 이용). 



17.2.2. .reloc 섹션 제거

.reloc섹션의 시작 offset은 C000이다. 이 섹션은 가장 마지막 부분에 위치하므로, C000부터 끝까지 삭제하면 된다. 다음 그림과 같이 HxD로 C000부터 파일의 끝까지 삭제한다.



17.2.3. IMAGE_FILE_HEADER 수정

앞서 물리적으로 .reloc섹션을 제거하였으나, 다른 PE헤더 정보들이 수정되지 않았기 때문에 파일이 정상적으로 실행되지 않는다. 현재 .reloc섹션 하나를 지웠으므로 전체 섹션의 개수에서 하나를 줄여야 한다. IMAGE_FILE_HEADER에서 Number of Sections항목을 5에서 4로 수정한다.



17.2.4. IMAGE_OPTIONAL_HEADER 수정

.rection 섹션이 제거되면서 전체 크기가 해당 섹션만큼 줄어들었다. 이미지 크기는 IMAGE_OPTIONAL_HEADER - Size of Image값에 명시되어있다.

위 그림과 같이 이미지의 크기는 11000이다. .reloc섹션의 VirtualSize값은 E40이고, 이를 Section Alignment에 맞게 확장하면 1000이 된다. 따라서 Size of Image값을 1000만큼 빼야한다. 

위 과정이 모두 완료되면 해당 파일은 정상적으로 실행이 된다.


'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 23  (0) 2016.01.17
Reverse Engineering Chap 14~15  (0) 2016.01.14
Reverse Engineering Chap 13  (0) 2016.01.12
Reverse Engineering Chap7-12  (0) 2016.01.10
Reverse Engineering Chap1-2  (0) 2016.01.10
Posted by 알 수 없는 사용자