본문 바로가기
개발/Windows

윈도우10에서 CreateRemoteThread를 이용한 DLL Injection

by lucidmaj7 2020. 4. 1.
728x90
반응형

CreateRemoteThread를 이용한 DLL Injection

DLL Injection을 하는 방법중에 하나로 RemoteThread를 생성하여 타겟프로세스에 원하는 DLL을 로드 하는 방법이 있습니다. 이 방법은 가장 간단하면서도 널리 쓰이는 방법 중에 하나입니다. CreateRemoteThread API를 이용하여 다른 프로세스에 쓰레드를 생성 할 수 있습니다.

CreateRemoteThread를 MSDN에서 찾아보면 Remarks에 다음과 같은 내용을 볼 수 있습니다.

https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread

 

CreateRemoteThread function (processthreadsapi.h) - Win32 apps

Creates a thread that runs in the virtual address space of another process.

docs.microsoft.com

Terminal Services isolates each terminal session by design. Therefore, CreateRemoteThread fails if the target process is in a different session than the calling process.

번역을 해보자면 터미널 서비스 프로스 들은 세션이 다르게 지정되어 실행되기 때문에 만약 타겟 프로세스가 다른 세션에서 실행중일 때 실패 한다는 이야기 입니다. Windows Vista 이후 즉 NT커널 6.x이후로 사용자 응용프로그램과 서비스 등이 실행되는데 세션이라는 개념이 도입되었습니다.

이렇게 널리 쓰이던 방식인 CreateRemoteThread를 이용한 DLL Injection에 위기가 왔지만 사람들은 더 하위 함수인 NtCreateThreadEx라는 함수를 사용하여 대체 할 수 있음을 알아내었습니다. 하지만 NtCreateThreadEx는 문서화 되지 않은 함수로 언제 갑자기 호출이 불가해도 할말이 없는 API였습니다. 아무튼 Windows 7에서부터 CreateRemoteThread로 다른 세션에 DLL Injection을 수행하면 0x08이라는 LastError를 리턴하면서 실패 하였지만 NtCreateThreadEx함수를 통해 DLL Injection을 성공 시킬 수 있었습니다.

세월이 흘러 Windows 10이 출시되고 NtCreateThreadEx로 DLL Injectino이 불가능 하다는 소리가 또 터져 나오기 시작했습니다. 해당글 들은 구글에서 검색만 해봐도 많은 글들을 볼 수 있었습니다. NtCreateThreadEx를 대체 하여 RtlCreateUserThread를 사용하라고 하고 있습니다.

직접 테스트를 해봤습니다.

다음은 DLL Injection을 수행하는 예시 코드입니다.

BOOL DLLInjectByRemoteThread(DWORD dwPID, LPCWSTR lpszDLLPath )
{
	HMODULE hKernel32 = NULL;
	HMODULE hNTDLL = NULL;
	FARPROC lpfnLoadLibrary = NULL;
	pfnNtCreateThreadEx fpNtCreateThread = NULL;
	HANDLE hTargetProc = NULL; 
	LPVOID dllPathAlloc = NULL;
	BOOL bSuccess = TRUE;
	HANDLE hThread = NULL;
	
	if (wcslen(lpszDLLPath) == 0)
	{
		bSuccess = FALSE;
		goto EXIT;
	}

	if (!PathFileExists(lpszDLLPath))
	{
		bSuccess = FALSE;
		OutputDebugString(_T("Error: DLL File is not exists"));
		goto EXIT;
	}

	hTargetProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
	if (!hTargetProc)
	{
		bSuccess = FALSE;
		OutputDebugString(_T("Error: fail to open Target process "));
		goto EXIT;
	}

	dllPathAlloc = VirtualAllocEx(hTargetProc, NULL, sizeof(WCHAR) * MAX_PATH, MEM_COMMIT, PAGE_READWRITE);

	if (dllPathAlloc == NULL)
	{
		OutputDebugString(_T("Error: VirtualAllocEx  "));
		bSuccess = FALSE;
		goto EXIT;
	}

	if (!WriteProcessMemory(hTargetProc, dllPathAlloc, lpszDLLPath, sizeof(WCHAR) * wcslen(lpszDLLPath) +sizeof(WCHAR), NULL))
	{
		OutputDebugString(_T("Error: WriteProcessMemory  "));
		bSuccess = FALSE;
		goto EXIT;
	}

	hKernel32=LoadLibrary(L"Kernel32.dll");
	if (!hKernel32)
	{
		OutputDebugString(_T("Error: LoadLibrary Kernel32.dll "));
		bSuccess = FALSE;
		goto EXIT;
	}
	lpfnLoadLibrary = GetProcAddress(hKernel32, "LoadLibraryW");

	if (!lpfnLoadLibrary)
	{
		OutputDebugString(_T("Error: GetProcAddress LoadLibraryW "));
		bSuccess = FALSE;
		goto EXIT;

	}

	hThread = CreateRemoteThread(hTargetProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpfnLoadLibrary, dllPathAlloc, 0, NULL);
	if (hThread == NULL)
	{
		OutputDebugString(_T("Error: CreateRemoteThread fail "));
		DWORD dwError = GetLastError();
		if (dwError == 5)
		{
			OutputDebugString(_T("Error: CreateRemoteThread GetLastError 5 "));
			bSuccess = FALSE;
			goto EXIT;
		}

		if (dwError == 8)
		{
			OutputDebugString(_T("Error: CreateRemoteThread GetLastError 8 "));
			hNTDLL = LoadLibrary(L"ntdll.dll");
			if (!hNTDLL)
			{
				bSuccess = FALSE;
				goto EXIT;
			}

		
			CLIENT_ID cid;
			pfnRtlCreateUserThread RtlCreateUserThread = (pfnRtlCreateUserThread)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlCreateUserThread");
			if (RtlCreateUserThread)
			{

				NTSTATUS status = 0;
				status = RtlCreateUserThread(hTargetProc, NULL, FALSE, 0, 0, 0, (LPTHREAD_START_ROUTINE)lpfnLoadLibrary, dllPathAlloc, &hThread, &cid);
				if (NT_SUCCESS(status) && hThread != NULL)
				{
					OutputDebugString(_T("success RtlCreateUserThread"));
					
			
				}
				else
				{
					OutputDebugString(_T("fail RtlCreateUserThread"));
					bSuccess = FALSE;
					goto EXIT;
				}
			}
			else
			{
				bSuccess = FALSE;
				goto EXIT;
			}

		}
	
	}
	OutputDebugString(_T("success inject"));
	if (hThread)
	{
		WaitForSingleObject(hThread, INFINITE);
	}

EXIT:
	
	if (dllPathAlloc)
	{
		VirtualFreeEx(hTargetProc, dllPathAlloc, 0, MEM_RELEASE);
	}

	if (hTargetProc)
	{
		CloseHandle(hTargetProc);
	}
	if (hThread)
	{
		CloseHandle(hThread);
	}
	if (hNTDLL)
	{
		FreeLibrary(hNTDLL);
	}
	if (hKernel32)
	{
		FreeLibrary(hKernel32);
	}

	return bSuccess;

}

 

일단 Windows 7 SP1 x64에서 테스트 해보았습니다.

Win7 64

첫번째 시도 CreateRemoteThread를 이용한 Injection에서는 GetLastError 8을 뱉으며 인젝션에 실패 하고 다시 RtlCreateRemoteThread로 시도하면서 다시 성공합니다. 즉 분명 Windows7에서는 CreateRemoteThread로 다른세션의 프로세스에 인젝션이 되지 않습니다.

다시 Windows 10 x64 1057버전에서 시행해 보았습니다.

Windows 10 x64 1057

Windows 10에서는 CreateRemoteThread함수를 통해 바로 인젝션이 됩니다.

 

물론 OS가 보호하거나 보호 드라이버 등으로 보호된 프로세스는 인젝션이 불가능 합니다. 하지만 MSDN의 설명과 다르게 최신 Windows10의 경우 인젝션이 예전 XP에서 처럼 CreateRemoteThread로 Injection이 가능 했습니다. 또한 NtCreateThread, RtlCreateUserThread를 통해서도 Injection이 가능했습니다. MS가 이러한 사항을 MSDN에 반영을 하지 않은 것인지, 버그 인지, 혼란만 가중 시키고 있습니다. 

샘플소스

https://github.com/lucidmaj7/DLLInjection

 

lucidmaj7/DLLInjection

DLL Injection Test App. Contribute to lucidmaj7/DLLInjection development by creating an account on GitHub.

github.com

 

참고

https://eram.tistory.com/entry/DLL-Injection-3-Injector-%EC%82%AC%EC%9A%A9

 

DLL Injection (3) - Injector 사용

인젝터만 만들어 놓으면 DLL Injection 를 할 때 가장 쉽게 하는 방법같습니다. [DLL Injection 기초 개념] [EAT 사용한 DLL Injection] 인젝터를 만드는 과정은 생각보다 많이 간단합니다. 첫번째 대상 프로세스..

eram.tistory.com

https://kblab.tistory.com/298

 

DLL Injection in kernel 6

DLL Injection in kernel 6 kernel version 6 이후부터 CreateRemoteThread()가 사실상 사용이 불가능한데, 이 API를 대신해서 ZwCreateThreadEx() API를 사용하면 Injection이 된다고 합니다. Windows 10 x64 환..

kblab.tistory.com

https://gwangyi.github.io/posts/dll-injection-by-createremotethread/

 

CreateRemoteThread로 DLL Injection하기

CreateRemoteThread로 DLL Injection하기 dll-injection hacking windows 15 Dec 2018 Table of Contents IntroductionBackgroundDebugging APIRegistryCreateRemoteThreadHookMechanismx86_64/WOW64 ProblemResultInjecting DllFuture WorkConclusion ChangeLog 2018/12/19: Dll

gwangyi.github.io

 

728x90
반응형

댓글