본문 바로가기

My Study/Programming&Theory

PE 파일의 .reloc 섹션

나름 PE파일 구조를 대부분 알고 있다고 생각했는데 생각해보니 .reloc 섹션에 대해서는 공부한 적이 없었다;;

단순히 PE파일을 메모리에 로드시킬 때 주소 재배치가 이뤄질 때 사용되는 섹션으로만 알고 있던게 전부이기 때문이다.

또한 그 섹션을 조작해서 무언가를 할일이 없었기 때문이다... 하지만 이젠 .reloc 섹션을 공부해야한다. .reloc 섹션을 파싱해서 프로그램을 조작해야하는 일이 생겼으므로...... gogo..


===========================================

원래 실행파일 재배치는 dll을 대상으로만 이루어 졌다. 왜냐하면 exe 파일 같은 경우는 해당 가상 주소 공간에 하나만 존재하는 것이고 dll은 같은 주소 공간에 여러개가 존재해 각각의 로드되는 위치가 겹칠경우 재배치를 해줘야하기 때문이다.

아래 그림을 봐보자.


위 그림은 nateon 실행파일에서 사용되는 dll들을 봐본 것이다. ( 아래로 더 있다.. )


그러면 각각 dll의 ImageBase를 봐보자.

시스템 dll 같은 경우는 기본적으로 ImageBase가 0x7... 어찌고로 시작하며 이미 다른 주소로 지정되어 있으므로 놔두고..

어플리케이션 개발자가 만든 dll 을 대상으로만 보겠다.


kcrypto.dll                                    => ImageBase 0x10000000

NateMessengerApiActiveX.dll     => ImageBase 0x10000000

NateSearchSafe.dll                      => ImageBase 0x10000000

CKAppEx.dll                                 => ImageBase 0x10000000


네이트온 폴더에 있는 여러 dll중 4개만 봐봤는데 전부 ImageBase는 0x10000000 이었다.

그 이유는 컴파일러에서 dll을 만들 때 기본적으로 옵션이 ImageBase가 0x10000000 이 되게끔 설정되어 있다.

다른 주소로 하고 싶으면..


저 부분을 임의대로 설정해 주면된다.


아무튼 dll은 저런 이유 때문에 재배치가 필수적으로 필요하고 그로인해 .reloc 섹션이 필요한 것이다.


하지만 Windows Vista부턴 exe 파일에도 .reloc 기능이 들어가 있다. 왜 exe파일에 재배치 기능이 필요한 것일까??

같은 가상 주소 공간에 2개의 exe가 로드되는 기술이 생겼나??...


가 아니라 Exploit 해킹 기법으로부터 어플리케이션을 보호하기 위해 생겨난 ASLR 기법 때문에 생긴 것이다. ( ASLR, DEP )

ASLR 기법은.. exe를 실행할 때마다 메모리에서 ImageBase 값이 PE Header 에 있는 0x00400000 값이 아니라 임의의 주소가 되버린다는 것이다. 그러면 방어 기법은 언제 사용될까?


간단히 설명하면 어플리케이션의 취약점을 찾고 자기의 공격 루틴이 실행되게끔 스택에서 return 값 부분을 덮어 씌워 공격 코드가 있는 부분으로 점프를 해야되는데.. 가상 주소가 파일을 실행할 때마다 랜덤이므로 점프할 주소를 예측하기 힘들다는 것이다. 그래서.. 방어가 이루어짐.. -_-; ( 다 뚫리는 세상이지만;; )


아무튼 exe 파일도 ASLR 기능 때문에 .reloc 섹션이 필요해진 것이다.

기능을 끄고 싶으면 위 그림에서 보이는 /DYNAMICBASE 부분을 끄면된다.


이제 제대로 .reloc 섹션에 대해 알아보자.


winnt.h에 보면 IMAGE_BASE_RELOCATION 이라는 구조체가 정의되어 있다.


그리고 또하나.. 실행 파일의 .reloc섹션을 봐보자 ( PEview )

두 그림을 번갈아보면서 이야기를 진행해보자. ( 위에껀 1번 그림, 아래껀 2번 그림 )


1번 그림에 있는 구조체와 2번 그림을 비교해서 보면 대충 구조는 파악이 될 것이다.

일단 각각의 구조체 멤버 설명부터 하겠다.


VirtualAddress : 기준 재배치가 시작되어야 할 메모리 상의 번지에 대한 RVA


2번 그림을 보면 지금 0x00001000 으로 나와있다. 그러면 PE 파일 전체적으로 보면 ImageBase가 0x00400000 이므로

0x00400000 + 0x00001000 = 0x00401000 가 기준 VA가 되는 것이다. 이제 저 기준 값을 가지고 offset 으로 접근하게 된다.

offset은 TypeOffset 멤버에 있으므로 잠시 스킵


SizeOfBlock : 재배치를 수행해야 할 참조 항목에 대한 바이트 수 ( IMAGE_BASE_RELOCATION 구조체 포함 )


이제 그 아래로 word 사이즈의 TypeOffset 값이 하나씩 쭉 있다.


TypeOffset 구조를 봐보자.


상위 4bit는 재배치 타입을 나타낸다.

1번 그림 아래쪽을 보면


재배치 타입이 나와 있는데 저 중에 사용되는 값은 3개 뿐이다..

#define IMAGE_REL_BASED_HIGHLOW               3

Win32 PE 파일의 경우 전부 이 값


#define IMAGE_REL_BASED_DIR64                 10

Win64 는 전부 이 값


#define IMAGE_REL_BASED_ABSOLUTE              0

간간히 재배치 그룹의 마지막 엔트리에 이 값도 오는데 IMAGE_BASE_RELOCATION 구조체가 4Byte 단위로 정렬되기 때문에 이것을 맞추어주기 위한 패딩으로 사용될 뿐.. 아무 작업도 하지 않음


그리고 그 위로 오는 재배치 오프셋이 아까 이야기하다 만 그 오프셋이다.

VirtualAddress RVA 값에 재배치 오프셋이 더해져서 계산되는 것이다.

보면 12bit인데 2^12 으로 0부터 시작해 최대로 더할 수 있는 값은 4095(0x0FFF)이다.

고로! offset이 0x1000( 페이지 크기 )은 못넘어가므로 RVA가 0x2000이 넘어가는 부분은 새로 IMAGE_BASE_RELOCATION 구조체를 정의해 주어야한다. 아래와 같이...


이제 모든 정보를 알았으므로 재배치 적용 받을 곳을 가리키는 주소는 아래와 같이 계산된다.

오리지널 ImageBase + IMAGE_BASE_RELOCATION.VirtualAddress + TypeOffset.재배치오프셋


저 위치에 있는 4Byte 값이 재배치 되는 것이다. 

아.. 한가지 말 안한게 있다.


왜 항상 4Byte만 재배치 받느냐??

실행파일에서 재배치를 받아야하는 부분은 컴파일 시 가상메모리 값이 파일상에 그대로 하드코딩 된 경우이다.

즉, 전역변수를 선언한다던지 import table을 사용하지 않은 함수를 호출한다던지 할 때에는 

4Byte 주소 값이 그대로 파일 상에 하드코딩 된다.

다음 그림을 봐보자.

보면 재배치를 받아야 하는 부분 값은 주소이므로 무조건 4Byte이다.


이제 로더에서는 어떻게 작동하는지 봐보자.


1. 로더는 디스크상에 존재하는 상태의 PE Header에서 오리지널 ImageBase와 

    메모리 상에 올라왔을 때의 ImageBase의 차이 값을 구한다.

    ( 변경된 ImageBase - 오리지널 ImageBase )


2. .reloc 섹션 정보를 토대로 메모리상에 올라온 실행파일에 1번에서 구한 차이 값을 적용시켜준다.


즉..

[오리지널 ImageBase + IMAGE_BASE_RELOCATION.VirtualAddress + TypeOffset.재배치오프셋] 

가 가리키고 있는 4Byte에 차이 값을 더해줌!!


위 과정을 .reloc 섹션에 있는 모든 TypeOffset 수만큼 수행한다는 것이다. 

( ollydbg로 볼땐 이미 이 모든 과정이 끝나있는 상태 )


마지막으로 하나 예를 살펴보겠다.


먼저 이 파일의 ImageBase는 0x00400000 이다.



.reloc 섹션 부분이다.

여기서 빨간색 네모친 부분의 TypeOffset 값을 보고 재배치를 받아야할 주소는?


답 : 0x00400000 + 0x1000 + 0x019 = 0x00401019 ( 0x00401019 위치가 가리키고 있는 4Byte가 재배치 됨 )


ImageBase에 해당 재배치 블럭의 VirtualAddress 값을 더해주고 TypeOffset에서 앞 4bit를 뺀 나머지 12bit값을 더해주면 된다.

실제로 그 위치를 가보자. ( 실행 상태에서 보면 이미 재배치가 적용되어 주소가 0x00401019 가 아니다. )



현재의 바뀐 ImageBase는 0x01310000 이다.

저 명령어 시작 주소가 끝 1Byte만 보면 0x16인데 3Byte를 더하면 0x19 부분인걸 알 수 있다.


정말 글 더럽게 쓴거같다 ㅡㅡ; 이해가 안된다면.. 절 탓하길 ㅠ..

아무튼.. 대충 이해했으니.. 이제 프로젝트에 적용시켜봐야지..; 흠..




'My Study > Programming&Theory' 카테고리의 다른 글

Bluepill Sample Code Test  (4) 2012.07.17
Intel VT-x 와 BSOD.. ㅠㅠ  (0) 2012.07.16
Visual Studio 에서 %n 서식 문자 사용하기  (0) 2012.05.21
ELF 파일의 PLT, GOT  (3) 2012.04.26
Calling Convention Process for AMD 64 Bit  (4) 2012.04.02