반응형

Dll Injection
API Hooking기법에 따라 차이는 있겠으나, API Hooking을 위해서는 대상프로세스의 주소 공간안에서의 메모리 조작이 필요하다.
이를 위해 사용되는 방법이 바로 Dll Injection이다. 즉 타겟 프로세스로 하여금 우리가 작성한 Dll을 로드하도록 하고, 해당 프로세스에 로드된 Dll에서 APIHooking하는 방식이다
.
많이 사용되는 Dll Injection방법으로는 아래의 세가지 방법이 있다
.
( Dll Injection
API Hooking뿐만 아니라, 소스코드가 없는 프로그램에 대한 패치나 구조분석 등에도 사용될 수 있다. )

 

(1) AppInit_DLLs 레지스트리 이용

1) 개요

User32.dll(User32.dll에서 Export API를 사용하는 모든 프로그램은) DLL_PROCESS_ATTACH 처리 과정에서 LoadLibrary()함수를 이용하여, 아래 키 값의 AppInit DLLs엔트리에 등록된 모든 Dll을 로드한다. 이러한 동작을 이용하여 우리의 Dll을 다른 프로세스에 Injection 시킨다.

n HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows
( AppInit DLLs
에는 스페이스(‘ ‘)를 구분자로 하여 여러 개의 Dll을 등록할 수 있다. )

2) 주의 사항

하지만 이 방법의 경우, 등록된 dll이 프로세스 생성과정의 전반부에서 로딩되므로, dll 로드과정에서는 kernel32.dll에서 export한 함수만을 안전하게 사용할 수 있다.(하단 URL참조)

모든 프로세스에 Injection하기 위해서는 시스템 리부팅이 필요하다. 간혹 이 기능이 동작하기 위해서는 무조건 리부팅이 필요하다고 기술한 문서들이 있는데, 리부팅하지 않더라도 해당 레지스트리에 Dll을 등록한 이후에 생성되는 프로세스는 영향을 받는다.

Dll Inject 시점을 임의로 조절할 수 없으며, Injection대상 프로세스를 지정할 수도 없다.

Dll Unload시킬 수 있는 방법이 없다.

가급적 이 방법 사용하지 않는 것이 좋을 것 같다.

3) 참고 URL
http://support.microsoft.com/kb/197571

 

(2) SetWindowsHook()함수 사용

1) 개요
SetWindowsHook() API를 이용하여 특정 HookType에 대해 Hooking을 시도하게 되면, Dll내의 Hook Procedure뿐만 아니라, Dll코드 전체가 대상 프로세스의 메모리공간에 로드 된다. 이러한 특성을 이용하여 다른 프로세스에 Injection한다.

2) 함수 원형

HHOOK SetWindowsHookEx(

int idHook, // type of hook to install

HOOKPROC lpfn, // address of hook procedure

HINSTANCE hMod, // handle to application instance

DWORD dwThreadId // identity of thread to install hook for

);

BOOL UnhookWindowsHookEx(

HHOOK hhk // handle to hook procedure to remove

);

3) 구현

Hook Handle공유

n SetWindowsHook()호출을 통해 리턴되는 HHOOK 타입의 핸들은, Hooking 대상 메시지(?) Hook체인으로 전달하기 위해, 모든 Dll 인스턴스들이 공유해야 한다. 이를 위해 shared속성을 갖는 섹션에 선언한다.

#pragma data_seg(".hkshared")

HHOOK   g_hHook = NULL;

#pragma data_seg()

#pragma comment(linker, "/SECTION:.hkshared,RWS) //Read|Write|Shared

 

(3) CreateRemoteThread()

1) 개요
CreateRemoteThread()를 이용하여 이미 존재하는 프로세스내에 원격스레드를 생성하고, 이 원격스레드의 시작 함수로 Kernel32.dll LoadLibrary()의 주소를, 파라미터로 우리가 로드하려하는 hookDll의 파일명(혹은 FullPath)를 전달한다.
이 방법은 CreateRemoteThread() 4번째 인자인lpStartAddress LoadLibrary()의 함수원형이 같다는 점에서 유효하다.( 엄밀히 말하자면 같지는 않지만, 4byte의 인자와 4byte의 리턴값을 취한다는 점에서 동일하게 취급할 수 있다.)

2) 함수원형

HANDLE CreateRemoteThread(

HANDLE hProcess, // handle to process to create thread in

LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to security attributes

DWORD dwStackSize, // initial thread stack size, in bytes

LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function

LPVOID lpParameter, // argument for new thread

DWORD dwCreationFlags, // creation flags

LPDWORD lpThreadId // pointer to returned thread identifier

);

3) 구현

전술한 내용을 이용하여 CreateRemoteThread()를 호출하려면 4번재 파라미터로 , 타겟프로세스 내에서의 LoadLibrary() 함수의 주소를 구하여 넘겨주어야 한다. 하지만 아시다시피 각 프로세스는 별도의 메모리 공간을 가지고 있다.

n Kernel32.dll, ntdll.dll, user32.dll등의 시스템 dll들은 중복되지 않는 고유의 Address를 갖으므로, Dll Injection을 시도하는 프로세스에서 구한 Address는 타겟 프로세스에서도 유효하다.( Windows System Dll들은 로딩시 Relocation을 피하기 위해 고유의 BaseAddress를 가지고 있다 )

CreateRemoteThread()의 다섯번째 인자인 lpParameter에는 우리가 로드할 Dll의 이름을 넘겨주어야 한다. 하지만 파라미터로 전달해야하는 hookDll의 파일명을 Dll Injection을 시도하는 프로세스의 주소로 넘겨주어서는 의미가 없다. 각각의 프로세스는 고유의 메모공간을 가지므로, Dll Injection을 시도하는 프로세스의 주소는 타겟 프로세스에서 유효하지 않다.

n 이를 위해 타겟 프로세스에 메모리 공간을 할당하고, 그 메모리에 우리의 hookDll의 이름을 적어주어야 하는데 다음의 함수들을 사용해서 구현할 수 있다.

HANDLE OpenProcess(

DWORD dwDesiredAccess,

BOOL bInheritHandle,

DWORD dwProcessId

);

OpenProcess()는 프로세스ID를 인자로 받아 해당 프로세스의 핸들을 리턴한다.

이 핸들값은 VirtualAllocEx(), WriteProcessMemory()의 첫번째 인자로 사용된다.

LPVOID VirtualAllocEx(

HANDLE hProcess,

LPVOID lpAddress,

SIZE_T dwSize,

DWORD flAllocationType,

DWORD flProtect

);

VertualAllocEx()는 첫번째 인자로 주어진 프로세스의 가상메모리내에 메모리를 할당한다.

BOOL WriteProcessMemory(

HANDLE hProcess,

LPVOID lpBaseAddress,

LPCVOID lpBuffer,

SIZE_T nSize,

SIZE_T* lpNumberOfBytesWritten

);

VertualAllocEx()는 첫번째 인자로 주어진 프로세스의 가상메모리내에 Write를 지원한다.

4) 기타

CreateRemoteThread()를 이용해 Injection시킨 Dll은 아래와 같은 절차로 Unload시킬 수 도 있다.

n Injection GetExitCodeThread()를 통해 LoadLibray()가 리턴한 값(모듈핸들)을 보관

n LoadLibrary()를 리모트 프로세스에서 실행시킨 것과 마찬가지 방법으로 FreeLibrary()를 실행(FreeLibrary역시 4바이트의 인자를 가지며, 4바이트의 값을 리턴한다)

Vista이상의 경우 다른 세션에 존재하는 프로세스를 대상으로 CreateRemoteThread()를 호출할 경우, 실패한다( lasterror: NOT_ENOUGH_MEMORY) 세션별로 Injection 프로세스를 띄워주면 되겠지만 용이치 않을 경우, ntdll!NTCreateThreadEx()를 사용하면 된다고 한다.(Vista이상의 OS만 유효함)

n (http://blog.naver.com/rkawk01?Redirect=Log&logNo=70046078078)

n http://code.google.com/p/easyhook-continuing-detours/source/browse/trunk/EasyHook_Specific/RemoteHook/RemoteHooking.cpp?spec=svn9&r=9

 

 

반응형

+ Recent posts