/*
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());
}
}
}