Adjust Solution0 and Solution1
This commit is contained in:
parent
28c2cfa290
commit
96f40aef26
@ -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<uint8_t*>(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<uint8_t*>(MainAppMappingView);
|
||||
std::string RSAPublicKeyPEM;
|
||||
std::Tstring&& TargetFileName = InstallationPath + TargetName;
|
||||
HANDLE hUpdater = NULL;
|
||||
|
||||
RSAPublicKeyPEM = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
|
||||
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<LPVOID*>(&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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
|
||||
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<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
|
||||
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<uint8_t*>(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<uint8_t*>(LibccMappingView);
|
||||
|
||||
RSAPublicKeyPEM = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<LPWSTR>(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 <Navicat installation path> [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<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::PEM>(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<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::NotSpecified>("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<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
|
||||
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 <Navicat installation path> [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<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::PEM>(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<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::NotSpecified>("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<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>().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;
|
||||
}
|
||||
@ -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();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user