diff --git a/navicat-patcher/Solution0.cpp b/navicat-patcher/Solution0.cpp index 201eb2c..65fe2bc 100644 --- a/navicat-patcher/Solution0.cpp +++ b/navicat-patcher/Solution0.cpp @@ -1,11 +1,14 @@ #include "def.hpp" -// Solution0 is for navicat premium of which the version < 12.0.25 -namespace patcher::Solution0 { +// The following APIs are in version.lib +// GetFileVersionInfoSize +// GetFileVersionInfo +// VerQueryValue +// #pragma comment(lib, "version.lib") - static std::Tstring InstallationPath; +namespace Patcher { - static const CHAR Keyword[] = + const char Solution0::Keyword[461] = "-----BEGIN PUBLIC KEY-----\r\n" "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I\r\n" "qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv\r\n" @@ -16,171 +19,136 @@ namespace patcher::Solution0 { "awIDAQAB\r\n" "-----END PUBLIC KEY-----\r\n"; - static const DWORD KeywordLength = sizeof(Keyword) - 1; + BOOL Solution0::SetPath(const std::Tstring& Path) { + DWORD Attr; - static LPCTSTR PossibleName[3] = { - TEXT("Navicat.exe"), // for Linux compatible, main program name is "Navicat.exe" in Linux, case sensitive - TEXT("Modeler.exe"), // for Linux compatible - TEXT("Rviewer.exe") // for Linux compatible - }; - - static LPCTSTR TargetName = NULL; - - static HMODULE hTarget = NULL; - - BOOL Init(const std::Tstring& Path) { - BOOL bSuccess = FALSE; - DWORD dwLastError = ERROR_SUCCESS; - DWORD attr = INVALID_FILE_ATTRIBUTES; - - attr = GetFileAttributes(Path.c_str()); - if (attr == INVALID_FILE_ATTRIBUTES) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ GetFileAttributes. CODE: 0x%08X\n"), dwLastError); - goto ON_Init_ERROR; + Attr = GetFileAttributes(Path.c_str()); + if (Attr == INVALID_FILE_ATTRIBUTES) { + if (GetLastError() == ERROR_INVALID_NAME || GetLastError() == ERROR_FILE_NOT_FOUND) + REPORT_ERROR("ERROR: Invalid path. Are you sure the path you specified is correct?"); + else + REPORT_ERROR_WITH_CODE("ERROR: GetFileAttributes failed.", GetLastError()); + return FALSE; } - if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Error: Path is not a directory.\n")); - goto ON_Init_ERROR; + if ((Attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { + REPORT_ERROR("ERROR: Path is not a directory."); + return FALSE; } + ReleaseFile(); + InstallationPath = Path; if (InstallationPath.back() != TEXT('\\') && InstallationPath.back() != TEXT('/')) InstallationPath.push_back(TEXT('/')); // for Linux compatible - bSuccess = TRUE; - - ON_Init_ERROR: - return bSuccess; - } - - BOOL CheckKey(RSACipher* cipher) { return TRUE; } - BOOL FindTargetFile() { - BOOL bSuccess = FALSE; - DWORD dwLastError = ERROR_SUCCESS; - - for (size_t i = 0; i < _countof(PossibleName); ++i) { - std::Tstring&& PossibleFileName = InstallationPath + PossibleName[i]; - - hTarget = LoadLibrary(PossibleFileName.c_str()); - if (hTarget == NULL && (dwLastError = GetLastError()) != ERROR_MOD_NOT_FOUND) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Unexpected Error @ LoadLibrary. CODE: 0x%08X\n"), dwLastError); - goto ON_FindTargetFile_ERROR; - } - if (hTarget) { - _tprintf_s(TEXT("Target has been found: %s\n"), PossibleName[i]); - TargetName = PossibleName[i]; - bSuccess = TRUE; - goto ON_FindTargetFile_ERROR; - } - } - - ON_FindTargetFile_ERROR: - return bSuccess; + // Solution0 does not have any requirements for RSA-2048 key + BOOL Solution0::CheckKey(RSACipher* cipher) const { + return TRUE; } - BOOL CheckFile() { - BOOL bFound = FALSE; + DWORD Solution0::TryFile(const std::Tstring& Name) { + std::Tstring MainAppFullName = InstallationPath + Name; + HANDLE hFile; + + hFile = CreateFile(MainAppFullName.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + nullptr, // default SA + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return GetLastError(); + + ReleaseFile(); + + MainAppHandle = hFile; + MainAppName = Name; + return ERROR_SUCCESS; + } + + DWORD Solution0::MapFile() { DWORD dwLastError = ERROR_SUCCESS; - HRSRC hRes = NULL; - HGLOBAL hGLobal = NULL; - PVOID lpData = NULL; - DWORD dwSize = 0; + HANDLE hMapping = NULL; + PVOID lpMapView = nullptr; - if (hTarget == NULL) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Error: Target has not been set yet.\n")); - goto ON_CheckFile_ERROR; - } - - hRes = FindResource(hTarget, TEXT("ACTIVATIONPUBKEY"), RT_RCDATA); - if (hRes == NULL) { + hMapping = CreateFileMapping(MainAppHandle, + nullptr, // default SA + PAGE_READWRITE, + 0, 0, // map all + nullptr); // we don't need a name + if (hMapping == NULL) { dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ FindResource. CODE: 0x%08X\n"), dwLastError); - goto ON_CheckFile_ERROR; + goto ON_Solution0_MapFile_ERROR; } - hGLobal = LoadResource(hTarget, hRes); - if (hGLobal == NULL) { + lpMapView = MapViewOfFile(hMapping, + FILE_MAP_READ | FILE_MAP_WRITE, + 0, 0, 0); // map all + if (lpMapView == nullptr) { dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ LoadResource. CODE: 0x%08X\n"), dwLastError); - goto ON_CheckFile_ERROR; + goto ON_Solution0_MapFile_ERROR; } - lpData = LockResource(hGLobal); - if (lpData == NULL) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ LockResource. CODE: 0x%08X\n"), dwLastError); - goto ON_CheckFile_ERROR; + ReleaseMap(); + + MainAppMappingView = lpMapView; + lpMapView = nullptr; + MainAppMappingHandle = hMapping; + hMapping = NULL; + + ON_Solution0_MapFile_ERROR: + if (hMapping) + CloseHandle(hMapping); + return dwLastError; + } + + BOOL Solution0::FindPatchOffset() { + BOOL bFound = FALSE; + DWORD dwFileSize = 0; + + uint8_t* lpFileContent = reinterpret_cast(MainAppMappingView); + dwFileSize = GetFileSize(MainAppHandle, nullptr); + + for (DWORD i = 0; i < dwFileSize; ++i) { + if (memcmp(lpFileContent + i, Keyword, KeywordLength) == 0) { + PatchOffset = i; + bFound = TRUE; + break; + } } - dwSize = SizeofResource(hTarget, hRes); - if (dwSize == 0) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ SizeofResource. CODE: 0x%08X\n"), dwLastError); - goto ON_CheckFile_ERROR; - } - - if (dwSize == KeywordLength && memcmp(lpData, Keyword, KeywordLength) == 0) { - FreeLibrary(hTarget); - hTarget = NULL; - bFound = TRUE; - } else { - FreeLibrary(hTarget); - hTarget = NULL; - TargetName = NULL; - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Resource doest not match.\n")); - goto ON_CheckFile_ERROR; - } - - ON_CheckFile_ERROR: + if (bFound) + _tprintf_s(TEXT("MESSAGE: [Solution0] Keyword has been found: offset = +0x%08lx.\n"), PatchOffset); return bFound; } - BOOL BackupFile() { - BOOL bSuccess = FALSE; - DWORD dwLastError = ERROR_SUCCESS; - std::Tstring&& TargetFileName = InstallationPath + TargetName; - std::Tstring&& BackupFileName = InstallationPath + TargetName + TEXT(".backup"); - - if (!CopyFile(TargetFileName.c_str(), BackupFileName.c_str(), TRUE)) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ CopyFile. CODE: 0x%08X\n"), dwLastError); - goto ON_BackupFile_ERROR; - } - - bSuccess = TRUE; - ON_BackupFile_ERROR: - return bSuccess; + DWORD Solution0::BackupFile() { + std::Tstring TargetFileFullName = InstallationPath + MainAppName; + std::Tstring BackupFileFullName = InstallationPath + MainAppName + TEXT(".backup"); + + if (!CopyFile(TargetFileFullName.c_str(), BackupFileFullName.c_str(), TRUE)) + return GetLastError(); + else + return ERROR_SUCCESS; } - BOOL Do(RSACipher* cipher) { + BOOL Solution0::MakePatch(RSACipher* cipher) { BOOL bSuccess = FALSE; - DWORD dwLastError = ERROR_SUCCESS; + uint8_t* lpFileContent = reinterpret_cast(MainAppMappingView); std::string RSAPublicKeyPEM; - std::Tstring&& TargetFileName = InstallationPath + TargetName; - HANDLE hUpdater = NULL; RSAPublicKeyPEM = cipher->ExportKeyString(); if (RSAPublicKeyPEM.empty()) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: cipher->ExportKeyString failed.\n")); + REPORT_ERROR("ERROR: cipher->ExportKeyString failed."); goto ON_Do_ERROR; } + // lambda function, replace '\n' to '\r\n' [](std::string& str, const std::string& OldSub, const std::string& NewSub) { std::string::size_type pos = 0; std::string::size_type srclen = OldSub.size(); @@ -190,96 +158,105 @@ namespace patcher::Solution0 { str.replace(pos, srclen, NewSub); pos += dstlen; } - } (RSAPublicKeyPEM, "\n", "\r\n"); // replace '\n' to '\r\n' + } (RSAPublicKeyPEM, "\n", "\r\n"); if (RSAPublicKeyPEM.length() != KeywordLength) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Public key length does not match.\n")); + REPORT_ERROR("ERROR: Public key length does not match."); goto ON_Do_ERROR; } - hUpdater = BeginUpdateResource(TargetFileName.c_str(), FALSE); - if (hUpdater == NULL) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ BeginUpdateResource. CODE: 0x%08X\n"), dwLastError); - goto ON_Do_ERROR; - } + _tprintf_s(TEXT("@%s+0x%08X\nPrevious:\n"), MainAppName.c_str(), PatchOffset); + Helper::PrintMemory(lpFileContent + PatchOffset, + lpFileContent + PatchOffset + KeywordLength, + lpFileContent); + + memcpy(lpFileContent + PatchOffset, RSAPublicKeyPEM.c_str(), KeywordLength); + + PRINT_MESSAGE("After:"); + Helper::PrintMemory(lpFileContent + PatchOffset, + lpFileContent + PatchOffset + KeywordLength, + lpFileContent); + PRINT_MESSAGE(""); - if (!UpdateResource(hUpdater, - RT_RCDATA, - TEXT("ACTIVATIONPUBKEY"), - MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), - (LPVOID)RSAPublicKeyPEM.c_str(), - KeywordLength)) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ UpdateResource. CODE: 0x%08X\n"), dwLastError); - goto ON_Do_ERROR; - } - bSuccess = TRUE; - ON_Do_ERROR: - EndUpdateResource(hUpdater, !bSuccess); return bSuccess; } - BOOL GetVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer) { - BOOL bSuccess = FALSE; - DWORD dwLastError = ERROR_SUCCESS; - std::Tstring&& TargetFileName = InstallationPath + TargetName; - DWORD dwSize = 0; - PVOID lpData = NULL; - VS_FIXEDFILEINFO* lpVersionInfo = NULL; - UINT VersionInfoSize = 0; +// DWORD Solution0::GetMainAppVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer) { +// BOOL bSuccess = FALSE; +// DWORD dwLastError = ERROR_SUCCESS; +// std::Tstring TargetFileFullName = InstallationPath + MainAppName; +// +// DWORD dwSize = 0; +// PVOID lpData = NULL; +// VS_FIXEDFILEINFO* lpVersionInfo = NULL; +// UINT VersionInfoSize = 0; +// +// dwSize = GetFileVersionInfoSize(TargetFileFullName.c_str(), +// &dwSize); // MSDN doesn't say it can be NULL. +// // so I use dwSize to receive this deprecated value +// if (dwSize == 0) { +// dwLastError = GetLastError(); +// REPORT_ERROR_WITH_CODE("ERROR: GetFileVersionInfoSize failed.", dwLastError); +// goto ON_Solution0_GetMainAppVersion_ERROR; +// } +// +// lpData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize); +// if (lpData == nullptr) { +// dwLastError = GetLastError(); +// REPORT_ERROR_WITH_CODE("ERROR: HeapAlloc failed.", dwLastError); +// goto ON_Solution0_GetMainAppVersion_ERROR; +// } +// +// if (!GetFileVersionInfo(TargetFileFullName.c_str(), NULL, dwSize, lpData)) { +// dwLastError = GetLastError(); +// REPORT_ERROR_WITH_CODE("ERROR: GetFileVersionInfo failed.", dwLastError); +// goto ON_Solution0_GetMainAppVersion_ERROR; +// } +// +// if (!VerQueryValue(lpData, TEXT("\\"), reinterpret_cast(&lpVersionInfo), &VersionInfoSize)) { +// dwLastError = GetLastError(); +// REPORT_ERROR_WITH_CODE("ERROR: VerQueryValue failed.", dwLastError); +// goto ON_Solution0_GetMainAppVersion_ERROR; +// } +// +// *lpMajorVer = lpVersionInfo->dwProductVersionMS; +// *lpMinorVer = lpVersionInfo->dwProductVersionLS; +// +// bSuccess = TRUE; +// ON_Solution0_GetMainAppVersion_ERROR: +// if (lpData) +// HeapFree(GetProcessHeap(), NULL, lpData); +// return bSuccess; +// } - dwSize = GetFileVersionInfoSize(TargetFileName.c_str(), - &dwSize); // MSDN doesn't say it can be NULL. - // so I use dwSize to receive this deprecated value - if (dwSize == 0) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ GetFileVersionInfoSize. CODE: 0x%08X\n"), dwLastError); - goto ON_GetVersion_ERROR; - } - - lpData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize); - if (lpData == NULL) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ HeapAlloc. CODE: 0x%08X\n"), dwLastError); - goto ON_GetVersion_ERROR; - } - - if (!GetFileVersionInfo(TargetFileName.c_str(), NULL, dwSize, lpData)) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ GetFileVersionInfo. CODE: 0x%08X\n"), dwLastError); - goto ON_GetVersion_ERROR; - } - - if (!VerQueryValue(lpData, TEXT("\\"), (LPVOID*)&lpVersionInfo, &VersionInfoSize)) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ VerQueryValue. CODE: 0x%08X\n"), dwLastError); - goto ON_GetVersion_ERROR; - } - - *lpMajorVer = lpVersionInfo->dwProductVersionMS; - *lpMinorVer = lpVersionInfo->dwProductVersionLS; - bSuccess = TRUE; - - ON_GetVersion_ERROR: - if (lpData) - HeapFree(GetProcessHeap(), NULL, lpData); - return bSuccess; + const std::Tstring& Solution0::GetMainAppName() { + return MainAppName; } - VOID Finalize() { - if (hTarget) { - FreeLibrary(hTarget); - hTarget = NULL; + void Solution0::ReleaseFile() { + ReleaseMap(); + + if (MainAppHandle != INVALID_HANDLE_VALUE && MainAppHandle) { + CloseHandle(MainAppHandle); + MainAppHandle = INVALID_HANDLE_VALUE; } } + + void Solution0::ReleaseMap() { + if (MainAppMappingView) { + UnmapViewOfFile(MainAppMappingView); + MainAppMappingView = nullptr; + } + + if (MainAppMappingHandle) { + CloseHandle(MainAppMappingHandle); + MainAppMappingHandle = NULL; + } + } + + Solution0::~Solution0() { + ReleaseFile(); + } } diff --git a/navicat-patcher/Solution1.cpp b/navicat-patcher/Solution1.cpp index f32c3e5..8783f10 100644 --- a/navicat-patcher/Solution1.cpp +++ b/navicat-patcher/Solution1.cpp @@ -1,141 +1,7 @@ #include "def.hpp" -// Solution1 is for navicat premium of which the version = 12.0.25 -namespace patcher::Solution1 { - - static std::Tstring InstallationPath; - - static const CHAR Keyword0[] = - "D75125B70767B94145B47C1CB3C0755E" - "7CCB8825C5DCE0C58ACF944E08280140" - "9A02472FAFFD1CD77864BB821AE36766" - "FEEDE6A24F12662954168BFA314BD950" - "32B9D82445355ED7BC0B880887D650F5"; - - static const DWORD KeywordSize0 = sizeof(Keyword0) - 1; - - static const uint8_t Keyword1[] = { - 0xFE, 0xEA, 0xBC, 0x01 - }; - - static const DWORD KeywordSize1 = sizeof(Keyword1); - - static const CHAR Keyword2[] = - "E1CED09B9C2186BF71A70C0FE2F1E0AE" - "F3BD6B75277AAB20DFAF3D110F75912B" - "FB63AC50EC4C48689D1502715243A79F" - "39FF2DE2BF15CE438FF885745ED54573" - "850E8A9F40EE2FF505EB7476F95ADB78" - "3B28CA374FAC4632892AB82FB3BF4715" - "FCFE6E82D03731FC3762B6AAC3DF1C3B" - "C646FE9CD3C62663A97EE72DB932A301" - "312B4A7633100C8CC357262C39A2B3A6" - "4B224F5276D5EDBDF0804DC3AC4B8351" - "62BB1969EAEBADC43D2511D6E0239287" - "81B167A48273B953378D3D2080CC0677" - "7E8A2364F0234B81064C5C739A8DA28D" - "C5889072BF37685CBC94C2D31D0179AD" - "86D8E3AA8090D4F0B281BE37E0143746" - "E6049CCC06899401264FA471C016A96C" - "79815B55BBC26B43052609D9D175FBCD" - "E455392F10E51EC162F51CF732E6BB39" - "1F56BBFD8D957DF3D4C55B71CEFD54B1" - "9C16D458757373E698D7E693A8FC3981" - "5A8BF03BA05EA8C8778D38F9873D62B4" - "460F41ACF997C30E7C3AF025FA171B5F" - "5AD4D6B15E95C27F6B35AD61875E5505" - "449B4E"; - - static const DWORD KeywordSize2 = sizeof(Keyword2) - 1; - - static const uint8_t Keyword3[] = { - 0x59, 0x08, 0x01, 0x00 - }; - - static const DWORD KeywordSize3 = sizeof(Keyword3); - - static const CHAR Keyword4[] = "92933"; - - static const DWORD KeywordSize4 = sizeof(Keyword4) - 1; - - static DWORD KeywordOffset[5] = { -1, -1, -1, -1, -1 }; - - static LPCTSTR TargetName = TEXT("libcc.dll"); - - static HANDLE hTarget = INVALID_HANDLE_VALUE; - static HANDLE hTargetMap = NULL; - static PVOID lpFileContent = NULL; - - BOOL Init(const std::Tstring& Path) { - BOOL bSuccess = FALSE; - DWORD dwLastError = ERROR_SUCCESS; - DWORD attr = INVALID_FILE_ATTRIBUTES; - - attr = GetFileAttributes(Path.c_str()); - if (attr == INVALID_FILE_ATTRIBUTES) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ GetFileAttributes. CODE: 0x%08X\n"), dwLastError); - goto ON_Init_ERROR; - } - - if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Error: Path is not a directory.\n")); - goto ON_Init_ERROR; - } - - InstallationPath = Path; - if (InstallationPath.back() != TEXT('\\') && InstallationPath.back() != TEXT('/')) - InstallationPath.push_back(TEXT('/')); // for Linux compatible - - bSuccess = TRUE; - - ON_Init_ERROR: - return bSuccess; - } - - BOOL CheckKey(RSACipher* cipher) { - BOOL bOk = FALSE; - std::string RSAPublicKeyPEM; - - RSAPublicKeyPEM = cipher->ExportKeyString(); - if (RSAPublicKeyPEM.empty()) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: cipher->ExportKeyString failed.\n")); - return FALSE; - } - - [](std::string& str, const std::string& OldSub, const std::string& NewSub) { - std::string::size_type pos = 0; - std::string::size_type srclen = OldSub.size(); - std::string::size_type dstlen = NewSub.size(); - - while ((pos = str.find(OldSub, pos)) != std::string::npos) { - str.replace(pos, srclen, NewSub); - pos += dstlen; - } - } (RSAPublicKeyPEM, "\n", "\r\n"); // replace '\n' to '\r\n' - - std::string encrypted_pem_text = EncryptPublicKey(RSAPublicKeyPEM.c_str(), - RSAPublicKeyPEM.length()); - - if (encrypted_pem_text[160] > '9' || encrypted_pem_text[160] < '1') - return FALSE; - - for (int i = 1; i < 8; ++i) - if (encrypted_pem_text[160 + i] > '9' || encrypted_pem_text[160 + i] < '0') - return FALSE; - - if (encrypted_pem_text[910] > '9' || encrypted_pem_text[910] < '1') - return FALSE; - - for (int i = 1; i < 5; ++i) - if (encrypted_pem_text[910 + i] > '9' || encrypted_pem_text[910 + i] < '0') - return FALSE; - - return TRUE; - } +namespace Helper { + std::string EncryptPublicKey(const std::string& public_key); static PIMAGE_SECTION_HEADER ImageSectionHeader(PVOID lpBase, LPCSTR lpSectionName) { IMAGE_DOS_HEADER* pFileHeader = NULL; @@ -159,189 +25,86 @@ namespace patcher::Solution1 { return NULL; } +} - BOOL FindTargetFile() { - DWORD dwLastError = ERROR_SUCCESS; - std::Tstring&& TargetFileName = InstallationPath + TargetName; - - hTarget = CreateFile(TargetFileName.c_str(), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (hTarget == INVALID_HANDLE_VALUE) { - dwLastError = GetLastError(); - if (dwLastError == ERROR_FILE_NOT_FOUND) { - return FALSE; - } else { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Unexpected Error @ CreateFile. CODE: 0x%08X\n"), dwLastError); - return FALSE; - } +namespace Patcher { + + const char* Solution1::Keywords[5] = { + "D75125B70767B94145B47C1CB3C0755E" + "7CCB8825C5DCE0C58ACF944E08280140" + "9A02472FAFFD1CD77864BB821AE36766" + "FEEDE6A24F12662954168BFA314BD950" + "32B9D82445355ED7BC0B880887D650F5", + + "\xfe\xea\xbc\x01", + + "E1CED09B9C2186BF71A70C0FE2F1E0AE" + "F3BD6B75277AAB20DFAF3D110F75912B" + "FB63AC50EC4C48689D1502715243A79F" + "39FF2DE2BF15CE438FF885745ED54573" + "850E8A9F40EE2FF505EB7476F95ADB78" + "3B28CA374FAC4632892AB82FB3BF4715" + "FCFE6E82D03731FC3762B6AAC3DF1C3B" + "C646FE9CD3C62663A97EE72DB932A301" + "312B4A7633100C8CC357262C39A2B3A6" + "4B224F5276D5EDBDF0804DC3AC4B8351" + "62BB1969EAEBADC43D2511D6E0239287" + "81B167A48273B953378D3D2080CC0677" + "7E8A2364F0234B81064C5C739A8DA28D" + "C5889072BF37685CBC94C2D31D0179AD" + "86D8E3AA8090D4F0B281BE37E0143746" + "E6049CCC06899401264FA471C016A96C" + "79815B55BBC26B43052609D9D175FBCD" + "E455392F10E51EC162F51CF732E6BB39" + "1F56BBFD8D957DF3D4C55B71CEFD54B1" + "9C16D458757373E698D7E693A8FC3981" + "5A8BF03BA05EA8C8778D38F9873D62B4" + "460F41ACF997C30E7C3AF025FA171B5F" + "5AD4D6B15E95C27F6B35AD61875E5505" + "449B4E", + + "\x59\x08\x01\x00", + + "92933" + }; + + const int Solution1::KeywordsLength[5] = { + 160, + 4, + 742, + 4, + 5 + }; + + BOOL Solution1::SetPath(const std::Tstring& Path) { + DWORD Attr; + + Attr = GetFileAttributes(Path.c_str()); + if (Attr == INVALID_FILE_ATTRIBUTES) { + if (GetLastError() == ERROR_INVALID_NAME || GetLastError() == ERROR_FILE_NOT_FOUND) + REPORT_ERROR("ERROR: Invalid path. Are you sure the path you specified is correct?"); + else + REPORT_ERROR_WITH_CODE("ERROR: GetFileAttributes failed.", GetLastError()); + return FALSE; } - + + if ((Attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { + REPORT_ERROR("ERROR: Path is not a directory."); + return FALSE; + } + + ReleaseFile(); + + InstallationPath = Path; + if (InstallationPath.back() != TEXT('\\') && InstallationPath.back() != TEXT('/')) + InstallationPath.push_back(TEXT('/')); // for Linux compatible + return TRUE; } - BOOL FindOffset() { - BOOL bSuccess = FALSE; - DWORD dwLastError = ERROR_SUCCESS; - IMAGE_SECTION_HEADER* textSection = NULL; - IMAGE_SECTION_HEADER* rdataSection = NULL; - - hTargetMap = CreateFileMapping(hTarget, - NULL, - PAGE_READWRITE, - 0, - 0, - NULL); - if (hTargetMap == NULL) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ CreateFileMapping. CODE: 0x%08X\n"), dwLastError); - goto ON_FindOffset_ERROR; - } - - lpFileContent = MapViewOfFile(hTargetMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); - if (lpFileContent == NULL) { - dwLastError = GetLastError(); - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ MapViewOfFile. CODE: 0x%08X\n"), dwLastError); - goto ON_FindOffset_ERROR; - } - - textSection = ImageSectionHeader(lpFileContent, ".text"); - if (textSection == NULL) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Cannot find .text section.\n")); - goto ON_FindOffset_ERROR; - } - - rdataSection = ImageSectionHeader(lpFileContent, ".rdata"); - if (textSection == NULL) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Cannot find .rdata section.\n")); - goto ON_FindOffset_ERROR; - } - - // ------------------------- - // try to search keyword0 - // ------------------------- - for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) { - if (memcmp((uint8_t*)lpFileContent + rdataSection->PointerToRawData + i, Keyword0, KeywordSize0) == 0) { - KeywordOffset[0] = rdataSection->PointerToRawData + i; - break; - } - } - - if (KeywordOffset[0] == -1) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Cannot find Keyword0.\n")); - goto ON_FindOffset_ERROR; - } else { - _tprintf_s(TEXT("Keyword0 has been found: offset = +0x%08X.\n"), KeywordOffset[0]); - } - - // ------------------------- - // try to search keyword1 - // ------------------------- - for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) { - if (memcmp((uint8_t*)lpFileContent + textSection->PointerToRawData + i, Keyword1, KeywordSize1) == 0) { - KeywordOffset[1] = textSection->PointerToRawData + i; - break; - } - } - - if (KeywordOffset[1] == -1) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Cannot find Keyword1.\n")); - goto ON_FindOffset_ERROR; - } else { - _tprintf_s(TEXT("Keyword1 has been found: offset = +0x%08X.\n"), KeywordOffset[1]); - } - - // ------------------------- - // try to search keyword2 - // ------------------------- - for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) { - if (memcmp((uint8_t*)lpFileContent + rdataSection->PointerToRawData + i, Keyword2, KeywordSize2) == 0) { - KeywordOffset[2] = rdataSection->PointerToRawData + i; - break; - } - } - - if (KeywordOffset[2] == -1) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Cannot find Keyword2.\n")); - goto ON_FindOffset_ERROR; - } else { - _tprintf_s(TEXT("Keyword2 has been found: offset = +0x%08X.\n"), KeywordOffset[2]); - } - - // ------------------------- - // try to search keyword3 - // ------------------------- - for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) { - if (memcmp((uint8_t*)lpFileContent + textSection->PointerToRawData + i, Keyword3, KeywordSize3) == 0) { - KeywordOffset[3] = textSection->PointerToRawData + i; - break; - } - } - - if (KeywordOffset[3] == -1) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Cannot find Keyword3.\n")); - goto ON_FindOffset_ERROR; - } else { - _tprintf_s(TEXT("Keyword3 has been found: offset = +0x%08X.\n"), KeywordOffset[3]); - } - - // ------------------------- - // try to search keyword4 - // ------------------------- - for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) { - if (memcmp((uint8_t*)lpFileContent + rdataSection->PointerToRawData + i, Keyword4, KeywordSize4) == 0) { - KeywordOffset[4] = rdataSection->PointerToRawData + i; - break; - } - } - - if (KeywordOffset[4] == -1) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Cannot find Keyword4.\n")); - goto ON_FindOffset_ERROR; - } else { - _tprintf_s(TEXT("Keyword4 has been found: offset = +0x%08X.\n"), KeywordOffset[4]); - } - - bSuccess = TRUE; - - ON_FindOffset_ERROR: - return bSuccess; - } - - BOOL BackupFile() { - BOOL bSuccess = FALSE; - DWORD dwLastError = ERROR_SUCCESS; - std::Tstring&& TargetFileName = InstallationPath + TargetName; - std::Tstring&& BackupFileName = InstallationPath + TargetName + TEXT(".backup"); - - if (!CopyFile(TargetFileName.c_str(), BackupFileName.c_str(), TRUE)) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("Failed @ CopyFile. CODE: 0x%08X\n"), dwLastError); - goto ON_BackupFile_ERROR; - } - - bSuccess = TRUE; - ON_BackupFile_ERROR: - return bSuccess; - } - - BOOL Do(RSACipher* cipher) { + BOOL Solution1::CheckKey(RSACipher* cipher) const { + BOOL bOk = FALSE; std::string RSAPublicKeyPEM; - std::string encrypted_pem_pubkey; RSAPublicKeyPEM = cipher->ExportKeyString(); if (RSAPublicKeyPEM.empty()) { @@ -361,7 +124,220 @@ namespace patcher::Solution1 { } } (RSAPublicKeyPEM, "\n", "\r\n"); // replace '\n' to '\r\n' - encrypted_pem_pubkey = EncryptPublicKey(RSAPublicKeyPEM.c_str(), RSAPublicKeyPEM.length()); + std::string encrypted_pem_text = Helper::EncryptPublicKey(RSAPublicKeyPEM); + + if (encrypted_pem_text[160] > '9' || encrypted_pem_text[160] < '1') + return FALSE; + + for (int i = 1; i < 8; ++i) + if (encrypted_pem_text[160 + i] > '9' || encrypted_pem_text[160 + i] < '0') + return FALSE; + + if (encrypted_pem_text[910] > '9' || encrypted_pem_text[910] < '1') + return FALSE; + + for (int i = 1; i < 5; ++i) + if (encrypted_pem_text[910 + i] > '9' || encrypted_pem_text[910 + i] < '0') + return FALSE; + + return TRUE; + } + + DWORD Solution1::TryFile(const std::Tstring& Name) { + std::Tstring MainAppFullName = InstallationPath + Name; + HANDLE hFile; + + hFile = CreateFile(MainAppFullName.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + nullptr, // default SA + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return GetLastError(); + + ReleaseFile(); + + LibccHandle = hFile; + LibccName = Name; + return ERROR_SUCCESS; + } + + DWORD Solution1::MapFile() { + DWORD dwLastError = ERROR_SUCCESS; + HANDLE hMapping = NULL; + PVOID lpMapView = nullptr; + + hMapping = CreateFileMapping(LibccHandle, + nullptr, // default SA + PAGE_READWRITE, + 0, 0, // map all + nullptr); // we don't need a name + if (hMapping == NULL) { + dwLastError = GetLastError(); + goto ON_Solution0_MapFile_ERROR; + } + + lpMapView = MapViewOfFile(hMapping, + FILE_MAP_READ | FILE_MAP_WRITE, + 0, 0, 0); // map all + if (lpMapView == nullptr) { + dwLastError = GetLastError(); + goto ON_Solution0_MapFile_ERROR; + } + + ReleaseMap(); + + LibccMappingView = lpMapView; + lpMapView = nullptr; + LibccMappingHandle = hMapping; + hMapping = NULL; + + ON_Solution0_MapFile_ERROR: + if (hMapping) + CloseHandle(hMapping); + return dwLastError; + } + + BOOL Solution1::FindPatchOffset() { + IMAGE_SECTION_HEADER* textSection = nullptr; + IMAGE_SECTION_HEADER* rdataSection = nullptr; + + uint8_t* lpFileContent = reinterpret_cast(LibccMappingView); + off_t Offsets[5] = { -1, -1, -1, -1, -1 }; + + textSection = Helper::ImageSectionHeader(lpFileContent, ".text"); + if (textSection == nullptr) { + // REPORT_ERROR("ERROR: Cannot find .text section."); + return FALSE; + } + + rdataSection = Helper::ImageSectionHeader(lpFileContent, ".rdata"); + if (textSection == nullptr) { + // REPORT_ERROR("ERROR: Cannot find .rdata section."); + return FALSE; + } + + // ------------------------- + // try to search Keywords[0] + // ------------------------- + for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) { + if (memcmp(lpFileContent + rdataSection->PointerToRawData + i, Keywords[0], KeywordsLength[0]) == 0) { + Offsets[0] = rdataSection->PointerToRawData + i; + break; + } + } + + if (Offsets[0] == -1) { + // REPORT_ERROR("ERROR: Cannot find Keywords[0]."); + return FALSE; + } + + // ------------------------- + // try to search Keywords[2] + // ------------------------- + for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) { + if (memcmp(lpFileContent + rdataSection->PointerToRawData + i, Keywords[2], KeywordsLength[2]) == 0) { + Offsets[2] = rdataSection->PointerToRawData + i; + break; + } + } + + if (Offsets[2] == -1) { + // REPORT_ERROR("ERROR: Cannot find Keywords[2]."); + return FALSE; + } + + // ------------------------- + // try to search Keywords[4] + // ------------------------- + for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) { + if (memcmp((uint8_t*)lpFileContent + rdataSection->PointerToRawData + i, Keywords[4], KeywordsLength[4]) == 0) { + Offsets[4] = rdataSection->PointerToRawData + i; + break; + } + } + + if (Offsets[4] == -1) { + // REPORT_ERROR("ERROR: Cannot find Keywords[4]."); + return FALSE; + } + + // ------------------------- + // try to search Keywords[1] and Keywords[3] + // ------------------------- + for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) { + if (memcmp(lpFileContent + textSection->PointerToRawData + i, Keywords[1], KeywordsLength[1]) == 0) { + + // Keywords[3] must be close to Keywords[1] + for (DWORD j = i - 64; j < i + 64; ++j) { + if (memcmp(lpFileContent + textSection->PointerToRawData + j, Keywords[3], KeywordsLength[3]) == 0) { + Offsets[1] = textSection->PointerToRawData + i; + Offsets[3] = textSection->PointerToRawData + j; + break; + } + } + + // Offsets[1] and Offsets[3] are set synchronously + // so check Offsets[1] is enough + if (Offsets[1] != -1) + break; + } + } + + if (Offsets[1] == -1) { + // REPORT_ERROR("ERROR: Cannot find Keywords[1] and Keywords[3]."); + return FALSE; + } + + PatchOffsets[0] = Offsets[0]; + PatchOffsets[1] = Offsets[1]; + PatchOffsets[2] = Offsets[2]; + PatchOffsets[3] = Offsets[3]; + PatchOffsets[4] = Offsets[4]; + _tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[0] has been found: offset = +0x%08lx.\n"), PatchOffsets[0]); + _tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[1] has been found: offset = +0x%08lx.\n"), PatchOffsets[1]); + _tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[2] has been found: offset = +0x%08lx.\n"), PatchOffsets[2]); + _tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[3] has been found: offset = +0x%08lx.\n"), PatchOffsets[3]); + _tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[4] has been found: offset = +0x%08lx.\n"), PatchOffsets[4]); + + return TRUE; + } + + DWORD Solution1::BackupFile() { + std::Tstring TargetFileFullName = InstallationPath + LibccName; + std::Tstring BackupFileFullName = InstallationPath + LibccName + TEXT(".backup"); + + if (!CopyFile(TargetFileFullName.c_str(), BackupFileFullName.c_str(), TRUE)) + return GetLastError(); + else + return ERROR_SUCCESS; + } + + BOOL Solution1::MakePatch(RSACipher* cipher) { + std::string RSAPublicKeyPEM; + std::string encrypted_pem_pubkey; + uint8_t* lpFileContent = reinterpret_cast(LibccMappingView); + + RSAPublicKeyPEM = cipher->ExportKeyString(); + if (RSAPublicKeyPEM.empty()) { + REPORT_ERROR("ERROR: cipher->ExportKeyString failed."); + return FALSE; + } + + [](std::string& str, const std::string& OldSub, const std::string& NewSub) { + std::string::size_type pos = 0; + std::string::size_type srclen = OldSub.size(); + std::string::size_type dstlen = NewSub.size(); + + while ((pos = str.find(OldSub, pos)) != std::string::npos) { + str.replace(pos, srclen, NewSub); + pos += dstlen; + } + } (RSAPublicKeyPEM, "\n", "\r\n"); // replace '\n' to '\r\n' + + encrypted_pem_pubkey = Helper::EncryptPublicKey(RSAPublicKeyPEM); // split encrypted_pem_pubkey to 5 part: |160 chars|8 chars|742 chars|5 chars|5 chars| // | | @@ -375,43 +351,102 @@ namespace patcher::Solution1 { uint32_t imm1 = std::stoul(encrypted_pem_pubkey1.c_str()); uint32_t imm3 = std::stoul(encrypted_pem_pubkey3.c_str()); - _tprintf_s(TEXT("\n")); - _tprintf_s(TEXT("@Offset +0x%08X, write string:\n"), KeywordOffset[0]); - printf_s("\"%s\"\n\n", encrypted_pem_pubkey0.c_str()); - memcpy((uint8_t*)lpFileContent + KeywordOffset[0], encrypted_pem_pubkey0.c_str(), 160); - _tprintf_s(TEXT("@Offset +0x%08X, write uint32_t:\n"), KeywordOffset[1]); - printf_s("0x%08X\n\n", imm1); - memcpy((uint8_t*)lpFileContent + KeywordOffset[1], &imm1, sizeof(uint32_t)); + // ---------------------------------- + // process PatchOffsets[0] + // ---------------------------------- + _tprintf_s(TEXT("@libcc.dll+0x%08X\nPrevious:\n"), PatchOffsets[0]); + Helper::PrintMemory(lpFileContent + PatchOffsets[0], + lpFileContent + PatchOffsets[0] + KeywordsLength[0], + lpFileContent); + memcpy(lpFileContent + PatchOffsets[0], encrypted_pem_pubkey0.c_str(), KeywordsLength[0]); + PRINT_MESSAGE("After:"); + Helper::PrintMemory(lpFileContent + PatchOffsets[0], + lpFileContent + PatchOffsets[0] + KeywordsLength[0], + lpFileContent); + PRINT_MESSAGE(""); - _tprintf_s(TEXT("@Offset +0x%08X, write string:\n"), KeywordOffset[2]); - printf_s("\"%s\"\n\n", encrypted_pem_pubkey2.c_str()); - memcpy((uint8_t*)lpFileContent + KeywordOffset[2], encrypted_pem_pubkey2.c_str(), 742); + // ---------------------------------- + // process PatchOffsets[1] + // ---------------------------------- + _tprintf_s(TEXT("@libcc.dll+0x%08X\nPrevious:\n"), PatchOffsets[1]); + Helper::PrintMemory(lpFileContent + PatchOffsets[1], + lpFileContent + PatchOffsets[1] + KeywordsLength[1], + lpFileContent); + memcpy(lpFileContent + PatchOffsets[1], &imm1, KeywordsLength[1]); + PRINT_MESSAGE("After:"); + Helper::PrintMemory(lpFileContent + PatchOffsets[1], + lpFileContent + PatchOffsets[1] + KeywordsLength[1], + lpFileContent); + PRINT_MESSAGE(""); - _tprintf_s(TEXT("@Offset +0x%08X, write uint32_t:\n"), KeywordOffset[3]); - printf_s("0x%08X\n\n", imm3); - memcpy((uint8_t*)lpFileContent + KeywordOffset[3], &imm3, sizeof(uint32_t)); + // ---------------------------------- + // process PatchOffsets[2] + // ---------------------------------- + _tprintf_s(TEXT("@libcc.dll+0x%08X\nPrevious:\n"), PatchOffsets[2]); + Helper::PrintMemory(lpFileContent + PatchOffsets[2], + lpFileContent + PatchOffsets[2] + KeywordsLength[2], + lpFileContent); + memcpy(lpFileContent + PatchOffsets[2], encrypted_pem_pubkey2.c_str(), KeywordsLength[2]); + PRINT_MESSAGE("After:"); + Helper::PrintMemory(lpFileContent + PatchOffsets[2], + lpFileContent + PatchOffsets[2] + KeywordsLength[2], + lpFileContent); + PRINT_MESSAGE(""); - _tprintf_s(TEXT("@Offset +0x%08X, write string:\n"), KeywordOffset[4]); - printf_s("\"%s\"\n\n", encrypted_pem_pubkey4.c_str()); - memcpy((uint8_t*)lpFileContent + KeywordOffset[4], encrypted_pem_pubkey4.c_str(), 5); + // ---------------------------------- + // process PatchOffsets[3] + // ---------------------------------- + _tprintf_s(TEXT("@libcc.dll+0x%08X\nPrevious:\n"), PatchOffsets[3]); + Helper::PrintMemory(lpFileContent + PatchOffsets[3], + lpFileContent + PatchOffsets[3] + KeywordsLength[3], + lpFileContent); + memcpy(lpFileContent + PatchOffsets[3], &imm3, KeywordsLength[3]); + PRINT_MESSAGE("After:"); + Helper::PrintMemory(lpFileContent + PatchOffsets[3], + lpFileContent + PatchOffsets[3] + KeywordsLength[3], + lpFileContent); + PRINT_MESSAGE(""); + // ---------------------------------- + // process PatchOffsets[4] + // ---------------------------------- + _tprintf_s(TEXT("@libcc.dll+0x%08X\nPrevious:\n"), PatchOffsets[4]); + Helper::PrintMemory(lpFileContent + PatchOffsets[4], + lpFileContent + PatchOffsets[4] + KeywordsLength[4], + lpFileContent); + memcpy(lpFileContent + PatchOffsets[4], encrypted_pem_pubkey4.c_str(), KeywordsLength[4]); + PRINT_MESSAGE("After:"); + Helper::PrintMemory(lpFileContent + PatchOffsets[4], + lpFileContent + PatchOffsets[4] + KeywordsLength[4], + lpFileContent); + PRINT_MESSAGE(""); return TRUE; } - VOID Finalize() { - if (lpFileContent) { - UnmapViewOfFile(lpFileContent); - lpFileContent = NULL; - } - if (hTargetMap) { - CloseHandle(hTargetMap); - hTargetMap = NULL; - } - if (hTarget) { - CloseHandle(hTarget); - hTarget = INVALID_HANDLE_VALUE; + void Solution1::ReleaseFile() { + ReleaseMap(); + + if (LibccHandle != INVALID_HANDLE_VALUE && LibccHandle) { + CloseHandle(LibccHandle); + LibccHandle = INVALID_HANDLE_VALUE; } } + void Solution1::ReleaseMap() { + if (LibccMappingView) { + UnmapViewOfFile(LibccMappingView); + LibccMappingView = nullptr; + } + + if (LibccMappingHandle) { + CloseHandle(LibccMappingHandle); + LibccMappingHandle = NULL; + } + } + + Solution1::~Solution1() { + ReleaseFile(); + } + } \ No newline at end of file diff --git a/navicat-patcher/_tmain.cpp b/navicat-patcher/_tmain.cpp index 56ccc1e..4893dc6 100644 --- a/navicat-patcher/_tmain.cpp +++ b/navicat-patcher/_tmain.cpp @@ -1,188 +1,254 @@ #include "def.hpp" -bool ConvertToUTF8(LPCSTR from, std::string& to) { - bool bSuccess = false; - int len = 0; - LPWSTR lpUnicodeString = nullptr; - - len = MultiByteToWideChar(CP_ACP, NULL, from, -1, NULL, 0); - if (len == 0) - goto ON_ConvertToUTF8_0_ERROR; - - lpUnicodeString = reinterpret_cast(HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - len * sizeof(WCHAR))); - if (lpUnicodeString == nullptr) - goto ON_ConvertToUTF8_0_ERROR; - - if (!MultiByteToWideChar(CP_ACP, NULL, from, -1, lpUnicodeString, len)) - goto ON_ConvertToUTF8_0_ERROR; - - len = WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, NULL, 0, NULL, NULL); - if (len == 0) - goto ON_ConvertToUTF8_0_ERROR; - - to.resize(len); - if (!WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, to.data(), len, NULL, NULL)) - 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; +static void help() { + PRINT_MESSAGE("Usage:"); + PRINT_MESSAGE(" navicat-patcher.exe [RSA-2048 PEM file]"); } -bool ConvertToUTF8(LPCWSTR from, std::string& to) { - bool bSuccess = false; - int len = 0; +static BOOL LoadKey(RSACipher* cipher, LPTSTR filename, Patcher::Solution0* pSolution0, Patcher::Solution1* pSolution1) { + if (filename) { + std::string PrivateKeyFileName; - len = WideCharToMultiByte(CP_UTF8, NULL, from, -1, NULL, 0, NULL, NULL); - if (len == 0) - goto ON_ConvertToUTF8_1_ERROR; + if (!Helper::ConvertToUTF8(filename, PrivateKeyFileName)) { + REPORT_ERROR("ERROR: ConvertToUTF8 failed."); + return FALSE; + } - to.resize(len); - if (!WideCharToMultiByte(CP_UTF8, NULL, from, -1, to.data(), len, NULL, NULL)) - goto ON_ConvertToUTF8_1_ERROR; + if (!cipher->ImportKeyFromFile(PrivateKeyFileName)) { + REPORT_ERROR("ERROR: cipher->ImportKeyFromFile failed."); + return FALSE; + } - while (to.back() == 0) - to.pop_back(); + if (pSolution0 && !pSolution0->CheckKey(cipher) || + pSolution1 && !pSolution1->CheckKey(cipher)) { + REPORT_ERROR("ERROR: The RSA private key you provide cannot be used."); + return FALSE; + } - bSuccess = true; + } else { + PRINT_MESSAGE("MESSAGE: Generating new RSA private key, it may take a long time."); -ON_ConvertToUTF8_1_ERROR: - return bSuccess; -} + do { + cipher->GenerateKey(2048); + } while (pSolution0 && !pSolution0->CheckKey(cipher) || + pSolution1 && !pSolution1->CheckKey(cipher)); // re-generate RSA key if one of CheckKey return FALSE -bool ConvertToUTF8(std::string& str) { - bool bSuccess = false; + if (!cipher->ExportKeyToFile("RegPrivateKey.pem")) { + REPORT_ERROR("ERROR: Failed to save RSA private key."); + return FALSE; + } - std::string temp; - bSuccess = ConvertToUTF8(str.c_str(), temp); - if (!bSuccess) - return false; + PRINT_MESSAGE("MESSAGE: New RSA private key has been saved to RegPrivateKey.pem."); + } - str = temp; - return true; + std::string PublicKeyString = cipher->ExportKeyString(); + if (PublicKeyString.empty()) { + REPORT_ERROR("ERROR: cipher->ExportKeyString failed."); + return FALSE; + } + + PRINT_MESSAGE("Your RSA public key:"); + PRINT_LPCSTR(PublicKeyString.c_str()); + return TRUE; } int _tmain(int argc, TCHAR* argv[]) { if (argc != 2 && argc != 3) { - _tprintf_s(TEXT("Usage:\n")); - _tprintf_s(TEXT(" navicat-patcher.exe [RSA-2048 PEM file]\n")); + help(); return 0; } - RSACipher* cipher = NULL; - DWORD dwMajorVer = 0; - DWORD dwMinorVer = 0; + RSACipher* cipher = nullptr; + Patcher::Solution0* pSolution0 = nullptr; + Patcher::Solution1* pSolution1 = nullptr; + + DWORD ErrorCode; cipher = RSACipher::Create(); - if (cipher == NULL) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("RSACipher::Create failed.\n")); + if (cipher == nullptr) { + REPORT_ERROR("ERROR: RSACipher::Create failed."); goto ON_tmain_ERROR; } - if (!patcher::Solution0::Init(argv[1])) + pSolution0 = new Patcher::Solution0(); + pSolution1 = new Patcher::Solution1(); + + if (!pSolution0->SetPath(argv[1])) { + PRINT_MESSAGE("The path you specified:"); + PRINT_LPCTSTR(argv[1]); goto ON_tmain_ERROR; - if (!patcher::Solution1::Init(argv[1])) + } + if (!pSolution1->SetPath(argv[1])) { + PRINT_MESSAGE("The path you specified:"); + PRINT_LPCTSTR(argv[1]); goto ON_tmain_ERROR; + } - if (argc == 3) { - std::string PrivateKeyFileName; +FindMainApp: + ErrorCode = pSolution0->TryFile(TEXT("Navicat.exe")); + if (ErrorCode == ERROR_SUCCESS) { + PRINT_MESSAGE("MESSAGE: Navicat.exe has been found."); + goto FindLibcc; + }else if (ErrorCode == ERROR_ACCESS_DENIED) { + PRINT_MESSAGE("ERROR: Cannot open Navicat.exe for ERROR_ACCESS_DENIED."); + PRINT_MESSAGE("Please re-run with Administrator privilege."); + goto ON_tmain_ERROR; + } + if (ErrorCode != ERROR_FILE_NOT_FOUND) { + REPORT_ERROR_WITH_CODE("ERROR: Cannot open Navicat.exe.", ErrorCode); + goto ON_tmain_ERROR; + } - if (!ConvertToUTF8(argv[2], PrivateKeyFileName)) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: ConvertToUTF8 failed.\n")); - goto ON_tmain_ERROR; - } + ErrorCode = pSolution0->TryFile(TEXT("Modeler.exe")); + if (ErrorCode == ERROR_SUCCESS) { + PRINT_MESSAGE("MESSAGE: Modeler.exe has been found."); + goto FindLibcc; + } + if (ErrorCode == ERROR_ACCESS_DENIED) { + PRINT_MESSAGE("ERROR: Cannot open Modeler.exe for ERROR_ACCESS_DENIED."); + PRINT_MESSAGE("Please re-run with Administrator privilege."); + goto ON_tmain_ERROR; + } + if (ErrorCode != ERROR_FILE_NOT_FOUND) { + REPORT_ERROR_WITH_CODE("ERROR: Cannot open Modeler.exe.", ErrorCode); + goto ON_tmain_ERROR; + } - if (!cipher->ImportKeyFromFile(PrivateKeyFileName)) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: cipher->ImportKeyFromFile failed.\n")); - goto ON_tmain_ERROR; - } + ErrorCode = pSolution0->TryFile(TEXT("Rviewer.exe")); + if (ErrorCode == ERROR_SUCCESS) { + PRINT_MESSAGE("MESSAGE: Rviewer.exe has been found."); + goto FindLibcc; + } + if (ErrorCode == ERROR_ACCESS_DENIED) { + PRINT_MESSAGE("ERROR: Cannot open Rviewer.exe for ERROR_ACCESS_DENIED."); + PRINT_MESSAGE("Please re-run with Administrator privilege."); + goto ON_tmain_ERROR; + } + if (ErrorCode != ERROR_FILE_NOT_FOUND) { + REPORT_ERROR_WITH_CODE("ERROR: Cannot open Rviewer.exe.", ErrorCode); + goto ON_tmain_ERROR; + } - if (patcher::Solution0::CheckKey(cipher) == FALSE || patcher::Solution1::CheckKey(cipher) == FALSE) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: RSA private key specified cannot be used.\n")); - goto ON_tmain_ERROR; - } + PRINT_MESSAGE("ERROR: Cannot find main application. Are you sure the path you specified is correct?"); + PRINT_MESSAGE("The path you specified:"); + PRINT_LPCTSTR(argv[1]); + goto ON_tmain_ERROR; + +FindLibcc: + ErrorCode = pSolution1->TryFile(TEXT("libcc.dll")); + if (ErrorCode == ERROR_SUCCESS) { + PRINT_MESSAGE("MESSAGE: libcc.dll has been found."); + } else if (ErrorCode == ERROR_FILE_NOT_FOUND) { + PRINT_MESSAGE("MESSAGE: libcc.dll is not found. Solution1 will be omitted."); + delete pSolution1; + pSolution1 = nullptr; + } else if (ErrorCode == ERROR_ACCESS_DENIED) { + PRINT_MESSAGE("ERROR: Cannot open libcc.dll for ERROR_ACCESS_DENIED."); + PRINT_MESSAGE("Please re-run with Administrator privilege."); + goto ON_tmain_ERROR; } else { - _tprintf_s(TEXT("Generating new RSA private key, it may take long time.\n")); + REPORT_ERROR_WITH_CODE("ERROR: Cannot open libcc.dll.", ErrorCode); + goto ON_tmain_ERROR; + } - do { - cipher->GenerateKey(2048); - } while (!patcher::Solution0::CheckKey(cipher) || !patcher::Solution1::CheckKey(cipher)); // re-generate RSA key if one of CheckKey return FALSE +SearchPublicKey: + PRINT_MESSAGE(""); + ErrorCode = pSolution0->MapFile(); + if (ErrorCode != ERROR_SUCCESS) { + _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); + _tprintf_s(TEXT("ERROR: Cannot map %s. CODE: 0x%08X\n"), + pSolution0->GetMainAppName().c_str(), + ErrorCode); + goto ON_tmain_ERROR; + } + if (!pSolution0->FindPatchOffset()) { + _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); + _tprintf_s(TEXT("ERROR: Cannot find RSA public key in %s.\n"), + pSolution0->GetMainAppName().c_str()); + goto ON_tmain_ERROR; + } - if (!cipher->ExportKeyToFile("RegPrivateKey.pem")) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Failed to save RSA private key.\n")); + if (pSolution1) { + ErrorCode = pSolution1->MapFile(); + if (ErrorCode != ERROR_SUCCESS) { + REPORT_ERROR_WITH_CODE("ERROR: Cannot map libcc.dll.", ErrorCode); goto ON_tmain_ERROR; } - - _tprintf_s(TEXT("New RSA private key has been saved to RegPrivateKey.pem.\n")); + if (!pSolution1->FindPatchOffset()) { + PRINT_MESSAGE("MESSAGE: Cannot find RSA public key in libcc.dll. Solution1 will be omitted."); + delete pSolution1; + pSolution1 = nullptr; + } } - // ------------------ - // begin Solution0 - // ------------------ - if (!patcher::Solution0::FindTargetFile()) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Cannot find main program. Are you sure the path you specified is correct?\n")); +LoadingKey: + PRINT_MESSAGE(""); + if (!LoadKey(cipher, argc == 3 ? argv[2] : nullptr, pSolution0, pSolution1)) + goto ON_tmain_ERROR; + +BackupFiles: + PRINT_MESSAGE(""); + ErrorCode = pSolution0->BackupFile(); + if (ErrorCode == ERROR_SUCCESS) { + _tprintf_s(TEXT("MESSAGE: %s has been backed up successfully.\n"), + pSolution0->GetMainAppName().c_str()); + } else if (ErrorCode == ERROR_ACCESS_DENIED) { + _tprintf_s(TEXT("ERROR: Cannot back up %s for ERROR_ACCESS_DENIED.\n"), + pSolution0->GetMainAppName().c_str()); + _tprintf_s(TEXT("Please re-run with Administrator privilege.\n")); + goto ON_tmain_ERROR; + } else if (ErrorCode == ERROR_FILE_EXISTS) { + _tprintf_s(TEXT("ERROR: The backup of %s has been found.\n"), + pSolution0->GetMainAppName().c_str()); + _tprintf_s(TEXT("Please remove %s.backup in Navicat installation path if you're sure %s has not been patched.\n"), + pSolution0->GetMainAppName().c_str(), + pSolution0->GetMainAppName().c_str()); + _tprintf_s(TEXT("Otherwise please restore %s by %s.backup and remove %s.backup then try again.\n"), + pSolution0->GetMainAppName().c_str(), + pSolution0->GetMainAppName().c_str(), + pSolution0->GetMainAppName().c_str()); + goto ON_tmain_ERROR; + } else { + _tprintf_s(TEXT("ERROR: Cannot back up %s. CODE: 0x%08X\n"), + pSolution0->GetMainAppName().c_str(), + ErrorCode); goto ON_tmain_ERROR; } - if (!patcher::Solution0::GetVersion(&dwMajorVer, &dwMinorVer)) + if (pSolution1) { + ErrorCode = pSolution1->BackupFile(); + if (ErrorCode == ERROR_SUCCESS) { + PRINT_MESSAGE("MESSAGE: libcc.dll has been backed up successfully."); + } else if (ErrorCode == ERROR_ACCESS_DENIED) { + PRINT_MESSAGE("ERROR: Cannot back up libcc.dll for ERROR_ACCESS_DENIED."); + PRINT_MESSAGE("Please re-run with Administrator privilege."); + goto ON_tmain_ERROR; + } else if (ErrorCode == ERROR_FILE_EXISTS) { + PRINT_MESSAGE("ERROR: The backup of libcc.dll has been found."); + PRINT_MESSAGE("Please remove libcc.dll.backup in Navicat installation path if you're sure libcc.dll has not been patched."); + PRINT_MESSAGE("Otherwise please restore libcc.dll by libcc.dll.backup and remove libcc.dll.backup then try again."); + goto ON_tmain_ERROR; + } else { + REPORT_ERROR_WITH_CODE("ERROR: Cannot back up libcc.dll.", ErrorCode); + goto ON_tmain_ERROR; + } + } + +MakingPatch: + PRINT_MESSAGE(""); + if (!pSolution0->MakePatch(cipher)) goto ON_tmain_ERROR; - if (!patcher::Solution0::CheckFile()) + if (pSolution1 && !pSolution1->MakePatch(cipher)) goto ON_tmain_ERROR; - if (!patcher::Solution0::BackupFile()) - goto ON_tmain_ERROR; - - if (!patcher::Solution0::Do(cipher)) - goto ON_tmain_ERROR; - - _tprintf_s(TEXT("RSA public key has been replaced by\n")); - printf_s("%s\n", cipher->ExportKeyString().c_str()); - _tprintf_s(TEXT("Solution0 has been done successfully.\n")); - _tprintf_s(TEXT("\n")); - - // for ver <= 12.0.24 - if (dwMajorVer == 0x000c0000 && dwMinorVer < 0x00180000) - goto ON_tmain_ERROR; // you don't need Solution1 patch. - - // ------------------ - // begin Solution1 - // ------------------ - if (!patcher::Solution1::FindTargetFile()) { - _tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__); - _tprintf_s(TEXT("ERROR: Cannot find libcc.dll. Are you sure the path you specified is correct?\n")); - goto ON_tmain_ERROR; - } - - if (!patcher::Solution1::FindOffset()) - goto ON_tmain_ERROR; - - if (!patcher::Solution1::BackupFile()) - goto ON_tmain_ERROR; - - if (!patcher::Solution1::Do(cipher)) - goto ON_tmain_ERROR; - - _tprintf_s(TEXT("Solution1 has been done successfully.\n")); - _tprintf_s(TEXT("\n")); + PRINT_MESSAGE("Solution0 has been done successfully."); + if (pSolution1) + PRINT_MESSAGE("Solution1 has been done successfully."); ON_tmain_ERROR: - patcher::Solution1::Finalize(); - patcher::Solution0::Finalize(); + delete pSolution1; + delete pSolution0; delete cipher; return 0; } \ No newline at end of file diff --git a/navicat-patcher/def.hpp b/navicat-patcher/def.hpp index f422c01..a81bdb6 100644 --- a/navicat-patcher/def.hpp +++ b/navicat-patcher/def.hpp @@ -90,7 +90,7 @@ namespace Patcher { // Return error code // Return ERROR_SUCCESS if success - DWORD GetMainAppVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer); + // DWORD GetMainAppVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer); const std::Tstring& GetMainAppName();