diff options
author | DJScias <DJScias@gmail.com> | 2015-06-30 16:05:50 +0200 |
---|---|---|
committer | Carbenium <carbenium@outlook.com> | 2015-07-03 22:15:52 +0200 |
commit | 7e906d7b1926394ba436315b7222b95f5473f79b (patch) | |
tree | 8a29dad02d272b37bc6da1a1e0cd29cecb25e5ae /src/tools/connection_patcher/Program.cpp | |
parent | c24787f6665b5ea2b696bdfa7134a19ab5a3c331 (diff) |
Tools/ConnectionPatcher: Add 'versions' file patching method
* This is necessary to allow connection to 6.1.2 after the 6.2.0 update released. Patching is version aware.
* Link is hardcoded to a github page after suggestion from Aokromes, it is not tied to any server this way
* The usage is optional. To patch use the "-e" option
* OOP-ify the tool a bit
Original implementation by DJScias
Closes #14980
Diffstat (limited to 'src/tools/connection_patcher/Program.cpp')
-rw-r--r-- | src/tools/connection_patcher/Program.cpp | 175 |
1 files changed, 73 insertions, 102 deletions
diff --git a/src/tools/connection_patcher/Program.cpp b/src/tools/connection_patcher/Program.cpp index 400bafbf6ba..7321871b5ba 100644 --- a/src/tools/connection_patcher/Program.cpp +++ b/src/tools/connection_patcher/Program.cpp @@ -28,23 +28,17 @@ #include <CompilerDefs.h> #include <boost/algorithm/string/replace.hpp> -#include <boost/filesystem.hpp> - -#include <iostream> -#include <fstream> -#include <boost/asio.hpp> +#include <boost/program_options.hpp> #if PLATFORM == PLATFORM_WINDOWS #include <Shlobj.h> #endif -using namespace boost::asio; -using boost::asio::ip::tcp; +namespace po = boost::program_options; namespace Connection_Patcher { - void copyDir(boost::filesystem::path const & source, boost::filesystem::path const & destination); - void GetFile(const std::string& serverName, int port, const std::string& getCommand, std::ostream& out); + po::variables_map GetConsoleArguments(int argc, char** argv); namespace { @@ -61,7 +55,7 @@ namespace Connection_Patcher // if (Authentication::ServerSignature::ClientValidateProof(x)) to if (true) patcher.Patch(PATCH::Password(), PATTERN::Password()); - std::string const moduleName(Helper::GetFileChecksum(patcher.binary) + ".auth"); + std::string const moduleName(Helper::GetFileChecksum(patcher.GetBinary()) + ".auth"); fs::path const modulePath (path / std::string(&moduleName[0], 2) / std::string(&moduleName[2], 2)); @@ -91,7 +85,7 @@ namespace Connection_Patcher boost::filesystem::create_directories(modulePath); std::ofstream outFile(module.string(), std::ofstream::out | std::ofstream::binary); - GetFile("xx.depot.battle.net", 1119, "/" + moduleName, outFile); + Helper::DownloadFile("xx.depot.battle.net", 1119, "/" + moduleName, outFile); outFile.close(); std::cout << "Done.\n"; } @@ -100,7 +94,7 @@ namespace Connection_Patcher } template<typename PATCH, typename PATTERN> - void do_patches(Patcher* patcher, boost::filesystem::path output) + void do_patches(Patcher* patcher, boost::filesystem::path output, bool patchVersionPath, uint32_t buildNumber) { std::cout << "patching Portal\n"; // '.logon.battle.net' -> '' to allow for set portal 'host' @@ -121,100 +115,55 @@ namespace Connection_Patcher // Creep::Instance::LoadModule() to allow for unsigned auth module patcher->Patch(PATCH::Signature(), PATTERN::Signature()); + if (patchVersionPath) + { + std::cout << "patching Versions\n"; + // sever the connection to blizzard's versions file to stop it from updating and replace with custom version + // hardcode %s.patch.battle.net:1119/%s/versions to trinity6.github.io/%s/%s/build/versi + std::string verPatch(Patches::Common::VersionsFile()); + std::string buildPattern = "build"; + + boost::algorithm::replace_all(verPatch, buildPattern, std::to_string(buildNumber)); + std::vector<unsigned char> verVec(verPatch.begin(), verPatch.end()); + patcher->Patch(verVec, Patterns::Common::VersionsFile()); + } + patcher->Finish(output); std::cout << "Patching done.\n"; } } - // adapted from http://stackoverflow.com/questions/8593608/how-can-i-copy-a-directory-using-boost-filesystem - void copyDir(boost::filesystem::path const & source, boost::filesystem::path const & destination) + po::variables_map GetConsoleArguments(int argc, char** argv) { - namespace fs = boost::filesystem; - if (!fs::exists(source) || !fs::is_directory(source)) - throw std::invalid_argument("Source directory " + source.string() + " does not exist or is not a directory."); - - if (fs::exists(destination)) - throw std::invalid_argument("Destination directory " + destination.string() + " already exists."); - - if (!fs::create_directory(destination)) - throw std::runtime_error("Unable to create destination directory" + destination.string()); - - for (fs::directory_iterator file(source); file != fs::directory_iterator(); ++file) + po::options_description all("Allowed options"); + all.add_options() + ("help,h", "print usage message") + ("path", po::value<std::string>()->required(), "Path to the Wow.exe") + ("extra,e", po::value<uint32_t>()->implicit_value(0), "Enable patching of versions file download path. Version can be specified explicitly.") + ; + + po::positional_options_description pos; + pos.add("path", 1); + + po::variables_map vm; + try { - fs::path current(file->path()); - if (fs::is_directory(current)) - copyDir(current, destination / current.filename()); - else - fs::copy_file(current, destination / current.filename()); + po::store(po::command_line_parser(argc, argv).options(all).positional(pos).run(), vm); + po::notify(vm); } - } - - // adapted from http://stackoverflow.com/questions/21422094/boostasio-download-image-file-from-server - void GetFile(const std::string& serverName, int port, const std::string& getCommand, std::ostream& out) - { - boost::asio::io_service io_service; - - // Get a list of endpoints corresponding to the server name. - tcp::resolver resolver(io_service); - tcp::resolver::query query(serverName, std::to_string(port)); - tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); - tcp::resolver::iterator end; - - // Try each endpoint until we successfully establish a connection. - tcp::socket socket(io_service); - boost::system::error_code error = boost::asio::error::host_not_found; - while (error && endpoint_iterator != end) + catch (std::exception& e) { - socket.close(); - socket.connect(*endpoint_iterator++, error); + std::cerr << e.what() << "\n"; } - boost::asio::streambuf request; - std::ostream request_stream(&request); - - request_stream << "GET " << getCommand << " HTTP/1.0\r\n"; - request_stream << "Host: " << serverName << ':' << port << "\r\n"; - request_stream << "Accept: */*\r\n"; - request_stream << "Connection: close\r\n\r\n"; - - // Send the request. - boost::asio::write(socket, request); - - // Read the response status line. - boost::asio::streambuf response; - boost::asio::read_until(socket, response, "\r\n"); - - // Check that response is OK. - std::istream response_stream(&response); - std::string http_version; - response_stream >> http_version; - unsigned int status_code; - response_stream >> status_code; - std::string status_message; - std::getline(response_stream, status_message); - - - // Read the response headers, which are terminated by a blank line. - boost::asio::read_until(socket, response, "\r\n\r\n"); - - // Process the response headers. - std::string header; - while (std::getline(response_stream, header) && header != "\r") - { - } + if (vm.count("help")) + std::cout << all << "\n"; - // Write whatever content we already have to output. - if (response.size() > 0) - { - out << &response; - } + if (!vm.count("path")) + throw std::invalid_argument("Wrong number of arguments: Missing client file."); - // Read until EOF, writing data to output as we go. - while (boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error)) - { - out << &response; - } + return vm; } } @@ -224,11 +173,19 @@ int main(int argc, char** argv) try { - if (argc != 2) - throw std::invalid_argument("Wrong number of arguments: Missing client file."); + bool patchVersionPath = false; + int wowBuild = 0; - std::string const binary_path(argv[1]); + auto vm = GetConsoleArguments(argc, argv); + // exit if help is enabled + if (vm.count("help")) + { + std::cin.get(); + return 0; + } + + std::string const binary_path(std::move(vm["path"].as<std::string>())); std::string renamed_binary_path(binary_path); wchar_t* commonAppData(nullptr); @@ -236,18 +193,32 @@ int main(int argc, char** argv) SHGetKnownFolderPath(FOLDERID_ProgramData, 0, NULL, &commonAppData); #endif - std::cout << "Creating patched binaries for "; + std::cout << "Creating patched binary..." << std::endl; Patcher patcher(binary_path); - switch (patcher.Type) + if (vm.count("extra")) + { + patchVersionPath = true; + wowBuild = vm["extra"].as<uint32_t>(); + + if (wowBuild == 0) + wowBuild = Helper::GetBuildNumber(patcher.GetBinary()); + + if (wowBuild == 0 || wowBuild < 10000 || wowBuild > 65535) // Build number has to be exactly 5 characters long + throw std::runtime_error("Could not retrieve build number or it was out of range. Build: " + std::to_string(wowBuild)); + + std::cout << "Determined build number: " << std::to_string(wowBuild) << std::endl; + } + + switch (patcher.GetType()) { case Constants::BinaryTypes::Pe32: std::cout << "Win32 client...\n"; boost::algorithm::replace_all(renamed_binary_path, ".exe", "_Patched.exe"); do_patches<Patches::Windows::x86, Patterns::Windows::x86> - (&patcher, renamed_binary_path); + (&patcher, renamed_binary_path, patchVersionPath, wowBuild); do_module<Patches::Windows::x86, Patterns::Windows::x86> ( "8f52906a2c85b416a595702251570f96d3522f39237603115f2f1ab24962043c.auth" @@ -260,7 +231,7 @@ int main(int argc, char** argv) boost::algorithm::replace_all(renamed_binary_path, ".exe", "_Patched.exe"); do_patches<Patches::Windows::x64, Patterns::Windows::x64> - (&patcher, renamed_binary_path); + (&patcher, renamed_binary_path, patchVersionPath, wowBuild); do_module<Patches::Windows::x64, Patterns::Windows::x64> ( "0a3afee2cade3a0e8b458c4b4660104cac7fc50e2ca9bef0d708942e77f15c1d.auth" @@ -272,12 +243,12 @@ int main(int argc, char** argv) std::cout << "Mac client...\n"; boost::algorithm::replace_all (renamed_binary_path, ".app", " Patched.app"); - copyDir ( boost::filesystem::path(binary_path).parent_path()/*MacOS*/.parent_path()/*Contents*/.parent_path() + Helper::CopyDir(boost::filesystem::path(binary_path).parent_path()/*MacOS*/.parent_path()/*Contents*/.parent_path() , boost::filesystem::path(renamed_binary_path).parent_path()/*MacOS*/.parent_path()/*Contents*/.parent_path() ); do_patches<Patches::Mac::x64, Patterns::Mac::x64> - (&patcher, renamed_binary_path); + (&patcher, renamed_binary_path, patchVersionPath, wowBuild); { namespace fs = boost::filesystem; @@ -291,7 +262,7 @@ int main(int argc, char** argv) break; default: - throw std::runtime_error("Type: " + std::to_string(static_cast<uint32_t>(patcher.Type)) + " not supported!"); + throw std::runtime_error("Type: " + std::to_string(static_cast<uint32_t>(patcher.GetType())) + " not supported!"); } std::cout << "Successfully created your patched binaries.\n"; |