PE File 재배치

Wooki·2021년 8월 19일
0

PE 재배치

PE 파일이 메모리에 로딩될 때 PE 헤더에 적혀있는 ImageBase 값의 주소에 로딩된다.
DLL(SYS) 파일의 경우 ImageBase 위치에 다른 DLL(SYS)파일이 먼저 로딩되어 있다면
다른 비어있는 주소 공간에 로딩되게 된다. 이런 과정을 PE 재배치라고 한다.

EXE 파일의 재배치

프로세스가 생성될 때 EXE 파일이 제일 먼저 메모리에 로딩된다. 그렇기 때문에
EXE에 대해서는 파일 재배치를 고려할 필요가 없지만, Windows Vista부터 보안 강화를 위해서 ASLR(Address Space Layout Randomization) 기능이 추가되었다.
간단히 설명하자면 파일이 실행될 마다 랜덤한 주소에 로딩시켜서 보안을 강화한 것이다.

이런 경우 하드코딩되어있는 주소들을 바뀐 ImageBase값에 맞게 고쳐주는 과정이 필요하다.

Base Relocation Table

PE 재배치 작업은 아래와 같이 진행된다.

  1. 프로그램에서 하드코딩된 주소들의 위치를 찾는다.
  2. 값을 읽은 후 ImageBase값 만큼 뺀다.
  3. 실제 로딩 주소를 더한다.

여기서 1번과 관련되어 PE 헤더에는 하드코딩된 주소들의 오프셋을 모아놓은 Base Relocation Table이 존재한다.

Base Relocation Table의 주소는 DataDirectory 배열의 6번째 항목에 들어있다.

PE View로 notepad.exe를 열어서 확인해 보면 Base Relocation Table의 RVA값은 2F000이 나온다.

해당 위치를 확인해 보니 Base Relocation Table이 나온다.

IMAGE_BASE_RELOCATION 구조체


//
// Based relocation format.
//

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

//
// Based relocation types.
//

#define IMAGE_REL_BASED_ABSOLUTE              0
#define IMAGE_REL_BASED_HIGH                  1
#define IMAGE_REL_BASED_LOW                   2
#define IMAGE_REL_BASED_HIGHLOW               3
#define IMAGE_REL_BASED_HIGHADJ               4
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_5    5
#define IMAGE_REL_BASED_RESERVED              6
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_7    7
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_8    8
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_9    9
#define IMAGE_REL_BASED_DIR64                 10

IMAGE_BASE_RELOCATION 구조체의 코드 모습이다.

RVADataComment
0002F0000001000VirtualAddress
0002F00400000150SizeOfBlock
0002F0083420TypeOffset
0002F00A342DTypeOffset
0002F00C3426TypeOffset

첫 번째 멤버인 VirtualAddress는 기준 주소(Base Address)라고 하고 , RVA 값이다.
두 번째 멤버인 SizeOfBlock은 각 블록의 크기를 말한다.
TypeOfset은 주석으로 표시되어 있는데 이 구조체 밑으로 WORD 타입 배열이 따라온다는 뜻이고,
이 배열항목의 값이 프로그램에 하드코딩된 주소들을 Offset이다.

즉 표에 따라 살펴보면(표는 위에서 PEview로 열어본 notepad.exe의 Base Relocation Table 기반)

VitualAddress의 값은 1000이고 SizeOfBlock 의 값은 150이다.
TypeOffset은 2바이트의 크기로 4비트의 Type과 12비트의 Offset이 합쳐진 형태다

Type(4bit)Offset(12bit)
3420

TypeOffset이 3420인 경우 위 표처럼 해석한다.

하드코딩 주소를 찾아가 보면

VitualAddress(1000) + Offset(420) = 1420(RVA)

RVA 1420으로 이동해보니 하드코딩되어 있는 주소가 나타난다.
00A010C4라는 IAT 주소가 로딩되어 있다. (ImageBase = A0000에 로딩된 상황)
00A010C4라는 주소가 어떻게 구해진 것인지 살펴보자

HxD로 1420부분을 확인해 보니 01001C20이 들어있다.

즉 원래는 01001C20으로 하드코딩 되어 있는 주소가

PE 재배치 과정을 거치면서

01001C20h - 01000000h(ImageBase) = 00001C20h (ImageBase만큼 뺄셈)

00001C20h + 00A00000h(실제 로딩 주소) = 00A01C20h 이 된다.

PE 로더가 모든 하드코딩된 주소들을 위처럼 찾아서 실제 로딩된 메모리 주소에 맞게 덮어쓴다(TypeOffset이 0이 될 때 까지- 0이 나오면 IMAGE_BASE_RELOCATION 구조체가 끝난다.)

profile
웹 개발자

0개의 댓글