text: #include <stdint.h>
  #include <windows.h>
  #include <limits.h>
  
  #include <shellapi.h>
  #include "dbg.h"
  #include "fsatrace.h"
  
  void
  injectProcess(HANDLE proc)
  {
  	HANDLE			tid;
  	BOOL			is32;
  	FARPROC			addr;
  	LPVOID			arg;
  	size_t			argsz;
  	char			dll[PATH_MAX];
  	int			ndll;
  	DWORD			rc;
  	static int		injecting;
  	extern IMAGE_DOS_HEADER __ImageBase;
  	ASSERT(proc);
  	ZeroMemory(dll, sizeof(dll));
  	CHK(ndll = GetModuleFileNameA((HMODULE)&__ImageBase, dll, sizeof(dll)));
  
  	// dll is one of mypath\fsatrace.exe, mypath\fsatrace64.dll or
  	// mypath\fsatrace32.dll
  	CHK(IsWow64Process(proc, &is32));
  	if (strcasecmp(&dll[ndll - 4], ".exe") == 0)
  		ndll -= 4; // .exe
  	else
  		ndll -= 6; // 32.dll or 64.dll
  	memcpy(&dll[ndll], is32 ? "32.dll" : "64.dll", 6);
  
  	argsz = strlen(dll) + 1;
  	CHK(0 !=
  	    (arg = VirtualAllocEx(
  		 proc, 0, argsz, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)));
  
  	if (is32 && !IS32) {
  		STARTUPINFO	    si;
  		PROCESS_INFORMATION pi;
  		const char *	    helpername = "fsatracehelper.exe";
  		char		    helper[PATH_MAX];
  		char *		    p;
  
  		// On 32bit Windows when we spawn fsatracehelper it reenters
  		// and tries to run itself again, if we detect this we abort
  		// since we don't need to trace the command fsatracehelper
  		// itself
  		if (injecting)
  			return;
  
  		ZeroMemory(&si, sizeof(si));
  		si.cb = sizeof(si);
  		memcpy(helper, dll, argsz);
  		p = strrchr(helper, '\\');
  		memcpy(p + 1, helpername, strlen(helpername) + 1);
  		injecting = 1;
  		CHK(CreateProcessA(0, helper, 0, 0, 0, 0, 0, 0, &si, &pi));
  		injecting = 0;
  		CHK(WAIT_OBJECT_0 ==
  		    WaitForSingleObject(pi.hProcess, INFINITE));
  		CHK(GetExitCodeProcess(pi.hProcess, &rc));
  		CHK(CloseHandle(pi.hProcess));
  		CHK(CloseHandle(pi.hThread));
  		addr = (FARPROC)(uintptr_t)rc;
  	} else
  		addr = GetProcAddress(
  		    GetModuleHandle("kernel32.dll"), "LoadLibraryA");
  
  	CHK(addr);
  	CHK(WriteProcessMemory(proc, arg, dll, argsz, NULL));
  	CHK(0 !=
  	    (tid = CreateRemoteThread(
  		 proc, 0, 0, (LPTHREAD_START_ROUTINE)addr, arg, 0, 0)));
  	CHK(-1 != ResumeThread(tid));
  	CHK(WAIT_OBJECT_0 == WaitForSingleObject(tid, INFINITE));
  	CHK(CloseHandle(tid));
  	CHK(VirtualFreeEx(proc, arg, 0, MEM_RELEASE));
  }
  
  void
  injectPID(DWORD pid)
  {
  	HANDLE h;
  	CHK(0 != (h = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid)));
  	injectProcess(h);
  	CHK(CloseHandle(h));
  }
  