_tmain.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #include <tchar.h>
  2. #include <windows.h>
  3. #include "Exception.hpp"
  4. #include "ExceptionSystem.hpp"
  5. #include "FileManipulation.hpp"
  6. #include "PatchSolution.hpp"
  7. #undef __BASE_FILE__
  8. #define __BASE_FILE__ TEXT("_tmain.cpp")
  9. #define PRINT_MESSAGE_LITERAL(m) _putts(TEXT(m))
  10. #define PRINT_PTSTR(m) _putts(m)
  11. #define PRINT_PCSTR(m) puts(m)
  12. #define PRINT_PCWSTR(m) _putws(m)
  13. static void Welcome() {
  14. _putts(TEXT("***************************************************"));
  15. _putts(TEXT("* Navicat Patcher by @DoubleLabyrinth *"));
  16. _putts(TEXT("* Version: 3.2 *"));
  17. _putts(TEXT("***************************************************"));
  18. _putts(TEXT(""));
  19. _putts(TEXT("Press Enter to continue or Ctrl + C to abort."));
  20. _gettchar();
  21. }
  22. static void Help() {
  23. _putts(TEXT("Usage:"));
  24. _putts(TEXT(" navicat-patcher.exe <Navicat Installation Path> [RSA-2048 PEM File Path]"));
  25. _putts(TEXT(""));
  26. _putts(TEXT(" <Navicat Installation Path> The folder path where Navicat is installed."));
  27. _putts(TEXT(" This parameter must be specified."));
  28. _putts(TEXT(""));
  29. _putts(TEXT(" [RSA-2048 PEM File Path] The path to an RSA-2048 private key file."));
  30. _putts(TEXT(" This parameter is optional."));
  31. _putts(TEXT(" If not specified, an RSA-2048 private key file"));
  32. _putts(TEXT(" named \"RegPrivateKey.pem\" will be generated."));
  33. _putts(TEXT(""));
  34. _putts(TEXT("Example:"));
  35. _putts(TEXT(" navicat-patcher.exe \"C:\\Program Files\\PremiumSoft\\Navicat Premium 12\""));
  36. }
  37. static void BackupFile(const TString& From, const TString& To) {
  38. if (::CopyFile(From.c_str(), To.c_str(), TRUE) == FALSE)
  39. throw SystemException(__BASE_FILE__, __LINE__, GetLastError(),
  40. TEXT("CopyFile failed."));
  41. }
  42. static void LoadKey(RSACipher* pCipher, PTSTR pKeyFileName,
  43. PatchSolution* pSolution0,
  44. PatchSolution* pSolution1,
  45. PatchSolution* pSolution2,
  46. PatchSolution* pSolution3) {
  47. if (pKeyFileName) {
  48. _tprintf_s(TEXT("[*] Import RSA-2048 key from file %s\n"), pKeyFileName);
  49. pCipher->ImportKeyFromFile<RSAKeyType::PrivateKey, RSAKeyFormat::PEM>(TStringEncode(pKeyFileName, CP_UTF8));
  50. if (pSolution0 && !pSolution0->CheckKey(pCipher) ||
  51. pSolution1 && !pSolution1->CheckKey(pCipher) ||
  52. pSolution2 && !pSolution2->CheckKey(pCipher) ||
  53. pSolution3 && !pSolution3->CheckKey(pCipher))
  54. throw Exception(__BASE_FILE__, __LINE__,
  55. TEXT("The RSA private key you provide cannot be used."));
  56. } else {
  57. _putts(TEXT("[*] Generating new RSA private key, it may take a long time."));
  58. do {
  59. pCipher->GenerateKey(2048);
  60. } while (pSolution0 && !pSolution0->CheckKey(pCipher) ||
  61. pSolution1 && !pSolution1->CheckKey(pCipher) ||
  62. pSolution2 && !pSolution2->CheckKey(pCipher) ||
  63. pSolution3 && !pSolution3->CheckKey(pCipher)); // re-generate RSA key if one of 'CheckKey's return false
  64. pCipher->ExportKeyToFile<RSAKeyType::PrivateKey, RSAKeyFormat::NotSpecified>("RegPrivateKey.pem");
  65. _putts(TEXT("[*] New RSA-2048 private key has been saved to RegPrivateKey.pem."));
  66. }
  67. std::string PublicKeyString = pCipher->ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
  68. _putts(TEXT("[*] Your RSA public key:"));
  69. printf_s("\n%s\n", PublicKeyString.c_str());
  70. }
  71. static void ExceptionReport(const Exception& e) noexcept {
  72. _tprintf_s(TEXT("[*] ERROR: %s\n"), e.Message().c_str());
  73. _tprintf_s(TEXT(" | - File: %s\n"), e.File().c_str());
  74. _tprintf_s(TEXT(" | - Line: %zu\n"), e.Line());
  75. if (e.HasErrorCode()) {
  76. _tprintf_s(TEXT(" | - ErrorCode: 0x%.8zx\n"), e.ErrorCode());
  77. _tprintf_s(TEXT(" | - ErrorString: %s\n"), e.ErrorString().c_str());
  78. }
  79. if (e.Hints().size() != 0) {
  80. _putts(TEXT(" | - Hints:"));
  81. for (auto& Hint : e.Hints())
  82. _tprintf_s(TEXT(" | %s\n"), Hint.c_str());
  83. }
  84. _putts(TEXT(""));
  85. }
  86. int _tmain(int argc, PTSTR argv[]) {
  87. if (argc != 2 && argc != 3) {
  88. Help();
  89. return 0;
  90. }
  91. Welcome();
  92. TString InstallationPath;
  93. TString MainExeName;
  94. TString LibccDllName;
  95. ResourceObject<CppObjectTraits<RSACipher>> pCipher;
  96. ResourceObject<CppObjectTraits<FileObject>> MainExe;
  97. ResourceObject<CppObjectTraits<FileMapViewObject>> MainExeMapper;
  98. ResourceObject<CppObjectTraits<FileObject>> LibccDll;
  99. ResourceObject<CppObjectTraits<FileMapViewObject>> LibccDllMapper;
  100. ResourceObject<CppObjectTraits<PatchSolution>> pSolution0;
  101. ResourceObject<CppObjectTraits<PatchSolution>> pSolution1;
  102. ResourceObject<CppObjectTraits<PatchSolution>> pSolution2;
  103. ResourceObject<CppObjectTraits<PatchSolution>> pSolution3;
  104. try {
  105. DWORD Attribute = GetFileAttributes(argv[1]);
  106. if (Attribute == INVALID_FILE_ATTRIBUTES)
  107. throw SystemException(__BASE_FILE__, __LINE__, GetLastError(),
  108. TEXT("GetFileAttributes failed."));
  109. if ((Attribute & FILE_ATTRIBUTE_DIRECTORY) == 0)
  110. throw Exception(__BASE_FILE__, __LINE__,
  111. TEXT("Path does not point to a directory."));
  112. InstallationPath = argv[1];
  113. if (InstallationPath.back() != TEXT('\\') && InstallationPath.back() != TEXT('/'))
  114. InstallationPath.push_back(TEXT('/')); // for Linux compatible
  115. } catch (Exception& e) {
  116. e.Hints().emplace_back(TEXT("Are you sure the path you specified is correct?"));
  117. e.Hints().emplace_back(TEXT("The path you specified:"));
  118. e.Hints().emplace_back(argv[1]);
  119. ExceptionReport(e);
  120. return -1;
  121. }
  122. pCipher.TakeOver(new RSACipher());
  123. // -----------------
  124. // Map files
  125. // -----------------
  126. do {
  127. try {
  128. _tprintf_s(TEXT("[*] Try to open libcc.dll ...... "));
  129. LibccDll.TakeOver(FileObject::Open<FileObject*>(InstallationPath + TEXT("libcc.dll"),
  130. GENERIC_READ | GENERIC_WRITE,
  131. FILE_SHARE_READ));
  132. LibccDllMapper.TakeOver(FileMapViewObject::Create<FileMapViewObject*>(LibccDll->GetHandle(),
  133. PAGE_READWRITE));
  134. LibccDllMapper->Map(FILE_MAP_READ | FILE_MAP_WRITE);
  135. LibccDllName = TEXT("libcc.dll");
  136. _tprintf_s(TEXT("Succeeded\n"));
  137. break;
  138. } catch (Exception& e) {
  139. if (e.HasErrorCode() && e.ErrorCode() == ERROR_FILE_NOT_FOUND) {
  140. _tprintf_s(TEXT("Not found\n"));
  141. LibccDllMapper.Release();
  142. LibccDll.Release();
  143. } else {
  144. _tprintf_s(TEXT("Failed\n"));
  145. if (e.HasErrorCode() && e.ErrorCode() == ERROR_ACCESS_DENIED)
  146. e.Hints().emplace_back(TEXT("Please re-run with Administrator privilege."));
  147. ExceptionReport(e);
  148. return -1;
  149. }
  150. }
  151. try {
  152. _tprintf_s(TEXT("[*] Try to open Navicat.exe ...... "));
  153. MainExe.TakeOver(FileObject::Open<FileObject*>(InstallationPath + TEXT("Navicat.exe"),
  154. GENERIC_READ | GENERIC_WRITE,
  155. FILE_SHARE_READ));
  156. MainExeMapper.TakeOver(FileMapViewObject::Create<FileMapViewObject*>(MainExe->GetHandle(),
  157. PAGE_READWRITE));
  158. MainExeMapper->Map(FILE_MAP_READ | FILE_MAP_WRITE);
  159. MainExeName = TEXT("Navicat.exe");
  160. _tprintf_s(TEXT("Succeeded\n"));
  161. break;
  162. } catch (Exception& e) {
  163. if (e.HasErrorCode() && e.ErrorCode() == ERROR_FILE_NOT_FOUND) {
  164. _tprintf_s(TEXT("Not found\n"));
  165. MainExeMapper.Release();
  166. MainExe.Release();
  167. } else {
  168. _tprintf_s(TEXT("Failed\n"));
  169. if (e.HasErrorCode() && e.ErrorCode() == ERROR_ACCESS_DENIED)
  170. e.Hints().emplace_back(TEXT("Please re-run with Administrator privilege."));
  171. ExceptionReport(e);
  172. return -1;
  173. }
  174. }
  175. try {
  176. _tprintf_s(TEXT("[*] Try to open Modeler.exe ...... "));
  177. MainExe.TakeOver(FileObject::Open<FileObject*>(InstallationPath + TEXT("Modeler.exe"),
  178. GENERIC_READ | GENERIC_WRITE,
  179. FILE_SHARE_READ));
  180. MainExeMapper.TakeOver(FileMapViewObject::Create<FileMapViewObject*>(MainExe->GetHandle(),
  181. PAGE_READWRITE));
  182. MainExeMapper->Map(FILE_MAP_READ | FILE_MAP_WRITE);
  183. MainExeName = TEXT("Modeler.exe");
  184. _tprintf_s(TEXT("Succeeded\n"));
  185. break;
  186. } catch (Exception& e) {
  187. if (e.HasErrorCode() && e.ErrorCode() == ERROR_FILE_NOT_FOUND) {
  188. _tprintf_s(TEXT("Not found\n"));
  189. MainExeMapper.Release();
  190. MainExe.Release();
  191. } else {
  192. _tprintf_s(TEXT("Failed\n"));
  193. if (e.HasErrorCode() && e.ErrorCode() == ERROR_ACCESS_DENIED)
  194. e.Hints().emplace_back(TEXT("Please re-run with Administrator privilege."));
  195. ExceptionReport(e);
  196. return -1;
  197. }
  198. }
  199. try {
  200. _tprintf_s(TEXT("[*] Try to open Rviewer.exe ...... "));
  201. MainExe.TakeOver(FileObject::Open<FileObject*>(InstallationPath + TEXT("Rviewer.exe"),
  202. GENERIC_READ | GENERIC_WRITE,
  203. FILE_SHARE_READ));
  204. MainExeMapper.TakeOver(FileMapViewObject::Create<FileMapViewObject*>(MainExe->GetHandle(),
  205. PAGE_READWRITE));
  206. MainExeMapper->Map(FILE_MAP_READ | FILE_MAP_WRITE);
  207. MainExeName = TEXT("Rviewer.exe");
  208. _tprintf_s(TEXT("Succeeded\n"));
  209. break;
  210. } catch (Exception& e) {
  211. if (e.HasErrorCode() && e.ErrorCode() == ERROR_FILE_NOT_FOUND) {
  212. _tprintf_s(TEXT("Not found\n"));
  213. MainExeMapper.Release();
  214. MainExe.Release();
  215. } else {
  216. _tprintf_s(TEXT("Failed\n"));
  217. if (e.HasErrorCode() && e.ErrorCode() == ERROR_ACCESS_DENIED)
  218. e.Hints().emplace_back(TEXT("Please re-run with Administrator privilege."));
  219. ExceptionReport(e);
  220. return -1;
  221. }
  222. }
  223. ExceptionReport(Exception(__BASE_FILE__, __LINE__,
  224. TEXT("None of target files has been found."),
  225. TEXT("Are you sure the path you specified is correct?"),
  226. TEXT("The path you specified:"),
  227. argv[1]));
  228. return -1;
  229. } while (false);
  230. // -----------
  231. // decide PatchSolutions
  232. // -----------
  233. if (MainExeMapper.IsValid()) {
  234. try {
  235. pSolution0.TakeOver(new PatchSolution0());
  236. pSolution0->SetFile(MainExeMapper->View<void>());
  237. if (pSolution0->FindPatchOffset() == false) {
  238. _putts(TEXT("[*] PatchSolution0 ...... Omitted"));
  239. pSolution0.Release();
  240. }
  241. } catch (Exception& e) {
  242. ExceptionReport(e);
  243. return -1;
  244. }
  245. } else {
  246. _putts(TEXT("[*] PatchSolution0 ...... Omitted"));
  247. }
  248. if (LibccDllMapper.IsValid()) {
  249. try {
  250. pSolution1.TakeOver(new PatchSolution1());
  251. pSolution2.TakeOver(new PatchSolution2());
  252. pSolution3.TakeOver(new PatchSolution3());
  253. pSolution1->SetFile(LibccDllMapper->View<void>());
  254. pSolution2->SetFile(LibccDllMapper->View<void>());
  255. pSolution3->SetFile(LibccDllMapper->View<void>());
  256. if (pSolution1->FindPatchOffset() == false) {
  257. _putts(TEXT("[*] PatchSolution1 ...... Omitted"));
  258. pSolution1.Release();
  259. }
  260. if (pSolution2->FindPatchOffset() == false) {
  261. _putts(TEXT("[*] PatchSolution2 ...... Omitted"));
  262. pSolution2.Release();
  263. }
  264. if (pSolution3->FindPatchOffset() == false) {
  265. _putts(TEXT("[*] PatchSolution3 ...... Omitted"));
  266. pSolution3.Release();
  267. }
  268. } catch (Exception& e) {
  269. ExceptionReport(e);
  270. return -1;
  271. }
  272. } else {
  273. _putts(TEXT("[*] PatchSolution1 ...... Omitted"));
  274. _putts(TEXT("[*] PatchSolution2 ...... Omitted"));
  275. _putts(TEXT("[*] PatchSolution3 ...... Omitted"));
  276. }
  277. if (pSolution0.IsValid() == false) {
  278. MainExeMapper.Release();
  279. MainExe.Release();
  280. }
  281. if (pSolution1.IsValid() == false && pSolution2.IsValid() == false && pSolution3.IsValid() == false) {
  282. LibccDllMapper.Release();
  283. LibccDll.Release();
  284. }
  285. if (pSolution0.IsValid() == false &&
  286. pSolution1.IsValid() == false &&
  287. pSolution2.IsValid() == false &&
  288. pSolution3.IsValid() == false)
  289. {
  290. ExceptionReport(Exception(__BASE_FILE__, __LINE__,
  291. TEXT("Cannot find Navicat official RSA public key."),
  292. TEXT("Are you sure your Navicat has not been patched/modified before?")));
  293. return -1;
  294. }
  295. // -------------
  296. // LoadKey
  297. // -------------
  298. try {
  299. LoadKey(pCipher,
  300. argc == 3 ? argv[2] : nullptr,
  301. pSolution0,
  302. pSolution1,
  303. pSolution2,
  304. pSolution3);
  305. } catch (Exception& e) {
  306. ExceptionReport(e);
  307. return -1;
  308. }
  309. // -------------
  310. // BackupFile
  311. // -------------
  312. try {
  313. if (MainExe.IsValid())
  314. BackupFile(InstallationPath + MainExeName,
  315. InstallationPath + MainExeName + TEXT(".backup"));
  316. } catch (Exception& e) {
  317. if (e.HasErrorCode() && e.ErrorCode() == ERROR_FILE_EXISTS) {
  318. e.Hints().emplace_back(TStringFormat(TEXT("The backup of %s has been found."),
  319. MainExeName.c_str()));
  320. e.Hints().emplace_back(TStringFormat(TEXT("Please remove %s.backup in Navicat installation folder if you're sure %s has not been patched."),
  321. MainExeName.c_str(),
  322. MainExeName.c_str()));
  323. e.Hints().emplace_back(TStringFormat(TEXT("Otherwise please restore %s by %s.backup and remove %s.backup then try again."),
  324. MainExeName.c_str(),
  325. MainExeName.c_str(),
  326. MainExeName.c_str()));
  327. }
  328. ExceptionReport(e);
  329. return -1;
  330. }
  331. try {
  332. if (LibccDll.IsValid())
  333. BackupFile(InstallationPath + LibccDllName,
  334. InstallationPath + LibccDllName + TEXT(".backup"));
  335. } catch (Exception& e) {
  336. if (e.HasErrorCode() && e.ErrorCode() == ERROR_FILE_EXISTS) {
  337. e.Hints().emplace_back(TStringFormat(TEXT("The backup of %s has been found."),
  338. LibccDllName.c_str()));
  339. e.Hints().emplace_back(TStringFormat(TEXT("Please remove %s.backup in Navicat installation folder if you're sure %s has not been patched."),
  340. LibccDllName.c_str(),
  341. LibccDllName.c_str()));
  342. e.Hints().emplace_back(TStringFormat(TEXT("Otherwise please restore %s by %s.backup and remove %s.backup then try again."),
  343. LibccDllName.c_str(),
  344. LibccDllName.c_str(),
  345. LibccDllName.c_str()));
  346. }
  347. ExceptionReport(e);
  348. return -1;
  349. }
  350. // -------------
  351. // MakePatch
  352. // -------------
  353. try {
  354. if (pSolution0.IsValid()) {
  355. pSolution0->MakePatch(pCipher);
  356. _putts(TEXT(""));
  357. }
  358. if (pSolution1.IsValid()) {
  359. pSolution1->MakePatch(pCipher);
  360. _putts(TEXT(""));
  361. }
  362. if (pSolution2.IsValid()) {
  363. pSolution2->MakePatch(pCipher);
  364. _putts(TEXT(""));
  365. }
  366. if (pSolution3.IsValid()) {
  367. pSolution3->MakePatch(pCipher);
  368. _putts(TEXT(""));
  369. }
  370. } catch (Exception& e) {
  371. ExceptionReport(e);
  372. return -1;
  373. }
  374. _putts(TEXT("[*] Patch has been done successfully."));
  375. _putts(TEXT("[*] Have fun and enjoy~"));
  376. return 0;
  377. }