본문 바로가기
Reversing/리버싱 핵심 원리

[리버싱 핵심 원리] 16장, Base Relocation Table

by Y06 2020. 11. 7.

16장, Base Relocation Table

16.1. PE 재배치

PE 파일(EXE, DLL, SYS)이 프로세스 가상 메모리에 로딩(loading)될 때 PE 헤더의 ImageBase 주소에 로딩된다. DLL(SYS) 파일의 경우 ImageBase 위치에 이미 다른 DLL(SYS) 파일이 로딩되어 있다면 다른 비어 있는 주소 공간에 로딩된다. 이것을 PE 파일 재배치라고 한다. 즉, PE 재배치란 PE 파일이 ImageBase에 로딩되지 못하고 다른 주소에 로딩될 때 수행되는 일련의 작업들을 의미한다.

 

16.1.1. DLL/SYS

 

TEST.EXE 프로세스에 A.DLL이 10000000 주소에 로딩되어 있다. 이후 B.DLL이 같은 주소(10000000)에 로딩을 시도하면 PE 로더는 비어 있는 주소(3C000000)에 B.DLL을 로딩시킨다.

 

16.1.2. EXE

 

프로세스가 생성될 때 EXE 파일이 가장 먼저 메모리에 로딩되기 때문에 EXE에서는 재배치를 고려하지 않아도 된다. 그러나 Windows Vista 이후부터는 보안 강화를 위해 ASLR(Address Space Layout Randomization) 기능이 추가 되었다. 이것은 EXE 파일이 실행될 때마다 랜덤한 주소에 로딩하는 것이다.

 

Windows Vista/7의 시스템 DLL들도 자신만의 고유한 ImageBase를 가지고 있지만 ASLR 기능으로 인해서 로딩 주소는 매 부팅 시마다 달라진다.

 

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

notepad의 ImageBase는 01000000이다.

 

Windows 7에서 notepad.exe의 EP 코드 부분이다. 현재 Windows 7의 ASLR의 기능에 의해서 00280000 주소에 로딩된 상태이다. 위의 Instruction을 보면 박스 표시 안에 프로세스 메모리 주소가 하드 코딩되어 있다.

ImageBase 주소에 로딩되지 않는 경우에 이 PE 재배치 작업이 없다면 프로그램은 정상적으로 실행될 수 없다.

 

16.3. PE 파일 재배치 동작 원리

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

- 값을 읽은 후 ImageBase만큰 뺀다. (VA -> RVA)

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

 

여기서의 핵심은 하드코딩된 주소 위치를 찾는 것이다. 이를 위해 PE 파일 내부에 Relocation Table이라고 하는 하드 코딩 조소들의 옵셋(위치)을 모아 놓은 목록이 존재한다. Relocation Table로 찾아가는 방법은 PE 헤더의 Base Relocation Table 항목을 따라가는 것이다.

 

16.3.1. Base Relocation Table

 

Base Relocation Table 주소는 PE 헤더에서 DataDirectory 배열의 여섯번째 항목에 들어있다.(배열 인덱스는 5)

 

16.3.2. IMAGE_BASE_RELOCATION 구조체

 

//
// Based relocation format.
//

typedef struct _IMAGE_BASE_RELOCATION {
     DWORD VirtualAddress;
     DWORD SizeOfBlock;
//   WORD TypeOffset[1];
} IMAGE_BASE_RELOCATION;

typedef IMAGE_BASE_RELOCATIONUNALIGED * PIMAGE_BASE_RELOCATION;

//
//  Based relocation types.
//

#define IMAGE_REL_BASED_ABSOLUTE
#define IMAGE_REL_BASED_HIGH
#define IMAGE_REL_BASED_LOW
#define IMAGE_REL_BASED_HIGHLOW
.
.
.

IMAGE_BASE_RELOCATION 구조체의 첫 번째 멤버 VirtualAddress는 기준 주소(Base Address)이며, 실제로는 RVA 값이가. 두 번째 멤버 Size 멤버 SizeOfBlock은 각단위 블록의 크기를 의미한다. 마지막으로 구조체 멤버는 아니지만 주석으로 표시된 TypeOffset 배열의 의미는 이 구조체 밑으로 WORD 타입의 배열이 따라온다는 뜻이다. 그리고 이 배열 항목의 값이 바로 프로그램에 하드코딩된 주소들의 옵셋이다.