먼저 원작자의 자료 : http://www.reversecore.com 에서 참고 했으며 Jeffrey Ritcher 의 Windows 책을 많이 참고 하였습니다.
DLL Injection에 대해 알아보겠습니다. 이글을 쓰는 목적은 보안 회사에서 개발자로 있다 보니 많이 접하게 되고 또 리버스 엔지니어링에 관심도 있고 해서 정리 해두고 자 함입니다. 물론 많은 부분을 이 싸이트에서 참고 하였지만 이렇게 정리 하니 다 제것이 되네요 ^^
DLL Injection에 대한 의미를 알아 보겠습니다.
(1) 의미 : 다른 프로세스로 하여금 LoadLibrary API 를 강제로 호출하도록 명령하여 내가 원하는 DLL를 Loading 시키는 것을 의미하며, 일반적인 DLL Loading 과 다른 점은 일반적인 DLL Loading은 자신의 프로세스에 DLL을 Loading 하는 반면DLL Injection의 경우는 다른 프로세스에 DLL를 Loading 시키는 것입니다.
여기서 중요한것은 다른 프로세스로 하여금 자신이 원하는 DLL를 강제로 LoadLibrary 하도록 한다는 점입니다. 이렇게 삽입된 DLL를 해당 프로세스(즉 타겟이 되는 프로세스)의 메모리에 대한 접근 권한을 가지기 때문에 실제로 사용자가 원하는 다양한 일을 할수 있습니다.
(2) 용도
1) 악성 코드로서의 일 - 정상적인 프로세스(Winlogon.exe, explorer.exe)에 몰래 숨어 다양한 나쁜짓을 할수가 있습니다.
2) 기능 개선 및 버그패치 - 어떤 프로그램에 Plug in 개념으로 붙어 기능개선이 가능하며 문제있는 코드, 데이타를 수정할수가 있습니다.
실제로 어떤 역할을 수행하는 dll, 즉 사용자가 어떤 기능을 넣은 dll이 있어야 겠고, 또한 그 dll을 inject 시켜줄 exe가 있어야 겠습니다.
실제로 exe 프로그램에서 dll을 inject하는 방법을 자세히 알아보겠습니다.
(3) DLL Injection를 구현하는 방법입니다.
1) 가장 일반적인 방법으로 Jeffrey Ritcher 가 제안한 CreateRemoteThread API를 이용하는 방법입니다.
a. 대상 프로세스(타겟이 되는)의 프로세스 핸들을 구합니다.
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
b. 대상프로세스(타겟이 되는)의 메모리에 Injection시킬 DLL경로를 써줍니다.
(쉬어가는 고개)
원래 Windows 구조상 메모리는 프로세스당 4GB의 독립적인 가상메모리를 갖으며, 이는 서로에게 침범을 받지 않도록
독립적인 형태로 구성 되어 있습니다. 그런데 예외적으로 Windows 운영체제는 Debug API를 제공하여 다른 프로세스의
메모리 공간에 접근 할수 있도록 하였습니다. 대표적인 API가 이곳에서 쓰게될 VirtualAllocEx(), VirtualFreeEx()
WriteProcessMemory(), ReadProcessMemory()입니다.
다시 본문으로 돌아와서 대상 프로세스의 메모리에 Injection 시킬 DLL경로를 써줍니다.
그러기 위해서는 대상 프로세스의 메모리공간을 DLL 파일 문자열 크기 경로(NULL 포함)만큼 할당합니다.
=>
LPVOID pRemoteBuf;
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
할당받은 대상 프로세스의 메모리 공간(pRemoteBuf)에 DLL 경로 문자열을 써줍니다.
=>
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDLLName, dwBufSize, NULL);
c. LoadLibrary API 주소를 가져옵니다.
왜냐하면 실제로 대상 프로세스로 하여금 LoadLibrary 하게 위해서는 LoadLibrary API 주소가 필요로하기 때문입니다.
HANDLE hMod;
hMod= GetModuleHandle("Kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryA");
실제로 pThreadProc, 4바이트주소가 필요하다는 의미입니다.
그런데 여기서 짚고 넘어 가야할 점이 있습니다.
우리가 알고자 하는 LoadLibrary API의 함수 시작 주소는 실제로 대상 프로세스(타겟이되는)의 함수 주소입니다.
그런데 위에서 말씀드린 소스는 실제 자신의 프로세스의 LoadLibrary 시작 주소입니다. 먼가 이상하지 않나여?
비밀은 여기에 있습니다.
실제로 대상 프로세스와 실제 자신의 프로세스의 LoadLibrary 시작 주소가 같다면 문제가 없을 것입니다.
일반적인 DLL 파일의 ImageBase는 0x1000000000으로 설정되어 있으며, 이미 로딩된 DLL 파일의 주소공간을
다른 프로세스도 함께 공유 하게 됩니다. DLL 주소 공간 공유 에대해서는 제 블로그를 한번 찾아 보시면 나옵니다.
DLL Injection 개념은 위와 같이 OS의 핵심 DLL들이 자신만의 고유한 주소에 로딩되는 것을 보장해주는 Windows
특성을 이용한 것입니다.
d. 이제 대상이 되는 프로세스(타겟 프로세스)로 하여금 LoadLibrary하도록 하는 코드만 있으면 끝입니다.
찾아보니 CreateRemoteThread() API 가 있네요. 이 CreateRemoteThread()라는 API는 다른 프로세스에게 쓰레드를
실행시키라고 명령하는 함수입니다.
여기서 우리가 할일은 원래의 CreateRemoteThread API는 다른 프로세스에게 쓰레드를 실행시켜주는 함수지만 쓰레드
실행이 아닌 아까 구한 LoadLibrary 함수를 호출하도록 하는 것입니다.
이것이 가능한 이유는 쓰레드 함수와 LoadLibrary 함수의 매개변수와 리턴값이 4바이트로 모두 같은이유입니다.
DWORD WINAPI ThreadProc(_in LPVOID lpParameter);
DWORD WINAPI LoadLibrary(_in LPCTSTR lpFileName);
각 API 함수 원형을 보면 바로 알수 잇죠??
이제 준비가 완료 되었습니다. 호출해줍시다.
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
WaitForSingleObject( hThread, INFINITE);
이렇게 되면 CreateRemoteThread는 실제로 대상 프로세스의 쓰레드를 실행 시킨것이 아니라 LoadLibrary 를 호출해
준셈이 됩니다.
2) 두번째 방법으로는 Windows 운영체제에서 기본적으로 제공하는 제공하는 레지스트리 키중에 APPInit_DLLs라는 것이 있습니다.
여기에 자신이 Injection 시킬 DLL를 써주면 모든 프로세스에 해당 DLL를 알아서 Injection 시켜 줍니다.
너무 강력하지만 레지스트리 키만 삭제 해버리면 무용지물이 되겠죠?? 그래서 잘 사용하지 않습니다.
3) 세번째로 SetWindowsHookEx() API를 이용하여 메시지 훅을 설치하면 OS에서 hook Procedure를 담당하고 있는 DLL를 윈도우를 가진 프로세스에 강제로 인젝션시켜 줍니다.
실제로 우리 회사(보안회사임)에서 SetWindowsHookEx를 이용하여 메시지 훅을 설치하여 윈도우를 가진 해킹 프로그램을
실제로 차단하는 소스가 있었습니다(실제로 안쓰지만 ^^)
훅 프로시져를 담당하고 있는 DLL에서(해당 해킹프로그램에 로드) 그 해킹 프로그램의 binary 값과 정책 binary 값과 비교하여 동일하면 그 프로세스를 강제 종료시키는 코드 였습니다.
4) 지금까지는 실제로 실행중인 프로세스에 강제로 Injection시키는 방법이었습니다. 이번에는 대상 프로그램 파일
자체를 수정하여 DLL를 강제로 로딩하는 방법입니다. 일종의 Crack으로 DLL Injection 하는 과정이 별도로 필요 없습니다.
파일 자체를 한번 수정하면 DLL Injection하는 과정이 별도로 필요없습니다.
실제로 notepad.exe 실행 파일에 dll를 로딩시켜 보겠습니다. notepad.exe 파일이 생성될때 자동으로 DLL를 로딩하기 위해서는
PE Header의 IMPORT DIRECTORY TABLE(IDT)에 DLL를 Import 하도록 추가해야 합니다.
이과정은 다음 블로그에 올리 도록 하겠습니다.
이제 DLL 을 Ejection 시키는 방법에 대해 알아보겠습니다. Injection 시키는 방법과 똑같습니다.
너무 성의가 없었나여?? 대상 프로세스(타겟이 되는 프로세스)로 하여금 FreeLibrary API를 호출하게 하면 됩니다.
(쉬어 가는 고개)
Windows Kernel Object에게는 Reference Count라고 하는 참조 카운트가 있습니다. LoadLibrary API를 10번 호출해주면
참조카운트가 10이되고 나중에 해제할때 FreeLibrary를 10번 호출해줌으로써 참조 카운트를 0으로 만들어 주어야 합니다
출처 : http://blog.naver.com/kkan22/80104819805
'ⓟrogramming > Programming' 카테고리의 다른 글
Processes VS Threads (0) | 2018.01.23 |
---|---|
ASN.1 (0) | 2010.11.04 |