DLL Injection 은어떻게이루어지는가? By bl4ck3y3 (http://hisjournal.net/blog) Abstract 루트킷을비롯하여바이러스, 악성코드등여러분야에두루쓰이는기법이 DLL Injection입니다. Windows에한정되어적용되는것이지만, Windows 자체의점유율이높은이유로아주효과적으로공격자가원하는작업을수행할수있는방법이죠. 최근루트킷에대해공부하면서이 DLL Injection이어떻게이루어지는알게된것을정리해봅니다. 2009 CERT-IS 1 http://cert-is.com
Content 1. DLL? 그게뭐야? ------------------------------------------------------------------------------------------------------------------------------------ 3 2. 레지스트리값을조작하여 Injection -------------------------------------------------------------------------------------------- 5 2.1. AppInit_DLLs --------------------------------------------------------------------------------------------------------------------- 5 2.2. Email-Worm.Win32.Warezov.nf ---------------------------------------------------------------------------------- 6 3. 윈도우후킹함수를이용하여 Injection --------------------------------------------------------------------------------------- 7 3.1. SetWindowsHookEx () --------------------------------------------------------------------------------------------------- 7 3.2. HookNotePadDll -------------------------------------------------------------------------------------------------------------- 8 4. 쓰레드를생성하여 Injection -------------------------------------------------------------------------------------------------------- 10 4.1. CreatRomoteThread () ------------------------------------------------------------------------------------------------ 10 5. Reference -------------------------------------------------------------------------------------------------------------------------------------------- 13 2009 CERT-IS 2 http://cert-is.com
1. DLL? 그게뭐야? DLL 은 Windows 에서사용되는동적연결라이브러리실행파일입니다. 말이어렵죠? 간단하게말해서, 실행할수있는아주작은프로그램의단위라고이해하시면되겠습니다. 라이브러리라는말은아시나요? 영어로 Library, 도서관이라는뜻이죠? 프로그램이작업을수행할때이라이브러리를참조하게됩니다. 라이브러리에포함된함수, 구조체, ( 추천하는방법은아니지만 ) 변수등을이용하는것이죠. 우리는프로그래밍을할때 (C 언어기준으로 ) 헤더파일을집어넣습니다. stdio.h, string.h 같은표준헤더부터, cimg.h, curl.h 같은사용자정의헤더까지다양하죠. 이런것을정적라이브러리라고합니다. 프로그램자체에포함되는라이브러리죠. [ 그림 1] RocketDock 이이용하는많은 DLL 파일들 이에반해동적연결라이브러리는 [ 그림 1] 에서처럼프로그램과는별도로존재합니다. 가장많이볼수 있는 kernel32.dll, user32.dll, gdi32.dll 등이동적연결라이브러리파일입니다. 프로그램은필요할때 이 DLL 을호출해서그안에있는함수를이용하지요. 2009 CERT-IS 3 http://cert-is.com
왜이렇게따로하냐구요? 이렇게함으로써두가지이익을얻을수있기때문입니다. 첫째는프로그램이메모리에적재되는용량을줄일수있다는점입니다. 프로그램자체에처음부터들 어있는게아니라, 필요할때호출하는방식이기때문에메모리에항상적재되어있을필요가없지요. 두번째는 DLL의코드가변경되어도원래의함수이름이나인자가그대로라면, 프로그램을다시컴파일하거나링킹을할필요가없다는점입니다. 정적라이브러리는변경될때마다매번컴파일하고링킹을새로해야하니 DLL은정말편리한녀석이죠. [ 그림 1] 에서 StackDocklet.dll을이용하는것을볼수있죠? 플러그인을이렇게 DLL 파일로지원할수도있습니다. StackDocklet.dll의내부코드가변경되어도함수의형태만유지된다면 RocketDock 자체를새로컴파일할필요는없겠죠? 2009 CERT-IS 4 http://cert-is.com
2. 레지스트리값을조작하여 Injection 2.1. AppInit_DLLs DLL Injection 에는여러방법이있습니다. 그중루트킷에이용되는세가지방법을알아보겠는데요. 첫번 째로레지스트리를조작하는방법입니다. HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs regedit 에서위주소의레지스트리값을확인해보면, 보통은값이비어있습니다. 그런데어떠한값이들 어있다면, 그리고그것이자신이모르는어떤파일이라면, 그것은악성코드일가능성이있습니다. 이레 지스트리값이무엇이냐구요? 바로이값이 DLL Injection 에참조되는레즈스트리값입니다. Windows 의많은어플리케이션들이 user32.dll 을호출합니다. 이 DLL 에는창관리자를호출하는 API 함수 들이있습니다. Windows 가기본적으로 GUI 환경이고그때문에어플리케이션들도 user32.dll 을호출하 기마련이죠. [ 그림 1] user32.dll 이 AppInit_DLLs 를참조하는개요 2009 CERT-IS 5 http://cert-is.com
그런데이 user32.dll 은특별한기능을가지고있습니다. [ 그림 1] 에서처럼 user32.dll 은 LoadLibrary() 함 수를이용하여 AppInit_DLLs 안에지정된 DLL 들을호출합니다. 이때 LoadLibrary() 의인자값으로 DLL_PROCESS_ATTACH 를지정해주기때문에프로세스중간에 DLL 이들어갈수있는것입니다. 공격자가이레지스트리값을악의적으로변경한다면악성코드를프로세스에심을수있죠. 대신이것이적용될려면재부팅이필요합니다. 그러나레지스트리값이변경되기이전에메모리에적재된프로세스일경우에재부팅이필요한것이지, 변경된이후에메모리에적재될프로세스라면굳이재부팅이안되더라도 DLL이삽입됩니다. 하지만이방법은해당레지스트리값만조사하면금방탐지될수있는단점이있습니다. 보통정상적인 경우라면위에서도언급했듯이값이비어있기때문이죠. 그렇더라도레지스트리가무엇인지모르는윈 도우즈사용자가대부분이기때문에이것만으로도꽤치명적이라할수있습니다. 2.2. Email-Worm.Win32.Warezov.nf Email-Worm.Win32.Warezov.nf 이라는웜이 AppInit_DLLs 값을변경하여 DLL Injection을시도하는한예입니다. 이것은이메일의첨부파일이실행되면악성 DLL을 C:\WINDOWS\system32에생성합니다. 그리고 AppInit_DLLs 값을변경하여이후에 user32.dll을호출하는프로세스에악성 DLL을삽입하죠. 이웜에대한자세한내용은아래참고문헌을읽어주세요. Email-Worm.Win32.Warezov.nf information File size : 135579 bytes MD5 : 88c8a817ae4645755fd1bb6704fabecb SHA1 : 2018a1b49b99f1c87863b4f7d1d116a181007482 SHA256 : f9bc52f93108f61c26fde81d1a9767ea4d6535c6ee4dc2d2ddf91de168ba300a TrID : File type identification 100.0% (.EXE) DOS Executable Generic (2000/1) ssdeep : 3072:a68TxpnIbL+SzOIZeniqbhxRPkdoH7rvUFsUloAO:a68TxiBOmeicbTUFsuoA PEiD : - packers (Kaspersky) : PE_Patch, UPack RDS : NSRL Reference Data Set 2009 CERT-IS 6 http://cert-is.com
3. 윈도우후킹함수를이용하여 Injection 3.1. SetWindowsHookEx () 이번에는 Windows에서정상적으로지원하는후킹함수를이용하는방법을알아보겠습니다. Windows는 OS와프로세스간에메시지를주고받는데요. 키보드를누른다던지, 마우스를클릭한다던지, 디버깅에관한메시지라던지그런것들을요. 그리고그렇게주고받는메시지를후킹할수있는함수도제공하고있습니다. [ 그림 1] SetWindowsHookEx() 함수의개요 SetWindowsHookEx() 함수가그것이죠. [ 그림 1] 처럼이함수에삽입할 DLL 의 Handler, 즉주소와함수의 주소를인자로넣음으로써메모리에올라간프로세스에삽입하게됩니다. SetWindowsHookEx (WH_KEYBOARD, KeyHookProc, hmodule, NULL); 위예처럼함수를작성합니다. hmodule 은삽입할 DLL 의주소입니다. 이것은 LoadLibrary() 함수로구할 수있죠. 그리고 KeyHookProc 은 DLL 의함수인데, GetProcAddress() 함수로구할수있고, CallBack 함수로등록할 수도있습니다. 주의할것은 KeyHookProc 는 CallNextHookEx() 함수를반환해야한다는것입니다. 후킹이 끝나고나서원래의작업을하기위해서죠. 만약, 원래의작업을하지않는다면, 사용자가무엇인가가잘 2009 CERT-IS 7 http://cert-is.com
못되었다는것을알수있고자칫하면블루스크린을띄울수도있거든요. [ 그림 1] 에서보면네번째인자로 dwthreadid 가지정되어있는데, 이것은 DLL 을삽입하려는쓰레드의 ID 입니다. GetCurrentThreadId() 함수로구할수있습니다. 이값이 0 이라면, 현재 Windows 데스크탑의 모든쓰레드가대상이되죠. [ 그림 2] idhook 테이블 첫번째인자가남았는데이것이후킹할메시지입니다. OS와여기에지정된메시지를주고받는쓰레드를후킹하지요. 이인자에들어갈수있는값은 [ 그림 2] 에정리되어있습니다. 키보드, 마우스, 디버깅, 쉘과관련된 15개의메시지들이있습니다. 이메시지들에대해더자세한내용은아래참고문헌에나와있으니여기서는생략하겠습니다. 마지막으로작업이모두끝나면메모리반환을위해서 UnhookWindowsHookEx() 함수로후킹을풀어줘 야합니다. 3.2. HookNotePadDll 아래는 SetWindowsHookEx() 함수를이용하는 HookNotePadDll 의소스입니다. #include <windows.h> 2009 CERT-IS 8 http://cert-is.com
#pragma data_seg(".npdata") HINSTANCE hmodule=null; HHOOK hkeyhook=null; HWND hwndbeeper=null; #pragma data_seg() #pragma comment (linker, "/SECTION:.npdata,RWS") LRESULT CALLBACK KeyHookProc(int ncode, WPARAM wparam, LPARAM lparam) { if (ncode>=0) { SendMessage(hWndBeeper,WM_USER+1,wParam,lParam); } return CallNextHookEx(hKeyHook,nCode,wParam,lParam); } extern "C" declspec(dllexport) void InstallHook(HWND hwnd) { hwndbeeper=hwnd; hkeyhook=setwindowshookex(wh_keyboard,keyhookproc,hmodule,null); } extern "C" declspec(dllexport) void UninstallHook() { UnhookWindowsHookEx(hKeyHook); } BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwreason, LPVOID lpres) { switch (fdwreason) { case DLL_PROCESS_ATTACH: hmodule=hinst; break; case DLL_PROCESS_DETACH: break; } return TRUE; } 2009 CERT-IS 9 http://cert-is.com
4. 쓰레드를생성하여 Injection 4.1. CreatRomoteThread () DLL Injection 의마지막세번째방법은 CreatRemoteThread() 함수를이용하는것입니다. [ 그림 1] CreatRemoteThread() 의개요 CreatRemoteThread() 함수는이름그대로쓰레드를만드는 API 함수입니다. 원격은다른프로세스에서 쓰레드를생성하기때문에붙은것이죠. [ 그림 1] 과같은구조로구성되어있고, Windows NT 계열에서 지원합니다. 첫번째인자인 hprocess 는쓰레드를생성할프로세스를가리킵니다. Windows 에서제공하는 OpenProcess() API 함수를이용해서구할수있으며, PID(Process ID) 값을이용합니다. OpenProcess() 의 원형은아래와같습니다. HANDLE WINAPI OpenProcess( in DWORD dwdesiredaccess, in BOOL binherithandle, 2009 CERT-IS 10 http://cert-is.com
); in DWORD dwprocessid 네번째인자, lpstartaddress는 LoadLibrary() 함수를가리킵니다. LoadLibray() 를이용하여 DLL을삽입하기때문이죠. 원래는쓰레드를생성할프로세스에서의 LoadLibray() 를가리켜야하지만, Windows는각프로세스의 kernel32.dll의베이스주소를일정하게관리하기때문에 DLL Loader에서사용하는 kernel32.dll의 LoadLibray() 를가리키더라도문제없다고합니다. LoadLibray() 의주소는 GetProcAddress() 를이용합니다. 원형은아래와같습니다. FARPROC WINAPI GetProcAddress( in HMODULE hmodule, in LPCSTR lpprocname ); 다섯번째인자인 lpparameter는프로세스안에서쓰레드가위치할메모리영역을가리킵니다. CreateRemoteThread() 는프로세스안에쓰레드를생성하는것이므로쓰레드를위한메모리를별도로생성해주어야하지요. 이때사용하는 API 함수가 VirtualAllockEx() 와 WriteProcessMemory() 입니다. VirtualAllockEx() 가메모리를할당하면, WriteProcessMemory() 로쓰는것이죠. 각각의원형은아래와같습니다. LPVOID WINAPI VirtualAllocEx( in HANDLE hprocess, in_opt LPVOID lpaddress, in SIZE_T dwsize, in DWORD flallocationtype, in DWORD flprotect ); BOOL WINAPI WriteProcessMemory( in HANDLE hprocess, in LPVOID lpbaseaddress, in LPCVOID lpbuffer, in SIZE_T nsize, out SIZE_T *lpnumberofbyteswritten 2009 CERT-IS 11 http://cert-is.com
); 나머지인자들은 lp* 는 NULL 로, dw* 는 0 으로넣습니다. 이중에서 dwcreationflags 에 0 을넣는것은쓰 레드가생성되는즉시실행하라는뜻입니다. 전체적으로정리해보죠. OpenProcess() 로 DLL을집어넣을프로세스를구합니다. 그리고 GetProcAddress() 로 DLL을로드하는 LoadLibrary() 의주소를구합니다. 마지막으로 VirtualAllockEx() 로 DLL이위치할메모리를할당하고 WriteProcessMemory() 로쓰게됩니다. 이모든것들을 CreateRemoteThread() 의인자값으로넣어서 DLL Loader에서실행합니다. 이러면 DLL Injection이된것입니다. 간단하죠? 하지만이방법은간단한대신쉽게탐지되기도합니다. CreateRemoteThread() 를호출하면 CreatThreat() 가호출되고, 그안에서다시 BaseThreadStartThunk() 가호출된다고합니다. 이 BaseThreadStartThunk() 를후킹해서 lpstartaddress가위에서설명한대로 LoadLibray() 나 GetProcAddress() 를가리킨다면 DLL Injection이라고간주하는것이죠. 2009 CERT-IS 12 http://cert-is.com
Reference 루트킷 : 윈도우커널조작의미학, Greg Hoglund, James Butler, 2007, 에이콘 Dynamic-link library :: http://en.wikipedia.org/wiki/dynamic-link_library Visual C++ DLL :: http://msdn.microsoft.com/ko-kr/library/1ez7dh12(vs.80).aspx 부팅할때읽는주요파일 :: http://fd.igrus.kr/?mid=study&document_srl=1013 Email-Worm.Win32.Warezov.nf 정보 :: http://blog.daum.net/virusmyths/6041710 SetWindowsHookEx() 함수를이용한방법 :: http://blog.naver.com/amanahnr/90032952064 Shield from DLL-Injection :: http://nerd.egloos.com/2940078 SetWindowsHookEx Function :: http://msdn.microsoft.com/library/ms644990.aspx CreateRemoteThread Function :: http://msdn.microsoft.com/en-us/library/ms682437(vs.85).aspx OpenProcess Function :: http://msdn.microsoft.com/en-us/library/ms684320(vs.85).aspx GetProcAddress Function :: http://msdn.microsoft.com/en-us/library/ms683212(vs.85).aspx VirtualAllocEx Function :: http://msdn.microsoft.com/en-us/library/aa366890(vs.85).aspx WriteProcessMemory Function :: http://msdn.microsoft.com/en-us/library/ms681674(vs.85).aspx 2009 CERT-IS 13 http://cert-is.com