리버싱/윈도우 리버싱

RVA와 섹션

cyanhe_wh 2021. 1. 21. 20:23
반응형

RVA는 디스크 상에 파일로 존재하는 PE의 파일 오프셋과 함께 로드되어 메모리의 이미지로 존재하는 PE의 메모리 번지 사이의 간극을 절충시켜주는 중요한 개념이다.

 

섹션은 PE 파일 전체를 구성하는 파일/메모리 블록의 단위다.

 

 

RVA(상대적 가상 주소 - Relative Virtual Address)

PE 파일 내의 파일 오프셋과 RVA는 관점이 다르다!

PE 구조에서 번지에 관계된 값, 즉 가상 주소 공간 상의 번지들은 전부 RVA 개념으로 표현된다.

RVA는 이미지가 메모리에 로드되었을 떄, 더 정확히 표현하면 해당 프로세스의 가상 주소 공간 내에 로드되었을 때

그 시작 주소에 대한 상대적 번지를 가리키는 개념으로, 메모리에서 PE의 시작 주소에 대한 상대적인 오프셋 값으로 생각할 수 있다.

파일 상태로 2차 메모리인 하드디스크에 존재하는 PE는 가상 메모리의 어떤 위치에 로드될지는 미리 알 수 없다.

32bit 시절에는 일반적으로 그 위치를 고정시켜서 EXE의 경우에는 디폴트로 0x00400000 번지에, DLL의 경우에는 디폴트로 0x10000000 번지에 PE 이미지가 로드되도록 했지만, 64bit에 들어서면서 보안상의 이유로 기본 설정에서 고정 주소 로드를 제거했기 때문에 전적으로 프로그램 로더가 판단해서 시작 번지를 결정한다.

따라서 PE에서의 가상 주소 공간에 대한 번지 참조는 아직 결정되지 않았지만, 로드될 이미지의 가상 시작 번지를 하나의 기준으로 하고, 그 번지에 대한 상대적 오프셋 값을 PE 파일에 기록하는 방식을 채택했다.

RVA를 가상 주소 공간 내의 실제 번지로 변환하기 위해서는 계산이 필요하다.

 

가상 주소(VA) = 이미지 로드 시작 번지(ImageBase) + RVA

 

이미지 로드 시작 번지는 IMAGE_OPTIONAL_HEADER 구조체의 ImageBase 필드에 임의로 지정할 수 있다.

예를 들어 이미지 로드 시작 번지가 0x00400000이고 RVA 값이 0x00005562라고 하면, 해당 PE 이미지가 가상 주소 공간에 로드되었을 때의 이 RVA에 해당하는 실제 번지는 0x00400000(ImageBase) + 0x00005562(RVA) = 0x00405562(VA)가 된다.

RVA는 절대 PE 파일 상의 오프셋이 아니다!!

 

각 섹션은 섹션 헤더에서 지정하는 RVA를 참조하여 PE 이미지가 매핑된 시작 번지부터 지정된 RVA에 정확하게 해당 섹션을 로드하게 된다. 따라서 해당 섹션의 PE 상의 파일 오프셋과 RVA는 달라지게 된다.

 

 

섹션(Section)

PE 파일에서 섹션은 프로그램의 실제 내용을 담고 있는 블록으로, PE가 가상 주소 공간에 로드된 후 이 섹션 내용이 참조되고 실행된다. 이떄 여기서 말하는 내용에 해당하는 것이, 가장 쉽게 생각할 수 있는 코드와 데이터일 것이다.

이 코드와 데이터를 비롯해 프로그램 실행에 관련된 여러 정보가 각각의 섹션에 배치된다.

 

코드 섹션 .text

프로그램을 실행하기 위한 코드를 담고 있는 섹션이다. CPU의 명령 포인터가 되는 IP 레지스터는 이 섹션 내에 존재하는 번지를 담는다.

32비트의 경우 VC++ 7.0부터 실행 가능 속성을 가진 동시에 초기화되지 않은 데이터와 이를 담고 있는 .textbss 섹션이 존재하기도 하는데, 이 섹션은 '증분 링크(Incremental Link)' 옵션이 설정된 경우 컴파일러에 의해 생성된다.

 

 

데이터 섹션 .data

초기화된 전역 변수들을 담고 있는, 읽고 쓰기가 가능한 섹션이다.

이전에는 초기화되지 않은 데이터를 위한 데이터 섹션의 일환으로 .bss 섹션을 제공했다.

여기서 초기화의 의미는 코드 상에서 명시적으로 초기값을 지정하지 않은 전역 변수를 의미한다.

이 섹션은 PE 파일 내에 존재할 수도 있지만, 가상 주소 공간에 매핑될 때는 보통 .data 섹션에 병합되기 떄문에 메모리에서는 볼 수 없다. 64bit에서는 PE 파일 자체에서 .bss 섹션을 .data 섹션에 병합해버리기 때문에 PE 파일에서도 존재하지 않는다.

 

 

읽기 전용 데이터 섹션 .rdata

.rdata에 배치되는 항목으로는 문자열 상수나 C++ 가상 함수 테이블 등이 있다.

코드 상에서 참조하는 읽기 전용 데이터뿐만 아니라 다른 섹션, 예를 들어 내보내기 섹션(.edata)이나 디버그 섹션(.debug) 등은 .rdata 섹션에 병합된다. 또한 가져오기 섹션(.idata)이나 자연 로드 섹션(.didata)의 경우도 증분 링크 옵션을 해제하면 역시 이 섹션으로 병합되어 버린다. 그리고 데이터 디렉터리의 여러 엔트리 또한 이 섹션 내에 위치한다.

 

OBJ파일의 경우 C/C++ 런타임 정보를 위한 .CRT 섹션도 존재하는데, 이 섹션도 C++ 클래스의 전역 객체 생성자와 소멸자 함수 호출을 위한 함수 포인터 등을 담는 섹션이지만 링커에 의해서 .rdata 섹션으로 병합된다.

 

VC++ 2015부터는 '흐름 제어 보호, CFG'라는 보안 기능을 명시적으로 지원하며, 이 기능을 위해 .gfids나 .00cfg라는 섹션도 제공하지만 역시 '증분 링크' 옵션을 해제할 경우 .rdata 섹션에 병합된다.

 

 

기준 재배치 섹션 .reloc

실행 파일에 대한 기준 재배치 정보를 담고 있는 섹션이다. 기준 재배치란 PE 이미지를 원하는 기본 주소에 로드하지 못하고 다른 주소에 로드했을 경우, 코드 상에서 가상 주소를 참조(예를 들어 포인터 연산 등)하는 경우 이 주소를 갱신해줘야 하는 것을 의미한다. 이런 가상 주소 갱신을 위해 기준 재배치 섹션이 필요하다.

 

 

내보내기(Export) 섹션 .edata

내보낼 함수에 대한 정보를 담고 있는 섹션이다.

일반적으로 함수/변수를 내보내는 경우는 DLL이 대부분이기 때문에 DLL의 PE에서 이 섹션을 발견할 수 있다.

하지만 이 섹션 역시 .rdata 섹션이 병합되기 때문에 DLL에서 별도의 섹션으로 존재하지 않는다.

대신 VC++가 만들어내는 내보내기 라이브러리 파일인 EXP 파일에서 이 섹션을 볼 수 있다.

 

 

가져오기(Import) 섹션 .idata

가져올 DLL과 그 함수/변수에 대한 정보를 담고 있는 섹션이다.

대표적으로 이 섹션 내에 IAT(Import Address Table)가 존재한다. 하지만 이 섹션은 '증분 링크' 옵션을 해제하면 .rdata 섹션에 병합된다.

 

 

자연 로드 섹션 .didat

DLL 지연 로딩(Delay-Loading)을 위한 섹션이다. 지연 로딩은 윈도우 2000부터 지원되는 DLL 로딩의 한 방식으로 암시적인 방식과 명시적인 방식을 혼합이다. 이 섹션 역시 '증분 링크' 옵션을 해제하면 .rdata 섹션에 병합된다.

 

 

TLS 섹션 .tls

__declspec(thread) 지시어와 함께 선언되는 스레드 지역 저장소(Thread Local Storage)를 위한 섹션이다.

이 섹션은 __declspec(thread) 지시어를 사용한 정적 TLS의 데이터의 초기화를 위해 존재한다.

 

 

리소스 섹션 .rsrc

대화상자, 아이콘, 커서, 버전 정보 등의 윈도우 PE 파일이 담고 있는 리소스 관련 데이터들이 이 섹션에 배치된다.

 

 

디버깅 섹션 .debug

이 섹션은 디버깅 정보를 담고 있다. 오래전부터 MS는 이 섹션에 디버깅 관련 기초 정보만을 담고, 실제 정보는 PDB 파일에 별도로 보관한다. 디버깅 섹션을 위해 OBJ 파일에는 가변 길이 코드 뷰의 포맷 심볼이나 타입 레코드를 담고 있는 .debug$S, .debug$T 섹션과 미리 컴파일된 헤더를 위한 .debug$P 섹션 등이 존재하는데, 링커는 이 섹션을 하나로 합쳐서 .debug 섹션을 구성해 PE 파일 내의 .rdata 섹션에 병합한다.

 

 

예외 섹션 .pdata

예외 정보를 담고 있는 섹션이다. IMAGE_RUNTIME_FUNCTION_ENTRY 구조체의 배열로 구성된다.

이 구조체는 CPU 플랫폼에 의존적이며, 테이블베이스 예외 처리(Table-Base Exception Handling)를 사용하는 플랫폼에서만 제공되기 때문에 x86 계열의 CPU에서는 이 섹션을 볼 수 없다. 따라서 32비트용 윈도우 PE에는 존재하지 않지만

AMD64나 IA-64 CPU를 기반으로 하는 64비트 PE에는 항상 존재하며, 64비트 예외 처리뿐만 아니라 코드 섹션을 구성하는 함수들의 분석에 있어서도 매우 중요한 역할을 한다. OBJ 파일에서는 예외 처리 테이블 정보를 담는 .xdata 섹션도 존재하지만, 이 섹션은 링크 과정을 거치면서 .pdata 섹션에 병합되어 PE 파일에는 존재하지 않는다.

반응형

'리버싱 > 윈도우 리버싱' 카테고리의 다른 글

PE 파일의 전체 구조  (0) 2021.01.21
PE 파일  (0) 2021.01.17
WinDbg, mona세팅 (구/신 버전 다 있음)  (0) 2021.01.01
WinDbg Preview  (0) 2020.12.31
디버깅 환경  (0) 2020.12.29