ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [리버싱 핵심원리 study] 24장 DLL 이젝션
    Reverse Engineering 2021. 1. 8. 03:49

    DLL 이젝션은 앞에서 다룬 DLL 인젝션과는 반대되는 개념으로, 특정 프로세스에 로딩된 DLL을 빼내는 방법이다. DLL 인젝션에서는 대상 process로 하여금 LoadLibrary API를 호출하도록 하는 반면, 이젝션에서는 FreeLibrary API를 호출하게끔 하는 방식으로 이루어져 있다. 

     

    1. DLL 이젝션 구현

    책에 나와있는 실습 코드를 분석해보자.

    #include "Windows.h"
    #include "tlhelp32.h"
    #include "tchar.h"
    
    #define DEF_PROC_NAME (L"notepad.exe")
    #define DEF_DLL_NAME (L"myhack.dll")
    
    DWORD FindProcessID(LPCTSTR szProcessName) {
    	DWORD dwPID = 0xFFFFFFFF;
    	HANDLE hSnapshot = INVALID_HANDLE_VALUE;
    	PROCESSENTRY32 pe;
    	
    	//시스템의 스냅샷 가져오기
    	pe.dwSize = sizeof(PROCESSENTRY32);
    	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
    
    	//프로세스 찾기
    	Process32First(hSnapshot, &pe);
    	do {
    		if (!_tcsicmp(szProcessName, (LPCTSTR)pe.szExeFile)) {
    			dwPID = pe.th32ProcessID;
    			break;
    		}
    	} while (Process32Next(hSnapshot, &pe));
    
    	CloseHandle(hSnapshot);
    
    	return dwPID;
    }
    
    BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) {
    /*......*/
    }
    
    BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName) {
    	BOOL bMore = FALSE, bFound = FALSE;
    	HANDLE hSnapshot, hProcess, hThread;
    	HMODULE hModule = NULL;
    	MODULEENTRY32 me = { sizeof(me) };
    	LPTHREAD_START_ROUTINE pThreadProc;
    
    	//dwPID = notepad 프로세스 ID
    	//TH32CS_SNAPMODULE 파라미터를 이용해 notepad 프로세스에 로딩된 DLL 이름을 얻는다.
    	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
    
    	bMore = Module32First(hSnapshot, &me);
    	for (; bMore; bMore = Module32Next(hSnapshot, &me)) {
    		if (!_tcsicmp((LPCTSTR)me.szModule, szDllName) || !_tcsicmp((LPCTSTR)me.szExePath, szDllName)) {
    			bFound = TRUE;
    			break;
    		}
    	}
    
    	if (!bFound) {
    		CloseHandle(hSnapshot);
    		return FALSE;
    	}
    
    	if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID))) {
    		_tprintf(L"OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError());
    		return FALSE;
    	}
    
    	hModule = GetModuleHandle(L"kernel32.dll");
    	pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary");
    	hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL);
    	WaitForSingleObject(hThread, INFINITE);
    
    	CloseHandle(hThread);
    	CloseHandle(hProcess);
    	CloseHandle(hSnapshot);
    
    	return TRUE;
    }
    
    int _tmain(int argc, TCHAR* argv[]) {
    	DWORD dwPID = 0xFFFFFFFF;
    
    	//process 찾기
    	dwPID = FindProcessID(DEF_PROC_NAME);
    	if (dwPID == 0xFFFFFFFF) {
    		_tprintf(L"There is no %s process!\n", DEF_PROC_NAME);
    		return 1;
    	}
    
    	_tprintf(L"PID of \"%s\" is %d\n", DEF_PROC_NAME, dwPID);
    
    	//privilege 바꾸기
    	if (!SetPrivilege(SE_DEBUG_NAME, TRUE))
    		return 1;
    
    	//eject dll
    	if (EjectDll(dwPID, DEF_DLL_NAME))
    		_tprintf(L"EjectDll(%d, \"%s\") success!!!\n", dwPID, DEF_DLL_NAME);
    	else
    		_tprintf(L"EjectDll(%d, \"%s\") failed!!!\n", dwPID, DEF_DLL_NAME);
    
    	return 0;
    }

    크게는 FindProcessID, SetPrivilege, EjectDll, main함수 이렇게 네 가지 함수로 구성되어 있다. (SetPrivilege 함수는 토큰 권한 관련하여 설정을 변경하는 함수인데, 정확한 원리는 파악하지 못하여 일단 주석 처리만 해놓았다.)

     

    - FindProcessID : 프로세스 이름 문자열을 받아 그에 대응되는 PID를 구하여 반환한다.

    - SetPrivilege : 토큰 권한 설정 함수

    - EjectDll : PID와 eject할 DLL이름을 매개변수로 갖는 함수로, 대상 프로세스에서 해당 DLL을 eject 한다.

     

    2. DLL 이젝션 실습

    이전에 실습한 DLL 인젝션 환경에서(notepad.exe에 myhack.dll이 인젝션 된 상황) myhack.dll을 eject 해보자. 먼저 이전 실습과 같이 동일한 환경을 구성해보자.

    myhack.dll이 인젝션된 상황

     

    cmd창에서 다음과 같이 명령어를 입력하여 EjectDll.exe를 실행한다.

    EjectDll.exe 실행
    myhack.dll eject

    위와 같이 myhack.dll이 notepad.exe에서 사라진 것을 확인할 수 있다.

    반응형

    댓글

Designed by Tistory.