123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- #include <errno.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #include <stdio.h>
- #include "Exception.hpp"
- #include "ExceptionSystem.hpp"
- #include "ResourceWrapper.hpp"
- #include "ResourceTraitsUnix.hpp"
- #include "Elf64Interpreter.hpp"
- #include "PatchSolutions.hpp"
- #include "Misc.hpp"
- static void Welcome(bool bWait) {
- puts("**********************************************************");
- puts("* Navicat Patcher (Linux) by @DoubleLabyrinth *");
- puts("* Version: 1.0 *");
- puts("**********************************************************");
- puts("");
- if (bWait) {
- puts("Press ENTER to continue or Ctrl + C to abort.");
- getchar();
- }
- }
- static void Help() {
- puts("Usage:");
- puts(" navicat-patcher [--dry-run] <Navicat installation path> [RSA-2048 Private Key File]");
- puts("");
- puts(" [--dry-run] Run patcher without applying any patches.");
- puts(" This parameter is optional.");
- puts("");
- puts(" <Navicat installation path> Path to directory where Navicat is installed.");
- puts(" This parameter must be specified.");
- puts("");
- puts(" [RSA-2048 Private Key File] Path to a PEM-format RSA-2048 private key file.");
- puts(" This parameter is optional.");
- puts("");
- }
- static bool ParseCommandLine(int argc, char* argv[], bool& bDryrun, std::string& szInstallPath, std::string& szKeyFilePath) {
- if (argc == 2) {
- bDryrun = false;
- szInstallPath = argv[1];
- szKeyFilePath.clear();
- return true;
- } else if (argc == 3) {
- if (strcasecmp(argv[1], "--dry-run") == 0) {
- bDryrun = true;
- szInstallPath = argv[2];
- szKeyFilePath.clear();
- return true;
- } else {
- bDryrun = false;
- szInstallPath = argv[1];
- szKeyFilePath = argv[2];
- return true;
- }
- } else if (argc == 4) {
- if (strcasecmp(argv[1], "--dry-run") == 0) {
- bDryrun = true;
- szInstallPath = argv[2];
- szKeyFilePath = argv[3];
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
- static void SelectPatchSolutions(ARL::ResourceWrapper<ARL::ResourceTraits::CppObject<nkg::PatchSolution>>& lpSolution0) {
- // pass
- }
- static void NavicatBackupDetect(std::string_view szFilePath) {
- std::string szBackupPath(szFilePath);
- szBackupPath += ".bak";
- if (nkg::Misc::FsIsExist(szBackupPath) == true) {
- while (true) {
- printf("[?] Previous backup %s is detected. Delete? (y/n)", szBackupPath.c_str());
- auto select = getchar();
- while (select != '\n' && getchar() != '\n') {}
- if (select == 'Y' || select == 'y') {
- nkg::Misc::FsDeleteFile(szBackupPath);
- break;
- } else if (select == 'N' || select == 'n') {
- throw ARL::Exception(__BASE_FILE__, __LINE__, "Backup file still existed. Patch abort!");
- } else {
- continue;
- }
- }
- printf("\n");
- }
- }
- static void NavicatBackupMake(std::string_view szFilePath) {
- std::string szBackupPath(szFilePath);
- szBackupPath += ".bak";
- nkg::Misc::FsCopyFile(szFilePath, szBackupPath);
- }
- static void LoadKey(nkg::RSACipher& Cipher,
- std::string_view szKeyFileName,
- nkg::PatchSolution* lpSolution0) {
- if (szKeyFileName.empty() == false) {
- printf("[*] Import RSA-2048 key from %s\n", szKeyFileName.data());
- Cipher.ImportKeyFromFile<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>(szKeyFileName);
- if (lpSolution0 && lpSolution0->CheckKey(Cipher) == false) {
- throw ARL::Exception(__BASE_FILE__, __LINE__, "The RSA private key you provide cannot be used.");
- }
- } else {
- printf("[*] Generating new RSA private key, it may take a long time...\n");
- do {
- Cipher.GenerateKey(2048);
- } while (lpSolution0 && lpSolution0->CheckKey(Cipher) == false); // re-generate RSA key if CheckKey return false
- }
- printf("[*] Your RSA private key:\n");
- printf(" %s\n",
- [&Cipher]() -> std::string {
- auto szPrivateKey = Cipher.ExportKeyString<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>();
- for (size_t pos = 0; (pos = szPrivateKey.find('\n', pos)) != std::string::npos; pos += strlen("\n ")) {
- szPrivateKey.replace(pos, 1, "\n ");
- }
- return szPrivateKey;
- }().c_str()
- );
- printf("[*] Your RSA public key:\n");
- printf(" %s\n",
- [&Cipher]() -> std::string {
- auto szPublicKey = Cipher.ExportKeyString<nkg::RSAKeyType::PublicKey, nkg::RSAKeyFormat::PEM>();
- for (size_t pos = 0; (pos = szPublicKey.find('\n', pos)) != std::string::npos; pos += strlen("\n ")) {
- szPublicKey.replace(pos, 1, "\n ");
- }
- return szPublicKey;
- }().c_str()
- );
- //printf("%s\n", Cipher.ExportKeyString<nkg::RSAKeyType::PublicKey, nkg::RSAKeyFormat::PEM>().c_str());
- printf("\n");
- }
- int main(int argc, char* argv[]) {
- bool bDryrun;
- std::string szInstallPath;
- std::string szKeyFilePath;
- if (ParseCommandLine(argc, argv, bDryrun, szInstallPath, szKeyFilePath) == false) {
- Welcome(false);
- Help();
- return -1;
- } else {
- Welcome(true);
- try {
- if (nkg::Misc::FsIsDirectory(szInstallPath) == false) {
- throw ARL::Exception(__BASE_FILE__, __LINE__, "Navicat installation path doesn't point to a directory.")
- .PushHint("Are you sure the path you specified is correct?")
- .PushFormatHint("The path you specified: %s", szInstallPath.c_str());
- }
- if (szKeyFilePath.empty() == false && nkg::Misc::FsIsFile(szKeyFilePath) == false) {
- throw ARL::Exception(__BASE_FILE__, __LINE__, "RSA key file path doesn't point to a file.")
- .PushHint("Are you sure the path you specified is correct?")
- .PushFormatHint("The path you specified: %s", szKeyFilePath.c_str());
- }
- while (szInstallPath.back() == '/') {
- szInstallPath.pop_back();
- }
- nkg::RSACipher Cipher;
- ARL::ResourceWrapper<ARL::ResourceTraits::CppObject<nkg::PatchSolution>> lpSolution0;
- std::string libcc_path;
- ARL::ResourceWrapper libcc_fd{ ARL::ResourceTraits::FileDescriptor{} };
- ARL::ResourceWrapper libcc_stat{ ARL::ResourceTraits::CppObject<struct stat>{} };
- ARL::ResourceWrapperEx libcc_mmap{ ARL::ResourceTraits::MapView{}, [&libcc_stat](void* p) {
- if (munmap(p, libcc_stat->st_size) < 0) {
- throw ARL::SystemError(__BASE_FILE__, __LINE__, errno, "munmap failed.");
- }
- } };
- ARL::ResourceWrapper libcc_interpreter{ ARL::ResourceTraits::CppObject<nkg::Elf64Interpreter>{} };
- //
- // try open libcc.so
- //
- libcc_path = szInstallPath + "/usr/lib/libcc.so";
- libcc_fd.TakeOver(open(libcc_path.c_str(), O_RDWR));
- if (libcc_fd.IsValid()) {
- printf("[+] Try to open libcc.so ... Ok!\n");
- } else {
- if (errno == ENOENT) {
- printf("[-] Try to open libcc.so ... Not found!\n");
- } else {
- throw ARL::SystemError(__BASE_FILE__, __LINE__, errno, "open failed.");
- }
- }
- puts("");
- //
- // try map libcc.so
- //
- if (libcc_fd.IsValid()) {
- libcc_stat.TakeOver(new struct stat());
- if (fstat(libcc_fd, libcc_stat) != 0) {
- throw ARL::SystemError(__BASE_FILE__, __LINE__, errno, "fstat failed.");
- }
- libcc_mmap.TakeOver(mmap(nullptr, libcc_stat->st_size, PROT_READ | PROT_WRITE, MAP_SHARED, libcc_fd, 0));
- if (libcc_mmap.IsValid() == false) {
- throw ARL::SystemError(__BASE_FILE__, __LINE__, errno, "mmap failed.");
- }
- libcc_interpreter.TakeOver(
- new nkg::Elf64Interpreter(nkg::Elf64Interpreter::Parse(libcc_mmap, libcc_stat->st_size))
- );
- lpSolution0.TakeOver(
- new nkg::PatchSolution0(*libcc_interpreter.Get())
- );
- }
- //
- // Make sure that there is one patch solution at least existing.
- //
- if (lpSolution0.IsValid() == false) {
- throw ARL::Exception(__BASE_FILE__, __LINE__, "No patch applied. Patch abort!")
- .PushHint("Are you sure your Navicat has not been patched/modified before?");
- }
- //
- // Finding patch offsets
- //
- if (lpSolution0.IsValid() && lpSolution0->FindPatchOffset() == false) {
- lpSolution0.Release();
- }
- printf("\n");
- //
- // decide which solutions will be applied
- //
- SelectPatchSolutions(lpSolution0);
- //
- // Make sure that there is one patch solution at least existing.
- //
- if (lpSolution0.IsValid() == false) {
- throw ARL::Exception(__BASE_FILE__, __LINE__, "No patch applied. Patch abort!")
- .PushHint("Are you sure your Navicat has not been patched/modified before?");
- }
-
- //
- // detecting backups
- //
- if (lpSolution0.IsValid()) {
- NavicatBackupDetect(libcc_path);
- }
- //
- //
- //
- LoadKey(Cipher, szKeyFilePath, lpSolution0);
- if (bDryrun == false) {
- //
- // Save private key if not given
- //
- if (szKeyFilePath.empty()) {
- Cipher.ExportKeyToFile<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>("RegPrivateKey.pem");
- }
- //
- // Making backups
- //
- if (lpSolution0.IsValid()) {
- NavicatBackupMake(libcc_path);
- }
- //
- // Making patch. No way to go back here :-)
- //
- if (lpSolution0.IsValid()) {
- lpSolution0->MakePatch(Cipher);
- }
-
- if (szKeyFilePath.empty()) {
- printf("[*] New RSA-2048 private key has been saved to\n");
- printf(" %s/RegPrivateKey.pem\n", nkg::Misc::FsCurrentWorkingDirectory().c_str());
- printf("\n");
- }
-
- puts("*******************************************************");
- puts("* PATCH HAS BEEN DONE SUCCESSFULLY! *");
- puts("* HAVE FUN AND ENJOY~ *");
- puts("*******************************************************");
- } else {
- puts("*******************************************************");
- puts("* DRY-RUN MODE ENABLE! *");
- puts("* NO PATCH WILL BE APPLIED! *");
- puts("*******************************************************");
- }
- return 0;
- } catch (ARL::Exception& e) {
- printf("[-] %s:%zu ->\n", e.ExceptionFile(), e.ExceptionLine());
- printf(" %s\n", e.ExceptionMessage());
- if (e.HasErrorCode()) {
- printf(" %s (0x%zx)\n", e.ErrorString(), e.ErrorCode());
- }
- for (const auto& Hint : e.Hints()) {
- printf(" Hints: %s\n", Hint.c_str());
- }
- return -1;
- }
- }
- }
|