DLL 인젝션을 하는 이유와 알려진 방법들
- CreateRemoteThread() API 활용
- 가장많이 사용되는 방법
- 레지스트리에서 AppInit_DLLs 값을 변경해서 인젝션
- HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows
- SetWindowsHookEx() API 활용
TCP Socket API hook
- Chatting client/server 예제를 활용해 Winsock API를 hook
- Server는 전형적인 멀티스레드 기반으로 구현
(접속하는 클라이언트 마다 스레드 생성) - 본 수업에서 예제 차제는 설명하지는 않음
- Server는 전형적인 멀티스레드 기반으로 구현
- 최초 Client 코드 수준에서 Hook 관련 코드를 추가해 동작을 확인하고 DLL Injection 기능을 추가하는 방식으로 확장
CreateRemoteTherad() 기반 DLL Injection
- DLL injection 대상 프로세스를 개방해 새로운 스레드를 생성해주는 API
- 스레드로 실행할 함수에 전달되어야 할 정보들 (매개변수 및 포인터가 가리키는 대상 메모리)은 대상 프로세스의 가상 메모리에 접근해 공간을 미리 확보하고 주소를 넘기는 방식
- 대상 시스템에는 본래 존재하지 않았던 코드가 외부에 의해 실해되는 것이 핵심
Remote 는 원격이란 의미이지만 여기서는 Process 안에 없는 , 외부의 이런의미이다. 원격코드는 개발자가 process에 작성하지 않은 코드이다.
하고자하는 것은 Injector에서 CreateRemoteThread를 통해 Target Process에서 스레드를 생성하게 하고 LoadLibrary(path[Injection DLL] )를 호출하게 하는것이다.
DWORD getChatClientPid(void)
{
DWORD aPid[1024] = { 0 };
DWORD dwNeeded = 0;
if (::EnumProcesses(aPid, sizeof(aPid), &dwNeeded))
{
DWORD count = dwNeeded / sizeof(DWORD);
HANDLE hProcess;
for (DWORD i = 0; i <= count; ++i)
{
hProcess = ::OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, aPid[i]);
if (hProcess != NULL)
{
TCHAR name[MAX_PATH + _MAX_FNAME] = { 0 };
::GetModuleFileNameEx(hProcess, NULL, name, sizeof(name));
if (wcsstr(name, L"chatClient.exe") != NULL)
{
::wprintf(L"%s [PID: %d]\n", name, aPid[i]);
return aPid[i];
}
::CloseHandle(hProcess);
}
//else
// cout << "ERROR: Failed to open process. [PID: " <<
// aPid[i] << "]\n";
}
}
return 0;
}
int main()
{
setlocale(LC_ALL, "");
DWORD pid = getChatClientPid();
if (pid == 0) {
puts("ERROR: Failed to get PID(Chat Cliet)!");
return 0;
}
HANDLE hProcess = injectDll(pid);
if (hProcess == NULL)
{
puts("ERROR: Failed to inject hook dll!");
return 0;
}
puts("Press 'q' to unload hook module...");
while (_getch() != 'q');
ejectDll(hProcess, pid);
::CloseHandle(hProcess);
return 0;
}
getChatClientPid에서 chatClient를 pid를 찾는다.
HANDLE injectDll(DWORD pid)
{
HANDLE hTarget = NULL;
wchar_t* pszParam = NULL;
HANDLE hThread = NULL;
DWORD threadId = 0;
DWORD threadExitCode = 0;
HMODULE(WINAPI * pfLoadLibraryW)(LPCWSTR) = NULL;
wchar_t szLibPath[MAX_PATH + _MAX_FNAME] = {
L"F:\\이해하면 인생이 바뀌는 Windows API hook\\ApiHook64"
L"\\x64\\Release\\16_sockHook.dll"
};
//_putws(szLibPath);
HMODULE hK32 = ::GetModuleHandle(L"Kernel32");
pfLoadLibraryW = (HMODULE(WINAPI *)(LPCWSTR))
::GetProcAddress(hK32, "LoadLibraryW");
hTarget = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hTarget == NULL)
goto CLEAN_UP;
pszParam = (wchar_t*)::VirtualAllocEx(hTarget,
NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE);
if (pszParam == NULL)
goto CLEAN_UP;
::WriteProcessMemory(hTarget, pszParam, szLibPath,
sizeof(szLibPath), NULL);
hThread = ::CreateRemoteThread(hTarget, NULL, 0,
(LPTHREAD_START_ROUTINE)pfLoadLibraryW,
pszParam, 0, &threadId);
if (hThread == NULL)
goto CLEAN_UP;
if (::WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0)
{
puts("*** Injection Success ***");
}
CLEAN_UP:
if (hThread != NULL) ::CloseHandle(hThread);
if (pszParam != NULL)
::VirtualFreeEx(hTarget, pszParam,
MAX_PATH + _MAX_FNAME, MEM_RELEASE);
return hTarget;
}
injectDLL에서 pid를 기반으로 process를 hTarget를 찾고 해당 process에
pfLoadLibraryW 함수를 수행하는 스레드를 실행시킨다.
그러면 send socket api를 hooking 하는 ddl 을 targetProcess (client chat)이 로드를 하게 된다.
void ejectDll(HANDLE hTarget, DWORD pid)
{
HANDLE hSnapshot = NULL;
HANDLE hThread = NULL;
MODULEENTRY32 me = { sizeof(me) };
hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
BOOL bFlag = Module32First(hSnapshot, &me);
for (; bFlag; bFlag = Module32Next(hSnapshot, &me))
{
if (!_wcsicmp(me.szModule, L"16_sockHook.dll") ||
!_wcsicmp(me.szExePath, L"16_sockHook.dll"))
{
HMODULE hModule = GetModuleHandle(L"kernel32.dll");
LPTHREAD_START_ROUTINE pThreadProc = (LPTHREAD_START_ROUTINE)
::GetProcAddress(hModule, "FreeLibrary");
hThread = CreateRemoteThread(hTarget, NULL, 0,
pThreadProc, me.modBaseAddr, 0, NULL);
if (hThread != NULL)
{
::WaitForSingleObject(hThread, INFINITE);
::CloseHandle(hThread);
puts("*** Ejection Success ****");
}
break;
}
}
::CloseHandle(hSnapshot);
return;
}
eject에서는 snapshot api를 통해 dll을 찾고 이를 FreeLibary로 언로드 시킨다.
'Operating System > 이해하면 인생이 바뀌는 Windows API hook' 카테고리의 다른 글
Inline hook (0) | 2024.12.02 |
---|---|
IAT hook (0) | 2024.12.02 |
사전지식 - 두 번째 (0) | 2024.11.27 |
사전 지식 - 첫 번째 (0) | 2024.11.22 |