My Study/System

DLL Injection (3) - Injector 사용

인젝터만 만들어 놓으면 DLL Injection 를 할 때 가장 쉽게 하는 방법같습니다. 


[DLL Injection 기초 개념]

[EAT 사용한 DLL Injection]


인젝터를 만드는 과정은 생각보다 많이 간단합니다.


첫번째 대상 프로세스의 핸들 값을 구합니다. 핸들 값을 구하는 API는 OpenProcess 입니다.



접근 권한은 PROCESS_ALL_ACCESS를 해도 좋고, 

PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ 를 해도 좋습니다.

(막상 적어놓으니 엄청 많네요.... 하핳..)

두번째 인자는 FALSE를 넣고 마지막에는 대상 프로세스의 PID를 넣습니다.


두번째, 대상 프로세스 메모리에 삽입할 DLL 경로의 크기만큼 메모리를 할당해야 합니다



첫번째 인자는 프로세스 핸들 값. 이건 위에서 구했죠??, 두번째 인자는 NULL을 줍니다. 세번째 인자는 DLL 경로의 크기 sizeof() * strlen 이런식으로 구하면 편하겠죠?? 네번째 인자는 MEM_COMMIT, 마지막 인자는 PAGE_READWRITE 입니다.


세번째, 할당 받은 메모리에 dll 경로를 씁니다. API는 WriteProcessMemory 입니다.



첫번째 인자는 프로세스 핸들값, 두번째는 VirtualAllocEx 의 반환 값을 이곳에 넣습니다. 세번째는 삽입할 DLL 경로를 LPVOID형으로 형변환하여 넣습니다. 네번째는 위에서 구한 DLL 경로 크기를 넣습니다. 마지막 인자는 NULL!


네번째, 호출할 LoadLibrary API 주소를 구해야합니다.

GetModuleHandle 을 사용하여 DLL 핸들 값을 가져오고, GetProcAddress 을 사용하여 DLL 내부에 있는 함수의 주소를 가져옵니다.

LoadLibrary는 kernel32.dll 에 있습니다.

이 API들은 EAT 를 이용한 Injection 시간에 적어 놨으니 패스,,,


마지막은 LoadLibrary를 호출함으로서 저희가 삽입한 DLL이 작동합니다. 이때 OS 버전에 따라 사용하는 API가 달라집니다.

XP 까지는 CreateRemoteThread를 사용하여 실행하였지만 Vista 이후에 업데이트가 되어 세션이 다르면 프로세스 호출에 실패합니다. 



그럼 어떠한 API를 사용해야할까요?

바로 ntdll.dll 에 들어있는 NtCreateThreadEx 와 RtlCreatUserThread 를 사용합니다.


NtCreateThreadEx는 CreateRemoteThread 함수 호출 했을 때 내부로 들어가면 최종적으로 호출하는 함수입니다.



이 글에서는 NtCreateThreadEx만 사용하고 RtlCreateUserThread은 github에 올려 두도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef NTSTATUS(WINAPI *LPFUN_NtCreateThreadEx)
(
    OUT PHANDLE hThread,
    IN ACCESS_MASK DesiredAccess,
    IN LPVOID ObjectAttributes,
    IN HANDLE ProcessHandle,
    IN LPTHREAD_START_ROUTINE lpStartAddress,
    IN LPVOID lpParameter,
    IN BOOL CreateSuspended,
    IN SIZE_T StackZeroBits,
    IN SIZE_T SizeOfStackCommit,
    IN SIZE_T SizeOfStackReserve,
    OUT LPVOID lpBytesBuffer
    );
cs


우선 NtCreateThreadEx는 위와 같은 형태를 가지고 있습니다. 위 형식을 적어놓은 이유가 NtCreateThreadEx는 일반적으로 헤더에서 받아오는 것이 아닌 ntdll.dll 에서 로드하여 가져와 함수 포인터로 사용해야하기 때문입니다.


제가 만든 코드 중 일부입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
    pRemoteMem = (LPVOID)VirtualAllocEx(hProcess, NULL, szBufSize, MEM_COMMIT, PAGE_READWRITE);
    if (pRemoteMem == NULL)
    {
        _tprintf(L"VirtualAllocEx error (0x%08X)\n", GetLastError());
        return FALSE;
    }
 
    int n = WriteProcessMemory(hProcess, pRemoteMem, szDllPath, szBufSize, NULL);
    if (n == 0)
    {
        _tprintf(L"WriteProcessMemory error (0x%08X)\n", GetLastError());
        return FALSE;
    }
 
    //get LoadLibraryA
    hModule = GetModuleHandle(L"kernel32.dll");
    if (hModule == NULL)
    {
        _tprintf(L"GetModuleHandle error (0x%08X)\n", GetLastError());
        return FALSE;
    }
 
    pThreadRoutine = (PTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
    if (pThreadRoutine == NULL)
    {
        _tprintf(L"LoadLibrary not found (0x%08X)\n", GetLastError());
        return FALSE;
    }
cs

위에서 설명한 순서대로 선언하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
HMNtDll = GetModuleHandle(L"ntdll.dll");
    if (HMNtDll == NULL)
    {
        _tprintf(L"GetModuleHandle error (0x%08X)\n", GetLastError());
        return FALSE;
    }
 
    fNtCreateThreadEx = (LPFUN_NtCreateThreadEx)GetProcAddress(HMNtDll, "NtCreateThreadEx");
    if (!fNtCreateThreadEx)
    {
        _tprintf(L"fNtCreateThreadEx call error (0x%08X)", GetLastError());
        return FALSE;
    }
 
    NTSTATUS status = fNtCreateThreadEx(
        &hThread,
        0x1FFFFF,
        NULL,
        hProcess,
        pThreadRoutine,
        pRemoteMem,
        FALSE,
        NULL,
        NULL,
        NULL,
        NULL
    );
cs

마지막으로 NtCreateThreadEx 를 ntdll.dll 에서 로드하여 사용하였습니다.


이렇게 하면 Injector를 제작하여 여러분들이 원하는 dll을 제작하여 프로세스에 넣으실 수 있을 겁니다.

단, Anti-Injection 기법이 적용되어 있으면 위 코드로는 삽입이 불가능합니다.


[x64 DLL_Injector 다운]


github에 제가 제작한 dll_injector를 올려두었습니다.

32비트 프로세스에 인젝트할 경우 x86으로 컴파일을 하시면 되고 64비트는 x64로 컴파일을 하시면 됩니다.

'My Study > System' 카테고리의 다른 글

Kernel Object  (0) 2016.06.29
API Hooking x86 x64  (0) 2016.05.23
DLL Injection (3) - Injector 사용  (0) 2016.05.23
DLL Injection (2) - EAT 를 이용한 DLL Injection  (0) 2016.05.23
DLL Injection (1) - 간단 기본 개념  (0) 2016.05.23
Memory : stack(스택)  (0) 2015.06.26

최근 트랙백

알림

이 블로그는 구글에서 제공한 크롬에 최적화 되어있고, 네이버에서 제공한 나눔글꼴이 적용되어 있습니다.