chap25. PE 패치를 이용한 DLL 로딩
25.1. 목표 & 실습파일
이전까지는 실행 중인 프로세스에 DLL를 강제로 인젝션하는 방법이였다면, 이번 챕터에서는 실행파일을 직접 수정하여 DLL을 강제로 로딩하는 방법에 대한 내용이다.
아래의 TextView.exe 파일을 수정하여 실행 시 myhack3.dll을 로딩하도록 만드는 것이 최종 목표이다.
TextView.exe 파일은 간단한 텍스트 뷰어이며, 원하는 파일을 마우스로 드롭하면 열 수 있다.
아래는 PEView를 이용하여 TextView.exe 실행파일의 IDT(Import Directory Table)를 살펴본 화면이다.
KERNEL32.dll, USER32.dll, GDI32.dll, SHELL32.dll 을 임포트하고 있다.
25.2. 소스코드 - myhack3.cpp
- DLLMain()
DLLMain()에서는 ThreadProc() 스레드를 실행시키고, ThreadProc() 에서는 DownloadURL()과 DropFile() 함수를 호출한다.
- DownloadURL()
DownloadURL() 함수는 szURL에 명시된 인터넷 파일을 다운받아서 szFile 경로에 저장하는 기능을 수행한다. (이 예제에서는 www.google.com 사이트에서 index.html 파일을 받아옴)
- DropFile()
DropFile() 함수는 다운받은 index.html 파일을 현재 프로세스에 드롭시켜서 그 내용을 보여준다. 즉, 이후에 TextView.exe 파일에 myhack3.dll을 임포트시키게 되면 TextView.exe 파일에서는 index.html 파일을 보여주게 된다.
- dummy()
dummy()함수는 myhack3.dll 파일에서 외부로 서비스하는 Export함수이다. 코드에서 보면 함수내에서 아무런 기능도 하지 않는 것을 확인할 수 있다. 아무런 기능을 하지 않는 함수를 추가한 이유는 TextView.exe 파일의 임포트 테이블에 myhack3.dll이 추가될 수 있도록 형식적인 완전성을 갖추기 위해서이다. PE 파일에서 DLL을 임포트한다는 것은 파일의 코드 내에서 그 DLL이 제공하는 Export 함수를 호출한다는 뜻이기 때문에 DLL 파일은 최소한 하나 이상의 Export 함수를 제공해야 한다.
25.3. TextView.exe 파일 패치 준비 작업
25.1에서 알아보았듯이 '.rdata' 섹션에 IDT가 있고, IDT는 IMAGE_IMPORT_DESCRIPTOR 구조체 배열로 이루어져 있다. (마지막은 NULL 구조체임)
위와 같이 IID 구조체의 크기는 14(hex)이며, 실제로 TextView.exe 에서도 IID 영역이 RVA:84CC~852F 이고 5개의 IID가 있으므로 각 IID의 크기는 14, 전체 크기는 64임을 알 수 있다.
PEView에서 주소 보기 옵션을 'File Offset'으로 변환하면 다음과 같이 IDT의 파일 오프셋은 76CC이다.
HxD 유틸리티에서 TextView.exe 파일을 열어 76CC~772F 영역을 확인하면 다음과 같다.
IDT바로 다음 부분은 다른 데이터가 존재하기 때문에 myhack3.dll을 위한 IID 구조체를 덧붙일 수 없는 것을 확인할 수 있다. 따라서 IDT 전체를 다른 위치로 옮긴 후 새로운 IID를 추가시켜야 한다.
<새로운 위치를 선택하는 방법>
1. 파일의 다른 빈 영역을 찾음
2. 파일의 마지막 섹션의 크기를 늘임
3. 파일 끝에 새로운 섹션을 추가함
첫번째 방법으로 해결하기 위해 '.rdata'에서 빈 공간을 찾으면 다음과 같다.
RVA:8C60~8DFF 영역이 Null-Padding 영역으로 보이는데, 진짜 Null-Padding 영역인지는 헤더를 통해 확인해야 한다.
'.rdata'의 헤더를 보면 Size of Raw Data(파일의 크기)는 2E00 이지만, Virtual Size(메모리의 크기)는 2C56 인 것을 알 수 있다. 즉, 뒷 부분의 1AA(2E00 - 2C56) 영역은 사용되지 않는 부분이기 때문에 이 위치에 IDT를 재구성하는 것이 문제가 되지 않는다는 것을 알 수 있다.
'.rdata'의 1AA만큼의 영역을 HxD 유틸리티를 이용하여 확인하면 다음과 같다.
25.4. TextView.exe 패치 작업
<Import Table의 RVA 값 변경>
기존의 TextView.exe 파일을 복사하여 새로운 이름 TextVeiw_Patch.exe를 하나 만들고, TextView.exe는 PEView로 열어서 PE 정보를 확인하고, TextView_Patch.exe는 HxD로 열어서 실제로 값을 변경시키는 방식으로 진행한다.
기존에 Import Table의 위치는 84CC(RVA)이고, 사이즈는 64이다.
이를 RVA 위치를 8C80, 크기를 78(64+14)로 변경한다.
<Bound Import Table 제거>
IMAGE_OPTIONAL_HEADER에 Bound Import Table이 있는데, 이는 DLL 로딩 속도를 향상시킬 수 있는 기법이다. 이 테이블은 옵션이기 때문에 반드시 존재할 필요가 없다. 따라서 0으로 변경하면 된다. (존재하지 않는 것은 상관 없지만, 존재하면서 정보가 잘못 입력되어 있으면 실행시 에러가 발생한다.) TextView.exe 파일은 이미 0으로 설정되어 있기 때문에 변경할 필요가 없다.
<새로운 IDT 생성>
기존의 IDT(RAW : 76CC~772F)를 복사하여 새로운 IDT 위치(RAW : 7E80)에 덮어쓴다.
<Name, INT, IAT 세팅>
이 상태에서 새로 생성한 IDT의 마지막 구조체 영역에(RAW : 7ED0)에 myhack3.dll을 위한 IID를 구성하여 추가시켜야 한다.
다음 그림과 같이 추가시킬 것이다. RVA 주소를 다음과 같이 정한 이유는 해당 공간이 비어있고 IID 바로 다음 영역이기 때문이다.
HxD의 왼쪽 파란색 글씨는 파일 오프셋이고, 빨간 글씨로 수정한 부분은 RVA를 입력한 것이므로 RVA와 RAW를 구분할 필요가 있다.
여기서 INT, Name, IAT의 주소는 빈 공간에 임의로 설정한 것이다. 따라서 해당 공간에는 정해진 형식에 따라 데이터를 채워야 한다. INT(Import Name Table)은 RVA 배열인데, 각 원소는 IMAGE_IMPORT_BY_NAME 구조체의 주소이다. IAT(Import Address Table) 또한 RVA 배열이며, 각 원소는 INT와 같은 값을 가져도 된다. INT가 정확하다면 IAT는 다른 값을 가져도 상관 없다. 어차피 메모리상에서 IAT의 영역은 PE로더에 의해 실제 함수 주소로 덮여 써지게 된다.
형식에 맞게 데이터를 추가시키면 다음과 같다.
<IAT 섹션의 Characteristics 변경>
IAT는 PE로더에 의해서 메모리에 로딩될 때 실제 함수 주소로 덮어 쓰여지게 되므로 해당 섹션은 반드시 WRITE 속성을 가져야 한다. '.rdata' 섹션의 헤더를 보면 다음과 같다.
Characteristics 속성에 IMAGE_SCN_MEM_WRITE (80 00 00 00)을 bit OR로 추가하게 되면 최종 Characteristics는 C0 00 00 40이 된다.
25.5. 검증
새로 만든 TextView_Patch.exe 파일을 PEView로 열어서 IDT를 확인하면 다음과 같이 myhack3.dll이 등록된 것을 확인할 수 있다.
또한 INT에 dummy() 함수가 추가된 것을 확인할 수 있다.
TextView_Patch.exe를 실행시켰을 때, Process Exploler로 프로세스를 살펴보면 myhack3.dll이 로딩되어 있는 것을 확인할 수 있다.
Chap26. PE Tools
다운로드 경로 : http://uinc.ru/files/neox/PE_Tools.shtml
26.1. 프로세스 메모리 덤프
리버싱에서 덤프(Dump)라는 것은 메모리의 내용을 그대로 파일로 저장시킨다는 뜻이다. 실행 압축된 프로그램의 경우 덤프롤 통해 내부 문자열 등을 빠르고 간단하게 확인할 수 있다는 장점이 있다.
화면 구성은 위의 사진과 같이 실행중인 프로세스가 상단에 위치하고, 프로세스를 선택하면 해당 프로세스에 로딩된 DLL이 하단에 표시된다. 프로세스를 우클릭하면 세가지 종류의 덤프를 선택할 수 있다.
<Dump Full>
메모리에 로딩되었을 때의 모습인 PE Image를 모두 덤프한다.(프로세스의 PE 헤더를 검사하여 ImageBase 주소에서부터 SizeOfImage 크기만큼)
<Dump Partial>
사용자가 지정하는 주소에서부터 지정하는 크기만큼 덤프한다.
<Dump Region>
프로세스 메모리(유저 영역)의 모든 분할 영역이 표시되며 state가 COMMIT인 메모리 영역에 대해 덤프 작업을 수행할 수 있다.
26.2. PE Editor
PE 파일을 수동으로 패치할 때에는 PE 헤더 정보를 수정해야 하는데, 이 때 PE Editor 기능을 사용하면 편리하다.
PE 파일을 드래그하거나 Tools - PE Editor 항목을 선택하여 이용할 수 있다.
'리버싱핵심원리' 카테고리의 다른 글
Reverse Engineering Chap 32 (0) | 2016.01.24 |
---|---|
Reverse Engineering Chap 28 (0) | 2016.01.24 |
Reverse Engineering Chap 24 (0) | 2016.01.20 |
Reverse Engineering Chap 18-20 (0) | 2016.01.17 |
Reverse Engineering Chap 23 (0) | 2016.01.17 |