/* Userspace Virtual Filesystem Copyright (C) 2015 Sebastian Herbord. All rights reserved. This file is part of usvfs. usvfs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. usvfs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ #include "pch.h" #include <../usvfs_dll/hookcontext.h> #include #include #include #include #include #include #include #include #include #include #include #include namespace bi = boost::interprocess; namespace bfs = boost::filesystem; using usvfs::SharedParameters; using usvfs::shared::SharedMemoryT; template T getParameter(std::vector& arguments, const std::string& key, bool consume) { auto iter = std::find(arguments.begin(), arguments.end(), std::string("--") + key); if ((iter != arguments.end()) && ((iter + 1) != arguments.end())) { T result = boost::lexical_cast(*(iter + 1)); if (consume) { arguments.erase(iter, iter + 2); } return result; } else { throw std::runtime_error(std::string("argument missing " + key)); } } template T getParameter(std::vector& arguments, const std::string& key, const T& def, bool consume) { auto iter = std::find(arguments.begin(), arguments.end(), std::string("--") + key); if ((iter != arguments.end()) && ((iter + 1) != arguments.end())) { T result = boost::lexical_cast(*(iter + 1)); if (consume) { arguments.erase(iter, iter + 2); } return result; } else { return def; } } static void exceptionDialog(int line, int num, ...) { va_list args; va_start(args, num); std::wstring wstr; WCHAR buf[256]; wstr.append(L"Unhandled USVFS proxy exception (line "); wsprintf(buf, L"%d): ", line); wstr.append(buf); for (int i = 0; i < num; i++) { wsprintf(buf, L"%S", va_arg(args, const char*)); if (i < num - 1) wsprintf(buf, L", "); wstr.append(buf); } MessageBox(NULL, wstr.data(), NULL, MB_OK); va_end(args); } int main(int argc, char** argv) { std::shared_ptr logger; std::vector arguments; std::copy(argv + 1, argv + argc, std::back_inserter(arguments)); std::string instance; try { SHMLogger::open("usvfs"); logger = spdlog::create("usvfs", "usvfs"); logger->set_pattern("%H:%M:%S.%e [%L] (proxy) %v"); instance = getParameter(arguments, "instance", true); } catch (const std::exception& e) { if (logger.get() == nullptr) { exceptionDialog(__LINE__, 1, e.what()); return 1; } try { logger->critical("{}", e.what()); } catch (const spdlog::spdlog_ex& e2) { exceptionDialog(__LINE__, 2, e.what(), e2.what()); // no way to log this } catch (const std::exception&) { logger->critical(e.what()); } return 1; } try { std::string executable = getParameter(arguments, "executable", "", true); int pid = getParameter(arguments, "pid", 0, true); int tid = getParameter(arguments, "tid", 0, true); logger->info("instance: {}", instance); logger->info("exe: {}", executable); logger->info("pid: {}", pid); if (executable.empty() && (pid == 0)) { logger->warn("not all required settings set"); return 1; } SharedMemoryT configurationSHM(bi::open_only, instance.c_str()); if (!configurationSHM.check_sanity()) { logger->warn("failed to connect to vfs"); return 1; } logger->info("size: {}", configurationSHM.get_size()); logger->info("addr: {0:p}", configurationSHM.get_address()); logger->info("objs: {}", configurationSHM.get_num_named_objects()); std::pair params = configurationSHM.find("parameters"); if (params.first == nullptr) { logger->error("failed to open shared configuration for {}", instance); return 1; } boost::filesystem::path p(winapi::wide::getModuleFileName(nullptr)); if (executable.empty()) { HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); HANDLE threadHandle = INVALID_HANDLE_VALUE; if (tid != 0) { threadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, tid); } BOOL blacklisted = FALSE; TCHAR szModName[MAX_PATH]; if (GetModuleFileNameEx(processHandle, NULL, szModName, sizeof(szModName) / sizeof(TCHAR))) { const auto appName = usvfs::shared::string_cast(szModName); if (params.first->executableBlacklisted(appName, {})) { logger->info("not injecting {} as application is blacklisted", appName); blacklisted = TRUE; } } if (!blacklisted) { usvfs::injectProcess(p.parent_path().wstring(), params.first->makeLocal(), processHandle, threadHandle); } } else { winapi::process::Result process = winapi::ansi::createProcess(executable) .arguments(arguments.begin(), arguments.end()) .workingDirectory(bfs::path(executable).parent_path().string()) .suspended()(); if (!process.valid) { return 1; } BOOL blacklisted = FALSE; if (params.first->executableBlacklisted(executable, {})) { logger->info("not injecting {} as application is blacklisted", executable); blacklisted = TRUE; } if (!blacklisted) { usvfs::injectProcess(p.parent_path().wstring(), params.first->makeLocal(), process.processInfo); } ResumeThread(process.processInfo.hThread); } return 0; } catch (const std::exception& e) { try { logger->critical("unhandled exception: {}", e.what()); logExtInfo(e); } catch (const spdlog::spdlog_ex& e2) { // no way to log this exceptionDialog(__LINE__, 2, e.what(), e2.what()); } catch (const std::exception&) { logger->critical(e.what()); } } }