QString KShell::joinArgs(const QStringList &args) { QString ret; for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) { if (!ret.isEmpty()) { ret.append(QLatin1Char(' ')); } ret.append(quoteArg(*it)); } return ret; }
int execute(char * const * args) { std::string commandLine; const char *arg0 = *args; const char *arg; char sep = 0; while ((arg = *args++) != NULL) { if (sep) { commandLine.push_back(sep); } if (needsQuote(arg)) { quoteArg(commandLine, arg); } else { commandLine.append(arg); } sep = ' '; } STARTUPINFO startupInfo; memset(&startupInfo, 0, sizeof(startupInfo)); startupInfo.cb = sizeof(startupInfo); PROCESS_INFORMATION processInformation; if (!CreateProcessA(NULL, const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW 0, // process attributes 0, // thread attributes FALSE, // inherit handles 0, // creation flags, NULL, // environment NULL, // current directory &startupInfo, &processInformation )) { log("error: failed to execute %s\n", arg0); return -1; } WaitForSingleObject(processInformation.hProcess, INFINITE); DWORD exitCode = ~0; GetExitCodeProcess(processInformation.hProcess, &exitCode); CloseHandle(processInformation.hProcess); CloseHandle(processInformation.hThread); return (int)exitCode; }
int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "usage:\n" " inject <dllname.dll> <command> [args] ...\n" " inject <dllname.dll> <process-id>\n" " inject <dllname.dll> !<process-name>\n" ); return 1; } BOOL bAttach = FALSE; DWORD dwProcessId = ~0; if (isNumber(argv[2])) { dwProcessId = atol(argv[2]); bAttach = TRUE; } else if (argv[2][0] == '!') { const char *szProcessName = &argv[2][1]; if (!getProcessIdByName(szProcessName, &dwProcessId)) { fprintf(stderr, "error: failed to find process %s\n", szProcessName); return 1; } bAttach = TRUE; fprintf(stderr, "dwProcessId = %lu\n", dwProcessId); } HANDLE hSemaphore = NULL; const char *szDll = argv[1]; if (!USE_SHARED_MEM) { SetEnvironmentVariableA("INJECT_DLL", szDll); } else { hSemaphore = CreateSemaphore(NULL, 1, 1, "inject_semaphore"); if (hSemaphore == NULL) { fprintf(stderr, "error: failed to create semaphore\n"); return 1; } DWORD dwWait = WaitForSingleObject(hSemaphore, 0); if (dwWait == WAIT_TIMEOUT) { fprintf(stderr, "info: waiting for another inject instance to finish\n"); dwWait = WaitForSingleObject(hSemaphore, INFINITE); } if (dwWait != WAIT_OBJECT_0) { fprintf(stderr, "error: failed to enter semaphore gate\n"); return 1; } SetSharedMem(szDll); } BOOL bAttachDwm = FALSE; PROCESS_INFORMATION processInfo; HANDLE hProcess; if (bAttach) { BOOL bRet; HANDLE hToken = NULL; bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken); if (!bRet) { fprintf(stderr, "error: OpenProcessToken returned %u\n", (unsigned)bRet); return 1; } LUID Luid; bRet = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid); if (!bRet) { fprintf(stderr, "error: LookupPrivilegeValue returned %u\n", (unsigned)bRet); return 1; } TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = Luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof tp, NULL, NULL); if (!bRet) { fprintf(stderr, "error: AdjustTokenPrivileges returned %u\n", (unsigned)bRet); return 1; } DWORD dwDesiredAccess = PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_TERMINATE; hProcess = OpenProcess( dwDesiredAccess, FALSE /* bInheritHandle */, dwProcessId); if (!hProcess) { logLastError("failed to open process"); return 1; } char szProcess[MAX_PATH]; DWORD dwRet = GetModuleFileNameEx(hProcess, 0, szProcess, sizeof szProcess); assert(dwRet); if (dwRet && stricmp(getBaseName(szProcess), "dwm.exe") == 0) { bAttachDwm = TRUE; } } else { std::string commandLine; char sep = 0; for (int i = 2; i < argc; ++i) { const char *arg = argv[i]; if (sep) { commandLine.push_back(sep); } if (needsQuote(arg)) { quoteArg(commandLine, arg); } else { commandLine.append(arg); } sep = ' '; } STARTUPINFO startupInfo; memset(&startupInfo, 0, sizeof startupInfo); startupInfo.cb = sizeof startupInfo; // Create the process in suspended state if (!CreateProcessA( NULL, const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW 0, // process attributes 0, // thread attributes TRUE, // inherit handles CREATE_SUSPENDED, NULL, // environment NULL, // current directory &startupInfo, &processInfo)) { DWORD dwLastError = GetLastError(); fprintf(stderr, "error: failed to execute %s (%lu)\n", commandLine.c_str(), dwLastError); if (dwLastError == ERROR_ELEVATION_REQUIRED) { fprintf(stderr, "error: target program requires elevated priviledges and must be started from an Administrator Command Prompt, or UAC must be disabled\n"); } return 1; } hProcess = processInfo.hProcess; } /* * XXX: Mixed architecture don't quite work. See also * http://www.corsix.org/content/dll-injection-and-wow64 */ { typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL); PFNISWOW64PROCESS pfnIsWow64Process; pfnIsWow64Process = (PFNISWOW64PROCESS) GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process"); if (pfnIsWow64Process) { BOOL isParentWow64 = FALSE; BOOL isChildWow64 = FALSE; if (pfnIsWow64Process(GetCurrentProcess(), &isParentWow64) && pfnIsWow64Process(hProcess, &isChildWow64) && isParentWow64 != isChildWow64) { fprintf(stderr, "error: binaries mismatch: you need to use the " #ifdef _WIN64 "32-bits" #else "64-bits" #endif " apitrace binaries to trace this application\n"); TerminateProcess(hProcess, 1); return 1; } } } if (bAttachDwm && IsWindows8OrGreater()) { // Switch to Microsoft Basic Display Driver before injecting, so that // we don't trace with it. devconDisable(DEVCON_CLASS_DISPLAY); Sleep(1000); } const char *szDllName; szDllName = "injectee.dll"; char szDllPath[MAX_PATH]; GetModuleFileNameA(NULL, szDllPath, sizeof szDllPath); getDirName(szDllPath); strncat(szDllPath, szDllName, sizeof szDllPath - strlen(szDllPath) - 1); #if 1 if (!injectDll(hProcess, szDllPath)) { TerminateProcess(hProcess, 1); return 1; } #endif DWORD exitCode; if (bAttach) { if (bAttachDwm) { restartDwmComposition(hProcess); } exitCode = 0; } else { // Start main process thread ResumeThread(processInfo.hThread); // Wait for it to finish WaitForSingleObject(hProcess, INFINITE); if (pSharedMem && !pSharedMem->bReplaced) { fprintf(stderr, "warning: %s was never used: application probably does not use this API\n", szDll); } exitCode = ~0; GetExitCodeProcess(hProcess, &exitCode); CloseHandle(processInfo.hThread); } CloseHandle(hProcess); if (hSemaphore) { ReleaseSemaphore(hSemaphore, 1, NULL); CloseHandle(hSemaphore); } return (int)exitCode; }
bool setupMsvcEnvironmentImpl() { if (getenv("VSINSTALLDIR")) return true; llvm::SmallString<128> tmpFilePath; if (llvm::sys::fs::createTemporaryFile("ldc_dumpEnv", "", tmpFilePath)) return false; /* Run `%ComSpec% /s /c "...\dumpEnv.bat <x86|amd64> > <tmpFilePath>"` to dump * the MSVC environment to the temporary file. * * cmd.exe /c treats the following string argument (the command) * in a very peculiar way if it starts with a double-quote. * By adding /s and enclosing the command in extra double-quotes * (WITHOUT additionally escaping the command), the command will * be parsed properly. */ auto comspecEnv = getenv("ComSpec"); if (!comspecEnv) { warning(Loc(), "'ComSpec' environment variable is not set, assuming 'cmd.exe'."); comspecEnv = "cmd.exe"; } std::string cmdExecutable = comspecEnv; std::string batchFile = exe_path::prependBinDir("dumpEnv.bat"); std::string arch = global.params.targetTriple->isArch64Bit() ? "amd64" : "x86"; llvm::SmallString<512> commandLine; commandLine += quoteArg(cmdExecutable); commandLine += " /s /c \""; commandLine += quoteArg(batchFile); commandLine += ' '; commandLine += arch; commandLine += " > "; commandLine += quoteArg(tmpFilePath); commandLine += '"'; const int exitCode = executeAndWait(commandLine.c_str()); if (exitCode != 0) { error(Loc(), "`%s` failed with status: %d", commandLine.c_str(), exitCode); llvm::sys::fs::remove(tmpFilePath); return false; } auto fileBuffer = llvm::MemoryBuffer::getFile(tmpFilePath); llvm::sys::fs::remove(tmpFilePath); if (fileBuffer.getError()) return false; const auto contents = (*fileBuffer)->getBuffer(); const auto size = contents.size(); // Parse the file. std::vector<std::pair<llvm::StringRef, llvm::StringRef>> env; size_t i = 0; // for each line while (i < size) { llvm::StringRef key, value; for (size_t j = i; j < size; ++j) { const char c = contents[j]; if (c == '=' && key.empty()) { key = contents.slice(i, j); i = j + 1; } else if (c == '\n' || c == '\r' || c == '\0') { if (!key.empty()) { value = contents.slice(i, j); } // break and continue with next line i = j + 1; break; } } if (!key.empty() && !value.empty()) env.emplace_back(key, value); } if (global.params.verbose) fprintf(global.stdmsg, "Applying environment variables:\n"); bool haveVsInstallDir = false; for (const auto &pair : env) { const std::string key = pair.first.str(); const std::string value = pair.second.str(); if (global.params.verbose) fprintf(global.stdmsg, " %s=%s\n", key.c_str(), value.c_str()); SetEnvironmentVariableA(key.c_str(), value.c_str()); if (key == "VSINSTALLDIR") haveVsInstallDir = true; } return haveVsInstallDir; }