#define _WIN32_WINNT 0x0502
#include <windows.h>
#include <stdio.h>

// Inject dll by calling CreateRemoteThread API to remote process
BOOL InjectDLLbyCreateRemoteThread(CHAR *pszClassName, CHAR *pszDll);

// Inject dll by manipulaing thread entry point to remote process
BOOL InjectDLLbySetThreadContext(CHAR *pszClassName, CHAR *pszDll);

int main(int argc, char* argv[]){

	// Inject some dlls into explorer.exe, report result
	if(InjectDLLbyCreateRemoteThread("Shell_TrayWnd","mapi32.dll"))
		printf("Successfully injected dll per CreateRemoteThread to explorer.exe\n");
	else
		printf("Unable to injected dll per CreateRemoteThread to explorer.exe %d\n",GetLastError());

	if(InjectDLLbySetThreadContext("Shell_TrayWnd","mshtml.dll"))
		printf("Successfully injected dll per SetThreadContext to explorer.exe\n");
	else
		printf("Unable to injected dll per SetThreadContext to explorer.exe %d\n",GetLastError());

	return 0;
}

BOOL InjectDLLbyCreateRemoteThread(CHAR *pszClassName, CHAR *pszDll)
{
	LPVOID lpRemoteDllPath, lpLoadLibrary;
	HANDLE hProcess, hRemoteThread;
	DWORD dwWritten;
	DWORD dwProcessID;
	
	// Get process and thread handle from explorer.exe
	GetWindowThreadProcessId(FindWindow(pszClassName,NULL), &dwProcessID);

	// Open process with desired acess
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessID);

	if (hProcess == NULL)
		return false;

	// Get address of LoadLibraryA inside kernel32.dll
	lpLoadLibrary = (VOID*)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

	// Allocate remote memory for dll path
	lpRemoteDllPath = (LPVOID)VirtualAllocEx(hProcess, NULL, strlen(pszDll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	
	// Write path to remote memory
	if (!WriteProcessMemory(hProcess, (LPVOID)lpRemoteDllPath, pszDll, strlen(pszDll) + 1, &dwWritten))
		return false;
	
	// Create remote thread by pointing to LoadLibraryA and assigning a pointer to the dll path
	hRemoteThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)lpLoadLibrary, (LPVOID)lpRemoteDllPath, NULL, NULL);

	if (hRemoteThread == NULL)
		return false;
	else
		CloseHandle(hRemoteThread);
	
	return true;
}

#pragma optimize("", off) 

// Injectionstub 
__declspec(naked) loadDll(void)
{
   _asm{
      push 0x10000000		// return address
      pushfd
      pushad
      push 0x10000000		// dll path address
      mov eax, 0x10000000	// LoadLibraryA address
      call eax
      popad
      popfd
      ret
   }
} 

__declspec(naked) loadDll_end(void)
{
	_asm{
		ret
	}
}

#pragma optimize("", on) 


BOOL InjectDLLbySetThreadContext(CHAR *pszClassName, CHAR *pszDll)
{
	DWORD dwProcessID, dwThreadID, dwStubLength, dwOldIP, dwOldProt, dwLoadLibAdr;
	HANDLE hProcess, hThread;
	LPVOID lpDllString;
	LPVOID lpStub;
	CONTEXT ctx;

	// Calc injection stub length
	dwStubLength = (DWORD)loadDll_end - (DWORD)loadDll;
	
	// Get address of LoadLibraryA inside kernel32.dll
	dwLoadLibAdr = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
	
	// Get process and thread handle from explorer.exe
	dwThreadID = GetWindowThreadProcessId(FindWindow(pszClassName,NULL), &dwProcessID);

	// Open process with desired acess
	hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, false, dwProcessID);

	if (hProcess == NULL)
		return false;

	// Allocate memory for our stub and the dll path
	lpDllString = VirtualAllocEx(hProcess, NULL, (strlen(pszDll) + 1), MEM_COMMIT, PAGE_READWRITE);
	lpStub      = VirtualAllocEx(hProcess, NULL, dwStubLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	// Copy dll path to previously allocated remote memory
	WriteProcessMemory(hProcess, lpDllString, pszDll, strlen(pszDll), NULL);

	// Open thread with desired access
	hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME, false, dwThreadID);

	if (hThread == NULL)
		return false;

	SuspendThread(hThread);
	
	ctx.ContextFlags = CONTEXT_CONTROL;

	// Load thread context
	if(!GetThreadContext(hThread, &ctx))
		return false;

	// Save old entrypoint
	dwOldIP = ctx.Eip;

	// Point to our injectionstub
	ctx.Eip = (DWORD)lpStub;
	ctx.ContextFlags = CONTEXT_CONTROL;
	
	// Change page access
	VirtualProtect(loadDll, dwStubLength, PAGE_EXECUTE_READWRITE, &dwOldProt);

	// Fill in stub
	memcpy((LPVOID)((DWORD)loadDll + 1), &dwOldIP, 4);
	memcpy((LPVOID)((DWORD)loadDll + 8), &lpDllString, 4);
	memcpy((LPVOID)((DWORD)loadDll + 13), &dwLoadLibAdr, 4);
	
	// Write filled stub to remote memory
    WriteProcessMemory(hProcess, lpStub, loadDll, dwStubLength, NULL);

	// Set manipulated context
	if(!SetThreadContext(hThread, &ctx))
		return false;


	// Wakeup suspended thread
	ResumeThread(hThread);

	// Wait during execution of our stub
	Sleep(15000);
	
	// Free remote memory
	VirtualFreeEx(hProcess, lpDllString, strlen(pszDll), MEM_DECOMMIT);
	VirtualFreeEx(hProcess, lpStub, dwStubLength, MEM_DECOMMIT);

	// Close process and thread handle
	CloseHandle(hProcess);
	CloseHandle(hThread);
	
    return true;
}