티스토리 뷰

Reversing/Concept

[Reversing] Code Injection

ch4njun 2020. 3. 4. 02:21
반응형

코드 인젝션이란 ?

 상대 Process에 독립 코드를 삽입한 후 실행시키는 기법.

 이때 삽입은 CreateRemoteThread API를 이용한다. 최근에는 해당 API가 제대로 동작하지 않는다고 알고 있는데 코드인젝션은 Windows 10 에서도 잘 동작한다...? 뭐지ㅠㅠ

 


 

뭘 인젝션해야할까 ?

코드 인젝션시 대상으로 하는 Process의 Memory에 인젝션해야 하는 것들은 아래와 같다.

 

 
 1. 사용할 API의 주소. ( LoadLibraryA, GetProcAddress )
    - 구조체에 FARPROC 자료형으로 선언하며 선택이 아니라 필수이다 !!
 2. 사용할 Library 명. ( Ex. user32.dll )
 3. 사용할 API 명. ( Ex. MessageBoxA )
 4. 사용할 데이터. ( Ex. ch4njun's code injection )
    - 2, 3, 4번은 구조체에 char형 2차원 배열에 문자열로 저장한다.

 

 

4가지 정보를 저장할 구조체를 선언하여 구조체변수를 만든다.

 

구조체를 만드는 이유는 CreateRemoteThread API 호출시 사용되는 Thread 함수에 전달할 수 있는 인자가 하나이기 때문에, 하나에 다 저장하여 전달해주기 위함이다.

 

이후 코드 인젝션을 위해 사용되는 함수에서 위와같이 구조체 변수를 선언한다.

 

그리고 위와같이 1, 2, 3, 4 번에 해당하는 데이터중 필요한 데이터를 구조체변수에 저장한다.

1번에 해당되는 데이터는 GetProcAddress API를 통해 반환받은 주소인데, 이 때 GetProcAddress API를 사용하기에 앞서서 LoadLibraryA API를 통해 kernel32.dll 을 변수 hMod에 로드해야한다.

 

그리고 VirtualAllocEx API를 이용해 대상 Process에 메모리공간을 할당받고, 그 주소에 구조체 변수의 주소를 전달하고 그 주소를 CreateRemoteThread API 호출시 Thread 함수 인자로써 전달하게 된다.

 

전체적인 코드는 아래에서 볼 수 있으니까 대충 흐름만 파악하자 !!

 

 


 

인젝션할 단독코드 구성 ?

 

우선 인젝션할 코드를 하나의 함수로 구성해야 한다. 그래야 CreateRemoteThread API 호출시 해당 함수의 주소를 전달함으로써 그 함수를 대상 Process에서 동작시킬수 있기 때문이다.

 

그 함수를 구성하기에 앞서 우선적으로 해야할 일이 있다.

이 함수에서 사용되는 API 주소들은 FARPROC 자료형으로 저장되어 넘어온다. 또한 해당 함수에서 GetProcAddress API를 통해 추가로 사용할 API들을 읽어올텐데, 그 자료형 또한 FARPROC 자료형이다.

 

때문에 내가 사용하고자 하는 자료형으로 형변환(DownCasting)을 진행해야 해당 API를 정상적으로 사용할 수 있다. 그래서 함수 작성에 앞서 이에 대한 API 형태를 typedef으로 정의해줘야 한다.

 

위와 같이 typedef을 통해 해당 API와 같은형태로 지정을 해두면 해당 모양으로 형변환 후 해당 API를 기존의 API와 동일하게 사용이 가능하다.

 

이후 위와같이 Thread에서 사용할 함수를 작성한다. 

이 내용은 얼마든지 자유롭게 변경할 수 있으며 상황에 맞게 사용하면 된다.

( 설명 안달아도 코드 보면 어느정도 이해가 될듯...? )

 

 

 


 

CreateRemoteThread API를 통한 인젝션 ?

 

이 과정은 앞 포스팅에서 설명했던 DLL 인젝션에서의 코드와 매우매우 유사하다.

 

차이점은 DLL 인젝션은 단순히 DLL의 경로만 대상 Process의 Memory에 저장한 후, kernel32.dll와 같은 주요 DLL들이 모든 Process의 같은 주소에 Load된다는 특징을 이용해서 kernel32.dll의 LoadLibraryA API의 주소를 대상 Process에게 CreateRemoteThread API를 통해 호출하게 만든다.

 

그러나 Code 인젝션에서는 내가 만든 Thread 함수도 대상 Process의 Memory에 저장하고, 그 함수의 주소를 대상 Process에게 CreateRemoteThread API를 통해 호출하도록 해야한다.

 

그리고 또한 Thread 함수에서 사용하는 데이터가 저장된 구조체 변수도 대상 Process의 Memory에 저장하고, CreateRemoteThread API를 호출할 때 인자로 전달해 줘야한다.

 

즉, 총 2번의 VirtualAllocEx API, WriteProcessMemory API 호출이 있어야 한다는 뜻이다.

                                  ( 함수 한번, 데이터 한번 )

 

API 호출 순서는 아래와 같다.


1. OpenProcess
2. VirtualAllocEx
3. WriteProcessMemory
4. VirtualAllocEx
5. WriteProcessMemory
6. CreateRemoteThread
7. WaitForSingleObject

 

코드를 보면 나머지 세부 과정은 이해가 될 것이다. ( DLL 인젝션 포스팅을 보고 왔다면 )

책에서는 할당받은 주소를 저장하는 pRemoteBuf_0, pRemoteBuf_1 을 배열로 처리하는데 이 부분에 있어서는 개발자에 따라 다르게 사용해도 전혀 상관이 없다.

 

위 코드에서 유일하게 생소한 부분이라 하면 50번 라인이다.

 

내가 작성한 Thread 함수를 대상 Process의 Memory에 쓰기위해 메모리 공간을 할당 받을 때 dwSize를통해 얼마의 공간을 할당받을지 결정하는데, ThreadProc 바로 다음에 있는 함수의 주소에서 ThreadProc의 주소를 빼는 방식을 통해 ThreadProc의 크기를 추출해 낼 수 있다.

( 따라서 함수의 순서에 유의해야 한다 )

 

 

 


main 함수는 어떻게 ?

 

 


실습 ?

 

 

Chrome.exe에 내가 원하는 코드를 인젝션하고 싶다면 그 Process의 PID가 필요하다.

때문에 Process Explorer를 통해 PID인 24220을 추출한다.

 

 

위와 같이 인자로 24220을 전달해 프로그램을 실행하게 되면, 해당 Chrome.exe에서 내가 작성한 코드가 실행되는 것을 확인할 수 있다. 당연히 Thread로써 실행된 것이기 때문에 Chrome.exe가 종료되면 해당 Thread도 종료되고 해당 MessageBox도 사라질 것이다.

 

 

 

#include <stdio.h>
#include <Windows.h>
#include <string.h>
#include <tchar.h>

typedef struct _THREAD_PARAM {
    FARPROC pFunc[2];
    char pStr[4][128];
}THREAD_PARAM, *PTHREAD_PARAM;

typedef HMODULE(WINAPI* myLoadLibraryA)(LPCSTR lpLibFileName);
typedef FARPROC(WINAPI* myGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
typedef INT(WINAPI* myMessageBoxA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);

DWORD ThreadProc(LPVOID pParam) {
    PTHREAD_PARAM param = (PTHREAD_PARAM)pParam;
    HMODULE hMod = NULL;
    myMessageBoxA pFunc = NULL;
 
    hMod = ((myLoadLibraryA)param->pFunc[0])(param->pStr[0]);
    pFunc = (myMessageBoxA)((myGetProcAddress)param->pFunc[1])(hMod, param->pStr[1]);
    pFunc(NULL, param->pStr[2], param->pStr[3], MB_OK); return 0;
}

BOOL CodeInjection(DWORD dwPID) {
    THREAD_PARAM param = { 0, };
    DWORD dwSize;
    HMODULE hMod = GetModuleHandleA("kernel32.dll");

    if (hMod) {
        param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
        param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
 
        strcpy_s(param.pStr[0], "user32.dll");
        strcpy_s(param.pStr[1], "MessageBoxA");
        strcpy_s(param.pStr[2], "Ch4njun's Code Injection Success!!");
        strcpy_s(param.pStr[3], "Code Injection Test");

        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);

        dwSize = sizeof(THREAD_PARAM);
        LPVOID pRemoteBuf_0 = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
        if (pRemoteBuf_0) {
            WriteProcessMemory(hProcess, pRemoteBuf_0, (LPCVOID)&param, dwSize, NULL);
            dwSize = (DWORD)CodeInjection - (DWORD)ThreadProc;

            LPVOID pRemoteBuf_1 = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
            if (pRemoteBuf_1) {
                WriteProcessMemory(hProcess, pRemoteBuf_1, (LPCVOID)ThreadProc, dwSize, NULL);

                HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pRemoteBuf_1, pRemoteBuf_0, 0, NULL);

               if (hThread) {
                    WaitForSingleObject(hThread, INFINITE);
                    CloseHandle(hThread);
                    CloseHandle(hProcess);

                    return TRUE;
               } else {
                    OutputDebugStringA("[ERROR] CreateRemoteThread() fail!!!\n");
               }
           }
        }
    }
    return FALSE;
}

int main(int argc, char* argv[]) {
    DWORD dwPID = 0;

    if (argc != 2) {
        printf(" Usage : %s [ PID ]\n", argv[0]); return 1;
    }
    dwPID = (DWORD)atol(argv[1]);
    CodeInjection(dwPID);

    return 0;
}
반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
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 30 31
글 보관함