From 398fe53796d09c9424ed15d9906f9150defbf7be Mon Sep 17 00:00:00 2001 From: Redbeanw44602 Date: Thu, 18 May 2023 17:07:59 +0800 Subject: [PATCH] 1.2.0 --- README.md | 5 +- main.cpp | 119 ++++++++++++++++------------------------------- patcher.cpp | 130 +++++++++++++++++++++++++++++++++------------------- patcher.h | 52 +++++++++++++++++---- utils.cpp | 44 +++++------------- utils.h | 7 +-- 6 files changed, 181 insertions(+), 176 deletions(-) diff --git a/README.md b/README.md index a72b912..c1455b6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A patcher, contains some patches for minecraft. ``` MCPatcher.exe [path] ``` - - You can provide no arguments and it will ask you for the path to binary. + - You can provide no arguments, and it will ask you for the path to binary. ``` MCPatcher.exe ``` @@ -18,7 +18,6 @@ MCPatcher.exe ### Platform: Windows > Binary: *Minecraft.Windows.exe* -> Tested: 1.19.22, 1.19.30, 1.19.40.22 (Preview) - +> As of 23/05/18, it is effective in all recent versions (release-1.19, preview-1.20), and theoretically supports all versions. - No Trial - No Chat Report (wip) diff --git a/main.cpp b/main.cpp index 0e8c759..7d83623 100644 --- a/main.cpp +++ b/main.cpp @@ -1,65 +1,43 @@ #include #include +#include +#include #include "patcher.h" #include "utils.h" -#include "logger.h" -constexpr unsigned int FAIL_CANNOT_OPEN_FILE = 0x1001; -constexpr unsigned int FAIL_CANNOT_READ_FILE = 0x1002; -constexpr unsigned int FAIL_CANNOT_FIND_BYTE = 0x1003; -constexpr unsigned int FAIL_CURRENT_PLATFORM_NO_PATCH = 0x1004; -constexpr unsigned int FAIL_BACKUP = 0x1005; +constexpr unsigned int FAIL_CANNOT_OPEN_FILE = (0x1001); +constexpr unsigned int FAIL_CANNOT_READ_FILE = (0x1002); +constexpr unsigned int FAIL_CANNOT_FIND_BYTE = (0x1003); +constexpr unsigned int FAIL_CURRENT_PLATFORM_NO_PATCH = (0x1004); +constexpr unsigned int FAIL_BACKUP = (0x1005); -#define VERSION "1.1.0" +#define VERSION "1.2.0" int main(int argc, char *argv[]) { // Welcome message. - Info("MCPatcher v{} OpenSource: github.com/Redbeanw44602/MCPatcher [MIT]",VERSION); + spdlog::set_pattern("[%H:%M:%S.%e] [%^%l%$] %v"); + spdlog::info("MCPatcher v{}, Repository: github.com/Redbeanw44602/MCPatcher [MIT]", VERSION); - // Add known patches; + // Add known patch(es); MCPatcher patcher; - // PatchName *from* [PV(preview)|FM(formal)|BT(beta)][VERSION][-][FUNCTION ADDRESS] - - patcher.registerPatch( - Platform::Win10, - "PV1193025-1403A4F20", - { - { - { 0x10, 0x84, 0xC0, 0x74, 0x15, 0xB0, /*O*/0x01, 0x48, 0x8B, 0x4C, 0x24, 0x30, 0x48, 0x33, 0xCC }, - { 0x10, 0x84, 0xC0, 0x74, 0x15, 0xB0, /*N*/0x00, 0x48, 0x8B, 0x4C, 0x24, 0x30, 0x48, 0x33, 0xCC } - }, - { - { 0x48, 0x83, 0xC3, 0x10, 0x48, 0x3B, 0xDF, 0x75, 0xEA, 0xB0, /*O*/0x01, 0x48, 0x8B, 0x7C, 0x24 }, - { 0x48, 0x83, 0xC3, 0x10, 0x48, 0x3B, 0xDF, 0x75, 0xEA, 0xB0, /*N*/0x00, 0x48, 0x8B, 0x7C, 0x24 } - } - } - ); - - patcher.registerPatch( - Platform::Win10, - "PV1198020-14124C910", - { - { - { 0x0D, 0xB8, 0x00, 0xEB, 0x04, 0x0F, 0xB6, 0x42, 0x10, 0x84, 0xC0, 0x74, 0x26, 0xB0, /*O*/0x01, 0x48 }, - { 0x0D, 0xB8, 0x00, 0xEB, 0x04, 0x0F, 0xB6, 0x42, 0x10, 0x84, 0xC0, 0x74, 0x26, 0xB0, /*N*/0x00, 0x48 } - } - } - ); + auto generalPatch = MCPatcher::compile( + "48 8B 42 08 48 8B 88 80 01 00 00 48 85 C9 74 07 E8 ?? ?? ?? 00 " + "EB 04 0F B6 42 10 84 C0 74 ?? B0 01(00) 48 8B 4C 24 ?? 48 33 CC"); + + patcher.registerPatch(Platform::Win10, "General_Patch_V2", generalPatch); // Ask for binary file; string strpath; - if (argc == 1) - { + if (argc == 1) { HRESULT result = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - if (SUCCEEDED(result)) - { - Info("Please open an executable for minecraft. (Minecraft.Windows.exe)"); + if (SUCCEEDED(result)) { + spdlog::info("Please open an executable for minecraft. (Minecraft.Windows.exe)"); IFileOpenDialog *openFile; CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast(&openFile)); @@ -71,53 +49,40 @@ int main(int argc, char *argv[]) { openFile->Show(nullptr); IShellItem *pItem; result = openFile->GetResult(&pItem); - if (SUCCEEDED(result)) - { + if (SUCCEEDED(result)) { PWSTR pPath; pItem->GetDisplayName(SIGDN_FILESYSPATH, &pPath); std::wstringstream path; path << pPath; strpath = wchar2string(path.str().c_str()); - Info("Selected {}.",strpath); + spdlog::info("Selected {}.",strpath); pItem->Release(); - } - else - { - Error("Open file failed!"); + } else { + spdlog::error("Open file failed!"); } openFile->Release(); CoUninitialize(); } if (strpath.empty()) return FAIL_CANNOT_OPEN_FILE; - } - else if (argc == 2) - { + } else if (argc == 2) { strpath = argv[1]; - } - else - { - Error("Wrong parameter!"); + } else { + spdlog::error("Wrong parameter!"); } // Open file; - if (!patcher.target(strpath)) - { - Error("Can't read executable file!"); + if (!patcher.target(strpath)) { + spdlog::error("Can't read executable file!"); return FAIL_CANNOT_READ_FILE; - } - else - { + } else { std::ofstream ofs(strpath + ".bak", std::ios::binary); ofs << patcher.getImage().rdbuf(); - if (ofs.good()) - { - Info("Backup created to: {}.bak",strpath); - } - else - { - Error("Fail to create backup!"); + if (ofs.good()) { + spdlog::info("Backup created to: {}.bak",strpath); + } else { + spdlog::error("Fail to create backup!"); return FAIL_BACKUP; } ofs.close(); @@ -127,22 +92,18 @@ int main(int argc, char *argv[]) { auto platform = Platform::Win10; auto patches = patcher.getPatches(platform); - if (patches.empty()) - { - Error("There are no patches available for the current platform."); + if (patches.empty()) { + spdlog::error("There are no patches available for the current platform."); return FAIL_CURRENT_PLATFORM_NO_PATCH; } // Do patch; - Info("Looking for bytes..."); - if (patcher.apply(platform)) - { - Info("Patch successfully."); - } - else - { - Error("Failed, if it is the latest version, please send issue."); + spdlog::info("Looking for bytes..."); + if (patcher.apply(platform)) { + spdlog::info("Patch successfully."); + } else { + spdlog::error("Failed, if it is the latest version, please send issue."); return FAIL_CANNOT_FIND_BYTE; } diff --git a/patcher.cpp b/patcher.cpp index 02320ca..2460c2e 100644 --- a/patcher.cpp +++ b/patcher.cpp @@ -3,61 +3,71 @@ // #include "patcher.h" +#include -void MCPatcher::registerPatch(Platform platform, const string& name, const vector& patch) { - for (auto& i : patch) - { - if (i.mBefore.size() != i.mAfter.size()) - { - Error("The wrong patch is being registered!"); - return; - } +void MCPatcher::registerPatch(Platform platform, const string& name, const PatchEntity& patch) { + if (patch.valid() && !name.empty()) { + mPatches[platform][name] = patch; } - mPatches[platform][name] = patch; } bool MCPatcher::apply(Platform platform) { - vector> needModify; - auto isOk = true; - for (auto& it : mPatches[platform]) - { - Info("Trying \"{}\" patch.", it.first); - Info("Need to find {} binary position...", it.second.size()); - needModify.clear(); - auto count = 0; - for (auto& bin : it.second) - { - count++; - auto pos = findBytes(mImage, bin.mBefore); - if (pos) - { - Info("Point {} founded, {}.", count, pos); - needModify.emplace_back(std::pair{pos, bin.mAfter}); - isOk = true; - } - else - { - Warn("Point {} not found, try the next set.", count); - isOk = false; - break; - } - } - if (isOk) + vector> needModify; + for (auto& it : mPatches[platform]) { + spdlog::info("Trying \"{}\" patch.", it.first); + needModify = handleBytes(it.second.mBytes); + if (needModify.empty()) { + spdlog::warn("Byte sequence not found."); + } else { + spdlog::info("Successfully found the byte sequence."); break; - } - if (!isOk || needModify.empty()) - return false; - for (auto& patch : needModify) - { - mImage.seekg(patch.first); - for (auto& bts : patch.second) - { - mImage.write((char *)&bts, sizeof(bts)); } } + if (needModify.empty()) return false; + for (auto& patch : needModify) { + mImage.seekg(patch.first - 1); + mImage.write((char *)&patch.second, sizeof(patch.second)); + } return mImage.good(); } +vector> MCPatcher::handleBytes(const vector &bytes) { + if (bytes.empty()) return {}; + vector> rtn; + mImage.seekg(0); + int matchedSize = 0; + BYTE chr; + while(mImage.read((char *)&chr, sizeof(chr))) { + auto& byte = bytes.at(matchedSize); + if (byte.mType == DataType::ALL) { + matchedSize++; + } else if (byte.mType == DataType::NORMAL) { + if (byte.mData == chr) { + matchedSize++; + } else { + matchedSize = 0; + rtn.clear(); + continue; + } + } + if (byte.mReplacer.mEnabled) { + rtn.emplace_back(std::pair {mImage.tellg(), byte.mReplacer.mData}); + } + if (matchedSize == bytes.size()) { + //for (auto& i : rtn) { + // mImage.seekg(i.first); + // for (int k = 0; k < 20; k++) { + // mImage.read((char *)&chr, sizeof(chr)); + // spdlog::info("byte -> {}", char2hex(chr)); + // } + // spdlog::info("address -> {}", i.first); + //} + return rtn; + } + } + return {}; +} + bool MCPatcher::target(const string& path) { mImage.open(path, std::ios::binary | std::ios::in | std::ios::out); return mImage.is_open(); @@ -67,12 +77,38 @@ fstream& MCPatcher::getImage() { return mImage; } -unordered_map>& MCPatcher::getPatches(Platform platform) { +unordered_map& MCPatcher::getPatches(Platform platform) { return mPatches[platform]; } MCPatcher::~MCPatcher() { - mImage.close(); - } + +// e.g. "74 ?? B0 01(00) 48" +// Checkless! Boom if input not correctly! +MCPatcher::PatchEntity MCPatcher::compile(string patchExp) { + PatchEntity rtn; + patchExp += " "; + int nextPosition = 0; + for (int i = 0; i < patchExp.size(); i++) { + if (i != nextPosition) continue; + auto pos = patchExp.find(" ", i, 1); + if (pos == patchExp.npos) throw CompileFailed(); + auto substr = patchExp.substr(i, pos - i); + ByteEntity entity; + if (substr.substr(0, 2) == "??") { + entity.mType = DataType::ALL; + } else { + entity.mType = DataType::NORMAL; + entity.mData = hex2char(substr.substr(0, 2)); + } + if (substr.find("(") != substr.npos) { + entity.mReplacer.mEnabled = true; + entity.mReplacer.mData = hex2char(substr.substr(3, 2)); + } + nextPosition = pos + 1; + rtn.add(entity); + } + return rtn; +} \ No newline at end of file diff --git a/patcher.h b/patcher.h index a577ffb..3031ce0 100644 --- a/patcher.h +++ b/patcher.h @@ -9,7 +9,6 @@ #include #include -#include "logger.h" #include "utils.h" using std::vector; @@ -18,7 +17,9 @@ using std::string; using std::fstream; enum class Platform { - Win10 + Win10, + Android, + IOS }; class MCPatcher { @@ -26,14 +27,31 @@ class MCPatcher { ~MCPatcher(); - using BinarySequence = vector; + enum class DataType { + NORMAL, // e.g. 0E + ALL // e.g. ?? + }; + + struct ByteEntity { + DataType mType = DataType::NORMAL; + BYTE mData = 0x00; + struct Replacer { + bool mEnabled = false; + BYTE mData = 0x00; + } mReplacer; + }; - struct SinglePatch { - BinarySequence mBefore; - BinarySequence mAfter; + struct PatchEntity { + vector mBytes; + void add(const ByteEntity& entity) { + mBytes.emplace_back(entity); + }; + [[nodiscard]] bool valid() const { + return !mBytes.empty(); + }; }; - void registerPatch(Platform, const string& name, const vector& patch); + void registerPatch(Platform platform, const string& name, const PatchEntity& patch); bool target(const string& path); @@ -41,11 +59,27 @@ class MCPatcher { fstream& getImage(); - unordered_map>& getPatches(Platform); + unordered_map& getPatches(Platform); + + static PatchEntity compile(string patchExpression); private: - unordered_map>> mPatches; + unordered_map> mPatches; fstream mImage; + using Address = long long; + + vector> handleBytes(const vector &bytes); +}; + +#include + +class CompileFailed : public std::exception { +public: + + [[nodiscard]] const char* what() const noexcept override { + return "Failed to compile patch expression."; + }; + }; diff --git a/utils.cpp b/utils.cpp index 746a46e..1cb5d8f 100644 --- a/utils.cpp +++ b/utils.cpp @@ -4,18 +4,23 @@ #include "utils.h" -string char2hex(unsigned char chr) -{ - /*for (auto i : tmpVec){ - }*/ +#include +#include + +string char2hex(BYTE chr) { std::ostringstream ss; auto bin = int(chr); ss << std::hex << bin; return ss.str(); } -string wchar2string(const wchar_t *wchar) -{ +unsigned char hex2char(std::string_view str) { + unsigned int value; + std::from_chars(str.data(), str.data() + str.size(), value, 16); + return static_cast(value); +} + +string wchar2string(const wchar_t *wchar) { const wchar_t *wText = wchar; DWORD bytes = WideCharToMultiByte(CP_OEMCP,NULL,wText,-1,nullptr,0,nullptr,FALSE); char *psText; @@ -25,30 +30,3 @@ string wchar2string(const wchar_t *wchar) delete []psText; return str; } - -unsigned long long findBytes(std::fstream& file, const vector &bytes) -{ - unsigned char chr; - std::vector tmpVec; - size_t length = bytes.size(); - size_t loops = 0LL; - file.clear(); - file.seekg(0, std::ios::beg); - while(file.read((char *)&chr, sizeof(chr))) - { - loops++; - tmpVec.emplace_back(chr); - auto it = tmpVec.rbegin(); - auto pos = 0; - while (it != tmpVec.rend()) - { - pos++; - if (pos > length || bytes.at(length - pos) != *it) - break; - else if (pos == length) - return loops - length; - ++it; - } - } - return 0; -} \ No newline at end of file diff --git a/utils.h b/utils.h index 30a7db1..14ffe63 100644 --- a/utils.h +++ b/utils.h @@ -5,17 +5,14 @@ #pragma once #include -#include -#include #include #include #include "Windows.h" -#include using std::string; using std::vector; -string char2hex(unsigned char chr); +string char2hex(BYTE chr); +unsigned char hex2char(std::string_view str); string wchar2string(const wchar_t *wchar); -unsigned long long findBytes(std::fstream& file, const vector &bytes);