잰이_IT/보안 - 리버싱

리버싱 핵심원리_ DLL Ejection

janey25 2018. 8. 4. 15:37

리버싱 핵심원리_ DLL Ejection

 

DLL Ejection
- DLL Injection의 반대 개념으로 프로세스에 강제 삽입한 DLL  제거
- 동작 원리는 CreateRemoteThread API를 이용한 DLL Injection 과 같다.


대상 프로세스로 하여금 LoadLibrary() API를 호출하도록 만드는 인젝션과 같이 FreeLibrary() API를 호출하게 하는 것이다.

 

 

1. 프로세스에 로딩된 DLL 정보 구하기

hSnapshot = CreateToolhelp32SnapShot(TH32CS_SNAPMODULE,dwPID)

 -> 프로세스에 로딩된 dll 의 정보를 얻을 수 있다
이렇게 구한 hSanpshot 핸들을 Module32First()/Module32Next() 함수에 넘겨주면 MODULEENTRY32 구조체에 해당 모듈 정보 세팅

 

 

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

hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);

 

 -> 프로세스 ID를 이용해서 대상 프로세스(notepad)의 프로세스 핸들을 구한다.  

추후에 이 프로세스 핸들을 이용해 CreateRemoteThread() API를 호출

 

 

3. FreeLibrary() API 주소 구하기

hModule = GetModuleHandle(L "kernel32.dll");
pThreadProc =  (LPTHREAD_START_ROUTINE)GetProcAddress(hModule,"FreeLibrary")

-> 시스템이 돌아가는 동안, kernel32.dll 은 모든 프로세스에서 같은 주소로 로딩
API()의 호출을 위해서는 FreeLibrary()의 주소를 알아야 하는데 위에서는 notepad.exe에 로딩된 Kernel32FreeLibrary 주소가 아니라 EjectDll.exe 프로세스에 로딩된 주소를 얻어오고 있다. ---->FreeLibrary 주소는 모든 프로세스에 동일!!

 

 

4. 대상 프로세스에 스레드를 실행시키기

 

hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL);

 

pThreadProc의 파라미터 -> FreeLibrary() API의 주소,
me.modBaseAddr 파라미터 -> 이젝션하기 원하는 DLL 로딩주소
스레드 함수로 FreeLibrary 함수 지정 후 스레드 파라미터에 DLL 로딩 주소를 넘겨주면 대상프로세스에서 FreeLibrary() API 호출완료
CreateRemoteThread() API의 의도는 외부 프로세스에 스레드 함수(FreeLibrary)실행 

 

#include <Windows.h>
#include <TlHelp32.h>
#include <tchar.h>
#define DEF_PROC_NAME (L"notepad.exe")
#define DEF_DLL_NAME (L"k3y6reak.dll")
DWORD FindProcessID(LPCTSTR szProcessName)
{
DWORD dwPID = 0xFFFFFFFF;
HANDLE hSnapShot = INVALID_HANDLE_VALUE;
PROCESSENTRY32 pe;
// Get System Snapshot
pe.dwSize = sizeof(PROCESSENTRY32);
hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
// Searching Process
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)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken))
{
_tprintf(L"OpenProcessToken error: %u\n", GetLastError());
return FALSE;
}
if (!LookupPrivilegeValue(NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
_tprintf(L"LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
_tprintf(L"AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
_tprintf(L"The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
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.exe's PID
// Get DLL_NAME in notepad process with TH32CS_SNAPMODULE Parameter
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;
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);
// Chane Privilege
if (!SetPrivilege(SE_DEBUG_NAME, TRUE))
{
return 1;
}
// Eject DLL
if (EjectDll(dwPID, DEF_DLL_NAME))
{
_tprintf(L"EjectDll(%d, \"%s\") sucess!!!\n", dwPID, DEF_DLL_NAME);
}
else
{
_tprintf(L"EjectDll(%d, \"%s\") failed!!!\n", dwPID, DEF_DLL_NAME);
}
return 0;
}