_tmain.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. #include <tchar.h>
  2. #include <windows.h>
  3. #include "Exception.hpp"
  4. #include "PatchSolution.hpp"
  5. #include "Helper.hpp"
  6. #undef __BASE_FILE__
  7. #define __BASE_FILE__ "_tmain.cpp"
  8. #define PRINT_MESSAGE_LITERAL(m) _putts(TEXT(m))
  9. #define PRINT_PTSTR(m) _putts(m)
  10. #define PRINT_PCSTR(m) puts(m)
  11. #define PRINT_PCWSTR(m) _putws(m)
  12. String InstallationPath;
  13. String MainAppName;
  14. String LibccName = TEXT("libcc.dll");
  15. static void Welcome() {
  16. PRINT_MESSAGE_LITERAL("***************************************************");
  17. PRINT_MESSAGE_LITERAL("* Navicat Patcher by @DoubleLabyrinth *");
  18. _tprintf_s(TEXT("* Release date: %-24s*\n"), TEXT(__DATE__));
  19. PRINT_MESSAGE_LITERAL("***************************************************");
  20. PRINT_MESSAGE_LITERAL("");
  21. PRINT_MESSAGE_LITERAL("Press Enter to continue or Ctrl + C to abort.");
  22. _gettchar();
  23. }
  24. static void Help() {
  25. PRINT_MESSAGE_LITERAL("Usage:");
  26. PRINT_MESSAGE_LITERAL(" navicat-patcher.exe <Navicat installation path> [RSA-2048 PEM file]");
  27. }
  28. static void SetPath(PTSTR pszPath) {
  29. DWORD Attr;
  30. Attr = GetFileAttributes(pszPath);
  31. if (Attr == INVALID_FILE_ATTRIBUTES)
  32. throw SystemError(__BASE_FILE__, __LINE__, GetLastError(),
  33. "GetFileAttributes fails.");
  34. if ((Attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
  35. throw Exception(__BASE_FILE__, __LINE__,
  36. "Path does not point to a directory.");
  37. InstallationPath = pszPath;
  38. if (InstallationPath.back() != TEXT('\\') && InstallationPath.back() != TEXT('/'))
  39. InstallationPath.push_back(TEXT('/')); // for Linux compatible
  40. }
  41. static void BackupFile(const String& From, const String& To) {
  42. if (::CopyFile(From.c_str(), To.c_str(), TRUE) == FALSE)
  43. throw SystemError(__BASE_FILE__, __LINE__, GetLastError(),
  44. "CopyFile fails.");
  45. }
  46. static void LoadKey(RSACipher* pCipher, PTSTR FileName,
  47. PatchSolution* pSolution0,
  48. PatchSolution* pSolution1,
  49. PatchSolution* pSolution2,
  50. PatchSolution* pSolution3) {
  51. if (FileName) {
  52. std::string PrivateKeyFileName = Helper::ConvertToUTF8(FileName);
  53. pCipher->ImportKeyFromFile<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::PEM>(PrivateKeyFileName);
  54. if (pSolution0 && !pSolution0->CheckKey(pCipher) ||
  55. pSolution1 && !pSolution1->CheckKey(pCipher) ||
  56. pSolution2 && !pSolution2->CheckKey(pCipher) ||
  57. pSolution3 && !pSolution3->CheckKey(pCipher))
  58. throw Exception(__BASE_FILE__, __LINE__,
  59. "The RSA private key you provide cannot be used.");
  60. } else {
  61. PRINT_MESSAGE_LITERAL("MESSAGE: Generating new RSA private key, it may take a long time.");
  62. do {
  63. pCipher->GenerateKey(2048);
  64. } while (pSolution0 && !pSolution0->CheckKey(pCipher) ||
  65. pSolution1 && !pSolution1->CheckKey(pCipher) ||
  66. pSolution2 && !pSolution2->CheckKey(pCipher) ||
  67. pSolution3 && !pSolution3->CheckKey(pCipher)); // re-generate RSA key if CheckKey return false
  68. pCipher->ExportKeyToFile<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::NotSpecified>("RegPrivateKey.pem");
  69. PRINT_MESSAGE_LITERAL("MESSAGE: New RSA private key has been saved to RegPrivateKey.pem.");
  70. }
  71. std::string PublicKeyString = pCipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
  72. PRINT_MESSAGE_LITERAL("");
  73. PRINT_MESSAGE_LITERAL("Your RSA public key:");
  74. PRINT_PCSTR(PublicKeyString.c_str());
  75. }
  76. static void ExceptionReport(const Exception& e) noexcept {
  77. printf_s("ERROR: @ %s - Line %d\n", e.SourceFile(), e.SourceLine());
  78. if (e.HasErrorCode()) {
  79. const char* aa = e.ErrorString();
  80. printf_s("ErrorCode = 0x%08lx\n", e.ErrorCode());
  81. printf_s("ErrorString: %s\n", e.ErrorString());
  82. } else {
  83. printf_s("%s\n", e.CustomMessage());
  84. }
  85. }
  86. int _tmain(int argc, PTSTR argv[]) {
  87. if (argc != 2 && argc != 3) {
  88. Help();
  89. return 0;
  90. }
  91. Welcome();
  92. ResourceGuard<CppObjectTraits<RSACipher>> pCipher;
  93. ResourceGuard<CppObjectTraits<FileMapper>> pMainExe;
  94. ResourceGuard<CppObjectTraits<FileMapper>> pLibccDLL;
  95. ResourceGuard<CppObjectTraits<PatchSolution>> pSolution0;
  96. ResourceGuard<CppObjectTraits<PatchSolution>> pSolution1;
  97. ResourceGuard<CppObjectTraits<PatchSolution>> pSolution2;
  98. ResourceGuard<CppObjectTraits<PatchSolution>> pSolution3;
  99. pCipher.TakeHoldOf(new RSACipher());
  100. try {
  101. SetPath(argv[1]);
  102. } catch (Exception& e) {
  103. ExceptionReport(e);
  104. PRINT_MESSAGE_LITERAL("Are you sure the path you specified is correct?");
  105. PRINT_MESSAGE_LITERAL("The path you specified:");
  106. PRINT_PTSTR(argv[1]);
  107. return 0;
  108. }
  109. // -----------
  110. // decide which PatchSolution
  111. // -----------
  112. do {
  113. pLibccDLL.TakeHoldOf(new FileMapper());
  114. try {
  115. pLibccDLL.GetHandle()->MapFile(InstallationPath + TEXT("libcc.dll"));
  116. pSolution3.TakeHoldOf(new PatchSolution3());
  117. pSolution3.GetHandle()->SetFile(pLibccDLL);
  118. if (pSolution3.GetHandle()->FindPatchOffset() == false) {
  119. PRINT_MESSAGE_LITERAL("MESSAGE: PatchSolution3 will be omitted.");
  120. pSolution3.Release();
  121. } else {
  122. break;
  123. }
  124. pSolution2.TakeHoldOf(new PatchSolution2());
  125. pSolution2.GetHandle()->SetFile(pLibccDLL);
  126. if (pSolution2.GetHandle()->FindPatchOffset() == false) {
  127. PRINT_MESSAGE_LITERAL("MESSAGE: PatchSolution2 will be omitted.");
  128. pSolution2.Release();
  129. } else {
  130. break;
  131. }
  132. pSolution1.TakeHoldOf(new PatchSolution1());
  133. pSolution1.GetHandle()->SetFile(pLibccDLL);
  134. if (pSolution1.GetHandle()->FindPatchOffset() == false) {
  135. PRINT_MESSAGE_LITERAL("MESSAGE: PatchSolution1 will be omitted.");
  136. pSolution2.Release();
  137. } else {
  138. break;
  139. }
  140. pLibccDLL.Release();
  141. } catch (Exception& e) {
  142. if (e.HasErrorCode() && e.ErrorCode() == ERROR_FILE_NOT_FOUND) {
  143. PRINT_MESSAGE_LITERAL("MESSAGE: libcc.dll is not found.");
  144. PRINT_MESSAGE_LITERAL(" PatchSolution1 will be omitted.");
  145. PRINT_MESSAGE_LITERAL(" PatchSolution2 will be omitted.");
  146. PRINT_MESSAGE_LITERAL(" PatchSolution3 will be omitted.");
  147. pLibccDLL.Release();
  148. } else {
  149. ExceptionReport(e);
  150. if (e.HasErrorCode() && e.ErrorCode() == ERROR_ACCESS_DENIED)
  151. PRINT_MESSAGE_LITERAL("Please re-run with Administrator privilege.");
  152. return 0;
  153. }
  154. }
  155. pMainExe.TakeHoldOf(new FileMapper());
  156. do {
  157. try {
  158. pMainExe.GetHandle()->MapFile(InstallationPath + TEXT("Navicat.exe"));
  159. MainAppName = TEXT("Navicat.exe");
  160. break;
  161. } catch (Exception& e) {
  162. if (!e.HasErrorCode() || e.ErrorCode() != ERROR_FILE_NOT_FOUND) {
  163. ExceptionReport(e);
  164. if (e.HasErrorCode() && e.ErrorCode() == ERROR_ACCESS_DENIED)
  165. PRINT_MESSAGE_LITERAL("Please re-run with Administrator privilege.");
  166. return 0;
  167. }
  168. }
  169. try {
  170. pMainExe.GetHandle()->MapFile(InstallationPath + TEXT("Modeler.exe"));
  171. MainAppName = TEXT("Modeler.exe");
  172. break;
  173. } catch (Exception& e) {
  174. if (!e.HasErrorCode() || e.ErrorCode() != ERROR_FILE_NOT_FOUND) {
  175. ExceptionReport(e);
  176. if (e.HasErrorCode() && e.ErrorCode() == ERROR_ACCESS_DENIED)
  177. PRINT_MESSAGE_LITERAL("Please re-run with Administrator privilege.");
  178. return 0;
  179. }
  180. }
  181. try {
  182. pMainExe.GetHandle()->MapFile(InstallationPath + TEXT("Rviewer.exe"));
  183. MainAppName = TEXT("Rviewer.exe");
  184. break;
  185. } catch (Exception& e) {
  186. if (!e.HasErrorCode() || e.ErrorCode() != ERROR_FILE_NOT_FOUND) {
  187. ExceptionReport(e);
  188. if (e.HasErrorCode() && e.ErrorCode() == ERROR_ACCESS_DENIED)
  189. PRINT_MESSAGE_LITERAL("Please re-run with Administrator privilege.");
  190. return 0;
  191. }
  192. }
  193. pMainExe.Release();
  194. } while (false);
  195. } while (false);
  196. // -------------
  197. // LoadKey
  198. // BackupFile
  199. // MakePatch
  200. // -------------
  201. try {
  202. LoadKey(pCipher, argc == 3 ? argv[2] : nullptr,
  203. pSolution0,
  204. pSolution1,
  205. pSolution2,
  206. pSolution3);
  207. if (pLibccDLL) {
  208. BackupFile(InstallationPath + LibccName, InstallationPath + LibccName + TEXT(".backup"));
  209. } else {
  210. BackupFile(InstallationPath + MainAppName, InstallationPath + MainAppName + TEXT(".backup"));
  211. }
  212. if (pSolution3.IsValid())
  213. pSolution3.GetHandle()->MakePatch(pCipher);
  214. if (pSolution2.IsValid())
  215. pSolution2.GetHandle()->MakePatch(pCipher);
  216. if (pSolution1.IsValid())
  217. pSolution1.GetHandle()->MakePatch(pCipher);
  218. if (pSolution0.IsValid())
  219. pSolution0.GetHandle()->MakePatch(pCipher);
  220. } catch (Exception& e) {
  221. ExceptionReport(e);
  222. if (e.HasErrorCode() && e.ErrorCode() == ERROR_FILE_EXISTS) {
  223. if (pLibccDLL.IsValid()) {
  224. _tprintf_s(TEXT("The backup of %s has been found.\n"), LibccName.c_str());
  225. _tprintf_s(TEXT("Please remove %s.backup in Navicat installation path if you're sure %s has not been patched.\n"),
  226. LibccName.c_str(),
  227. LibccName.c_str());
  228. _tprintf_s(TEXT("Otherwise please restore %s by %s.backup and remove %s.backup then try again.\n"),
  229. LibccName.c_str(),
  230. LibccName.c_str(),
  231. LibccName.c_str());
  232. } else {
  233. _tprintf_s(TEXT("The backup of %s has been found.\n"), MainAppName.c_str());
  234. _tprintf_s(TEXT("Please remove %s.backup in Navicat installation path if you're sure %s has not been patched.\n"),
  235. MainAppName.c_str(),
  236. MainAppName.c_str());
  237. _tprintf_s(TEXT("Otherwise please restore %s by %s.backup and remove %s.backup then try again.\n"),
  238. MainAppName.c_str(),
  239. MainAppName.c_str(),
  240. MainAppName.c_str());
  241. }
  242. }
  243. return 0;
  244. }
  245. PRINT_MESSAGE_LITERAL("");
  246. PRINT_MESSAGE_LITERAL("MESSAGE: Patch has been done successfully.");
  247. return 0;
  248. }