aboutsummaryrefslogtreecommitdiff
path: root/src/tools/connection_patcher/Program.cpp
diff options
context:
space:
mode:
authorDJScias <DJScias@gmail.com>2015-06-30 16:05:50 +0200
committerCarbenium <carbenium@outlook.com>2015-07-03 22:15:52 +0200
commit7e906d7b1926394ba436315b7222b95f5473f79b (patch)
tree8a29dad02d272b37bc6da1a1e0cd29cecb25e5ae /src/tools/connection_patcher/Program.cpp
parentc24787f6665b5ea2b696bdfa7134a19ab5a3c331 (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.cpp175
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";