2016. 1. 17. 04:30

프로세스의 DLL 확인

DLL 인젝션을 진행하기 전 프로세스에 로드된 DLL을 확인하는 방법을 설명한다.




프로세스에 로드된 DLL은 올리디버거나 Process Explorer를 이용하여 확인할 수 있다. 올리디버거에서는 E버튼을 클릭하여 열린 Excutable modules 윈도우에서 확인할 수 있다. 그리고 Process Explorer에서는 View > Lower Pane View > DLLs를 클릭하면 하단에서 확인할 수 있다.


DLL 인젝션

DLL 인젝션이란 말 그대로 실행중인 프로세스에 임의의 DLL을 주입하는 것이다. 윈도우즈의 프로세스들은 DLL을 로드할 때 자신의 메모리 영역에 DLL의 코드를 로드한다. 그렇기 때문에 주입된 DLL은 해당 프로세스의 메모리 영역에 접근할 수 있는 권한을 갖게 되고 많은 일을 할 수 있다. 이후부터 DLL 인젝션을 수행하기 위한 방법을 설명한다.


DLL 코드

DLL 인젝션이 성공하여 DLL의 엔트리 포인트인 DllMain함수가 실행되면 간단히 메시지 박스를 띄운다.


원격 스레드 생성

윈도우즈 API를 이용하여 쉽게 DLL 인젝션을 수행할 수 있다.

DLL 인젝션을 수행하는 코드. 인자로 PID와 DLL의 경로를 입력받고 DLL 인젝션을 수행한다.

OpenProcess 

VirtualAllocEx

WriteProcessMemory

GetModuleHandle

GetProcAddress

CreateRemoteThread

DLL 인젝션은 위의 표에 있는 API만 이용하면 수행할 수 있다. CreateRemoteThread함수가 DLL 인젝션에 핵심적인 역할을 하며 나머지 함수들은 모두 CreateRemoteThread함수를 위해 사용된다. 이 함수를 중심으로 코드를 분석해보자.


26번째 줄의 CreateRemoteThread함수는 다른 프로세스에 특정한 스레드를 실행하기 위해 사용된다. 인자로 전달되는 process, threadProc, buffer의 용도를 살펴보자.


process가 사용된 곳의 인자에는 프로세스의 핸들이 전달되어야한다. 16번째 줄에서 인자로 쓰였던 process 변수가 정의된다. OpenProcess함수를 이용하여 프로그램에 인자로 전달했던 pid로부터 프로세스의 핸들을 가져온다.


threadProc가 사용된 곳의 인자에는 스레드로 실행시킬 함수의 포인터가 전달되어야한다. 23, 24번째 줄에서 kernel32.dll의 LoadLibraryW 함수의 포인터 주소를 가져오고 LoadLibraryW 함수의 포인터가 threadProc에 저장된다.


buffer가 사용된 곳의 인자에는 스레드로 실행되는 함수에 전달될 인자가 전달되어야한다. 주의할 점은 다른 프로세스에서 LoadLibraryW 함수가 실행되기 때문에 전달되는 인자는 다른 프로세스의 환경에 맞춰주어야 한다는 것이다. 18, 21번째 줄에서 이 작업을 한다. VirtualAllocEx 함수로 다른 프로세스에 메모리 영역을 동적으로 할당하고, 이 영역에 WriteProcessMemory 함수를 이용하여 인자로 전달 될 DLL의 경로를 메모리에 기록한다.


과정을 요약하면 다음과 같다.

  1. OpenProcess 함수로 DLL 인젝션을 수행되는 프로세스의 핸들을 가져온다.
  2. VirtualAllocEx 함수로 DLL 인젝션이 수행되는 프로세스에서 메모리 동적 할당을 한다.
  3. WriteProcessMemory 함수로 DLL 인젝션이 수행되는 프로세스에 DLL의 경로를 기록한다.(2번 과정에서 얻은 주소에 기록)
  4. GetModuleHandle 함수와 GetProcAddress 함수를 이용하여 kernel32.dll의 LoadLibraryW 함수의 주소를 얻는다.
  5. CreateRemoteThread 함수로 DLL 인젝션을 수행한다.
CreateRemoteThread 함수로 다른 프로세스에서 LoadLibraryW 함수가 실행되고, LoadLibraryW 함수의 인자에는 우리가 주입하기 원하는 DLL의 경로가 전달되기 때문에 DLL 인젝션이 수행된다.

아래의 예시는 PID가 5436인 Process Explorer에 DLL 인젝션을 수행한 모습이다.

00FA0000 주소에 injected.dll 문자열이 저장되어 있다.


참고
CreateRemoteThread 함수를 사용할 때 인자들은 첫 번째 인자에 해당하는 프로세스의 환경에 맞추어 전달하라고 했다. buffer는 그렇게 전달하였으나 LoadLibraryW 함수의 포인터는 그냥 현재 프로세스에서 구한 것을 그대로 전달하였다. 이렇게 해도 실행에 문제가 없는 이유는, kernel32.dll 처럼 시스템 dll 들은 재배치가 일어나지 않아서 모든 프로세스에서 같은 주소에 로드되기 때문이다.

레지스트리
아주 간단한 방법으로 DLL 인젝션을 수행할 수 있다.

레지스트리에서 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows 경로로 이동한 후 AppInit_DLLs를 수정한다.

운영체제에 의해 AppInit_DLLs의 값에 있는 DLL은 실행되는 모든 프로세스에 주입된다. 이는 재부팅 이후부터 적용되니 재부팅을 하여 확인해보자.


이렇게 블루스크린이 뜨는 걸 보면 부팅 프로세스부터 잘 적용이 되는 것 같다.


후킹 API 사용

'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 24  (0) 2016.01.20
Reverse Engineering Chap 18-20  (0) 2016.01.17
Reverse Engineering Chap 14~15  (0) 2016.01.14
Reverse Engineering Chap 16-17  (0) 2016.01.14
Reverse Engineering Chap 13  (0) 2016.01.12
Posted by 지환태