리버싱/윈도우

리버스 엔지니어링 1 : PE 공부 전 필요한 기본지식

parktest0325 2020. 8. 23. 22:07

Program Loader : 윈도우 서브시스템으로 존재하며 exe를 실행하면 로더가 exe파일을 열고 구조를 분석해서 적절히 메모리에 로드(Import 테이블도 확인해서 필요한 dll까지 같이 로드함)하고 프로그램의 진입점으로 들어가게 한다.

 

PE : Portable Excecutable. 플랫폼(CPU)에 상관없이 윈도우 운영체제 위에서는 무조건 실행 가능한 파일포맷

 - COFF(Common Object File Format) 을 계승한 파일 포맷

 - dll, exe은 동일한 파일구조(PE)를 갖는다

 - 첫 2byte가 MZ로 시작하고 

 - PE+ : 64bit PE 포맷

 

Image(=파일) : 실체에 대한 그림자, 허상이라는 뜻.

PE 파일은 하드디스크에 파일로 존재하다가 메모리에 로드될 때는 4gb(32bit=2^32) 또는 16eb(64bit=2^64)의 가상메모리를 할당받고 가상메모리관리자는 페이지파일 영역을 하드디스크에 유지하며 페이지파일과 적절한 스와핑, 매핑을 통해 실제 메모리에 프로세스의 일부를 올리고 내리면서 프로세스가 가상메모리 공간을 소유한것처럼 속이게된다.

 

공유메모리도 프로세스가 커널에 요청하면 물리메모리에 공간을 할당해주고 프로세스들이 접근할 수 있도록 가상메모리와 매핑하는 구조이다. 

 

IMAGE_xxx_xxxx 는 전부 WinNT.h 헤더파일에 정의된 구조체이다.

도스와 호환을 위한 IMAGE_DOS_HEADER 이후에 IMAGE_NT_HEADERS의 PE 시그니처 부터 시작된다. 

IMAGE_FILE_HEADER : PE 파일의 정보

IMAGE_OPTIONAL_HEADER : PE 파일이 메모리에 로드될때 중요한 정보인 섹션의 위치 및 크기를 나타내는 IMAGE_DATA_DIRECTORY 구조체배열이 포함

IMAGE_SECTION_HEADER : 각 섹션에 대한 정보 포함

SECTION : 실제 코드나 데이터가 섹션이라는 블록 단위로 저장

 

RVA : Relative Virtual Address. 이미지가 가상메모리에 로드되었을때 시작주소에 대한 상대적 주소 32bit시스템에서 exe는 0x00400000, dll은 0x10000000으로 시작주소가 고정되었지만 64bit부터 프로그램 로더가 판단해서 지정함

VA : Virtual Address. 가상주소 상 절대주소. VA = ImageBase + RVA

ImageBase는 IMAGE_OPTIONAL_HEADER구조체의 ImageBase 필드에 임의로 지정할 수 있음

 

SECTION : 실제 코드나 데이터가 담긴 블록. PE가 가상메모리에 로드된 후 섹션의 내용이 참조되고 실행된다.

- 코드섹션 .text (rx) : 실제 프로그램 코드를 담고있는 섹션 EIP, RIP 레지스터는 이 섹션의 주소를 가리킨다.

 * .textbss 섹션 : 코드와 초기화되지 않은 데이터가 함께 담긴 섹션. Incremental Link 옵션을 설정하면 생성된다.

- 데이터섹션 .data (rw) : 초기화된(명시적으로 초기값 지정) 전역 변수들을 담고있는 섹션. 초기화되지 않은 전역 변수의 .bss 섹션은 가상주소에 매핑될때 .data 섹션과 병합되어 메모리에서 볼수없고, 64bit는 PE헤더에서도 병합했다.

- 읽기전용 데이터섹션 .rdata (r) : 읽기 전용으로 문자열상수, C++가상함수 테이블, 내보내기섹션(.edata), 디버그섹션(.debug)가 병합되어 있고, 가져오기섹션(.idata), 지연로드섹션(didata)도 증분링크 옵션을 제거하면 병합될 수 있다. VC++ 2015부터 흐름제어보호, CFG라는 보안기능으로 생긴 .gfids, .00cfg 섹션도 증분링크 옵션을 해제하면 병합된다.

- 기준 재배치 섹션 .reloc : PE 이미지를 원하는 기본주소에 로드하지 못하고 다른 주소에 로드한 경우 코드상에서 가상주소를 참조(포인터연산 등)할때 가상주소를 갱신해줘야 하고 이를 위해 기준 재배치 섹션이 필요하다.

- 내보내기 섹션 .edata : 내보낼 함수에 대한 정보를 담고있는 섹션. 대부분의 DLL에서 함수나 변수를 내보내기 때문에 DLL에 존재하지만, .rdata에 병합되기 때문에 별도로 존재하진 않는다. 또 VC++에서 내보내기 라이브러리 파일인 EXP 파일에서 볼 수 있다.

- 가져오기 섹션 .idata : 가져올 DLL, 함수, 변수에 대한 정보를 담고있는 섹션. 이 섹션 내에 IAT가 존재함. 증분링크 옵션을 해제하면 rdata 섹션에 병합됨

- 지연 로드 섹션 .didat : window 2000부터 지원하는 DLL 지연로딩을 위한 섹션. 증분링크 옵션 해제 시 .rdata에 병합

- TLS 섹션 .tls : __declspec(thread) 지시어를 사용한 정적 TLS 데이터 초기화를 위해 선언되는 스레드 로컬 스토리지를 위한 섹션. 

- 리소스 섹션 .rsrc : 대화상자, 아이콘, 커서, 버전정보 등 윈도우 리소스 관련 데이터들이 존재함

- 디버깅 섹션 .debug : 디버깅 관련 기초정보를 담고 실제 정보는 PDB 파일에 별도로 보관. 디버깅 섹션을 위해 obj 파일에서는 가변길이 코드 뷰의 포맷심볼이나 타입 레코드를 담고있는 .debug$S, .debug$T섹션, 미리 컴파일된 헤더를 위한 .debug$P 섹션이 있는데, 링커가 이 섹션을 하나로 합쳐서 .debug 섹션을 구성하고 .rdata 섹션에 병합한다.

- 예외 섹션 .pdata(r) : CPU 플랫폼에 의존적이며 테이블베이스 예외처리를 사용하는 플랫폼에서만 제공되기 때문에 x86계열 CPU 에서는 볼 수 없다. obj 파일에서는 .예외처리 테이블 정보를 담는 .xdata 섹션도 있지만 링크과정을 거치며 .pdata 섹션에 병합된다.

 

이외에도 obj 파일에는 .drectve, .sdata, .srdata 등 더 많은 섹션이 있다.

 

가상메모리 : 프로세스는 32bit=4gb, 64bit=16eb 크기의 가상 메모리를 가진다. 이 공간을 RAM과 연결해주는것이 커널모드에 위치한 윈도우 컴포넌트인 가상메모리 관리자(VMM)이다.

프로세스의 스레드가 가상메모리의 특정 번지를 접근할 때 가상메모리 관리자는 해당 번지가 소속된 페이지파일을 디스크에서 가져와 램에 올리고(스왑) 가상메모리와 매핑시켜준다. 

쉬고있는 가상메모리 페이지 파일은 윈도우 설치 드라이브의 루트 경로에 pagefile.sys라는 이름으로 존재하며 설정을 통해 크기를 조절할 수 있다.

 

페이지는 해제, 예약, 확정 상태가 존재하며 해제상태는 영역이 할당되지 않은 상태이고, VirtualAlloc 등의 함수로 가상메모리 공간을 할당하게되면 예약상태가 된다. 예약 영역의 시작번지는 윈도우의 가상메모리 할당 단위인 64kb 배수값이고 페이지 크기인 4kb단위로 관리된다.

메모리가 사용되기 위해서는 확정 상태여야 하고 RAM이나 pagefile.sys같은 가상메모리 페이지 파일에 올라가면 확정상태가 된다. 확정 상태 영역을 접근할때 RAM이 아닌 pagefile.sys에 존재하면 스와핑이 이뤄진다. 

* 프로세스의 모든 가상메모리 공간이 pagefile.sys에 저장되는것이 아니고, 확정되서 사용하다가 확정된 메모리가 잠시 사용되지 않을때 램에서 내려가는 공간이다.

 

메모리 매핑 파일 : 일반 파일이지만 PageFile.sys 처럼 메모리에 매핑한 파일. 사용자들은 CreateFileMapping, MapViewOfFile, UInmapViewOfFile 함수로 직접 디스크 내의 데이터파일에 액세스하거나 IPC수단의 메모리 공유 목적으로 사용하지만 시스템은 exe와 dll 파일의 로드와 실행 목적으로 PE파일을 MMF로 사용한다. 

exe 파일을 실행할때 시스템은 새로운 프로세스 커널 객체를 생성하고 가상주소공간을 생성한다. 이후 가상공간의 exe 파일을 포함할만큼의 충분히 큰 주소공간을 예약하는데 이 예약된 영역은 exe 파일 내부에서 예약(PageFile.sys처럼 사용)한다. 이후 여러 dll 파일을 로드할때도 마찬가지로 디스크의 dll 파일을 MMF로 사용하여 페이지 파일역할을 수행한다.

동일한 exe 파일을 두번 열었을때 두 프로세스가 하나의 PE 파일을 공동 페이지 파일로 사용하게 된다. 이때 하나의 프로세스에서 메모리에 데이터를 쓸경우 메모리 페이지의 속성이 즉각 반영될 수도 있지만, 해당 페이지가 실행가능 속성이 있다면 쓰기 동작을 했을경우 Copy-On-Write라는 메커니즘을 통해 페이지에 갱신되기 전에 PageFile.sys로 복사본을 백업한 후 해당 페이지를 갱신하게 되어 독립적인 가상메모리를 유지할 수 있게 된다. 

 

도구

DumpBin.exe : 비주얼 스튜디오에서 제공되며 PE 파일을 덤프하는데 유용한 도구이다. pe포맷, lib, exp, obj도 지원

PEBrowse64.exe : Smidgeonsoft 에서 제공하는 GUI PE 분석 툴

PEExplorer.exe : PE 파일구조를 트리 리스트뷰로 보여줌