반응형

DLL Injection 구현 방법


몇 가지 구현 방법이 있습니다.

그 중에서 가장 유명한 방법이 CreateRemoteThread() API 를 이용하는 방법입니다.

이 방법은 윈도우즈 프로그래밍 서적의 바이블인 Jeffrey Richter Programming Applications for Microsoft Windows 에 소개된 내용입니다.

일단 소스 코드를 보겠습니다. (엔지니어에게는 백 마디 설명 보다는 역시 소스 코드를 한번 보는게 낫죠.)

먼저 Injection 시킬 myhack.dll 소스 코드입니다.

myhack.cpp


// myhack.cpp

#include "stdio.h"
#include "windows.h"

#pragma comment(lib, "urlmon.lib")

#define DEF_NAVER_ADDR ("http://www.naver.com/index.html")
#define DEF_INDEX_PATH ("c:\\index.html")

DWORD WINAPI ThreadProc(LPVOID lParam)
{
    URLDownloadToFile(NULL, DEF_NAVER_ADDR, DEF_INDEX_PATH, 0, NULL);
    return 0;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    HANDLE hThread = NULL;

    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH :
            hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
            CloseHandle(hThread);
            break;
    }
  
    return TRUE;
}

아주 간단한 코드입니다.

DllMain() 을 보시면 DLL 이 로딩(DLL_PROCESS_ATTACH)될 때 스레드(ThreadProc)를 실행합니다.

ThreadProc() 의 내용은 urlmon.dll 의 URLDownloadToFile() 함수를 실행시켜서 네이버 초기화면(index.html)을 다운받습니다.

프로세스에 DLL Injection 이 발생하면 해당 DLL 의 DllMain() 함수가 호출된다고 이전 포스트에서 설명드렸습니다. 따라서 notepad.exe 프로세스에 myhack.dll 이 Injection 되면 결국 URLDownloadToFile() 함수가 실행될 것입니다.

* DLLMain() 에서 직접 URLDownloadToFile() 을 호출하면 간혹 hang 이 걸리는 경우가 있어서, 별도의 스레드를 생성하여 호출하도록 프로그래밍 하였습니다.



이제 myhack.dll 을 notepad.exe 프로세스에 Injection 시켜줄 프로그램(InjectDll.exe)의 소스코드를 보시겠습니다.

InjectDll.cpp


// InjectDll.exe

#include "stdio.h"

#include "windows.h"
#include "tlhelp32.h"

#define DEF_PROC_NAME ("notepad.exe")
#define DEF_DLL_PATH ("c:\\myhack.dll")

DWORD FindProcessID(LPCTSTR szProcessName);
BOOL InjectDll(DWORD dwPID, LPCTSTR szDllName);

int main(int argc, char* argv[])
{
    DWORD dwPID = 0xFFFFFFFF;
 
    // find process
    dwPID = FindProcessID(DEF_PROC_NAME);
    if( dwPID == 0xFFFFFFFF )
    {
        printf("There is no <%s> process!\n", DEF_PROC_NAME);
        return 1;
    }

    // inject dll
    InjectDll(dwPID, DEF_DLL_PATH); 

    return 0;
}

DWORD FindProcessID(LPCTSTR szProcessName)
{
    DWORD dwPID = 0xFFFFFFFF;
    HANDLE hSnapShot = INVALID_HANDLE_VALUE;
    PROCESSENTRY32 pe;

    // Get the snapshot of the system
    pe.dwSize = sizeof( PROCESSENTRY32 );
    hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, NULL );

    // find process
    Process32First(hSnapShot, &pe);
    do
    {
        if(!_stricmp(szProcessName, pe.szExeFile))
        {
            dwPID = pe.th32ProcessID;
            break;
        }
    }
    while(Process32Next(hSnapShot, &pe));

    CloseHandle(hSnapShot);

    return dwPID;
}

BOOL InjectDll(DWORD dwPID, LPCTSTR szDllName)
{
    HANDLE hProcess, hThread;
    HMODULE hMod;
    LPVOID pRemoteBuf;
    DWORD dwBufSize = lstrlen(szDllName) + 1;
    LPTHREAD_START_ROUTINE pThreadProc;

    // #1. dwPID 를 이용하여 대상 프로세스(notepad.exe)의 HANDLE을 구함
    if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
        return FALSE;

    // #2. 대상 프로세스(notepad.exe) 메모리에 szDllName 크기만큼 메모리를 할당
    pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);

    // #3. 할당 받은 메모리에 myhack.dll 경로("c:\\myhack.dll")를 씀
    WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL);

    // #4. LoadLibraryA() API 주소를 구함
    hMod = GetModuleHandle("kernel32.dll");
    pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryA");

    // #5. notepad.exe 프로세스에 스레드를 실행
    hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
    WaitForSingleObject(hThread, INFINITE); 

    CloseHandle(hThread);
    CloseHandle(hProcess);

    return TRUE;
}

역시 코드가 간결합니다. (편의상 예외처리, 리턴값 체크 등의 코드는 생략하였습니다.)

main() 함수에서는 2개의 서브 함수를 호출하고 있습니다.

FindProcessID(DEF_PROC_NAME) 함수는 프로세스 이름으로 PID(Process ID) 를 구해주는 함수입니다. (설명은 생략합니다.) 그리고 InjectDll(dwPID, DEF_DLL_PATH) 함수가 바로 DLL Injection 을 해주는 핵심 함수입니다.

InjectDll() 함수를 자세히 살펴보겠습니다.

InjectDll() 함수는 대상 프로세스(notepad.exe)로 하여금 스스로 LoadLibrary("myhack.dll") API 를 호출하도록 명령하는 기능을 가지고 있습니다.

#1. 대상 프로세스 핸들 구하기

hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID))

OpenProcess() API 를 이용해서 notepad.exe 의 프로세스 핸들을 구합니다. (이때 미리 구해놓은 PID 를 사용함)
이 프로세스 핸들(hProcess)을 이용해서 해당 프로세스(notepad.exe)를 제어할 수 있습니다.

#2-3. 대상 프로세스 메모리에 Injection 시킬 DLL 경로를 써주기

pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);

대상 프로세스(notepad.exe)에게 로딩할 DLL 파일의 경로(문자열)를 알려줘야 합니다.
아무 메모리 공간에 쓸 수 없으므로 VirtualAllocEx() API 를 이용하여 대상 프로세스(notepad.exe) 메모리 공간에 버퍼를 할당합니다. 버퍼 크기는 DLL 경로 문자열 길이(NULL 포함)입니다. 

* 주의! 
VirtualAllocEx() 함수의 리턴값(pRemoteBuf)은 할당된 버퍼 주소입니다. 이 주소는 내 프로세스(Inject.exe)의 메모리 주소가 아니라 hProcess 핸들이 가리키는 대상 프로세스(notepad.exe)의 메모리 주소라는것을 꼭 기억하시기 바랍니다.


WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL);

할당 받은 버퍼 주소(pRemoteBuf)에 WriteProcessMemory() API 를 이용하여 DLL 경로 문자열("C:\\myhack.dll")을 써줍니다.

이로써 대상 프로세스(notepad.exe) 메모리 공간에 Injection 시킬 DLL 파일의 경로가 생겼습니다.

* 참고
Win32 프로그래밍을 처음 배울 때 분명 다른 프로세스의 메모리에 읽고 쓰는 일이 어렵다고(혹은 불가능하다고) 배웠습니다. 하지만 실제로는 다른 프로세스의 메모리 공간에 접근을 못하면 운영체제도 답답해 집니다. (예를 들어 다른 프로세스 메모리에 접근 할 수 없다면 디버거 제작이 불가능해지지요.) 그래서 Windows 운영체제는 Debug API 를 제공하여 다른 프로세스 메모리 공간에 접근 할 수 있도록 하였습니다. 대표적인 Debug API 가 바로 위에서 소개해 드린 VirtualAllocEx(), VirtualFreeEx(), WriteProcessMemory(), ReadProcessMemory() 등이 있습니다.

#4. LoadLibraryA() API 주소를 구하기

hMod = GetModuleHandle("kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryA");


LoadLibrary() API 를 호출시키기 위해 그 주소가 필요합니다.
(LoadLibraryA() 는 LoadLibrary() 의 ASCII 문자열 버전입니다.)

위 코드의 의미를 잘 생각해봐야 합니다.
우리는 분명 notepad.exe 에 로딩된 kernel32.dll 의 LoadLibraryA() API 의 시작 주소를 알아내야 합니다.
하지만 위 코드는 InjectDll.exe 에 로딩된 kernel32.dll 의 LoadLibraryA() API 의 시작 주소를 얻어내고 있습니다.

notepad.exe 에 로딩된 kernel32.dll 과 InjectDll.exe 에 로딩된 kernel32.dll 의 메모리 시작 위치(ImageBase)가 동일 하다면 위 코드는 문제가 없습니다.

일반적인 DLL 파일의 ImageBase 는 0x10000000 으로 설정되기 때문에 a.dll 과 b.dll 을 차례대로 로딩하면 a.dll 은 정상적으로 0x1000000 주소에 로딩이 되겠지만 b.dll 은 자신이 원하는 0x10000000 주소에 로딩되지 못하고 다른 비어 있는 주소 공간에 로딩됩니다. 즉, DLL Relocation 이 발생하는 것입니다. (a.dll 이 같은 주소에 이미 로딩되어 있기 때문입니다.)

만약 kernel32.dll 이 프로세스마다 다른 주소에 로딩된다면 위 코드는 잘못된 것입니다.
하지만 실제 Winodows 운영체제에서 kernel32.dll 은 프로세스마다 같은 주소에 로딩됩니다.

어째서 그런걸까요?

PE View 를 통해서 Windows 운영체제의 핵심 DLL 파일들의 ImageBase 값을 조사해 봤습니다.
(Windows XP SP3 KOR 버전입니다. Windows 업데이트 상태에 따라서 아래 값들은 달라질 수 있습니다.)

DLL file        ImageBase       SizeOfImage
--------------------------------------------
msvcrt.dll      77BC0000        00058000
user32.dll      77CF0000        00090000
gdi32.dll       77E20000        00049000
advapi32.dll    77F50000        000A8000
kernel32.dll    7C7D0000        00130000
shell32.dll     7D5A0000        007FD000
...


Microsoft 에서 친절하게 OS 핵심 DLL 파일들의 ImageBase 값을 이쁘게 정리해놨습니다.
즉, 자신들끼리 절대로 겹치지 않고 따라서 DLL Relocation 이 발생하지 않습니다.

Dll Injection 기법은 위와같이 OS 핵심 DLL 들은 자신만의 고유한 주소에 로딩된는 것을 보장해주는 Windows 특성을 이용한 것입니다. (이 특성이 Windows 보안 취약점으로 이용되기도 합니다.)

따라서 InjectDll.exe 프로세스에 import 된 LoadLibraryA() 주소와 notepad.exe 프로세스에 import 된 LoadLibraryA() 주소는 동일합니다.

* 참고!
모든 Windows 프로세스는 kernel32.dll 을 로딩합니다.
PE Header 를 조작하여 IAT 에서 kernel32.dll 항목을 제거해버려도 loader 가 강제로 kernel32.dll 을 로딩시켜버립니다. (XP 부터 해당됨. 2000 에서는 실행불가.)


#5. 대상 프로세스에 스레드를 실행 시킴

모든 준비는 끝났고 마지막으로 notepad.exe 로 하여금 LoadLibraryA() API 를 호출하도록 명령만 내리면 됩니다. 하지만 Windows 에서는 그런 API 를 제공하지 않습니다.

그래서 편법(?)으로 CreateRemoteThread() API 를 사용합니다.
(편법이라기 보다는 DLL Injection 의 정석이라고 말 할 수 있지요.)

CreateRemoteThread() API 는 다른 프로세스에게 스레드를 실행시켜주는 함수입니다.

HANDLE WINAPI CreateRemoteThread(
  __in   HANDLE                   hProcess,             // 프로세스 핸들
  __in   LPSECURITY_ATTRIBUTES    lpThreadAttributes,
  __in   SIZE_T                   dwStackSize,
  __in   LPTHREAD_START_ROUTINE   lpStartAddress,       // 스레드 함수 주소
  __in   LPVOID                   lpParameter,          // 스레드 파라미터 주소

  __in   DWORD                    dwCreationFlags,
  __out  LPDWORD                  lpThreadId
);


첫번째 파라미터인 hProcess 만 빼면 일반적으로 사용되는 CreateThread() 함수와 다 똑같습니다.

hProcess 파라미터가 바로 스레드를 실행시킬 프로세스의 핸들입니다.
lpStartAddress 와 lpParameter 파라미터는 각각 스레드 함수 주소와 스레드 파라미터 주소입니다.
중요한건 이 주소들이 대상 프로세스의 가상 메모리 공간의 주소이어야 한다는 것입니다. (그래야 그 프로세스에서 인식을 할 수 있겠죠.)

좀 어리둥절 하시죠?
다른 프로세스에 DLL 을 injection 시키는데 스레드가 무슨 상관일까요?

스레드 함수 ThreadProc() 과 LoadLibrary() API 를 보시면 힌트를 얻을 수 있습니다.

DWORD WINAPI ThreadProc(
  __in  LPVOID           lpParameter
);

HMODULE WINAPI LoadLibrary(
  __in  LPCTSTR          lpFileName
);


두 함수 모두 4 byte 파라미터를 받고, 4 byte 값을 리턴하지요.
바로 여기서 아이디어를 얻은 것입니다.

CreateRemoteThread() 를 호출해서 4 번째 파라미터 lpStartAddress 에 "LoadLibrary() 주소"를 주고, 5 번째 파라미터 lpParameter 에 원하는 "DLL 의 경로" 문자열을 주면 됩니다. (반드시 대상 프로세스의 가상 메모리 공간에의 주소이여야 합니다.)

우린 이미 위에서 다 준비해놨지요. 편안하게 호출해주면 됩니다.

hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);

  pThreadProc = notepad.exe 의 LoadLibraryA() 주소
  pRemoteBuf = notepad.exe 의 "c:\\myhack.dll" 문자열 주소


CreateRemoteThread() 는 스레드를 생성하는 것이 아니라 실제로는 LoadLibraryA() 를 호출 시키는 것입니다.



+---+

CreateRemoteThread() 를 이용한 Dll Injection 기법에 대한 설명을 마치겠습니다.

처음에는 잘 이해가 되지 않을 수 있습니다. 설명을 다시 차근차근 읽어보시고 직접 실습해 보세요.

다음 번에는 다른 Dll Injection 기법들과 한번 Injection 된 Dll 을 꺼내는 (Ejection) 방법에 대해서 설명드리도록 하겠습니다.


Dll Injection - 다른 프로세스에 침투하기 (3)


ReverseCore

반응형
반응형

2009년 7월 7일부터 시작된 무차별 DDoS 공격으로 인하여 나라 전체가 큰 혼란에 빠져버렸습니다.

이번 DDoS 사이버 테러를 지켜보면서 풀리지 않는 3 가지 의혹(누가? 왜? 어떻게?) 에 대해서 제 나름의 생각을 정리해 보겠습니다.



#1. Who?


누가 이러한 사이버 공격을 감행하는 걸까요?


개인? 혹은 단체?

규모있는 단체일 가능성이 높습니다.

이에 대한 근거로는 DDoS 공격에 사용된 좀비 PC 가 수 만대에 이를 정도로 널리 악성코드를 감염시켰다는 점입니다.
통상적으로 이렇게 기존 AV 제품에 걸리지 않고 단기간에 널리 퍼지기 위한 조건은 아래와 같습니다.

  • 악성코드의 제작이 마치 상용 SW 제품과 같은 단계(기획, 개발, 테스트, 배포)를 거칩니다.
    => 버그 없이 잘 동작하는 악성코드가 만들어집니다.
  • 진단을 회피하기 위하여 AV 제품들에 대한 연구가 선행되어야 합니다.
    => 많은 테스트를 거쳐서 기존 AV 제품들에게 진단되지 않을때까지 소스를 고치고 또 고칩니다.
  • 빠른 시간내에 다양한 변종을 만들어 냅니다.
    => 시간이 지나면 AV 제품들이 진단을 하기 시작합니다.
         그때 바로 변종을 퍼뜨려 추가적인 공격을 시도합니다.

위 조건들을 모두 만족하기 위해서는 각 분야의 전문가 집단이 필요할 수 밖에 없습니다.


이와 같은 사이버 테러 단체의 특징을 한번 생각해 보죠.

이들은 2009.07.09 현재까지 총 3 회의 DDoS 공격을 무차별로 퍼붓고 있습니다.
만약 경찰에 잡히기라도 하는 날에는 인생이 그대로 끝장남에도 불구하고, 지속적으로 대담하게 공격을 반복하고 있습니다.

이 사이버 테러 단체는 한 마디로 대한민국 공권력은 안중에도 없습니다.
즉, 대한민국 공권력의 영향을 받지 않는 사람들일 가능성이 높습니다.

또한 정교한 악성코드를 기획/제작/테스트/배포하는 데에는 많은 리소스(인력, 자금)가 필요하기 때문에, 이들의 배후에는 든든한 후원세력이 있다고 생각해 볼 수 있겠습니다.



#2. Why?


도대체 그들은 왜 이런 공격을 하는 걸까요?
이 공격으로 뭘 원하는 거죠?

이번 DDoS 공격 의도를 정확히 알 수는 없지만, 아래와 같이 추정해 볼 수는 있습니다.

  • 사회 혼란을 노림
  • 대한민국의 전반적인 IT 인프라 테스트
    => 인터넷 의존도, 시스템 의존도, 대한민국의 사이버 안보 능력, DDoS 대처 능력 등
  • 자신들의 공격 실력 검증
    => 악성코드 제작/배포 능력, 역추적 방지 능력 등

아직까지도 의도가 불분명합니다.
저도 확신이 서지 않습니다. 아마도 위의 3 가지 모두를 노렸다고 밖에는 생각되지 않네요.

더군다나 하드디스크의 MBR 을 날리는 기능이 포함되었다고 하는데요, 기존의 돈을 노리는 악성코드들과는 차원이 틀립니다.
말 그대로 "사이버 테러" 입니다.

하지만 이번 DDoS 사이버 테러에 의해서 우리도 큰 교훈을 얻었습니다.

우리 나라 인터넷 환경은 DDoS 공격에 매우 취약하며, 맘 먹고 달려들면 중요 사이트를 다운시키는것은 일도 아니라는 것을 말이죠.

사실 http 프로토콜 자체가 DDoS 공격에 취약하도록 설계되었기 때문에, 이것은 비단 우리 나라만의 문제라고 볼 수 는 없습니다. 단, 사후 대응 능력은 분명 짚고 넘어가야 할 것입니다. 며칠째 반복되는 공격에 속수무책으로 당하고만 있다는 건 분명 문제가 있습니다.

대표적인 예로 중국에서는 오래전부터 군대 조직내에 사이버전을 수행할 수 있는 특수부대를 양성하고 있다고 합니다. 우리나라도 이번 기회에 그에 대한 대비를 철저히 해야 할 것입니다.
인터넷도 국가 기간망(도로, 통신, 기타)으로 볼 수 있으니까요. 충분히 적들의 공격대상이 될 수 있습니다.



#3. How?


엔지니어로써 가장 궁금했던 부분입니다.

도대체 어떻게 수 만대의 PC 가 악성코드에 감염되어 DDoS 공격을 위한 좀비 PC 가 되었을까요?
사용된 악성코드들을 살펴보니 그 중에 웜(자체 전파 기능을 가짐)은 없었는데 말이죠.

아직까지도 정부기관과 AV 업체들은 좀비 PC 가 어떤 경로를 통하여 감염이 되었는지 파악하지 못하고 있습니다.
(아예 감염 경로 파악이 불가능하다는 말도 나오고 있는 실정입니다.)

잠깐 기억을 되돌려서 예전에 세상을 떠들썩하게 했던 악성코드 사건들을 생각해 보겠습니다.

  • CIH 바이러스 - 감염된 시스템은 특정 날짜에 ROM BIOS 가 날라감
    => 각 AV 업체에서 사건 발생 1년 전에 이미 대응을 마쳤으며, 지속적으로 주의 경보를 하였습니다.
    => 문제는 사람들이 경보를 무시하고 최신 엔진으로 업데이트 하지 않아서 피해가 엄청났었죠.
  • 1.25 인터넷 대란 - Slammer 웜이 MS-SQL DB Server 의 보안 취약점을 공격하여 전세계 인터넷이 마비 되었습니다.
    => MS 에서 이미 사건 발생 6 개월 전에 보안 패치를 내려보냈으며,
        각 AV 업체 또한 Slammer 웜에 대한 진단 시그니처를 가지고 있었습니다.
    => 사람들이 윈도우 보안패치와 AV 최신엔진 업데이트를 소홀히 하였기 때문에 엄청난 피해가 발생하였습니다.


위 두 사례 모두 PC 사용자들이 윈도우 보안패치AV 최신엔진 업데이트만 했었어도 충분히 막을 수 있는 사건이었습니다.

전 이번 DDoS 사이버 테러에 사용된 악성코드들 또한 (과거와 같이) 기존의 보안 취약점을 이용한 것이라고 생각합니다.

제가 생각하는 감염 시나리오는 이렇습니다.

1) 해커가 사람들이 많이 접속하는 사이트(예:포탈, 관공서 등)를 해킹하여 특정 페이지를 변조하여 IFrame 을 심어둡니다.
2) 해당 페이지에 접속한 사람들은 자신도 모르게 IFrame 에 쓰여진 주소로 이동하여 IE 취약점을 통하여 악성 파일을 다운 받아 실행하게 됩니다.
3) 해커는 역추적을 방지하기 위해 일정 시간이 지나면 변조한 페이지를 원래대로 복원시킵니다.

외부로 전파하는 기능을 가진 웜(Worm)을 사용하지 않고 단기간내에 불특정 다수를 감염시키면서, 동시에 감염 경로를 숨기기 위해서는 위 방법이 가장 좋다고 봅니다.

기존 웜을 통한 악성코드 전파 방법은 다른 시스템에 전파하기 위해 네트워크 스캐닝(윈도우 보안 취약점 패킷 전송)을 하는데, 이런 흔적은 AV 업체의 주목을 끌어 사전에 걸릴 확률이 높습니다.

따라서 이번 DDoS 사이버 테러의 경우는 매우 설계가 잘 되어 있고, 효과가 좋다고 볼 수 있습니다.
(공격자들은 프로가 맞습니다.)

좀 더 위험한 추정을 하자면 공격자는 사이트 관리자 중 한명과 내통하고 있다고 볼 수 도 있습니다.
이건 제가 영화를 너무 좋아하는 관계로 너무 지나친 비약이라고 할 수 있지요.
하지만 자고로 최고의 해킹은 내부 해킹이라고 하였습니다. 절대 발각 될 수 없지요.



+-----+

위 얘기들은 모두 제 자신의 추정일 뿐이며 사실로 밝혀진게 아닙니다. ^^

참고만 하시기 바랍니다.

마지막으로 한 말씀 드리겠습니다.

좀비 PC 가 되지 않도록 윈도우 보안 업데이트와 AV 최신 엔진 업데이트를 철저히 하도록 해야 겠습니다.




반응형
반응형

DLL Injection 에 대해서 자세히 알아보겠습니다.

DLL Injection 기법은 다른 프로세스에 침투하는 가장 쉽고 강력한 방법입니다.



DLL Injection 이란?


다른 프로세스에 특정 DLL 파일을 강제로 삽입시키는 것입니다.

더 정확히 표현하면 다른 프로세스에게 LoadLibrary() API 를 호출하도록 명령하여 내가 원하는 DLL 을 loading 시키는 것입니다.

따라서 DLL Injection 이 일반적인 DLL loading 과 다른점은 loading 대상이 되는 프로세스가 내 자신이냐 아니면 다른 프로세스냐 하는 것입니다.

아래 그림을 봐주세요.


<Fig. 1>

notepad 프로세스에 myhack.dll 을 강제로 삽입시켰습니다.
(원래 notepad 는 myhack.dll 을 로딩하지 않습니다.)

notepad 프로세스에 로딩된 myhack.dll 은 notepad 프로세스 메모리에 대한 (정당한) 접근권한이 생겼기 때문에 사용자가 원하는 어떤 일이라도 수행할 수 있습니다. (예: notepad 에 통신기능을 추가하여 메신저나 텍스트 웹브라우저 등으로 바꿔버릴 수도 있습니다.)



DLL Injection 사용 목적


LoadLibrary() API 를 이용해서 어떤 DLL 을 로딩시키면 해당 DLL 의 DllMain() 함수가 실행됩니다.

DLL Injection 의 동작원리는 외부에서 다른 프로세스로 하여금 LoadLibrary() API 를 호출하도록 만드는 것이기 때문에 (일반적인 DLL loading 과 마찬가지로) 강제 삽입된 DLL 의 DllMain() 함수가 실행됩니다.

또한 삽입된 DLL 은 해당 프로세스의 메모리에 대한 접근권한을 갖기 때문에 사용자가 원하는 다양한 일(버그 패치, 기능 추가, 기타)을 수행 할 수 있습니다.

그런데 문제는 대부분 악의적인 용도로 사용된다는 것입니다.

- 악성 코드

정상적인 프로세스(winlogon.exe, services.exe, svchost.exe, explorer.exe, etc)에 몰래 숨어들어가 악의적인 짓들을 합니다. 다른 악성 파일을 다운받거나, 몰래 백도어를 열어두고 외부에서 접속하거나, 키로깅 등의 나쁜짓을 하는 것이죠.

정상 프로세스 내부에서 벌어지는 일이라서 일반적인 PC 사용자들은 눈치채기 어렵습니다.
만약 explorer.exe 가 80 포트로 어떤 사이트에 접속시도를 한다고 생각해보세요.
일반인들은 그냥 정상 프로세스의 정상적인 동작으로 생각하기 쉽습니다.

- 유해 프로그램, 사이트 차단 프로그램

부모님들께서 아이들의 건전한 PC 사용을 위해 설치하는 '프로세스 차단 프로그램' 등이 있습니다.
주로 게임 프로그램과 성인 사이트 접속 등을 방지하는 역할을 하지요.

아이들 입장에서야 원수(?)같은 프로그램이라서 미친듯이 해당 프로세스를 종료하려 듭니다.
DLL Injection 기법으로 정상 프로세스에 살짝 숨어들어간다면 들키지도 않고, 프로세스 강제 종료에도 안전하게 됩니다. (Windows 핵심 프로세스를 종료하면 시스템이 같이 종료되기 때문에 결국 '차단' 하려는 목적을 달성하는 셈이지요.)

- 기능 개선 및 (버그) 패치 

만약 어떤 프로그램의 소스 코드가 없거나 수정이 여의치 않을 때 DLL Injection 을 사용하여 전혀 새로운 기능을 추가하거나 (PlugIn 개념) 문제가 있는 코드, 데이타를 수정할 수 있습니다.
일단 프로세스 메모리에 침투한 DLL 은 해당 프로세스의 메모리에 자유롭게 접근 할 수 있기 때문에 코드, 데이타를 고칠 수 있습니다.
저도 예전에 인터넷에서 다운받은 헥사 에디터에 버그가 있길래 DLL Injection 기법을 이용해서 해당 버그 코드를 간단히 패치해서 사용한 적이 있습니다. (그냥 다른 헥사 에디터를 다운 받아도 써도 되지만 고쳐 쓰고 싶은 마음에... ^^)

- API Hooking

다음번에 설명드릴 주제인데요, API Hooking 에 DLL Injection 기법이 많이 사용됩니다.
정상적인 API 호출을 중간에서 후킹하여 제가 원하는 기능을 추가 (혹은 기존 기능을 제거)하는 목적으로 사용됩니다.

이 역시 삽입된 DLL 은 해당 프로세스의 메모리에 대한 접근 권한을 가지고 있다는 특성을 잘 활용한 것입니다.



DLL Injection 간단 실습


notepad.exe 프로세스에 myhack.dll 을 injection 시키도록 하겠습니다.
=> myhack.dll 은 www.naver.com/index.html 을 다운받도록 프로그래밍 하였습니다.

myhack.dll

InjectDll.exe


1) InjectDll.exe 와 myhack.dll 을 다운받아 C:\ 에 복사합니다.
2) 메모장(notepad.exe) 을 실행합니다.
3) InjectDll.exe 를 실행합니다.

Process Explorer 를 이용하여 notepad.exe 프로세스에 Injection 된 myhack.dll 을 확인해 보겠습니다.


<Fig. 2>

notepad.exe 프로세스 메모리 공간에 myhack.dll 이 들어와 있는게 보이시죠?

C:\index.html (네이버 초기화면 html) 파일이 정상적으로 생겼는지 볼까요?


<Fig. 3>

index.html 파일을 메모장으로 열어보겠습니다.


<Fig. 4>

정상적으로 notepad.exe 프로세스에 myhack.dll 이 Injection 되어 http://www.naver.com/index.html 파일을 받아왔습니다.

이와 같이 다른 프로세스에 침투하여 원하는 동작을 마음껏 수행할 수 있는 Dll Injection 기법의 원리와 구현 방법에 대해서 알아보겠습니다.


Dll Injection - 다른 프로세스에 침투하기 (2)


ReverseCore

반응형
반응형


Process Explorer


Windows 최고의 프로세스 관리 도구 Process Explorer 입니다.

https://technet.microsoft.com/en-us/sysinternals/bb896653.aspx

저 유명한 sysinternals (현재는 MS에 인수되었음) 의 Mark Russinovich 씨가 만든 프로세스 관리 유틸리티입니다.

이분은 Windows 운영체제에 대해서 매우 해박한 지식을 갖고 있으며,
유용한 유틸리티(FileMon, RegMon, TcpView, DbgView, AutoRuns, Rootkit Revealer, etc) 들을 만들어 공개하였습니다.

언젠가 한번은 FileMon 과 RegMon 의 소스 코드를 공개하신적이 있습니다. (지금은 없어졌지요.)
Windows 운영체제 초창기에 (맨땅에 헤딩하던) 시스템 드라이버 개발자들에게 있어서
그 소스들은 그야말로 사막의 오아시스 같은 존재였습니다.

각설하고 Process Explorer 의 실행화면을 보실까요.


< Fig.1 - Process Explorer 실행화면 >

Windows 작업관리자와는 비교 할 수 없는 아주 뛰어난 화면 구성을 보여주고 있습니다.

화면 위의 좌측에는 현재 실행중인 프로세스들을 Parent/Child 의 트리 구조로 표시하고 있습니다. (무려 아이콘 까지!!!)
우측에는 프로세스 각각의 PID, CPU 점유율, 등록정보 등을 보여줍니다. (Option 을 통해 더 추가 가능)

화면 아래(욥션)에는 선택된 프로세스에 매핑된 DLL 정보 또는 해당 프로세스에서 오픈한 object handle 을 표시합니다.



구체적으로 뭐가 좋은거죠?


좋아 보이기는 하는데 구체적으로 뭐가 좋은건지 궁금하시죠?

저는 리버싱 할 때 항상 Process Explorer 를 같이 띄워놓고 합니다.
제가 Process Explorer 를 좋아하는 이유는 이렇습니다.

  • Parent/Child 프로세스 트리 구조
  • 프로세스 실행/종료시 각각의 색깔(초록/빨강)로 표시
  • 프로세스 suspend 기능 (실행 중지)
  • 프로세스 종료(kill) 기능 (Kill Process Tree 기능 지원)
  • DLL/Handle 검색 (프로세스에 인젝션된 DLL 검색 또는 특정 파일을 오픈한 프로세스 검색)

  • 이외에도 다양한 기능들이 있습니다만, 위 기능들이 특히 리버싱 할 때 많이 사용되는 기능들입니다.
    그리고 꾸준한 업데이트(버그 수정, 기능 추가)도 큰 장점입니다.



    sysinternals


    sysinternals 홈페이지에 가보시면 Process Explorer 의 미니 콘솔 버전들이 있습니다.
    (PsKill, PsSuspend, PsList, etc)

    이 유틸들도 받아서 실행해 보세요. Process Explorer 의 기능을 축소시킨 멋진 콘솔 버전 프로그램들입니다.

    리버싱을 위해 Windows 내부구조를 공부하시는 분들께서는 간단히 이런 콘솔 프로그램을 따라 만들어 보세요.
    프로세스와 DLL 등에 대한 이해를 높일 수 있습니다.
    (제 경험상 따라 만드는 방법이 실력 향상을 위한 가장 좋은 방법입니다. ^^)



    이상으로 최고의 프로세스 관리 유틸리티 Process Explorer 에 대한 소개를 마칩니다.



    반응형

    'tool' 카테고리의 다른 글

    PEView.exe  (21) 2013.01.27
    HxD.exe 기능 추가!  (12) 2012.06.14
    리버싱 현업에서 사용되는 디버거(Debugger)들  (33) 2010.09.29
    InjDll.exe – DLL Injection/Ejection 전용 도구  (43) 2010.03.15
    www.virustotal.com  (3) 2009.03.20
    www.google.com  (2) 2009.03.06
    반응형


    PE File Format


    지금까지 오랜 시간에 걸쳐 PE(Portable Executable) File Format 에 대해 살펴보았습니다.

    PE 스펙을 보면 각 구조체 멤버 하나하나 자세히 기술하고 있지만
    리버싱에서 주목해야 하는 멤버들만 추려서 설명드렸습니다.

    특히 IAT, EAT 에 관한 내용은 실행압축(Run-Time Packer), Anti-Debugging, DLL Injection, API Hooking
    매우 다양한 중/고급 리버싱 주제들의 기반 지식이 됩니다.

    hex editor 와 연필, 종이만 가지고 IAT/EAT 의 주소를 하나하나 계산해서
    파일/메모리 에서 실제 주소를 찾는 훈련을 많이 해보시기 바랍니다.

    쉽지 않은 내용이지만 그만큼 리버싱에서 중요한 위치를 차지하고 있기 때문에
    고급 리버싱을 원하는 분들께서는 반드시 습득하셔야 합니다.



    PEView.exe


    간단하고 사용하기 편리한 PE Viewer 프로그램(PEView.exe)을 소개해 드립니다.
    (개인이 만든 무료 공개 SW 입니다.)

    http://www.magma.ca/~wjr/PEview.zip

    아래는 PEView.exe 의 실행 화면입니다.


    PE Header 를 각 구조체 별로 보기 쉽게 표현해주고, RVA <-> File Offset 변환을 간단히 수행해줍니다.
    (제가 설명드렸던 내용과 용어 사용에 있어서 약간 틀릴 수 있습니다. 둘 다 익혀두시는게 의사소통에 좋습니다.)

    위와 같은 PE Viewer 를 직접 제작해 보시는 것을 추천드립니다.
    저 또한 처음 PE Header 를 공부할 때 (검증을 위해) 콘솔 기반의 PE Viewer 를 만들어서 지금까지 잘 사용하고 있습니다.
    직접 제작하다 보면 자신이 잘 몰랐거나 잘 못 이해하던 부분을 정확히 파악하고 제대로 공부할 수 있습니다.



    PE Patch


    PE 스펙은 말 그대로 권장 스펙이기 때문에 각 구조체 내부에 보면 사용되지 않는 많은 멤버들이 많이 있습니다.

    또한 말 그대로 스펙만 맞추면 PE 파일이 되기 때문에 일반적인 상식을 벗어나는 PE 파일을 만들어 낼 수 있습니다.

    PE Patch 란 바로 그런 PE 파일을 말합니다.
    PE 스펙에 어긋나지는 않지만 굉장히 창의적인(?) PE Header 를 가진 파일들입니다.
    (정확히 표현하면 PE Header 를 이리저리 꼬아 놨다고 할 수 있습니다.)

    PE Patch 만 해도 따로 고급 주제로 다뤄야 할 만큼 (리버싱에 있어서) 넓고도 깊은 분야입니다.

    한가지만 소개해 드리겠습니다.
    지금까지 배웠던 PE Header 에 대한 상식이 사뿐히 깨지는 경험을 하실 수 있습니다.
    (그러나 PE 스펙에 벗어난건 없답니다.)

    아래 사이트는 tiny pe 라고 가장 작은 크기의 PE 파일을 만드는 내용입니다.

    http://blogs.securiteam.com/index.php/archives/675

    411 byte 크기의 (정상적인) PE 파일을 만들어 냈습니다.
    IMAGE_NT_HEADERS 구조체 크기만 해도 248 byte 라는걸 생각하면 이것은 매우 작은 크기의 PE 파일입니다.

    다른 사람들이 계속 도전해서 304 byte 크기의 파일까지 나타나게 됩니다.

    그리고 마지막으로 어떤 다른 사람이 위 사이트를 본 후 자극을 받아서
    아래와 같이 극단적이고 매우 황당한 PE 파일을 만들어 내었습니다.

    http://www.phreedom.org/solar/code/tinype/

    이곳에 가면 Windows XP 에서 정상 실행되는 97 byte 짜리 PE 파일을 다운 받을 수 있습니다.
    (2009년 4월 현재까지 최고 기록입니다.)
    또한 PE Header 와 tiny pe 제작과정에 대한 내용을 자세히 설명하고 있어서 읽어보시면 크게 도움이 되실 겁니다.
    (약간의 assembly 언어에 대한 지식이 요구됩니다.)

    모두 다운 받아서 하나씩 분석해 보시기 바랍니다. 분명 크게 도움이 됩니다.



    Epilogue


    이러한 PE patch 파일들은 저뿐만 아니라 일반적인 리버서들의 고정관념을 깨트리는 내용이며
    그래서 리버싱 공부가 더 즐겁습니다.

    PE Header 에 대해서 다시 한번 강조 하고 싶은 내용은 아래와 같습니다.

    - PE 스펙은 그저 스펙일 뿐이다. (만들어 놓고 사용되지 않는 내용이 많다.)
    - 내가 지금 알고 있는 PE Header 에 대한 지식도 잘 못된 부분이 있을 수 있다.
       (tiny pe 외에도 PE header 를 조작하는 여러 창의적인 기법들이 계속 쏟아져 나온다.)
    - 항상 모르는 부분을 체크해서 보강하자.

    앞으로 제 블로그에서 다양한 형태의 PE 파일들을 분석할 예정입니다.
    재밌고 특이한 PE Header 조작 기법에 대해서는 그때 그때 소개해 드리도록 하겠습니다.




    반응형

    + Recent posts