반응형
DLL Injection
DLL Injection은 특정 DLL을 다른 프로세스의 주소 공간에 강제로 삽입하여 해당 프로세스의 동작을 조작하는 기술임. 주로 프로그램을 모니터링하거나 조작하는 목적에서 사용되며, 악성 코드가 다른 프로그램에 삽입되어 악의적인 동작을 수행하도록 하는 데 악용되기도 함.
DLL Injection의 동작 원리
대표적인 DLL Injection 방식으로 CreateRemoteThread() API를 이용한 방법이 있음. 이 방식은 대상 프로세스로 하여금 특정 DLL을 강제로 로드하도록 유도함. 주요 동작 단계는 다음과 같음.
1. LoadLibrary() 호출 유도
- CreateRemoteThread() API를 사용하여 대상 프로세스에 새로운 스레드를 생성함.
- 새롭게 생성된 스레드가 LoadLibrary() 함수를 호출하여 지정된 DLL을 로드하게 됨.
- 이 과정에서 대상 프로세스는 원래 의도하지 않은 DLL을 강제로 로드하게 됨.
2. FreeLibrary() 호출 유도
- DLL을 언로드하고자 할 때는 FreeLibrary() 함수를 호출하도록 유도함.
- CreateRemoteThread()를 통해 대상 프로세스 내에서 FreeLibrary() 호출을 트리거함으로써 DLL을 해제함.
DLL 이젝션 구현
// EjectDll.cpp
#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);
// Get a snapshot of the system
hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
// Find the 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, lpszPrivilege, &luid)) {
_tprintf(L"LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = (bEnablePrivilege) ? SE_PRIVILEGE_ENABLED : 0;
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;
// Take a snapshot of the modules in the process
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;
}
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
if (!hProcess) {
_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;
// Find the 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);
// Set 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;
}
- 프로세스에 로딩된 DLL 정보 구하기
CreateToolhelp32Snapshot 함수와 Module32First/Module32Next 함수를 사용하여 프로세스에 로딩된 모든 DLL 목록을 가져옴. 이 과정에서 제거할 DLL 이름과 일치하는 모듈을 찾음 - 대상 프로세스 핸들 구하기
OpenProcess 함수를 통해 대상 프로세스의 핸들을 얻기. 핸들을 통해 프로세스에 접근가능하고, DLL을 제거하는 작업을 수행가능 - FreeLibrary() API 주소 구하기
GetModuleHandle 함수로 kernel32.dll 모듈 핸들을 얻고 GetProcAddress 함수를 사용해 FreeLibrary 함수의 주소를 가져옴. FreeLibrary는 특정 DLL을 프로세스에서 언로드할 때 사용하는 함수 - 대상 프로세스에 스레드를 실행시킴
CreateRemoteThread 함수를 이용해 대상 프로세스 내에서 FreeLibrary 함수를 실행하는 스레드를 생성, 이로 인해 대상 DLL이 해당 프로세스에서 언로드, 스레드 종료 후 핸들을 닫아버림
반응형
'공부해요 > 리버싱_핵심원리' 카테고리의 다른 글
26. PE Tools (0) | 2024.11.06 |
---|---|
25. PE 패치를 이용한 DLL 로딩 (0) | 2024.11.06 |
23. DLL 인젝션 (1) | 2024.11.04 |
22. 악의적인 목적으로 사용되는 키로거 (3) | 2024.11.04 |
21. Windows 메시지 후킹 (3) | 2024.11.04 |