diff --git a/navicat-patcher/EncryptPublicKey.cpp b/navicat-patcher/EncryptPublicKey.cpp deleted file mode 100644 index 1d862de..0000000 --- a/navicat-patcher/EncryptPublicKey.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// to avoid "AES_KEY" definaition conflict -#include "NavicatCrypto/NavicatCrypto.hpp" - -namespace patcher { - - static Navicat11Crypto cipher("23970790", 8); - - std::string EncryptPublicKey(const char* public_key, size_t len) { - auto&& temp = cipher.EncryptString(public_key, len); - return std::string(temp.begin(), temp.end()); - } - -} \ No newline at end of file diff --git a/navicat-patcher/Helper.cpp b/navicat-patcher/Helper.cpp new file mode 100644 index 0000000..8bb7d4e --- /dev/null +++ b/navicat-patcher/Helper.cpp @@ -0,0 +1,153 @@ +#include "def.hpp" +#include "NavicatCrypto.hpp" + +namespace Helper { + + static Navicat11Crypto NavicatCipher("23970790", 8); + + std::string EncryptPublicKey(const std::string& PublicKeyString) { + return NavicatCipher.EncryptString(PublicKeyString.c_str(), + PublicKeyString.length()); + } + + bool ConvertToUTF8(LPCSTR from, std::string& to) { + bool bSuccess = false; + int RequireLength = 0; + LPWSTR lpUnicodeString = nullptr; + + RequireLength = MultiByteToWideChar(CP_ACP, NULL, from, -1, nullptr, 0); + if (RequireLength == 0) + goto ON_ConvertToUTF8_0_ERROR; + + lpUnicodeString = reinterpret_cast(HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + RequireLength * sizeof(WCHAR))); + if (lpUnicodeString == nullptr) + goto ON_ConvertToUTF8_0_ERROR; + + if (!MultiByteToWideChar(CP_ACP, NULL, from, -1, lpUnicodeString, RequireLength)) + goto ON_ConvertToUTF8_0_ERROR; + + RequireLength = WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, nullptr, 0, nullptr, nullptr); + if (RequireLength == 0) + goto ON_ConvertToUTF8_0_ERROR; + + to.resize(RequireLength); + + if (!WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, to.data(), RequireLength, nullptr, nullptr)) + goto ON_ConvertToUTF8_0_ERROR; + + while (to.back() == 0) + to.pop_back(); + + bSuccess = true; + + ON_ConvertToUTF8_0_ERROR: + if (lpUnicodeString) + HeapFree(GetProcessHeap(), NULL, lpUnicodeString); + + return bSuccess; + } + + bool ConvertToUTF8(LPCWSTR from, std::string& to) { + bool bSuccess = false; + int RequireLength = 0; + + RequireLength = WideCharToMultiByte(CP_UTF8, NULL, from, -1, nullptr, 0, nullptr, nullptr); + if (RequireLength == 0) + goto ON_ConvertToUTF8_1_ERROR; + + to.resize(RequireLength); + if (!WideCharToMultiByte(CP_UTF8, NULL, from, -1, to.data(), RequireLength, nullptr, nullptr)) + goto ON_ConvertToUTF8_1_ERROR; + + while (to.back() == 0) + to.pop_back(); + + bSuccess = true; + + ON_ConvertToUTF8_1_ERROR: + return bSuccess; + } + + bool ConvertToUTF8(std::string& str) { + bool bSuccess = false; + std::string temp; + + bSuccess = ConvertToUTF8(str.c_str(), temp); + if (bSuccess) + str = temp; + + return bSuccess; + } + + void ErrorReport(LPCTSTR at, UINT line, LPCTSTR msg) { + _tprintf_s(TEXT("@%s LINE: %u\n"), at, line); + _tprintf_s(TEXT("%s\n"), msg); + } + + void ErrorReport(LPCTSTR at, UINT line, LPCTSTR msg, DWORD err_code) { + _tprintf_s(TEXT("@%s LINE: %u\n"), at, line); + _tprintf_s(TEXT("%s CODE: 0x%08X\n"), msg, err_code); + } + + template + static __forceinline bool ProbeForRead(const void* p, void* out) { + __try { + *reinterpret_cast<_Type*>(out) = *reinterpret_cast(p); + return true; + } __except (1) { + return false; + } + } + + void PrintMemory(const void* a, const void* b, const void* base) { + const uint8_t* start = reinterpret_cast(a); + const uint8_t* end = reinterpret_cast(b); + const uint8_t* base_ptr = reinterpret_cast(base); + + if (start >= end) + return; + + while (reinterpret_cast(start) % 16) + start--; + + while (reinterpret_cast(start) % 16) + end++; + + while (start < end) { + uint16_t value[16] = {}; + + if (base_ptr) + _tprintf(TEXT("+0x%p "), reinterpret_cast(start - base_ptr)); + else + _tprintf(TEXT("0x%p "), start); + + for (int i = 0; i < 16; ++i) { + if (ProbeForRead(start + i, value + i)) { + _tprintf(TEXT("%02x "), value[i]); + } else { + value[i] = -1; + _tprintf(TEXT("?? ")); + } + } + + _tprintf(TEXT(" ")); + + for (int i = 0; i < 16; ++i) { + if (value[i] < 0x20) { + _tprintf(TEXT(".")); + } else if (value[i] > 0x7e) { + _tprintf(TEXT(".")); + } else { + _tprintf(TEXT("%c"), value[i]); + } + } + + _tprintf(TEXT("\n")); + + start += 0x10; + } + } + +} \ No newline at end of file diff --git a/navicat-patcher/def.hpp b/navicat-patcher/def.hpp index f4d576b..f422c01 100644 --- a/navicat-patcher/def.hpp +++ b/navicat-patcher/def.hpp @@ -2,41 +2,169 @@ #include #include #include - #include "RSACipher.hpp" -#pragma comment(lib, "version.lib") // GetFileVersionInfoSize, GetFileVersionInfo, VerQueryValue are in this lib -namespace std { #ifdef UNICODE - typedef wstring Tstring; +namespace std { typedef wstring Tstring; } #else - typedef string Tstring; -#endif // UNICODE +namespace std { typedef string Tstring; } +#endif + +namespace Helper { + std::string EncryptPublicKey(const std::string& PublicKeyString); + + bool ConvertToUTF8(LPCSTR from, std::string& to); + bool ConvertToUTF8(LPCWSTR from, std::string& to); + bool ConvertToUTF8(std::string& str); + + void ErrorReport(LPCTSTR at, UINT line, LPCTSTR msg); + void ErrorReport(LPCTSTR at, UINT line, LPCTSTR msg, DWORD err_code); + + void PrintMemory(const void* a, const void* b, const void* base); } -namespace patcher { +#define REPORT_ERROR(msg) Helper::ErrorReport(TEXT(__FUNCTION__), __LINE__, TEXT(msg)) +#define REPORT_ERROR_WITH_CODE(msg, err_code) Helper::ErrorReport(TEXT(__FUNCTION__), __LINE__, TEXT(msg), (err_code)) - std::string EncryptPublicKey(const char* public_key, size_t len); +#define PRINT_MESSAGE(msg) _tprintf_s(TEXT("%s\n"), TEXT(msg)) +#define PRINT_LPCTSTR(msg) _tprintf_s(TEXT("%s\n"), (msg)) +#define PRINT_LPCSTR(msg) printf_s("%s\n", (msg)) +#define PRINT_LPCWSTR(msg) wprintf_s(L"%s\n", (msg)) - namespace Solution0 { - BOOL Init(const std::Tstring& Path); - BOOL CheckKey(RSACipher* cipher); - BOOL FindTargetFile(); - BOOL CheckFile(); - BOOL BackupFile(); - BOOL Do(RSACipher* cipher); - BOOL GetVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer); - VOID Finalize(); - } +namespace Patcher { - namespace Solution1 { - BOOL Init(const std::Tstring& Path); - BOOL CheckKey(RSACipher* cipher); - BOOL FindTargetFile(); - BOOL FindOffset(); - BOOL BackupFile(); - BOOL Do(RSACipher* cipher); - VOID Finalize(); - } + // Solution0 will replace the RSA public key stored in main application. + class Solution0 { + private: + static const char Keyword[461]; + static constexpr int KeywordLength = 460; -} \ No newline at end of file + std::Tstring InstallationPath; + std::Tstring MainAppName; + HANDLE MainAppHandle; + HANDLE MainAppMappingHandle; + PVOID MainAppMappingView; + off_t PatchOffset; + public: + + Solution0() : InstallationPath(), + MainAppName(), + MainAppHandle(INVALID_HANDLE_VALUE), + MainAppMappingHandle(NULL), + MainAppMappingView(nullptr), + PatchOffset(-1) {} + + BOOL SetPath(const std::Tstring& Path); + + // Solution0 does not have any requirements for RSA-2048 key + BOOL CheckKey(RSACipher* cipher) const; + + // Return error code + // It may return + // ERROR_SUCCESS (target has been set successfully) + // ERROR_FILE_NOT_FOUND (try another name) + // ERROR_ACCESS_DENIED (you need Administrator privilege) + // ... + DWORD TryFile(const std::Tstring& MainAppName); + + // Return error code + // It may return + // ERROR_SUCCESS (target has been mapped successfully) + // ... + DWORD MapFile(); + + // Return TRUE if found, other return FALSE + BOOL FindPatchOffset(); + + // Return error code + // It may return + // ERROR_SUCCESS (file has been backed up successfully) + // ERROR_FILE_EXISTS (you should remove backup file first) + // ERROR_ACCESS_DENIED (you need Administrator privilege) + // ... + DWORD BackupFile(); + + // Make a patch based on RSA private key + // Return TRUE if success, otherwise return FALSE + BOOL MakePatch(RSACipher* cipher); + + // Return error code + // Return ERROR_SUCCESS if success + DWORD GetMainAppVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer); + + const std::Tstring& GetMainAppName(); + + // Close handle returned by CreateFile with a implicit call towards ReleaseMap + void ReleaseFile(); + + // Unmap view returned by MapViewOfFile and + // close handle returned by CreateFileMapping + void ReleaseMap(); + + ~Solution0(); + }; + + // Solution0 will replace the RSA public key stored in libcc.dll + class Solution1 { + private: + static const char* Keywords[5]; + static const int KeywordsLength[5]; + + std::Tstring InstallationPath; + std::Tstring LibccName; + HANDLE LibccHandle; + HANDLE LibccMappingHandle; + PVOID LibccMappingView; + off_t PatchOffsets[5]; + public: + Solution1() : InstallationPath(), + LibccName(), + LibccHandle(INVALID_HANDLE_VALUE), + LibccMappingHandle(NULL), + LibccMappingView(nullptr), + PatchOffsets{-1, -1, -1, -1, -1} {} + + BOOL SetPath(const std::Tstring& Path); + + // Solution0 does not have any requirements for RSA-2048 key + BOOL CheckKey(RSACipher* cipher) const; + + // Return error code + // It may return + // ERROR_SUCCESS (target has been set successfully) + // ERROR_FILE_NOT_FOUND (try another name) + // ERROR_ACCESS_DENIED (you need Administrator privilege) + // ... + DWORD TryFile(const std::Tstring& MainAppName); + + // Return error code + // It may return + // ERROR_SUCCESS (target has been mapped successfully) + // ... + DWORD MapFile(); + + // Return TRUE if found, other return FALSE + BOOL FindPatchOffset(); + + // Return error code + // It may return + // ERROR_SUCCESS (file has been backed up successfully) + // ERROR_FILE_EXISTS (you should remove backup file first) + // ERROR_ACCESS_DENIED (you need Administrator privilege) + // ... + DWORD BackupFile(); + + // Make a patch based on RSA private key + // Return TRUE if success, otherwise return FALSE + BOOL MakePatch(RSACipher* cipher); + + // Close handle returned by CreateFile with a implicit call towards ReleaseMap + void ReleaseFile(); + + // Unmap view returned by MapViewOfFile and + // close handle returned by CreateFileMapping + void ReleaseMap(); + + ~Solution1(); + }; +}