diff --git a/Main.cpp b/Main.cpp index 27bc1dc..c6e5153 100644 --- a/Main.cpp +++ b/Main.cpp @@ -8,11 +8,61 @@ #include #include -std::vector GetArguments() +struct Arguments { + std::vector syringe_args; + std::string game_args; +}; + +size_t FindSeparator(const std::wstring& cmdLine) +{ + bool inQuotes = false; + size_t len = cmdLine.length(); + for (size_t i = 0; i < len; ++i) + { + if (cmdLine[i] == L'\\' && i + 1 < len && cmdLine[i + 1] == L'"') + { + i += 1; + continue; + } + + if (cmdLine[i] == L'"') + { + inQuotes = !inQuotes; + continue; + } + + if (!inQuotes && cmdLine[i] == L' ') + { + if (i + 3 < len && cmdLine[i + 1] == L'-' && cmdLine[i + 2] == L'-' && cmdLine[i + 3] == L' ') + { + return i; + } + } + } + return std::wstring::npos; +} + +Arguments GetArguments() +{ + std::wstring wszSyringeArgs; + std::wstring wszGameArgs; + std::wstring lpCmdLine = GetCommandLineW(); + auto separator = FindSeparator(lpCmdLine); + if (separator != std::wstring::npos) + { + wszSyringeArgs = lpCmdLine.substr(0, separator); + wszGameArgs = lpCmdLine.substr(separator + 4); + } + else + { + wszSyringeArgs = lpCmdLine; + wszGameArgs = L""; + } + // Get argc, argv in wide chars int argc = 0; - LPWSTR* argvW = CommandLineToArgvW(GetCommandLineW(), &argc); + LPWSTR* argvW = CommandLineToArgvW(wszSyringeArgs.c_str(), &argc); // Convert to UTF-8. Skip the first argument as it contains the path to Syringe itself std::vector argv(argc - 1); @@ -25,10 +75,17 @@ std::vector GetArguments() LocalFree(argvW); - return argv; + int len = WideCharToMultiByte(CP_UTF8, 0, wszGameArgs.c_str(), -1, nullptr, 0, nullptr, nullptr); + std::string gameArgs = std::string(len - 1, '\0'); + WideCharToMultiByte(CP_UTF8, 0, wszGameArgs.c_str(), -1, gameArgs.data(), len, nullptr, nullptr); + + return { + argv, + gameArgs, + }; } -int Run(const std::vector& arguments) +int Run(const Arguments& arguments) { constexpr auto const VersionString = "SyringeEx " SYRINGEEX_VER_TEXT ", based on Syringe 0.7.2.0"; @@ -39,14 +96,14 @@ int Run(const std::vector& arguments) Log::WriteLine(VersionString); Log::WriteLine("==============="); Log::WriteLine(); - Log::WriteLine("WinMain: arguments = \"%.*s\"", printable(arguments)); + Log::WriteLine("WinMain: arguments = \"%.*s\"", printable(arguments.syringe_args)); auto failure = "Could not load executable."; auto exit_code = ERROR_ERRORS_ENCOUNTERED; try { - auto const command = parse_command_line(arguments); + auto const command = parse_command_line(arguments.syringe_args); Log::WriteLine( "WinMain: Trying to load executable file \"%.*s\"...", @@ -62,10 +119,10 @@ int Run(const std::vector& arguments) Log::WriteLine( "WinMain: SyringeDebugger::Run(\"%.*s\");", - printable(command.game_arguments)); + printable(arguments.game_args)); Log::WriteLine(); - Debugger.Run(command.game_arguments); + Debugger.Run(arguments.game_args); Log::WriteLine("WinMain: SyringeDebugger::Run finished."); Log::WriteLine("WinMain: Exiting on success."); return ERROR_SUCCESS; @@ -84,7 +141,7 @@ int Run(const std::vector& arguments) { MessageBoxA( nullptr, "Syringe cannot be run like that.\n\n" - "Usage:\nSyringe.exe [-i= ...] [--args=\"\"]", + "Usage:\nSyringe.exe [-i= ...] [-- ]", VersionString, MB_OK | MB_ICONINFORMATION); Log::WriteLine( diff --git a/README.md b/README.md index fe1af63..34da3d1 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,10 @@ syringe.exe game.exe ### Passing Arguments to the Target Executable -Use `--args="..."` to provide arguments for the launched process: +Use `--` as a delimiter to pass arguments to the launched process. All arguments after `--` will be forwarded directly to the target executable: ``` -syringe.exe game.exe --args="-CD. -SPAWN" +syringe.exe game.exe -- -CD. -SPAWN ``` ### DLL Injection Behavior diff --git a/Support.h b/Support.h index e3b699b..56b36dc 100644 --- a/Support.h +++ b/Support.h @@ -28,13 +28,10 @@ inline auto trim(std::string_view string) noexcept inline auto parse_command_line(const std::vector& arguments) { - static constexpr std::string_view ARGS_FLAG = "--args="; - struct argument_set { std::vector syringe_arguments; std::string executable_name; - std::string game_arguments; }; if (arguments.empty()) @@ -51,26 +48,25 @@ inline auto parse_command_line(const std::vector& arguments) if (!exe_found && !arg.starts_with("-")) { exe_found = true; - ret.executable_name = arg; - continue; - } + if (arg.starts_with('"') && arg.ends_with('"')) + ret.executable_name = arg.substr(1, arg.length() - 2); + else + ret.executable_name = arg; - // game arguments: --args="blob" - if (arg.starts_with(ARGS_FLAG)) - { - // extract after --args= - std::string blob = arg.substr(ARGS_FLAG.size()); - ret.game_arguments = blob; continue; } // Syringe arguments - ret.syringe_arguments.push_back(arg); + if (arg.starts_with("-i=\"") && arg.ends_with('"')) + ret.syringe_arguments.push_back("-i=" + arg.substr(4, arg.length() - 5)); + else + ret.syringe_arguments.push_back(arg); } if (!exe_found || ret.executable_name.empty()) throw invalid_command_arguments{}; + return ret; }