Solution1.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. #include "def.hpp"
  2. // Solution1 is for navicat premium of which the version = 12.0.25
  3. namespace patcher::Solution1 {
  4. static BOOL CheckRSAKeyIsAppropriate(RSA* PrivateKey) {
  5. char* pem_pubkey = GetPEMText(PrivateKey);
  6. if (pem_pubkey == nullptr)
  7. return FALSE;
  8. std::string encrypted_pem_text = EncryptPublicKey(pem_pubkey, strlen(pem_pubkey));
  9. delete[] pem_pubkey;
  10. if (encrypted_pem_text[160] > '9' || encrypted_pem_text[160] < '1')
  11. return FALSE;
  12. for (int i = 1; i < 8; ++i)
  13. if (encrypted_pem_text[160 + i] > '9' || encrypted_pem_text[160 + i] < '0')
  14. return FALSE;
  15. if (encrypted_pem_text[910] > '9' || encrypted_pem_text[910] < '1')
  16. return FALSE;
  17. for (int i = 1; i < 5; ++i)
  18. if (encrypted_pem_text[910 + i] > '9' || encrypted_pem_text[910 + i] < '0')
  19. return FALSE;
  20. return TRUE;
  21. }
  22. static RSA* GenerateAppropriateRSAKey() {
  23. while (true) {
  24. RSA* Key = GenerateRSAKey();
  25. if (Key == nullptr)
  26. return nullptr;
  27. if (CheckRSAKeyIsAppropriate(Key)) {
  28. return Key;
  29. } else {
  30. RSA_free(Key);
  31. }
  32. }
  33. }
  34. static BOOL FindPatchOffset(LPCTSTR libcc_dll_path, DWORD Offset[5]) {
  35. Offset[0] = 0;
  36. Offset[1] = 0;
  37. Offset[2] = 0;
  38. Offset[3] = 0;
  39. Offset[4] = 0;
  40. HANDLE h_libcc = CreateFile(libcc_dll_path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  41. if (h_libcc == INVALID_HANDLE_VALUE) {
  42. _tprintf_s(TEXT("Failed to open libcc.dll. CODE: 0x%08x @[FindPatchOffset -> CreateFile]\r\n"), GetLastError());
  43. return FALSE;
  44. }
  45. // DWORD is enough, you know libcc.dll cannot be larger than 4GB
  46. DWORD libcc_size = GetFileSize(h_libcc, nullptr);
  47. HANDLE h_libcc_map = CreateFileMapping(h_libcc, nullptr, PAGE_READONLY, 0, 0, nullptr);
  48. if (h_libcc_map == NULL) {
  49. _tprintf_s(TEXT("Failed to create mapping for libcc.dll. CODE: 0x%08x @[FindPatchOffset -> CreateFileMapping]\r\n"), GetLastError());
  50. CloseHandle(h_libcc);
  51. return FALSE;
  52. }
  53. const uint8_t* libcc = reinterpret_cast<const uint8_t*>(MapViewOfFile(h_libcc_map, FILE_MAP_READ, 0, 0, 0));
  54. if (libcc == nullptr) {
  55. _tprintf_s(TEXT("Failed to map libcc.dll. CODE: 0x%08x @[FindPatchOffset -> MapViewOfFile]\r\n"), GetLastError());
  56. CloseHandle(h_libcc_map);
  57. CloseHandle(h_libcc);
  58. return FALSE;
  59. }
  60. const IMAGE_DOS_HEADER* libcc_dos_header = reinterpret_cast<const IMAGE_DOS_HEADER*>(libcc);
  61. // check dos signature
  62. if (libcc_dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
  63. _tprintf_s(TEXT("libcc.dll does not have a valid DOS header. @[FindPatchOffset]\r\n"));
  64. UnmapViewOfFile(libcc);
  65. CloseHandle(h_libcc_map);
  66. CloseHandle(h_libcc);
  67. return FALSE;
  68. }
  69. const IMAGE_NT_HEADERS* libcc_nt_header = reinterpret_cast<const IMAGE_NT_HEADERS*>(libcc + libcc_dos_header->e_lfanew);
  70. // check nt signature
  71. if (libcc_nt_header->Signature != IMAGE_NT_SIGNATURE) {
  72. _tprintf_s(TEXT("libcc.dll does not have a valid NT header. @[FindPatchOffset]\r\n"));
  73. UnmapViewOfFile(libcc);
  74. CloseHandle(h_libcc_map);
  75. CloseHandle(h_libcc);
  76. return FALSE;
  77. }
  78. // check if a dll
  79. if ((libcc_nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) {
  80. _tprintf_s(TEXT("libcc.dll is not a DLL file. @[FindPatchOffset]\r\n"));
  81. UnmapViewOfFile(libcc);
  82. CloseHandle(h_libcc_map);
  83. CloseHandle(h_libcc);
  84. return FALSE;
  85. }
  86. // check if 32-bits or 64-bits
  87. #if defined(_M_X64)
  88. if (libcc_nt_header->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 || libcc_nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  89. _tprintf_s(TEXT("libcc.dll is not a 64-bits DLL file. @[FindPatchOffset]\r\n"));
  90. #elif defined(_M_IX86)
  91. if (libcc_nt_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386 || libcc_nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  92. #else
  93. #error "unknown arch"
  94. #endif
  95. _tprintf_s(TEXT("libcc.dll is not a 32-bits DLL file. @[FindPatchOffset]\r\n"));
  96. UnmapViewOfFile(libcc);
  97. CloseHandle(h_libcc_map);
  98. CloseHandle(h_libcc);
  99. return FALSE;
  100. }
  101. WORD section_num = libcc_nt_header->FileHeader.NumberOfSections;
  102. const IMAGE_SECTION_HEADER* libcc_section_headers = reinterpret_cast<const IMAGE_SECTION_HEADER*>(
  103. libcc + libcc_dos_header->e_lfanew + sizeof(libcc_nt_header->Signature) + sizeof(libcc_nt_header->FileHeader) + libcc_nt_header->FileHeader.SizeOfOptionalHeader
  104. );
  105. const IMAGE_SECTION_HEADER* rdata_section = nullptr;
  106. for (WORD i = 0; i < section_num; ++i) {
  107. if (*reinterpret_cast<const uint64_t*>(libcc_section_headers[i].Name) == 0x61746164722e) { // b'\x00\x00atadr.'
  108. rdata_section = libcc_section_headers + i;
  109. break;
  110. }
  111. }
  112. if (rdata_section == nullptr) {
  113. _tprintf_s(TEXT(".rdata section is not found. @[FindPatchOffset]\r\n"));
  114. UnmapViewOfFile(libcc);
  115. CloseHandle(h_libcc_map);
  116. CloseHandle(h_libcc);
  117. return FALSE;
  118. }
  119. const IMAGE_SECTION_HEADER* text_section = nullptr;
  120. for (WORD i = 0; i < section_num; ++i) {
  121. if (*reinterpret_cast<const uint64_t*>(libcc_section_headers[i].Name) == 0x747865742e) { // b'\x00\x00\x00txet.'
  122. text_section = libcc_section_headers + i;
  123. break;
  124. }
  125. }
  126. if (text_section == nullptr) {
  127. _tprintf_s(TEXT(".text section is not found. @[FindPatchOffset]\r\n"));
  128. UnmapViewOfFile(libcc);
  129. CloseHandle(h_libcc_map);
  130. CloseHandle(h_libcc);
  131. return FALSE;
  132. }
  133. // search offset[0]
  134. {
  135. const uint8_t keyword[] = "D75125B70767B94145B47C1CB3C0755E";
  136. const uint8_t* start = libcc + rdata_section->PointerToRawData;
  137. DWORD section_size = rdata_section->SizeOfRawData;
  138. for (DWORD i = 0; i < section_size; ++i) {
  139. if (start[i] == keyword[0]) {
  140. bool found = true;
  141. for (DWORD j = 1; j < sizeof(keyword) - 1; ++j)
  142. if (start[i + j] != keyword[j]) {
  143. found = false;
  144. break;
  145. }
  146. if (found) {
  147. Offset[0] = rdata_section->PointerToRawData + i;
  148. break;
  149. }
  150. }
  151. }
  152. }
  153. // search offset[2]
  154. {
  155. const uint8_t keyword[] = "E1CED09B9C2186BF71A70C0FE2F1E0AE";
  156. const uint8_t* start = libcc + rdata_section->PointerToRawData;
  157. DWORD section_size = rdata_section->SizeOfRawData;
  158. for (DWORD i = 0; i < section_size; ++i) {
  159. if (start[i] == keyword[0]) {
  160. bool found = true;
  161. for (DWORD j = 1; j < sizeof(keyword) - 1; ++j)
  162. if (start[i + j] != keyword[j]) {
  163. found = false;
  164. break;
  165. }
  166. if (found) {
  167. Offset[2] = rdata_section->PointerToRawData + i;
  168. break;
  169. }
  170. }
  171. }
  172. }
  173. // search offset[4]
  174. {
  175. const uint8_t keyword[] = "92933";
  176. const uint8_t* start = libcc + rdata_section->PointerToRawData;
  177. DWORD section_size = rdata_section->SizeOfRawData;
  178. for (DWORD i = 0; i < section_size; ++i) {
  179. if (start[i] == keyword[0]) {
  180. bool found = true;
  181. for (DWORD j = 1; j < sizeof(keyword) - 1; ++j)
  182. if (start[i + j] != keyword[j]) {
  183. found = false;
  184. break;
  185. }
  186. if (found) {
  187. Offset[4] = rdata_section->PointerToRawData + i;
  188. break;
  189. }
  190. }
  191. }
  192. }
  193. // search offset[1]
  194. {
  195. const uint8_t keyword[] = { 0xfe, 0xea, 0xbc, 0x01 };
  196. const uint8_t* start = libcc + text_section->PointerToRawData;
  197. DWORD section_size = text_section->SizeOfRawData;
  198. for (DWORD i = 0; i < section_size; ++i) {
  199. if (start[i] == keyword[0]) {
  200. bool found = true;
  201. for (DWORD j = 1; j < sizeof(keyword); ++j)
  202. if (start[i + j] != keyword[j]) {
  203. found = false;
  204. break;
  205. }
  206. if (found) {
  207. Offset[1] = text_section->PointerToRawData + i;
  208. break;
  209. }
  210. }
  211. }
  212. }
  213. // search offset[3]
  214. {
  215. const uint8_t keyword[] = { 0x59, 0x08, 0x01, 0x00 };
  216. const uint8_t* start = libcc + text_section->PointerToRawData;
  217. DWORD section_size = text_section->SizeOfRawData;
  218. for (DWORD i = 0; i < section_size; ++i) {
  219. if (start[i] == keyword[0]) {
  220. bool found = true;
  221. for (DWORD j = 1; j < sizeof(keyword); ++j)
  222. if (start[i + j] != keyword[j]) {
  223. found = false;
  224. break;
  225. }
  226. if (found) {
  227. Offset[3] = text_section->PointerToRawData + i;
  228. break;
  229. }
  230. }
  231. }
  232. }
  233. UnmapViewOfFile(libcc);
  234. CloseHandle(h_libcc_map);
  235. CloseHandle(h_libcc);
  236. if (Offset[0] == 0 || Offset[1] == 0 || Offset[2] == 0 || Offset[3] == 0 || Offset[4] == 0) {
  237. _tprintf_s(TEXT("Failed to find all patch offset. Is libcc.dll from official? Or you've patched?\r\n"));
  238. return FALSE;
  239. } else {
  240. return TRUE;
  241. }
  242. }
  243. BOOL Do(LPCTSTR libcc_dll_path, LPCTSTR prepared_key_file) {
  244. // uint8_t expected_hash[SHA256_DIGEST_LENGTH] = {
  245. // 0x60, 0x7e, 0x0a, 0x84, 0xc7, 0x59, 0x66, 0xb0,
  246. // 0x0f, 0x3d, 0x12, 0xfa, 0x83, 0x3e, 0x91, 0xd1,
  247. // 0x59, 0xe4, 0xf5, 0x1a, 0xc5, 0x1b, 0x6b, 0xa6,
  248. // 0x6f, 0x98, 0xd0, 0xc3, 0xcb, 0xef, 0xdc, 0xe0
  249. // };
  250. //
  251. // if (!Check_libcc_Hash(libcc_dll_path, expected_hash))
  252. // return FALSE;
  253. DWORD Patch_Offset[5];
  254. if (!FindPatchOffset(libcc_dll_path, Patch_Offset))
  255. return FALSE;
  256. if (!BackupFile(libcc_dll_path))
  257. return FALSE;
  258. RSA* PrivateKey = nullptr;
  259. if (prepared_key_file != nullptr) {
  260. PrivateKey = ReadRSAPrivateKeyFromFile(prepared_key_file);
  261. if (PrivateKey == nullptr)
  262. return FALSE;
  263. if (!CheckRSAKeyIsAppropriate(PrivateKey)) {
  264. _tprintf_s(TEXT("The key is not appropriate to use. @[patcher::Solution1::Do -> CheckRSAKeyIsAppropriate]\r\n"));
  265. RSA_free(PrivateKey);
  266. return FALSE;
  267. }
  268. } else {
  269. PrivateKey = GenerateAppropriateRSAKey();
  270. if (PrivateKey == nullptr)
  271. return FALSE;
  272. if (!WriteRSAPrivateKeyToFile(TEXT("RegPrivateKey.pem"), PrivateKey)) {
  273. RSA_free(PrivateKey);
  274. return FALSE;
  275. }
  276. }
  277. char* pem_pubkey = GetPEMText(PrivateKey);
  278. if (pem_pubkey == nullptr)
  279. return FALSE;
  280. std::string encrypted_pem_pubkey = EncryptPublicKey(pem_pubkey, strlen(pem_pubkey));
  281. delete[] pem_pubkey; // we do not need it anymore
  282. RSA_free(PrivateKey); // we do not need it anymore
  283. // split encrypted_pem_pubkey to 5 part: |160 chars|8 chars|742 chars|5 chars|5 chars|
  284. // | |
  285. // \ / \ /
  286. // imm1 imm3
  287. std::string encrypted_pem_pubkey0(encrypted_pem_pubkey.begin(), encrypted_pem_pubkey.begin() + 160);
  288. std::string encrypted_pem_pubkey1(encrypted_pem_pubkey.begin() + 160, encrypted_pem_pubkey.begin() + 160 + 8);
  289. std::string encrypted_pem_pubkey2(encrypted_pem_pubkey.begin() + 160 + 8, encrypted_pem_pubkey.begin() + 160 + 8 + 742);
  290. std::string encrypted_pem_pubkey3(encrypted_pem_pubkey.begin() + 160 + 8 + 742, encrypted_pem_pubkey.begin() + 160 + 8 + 742 + 5);
  291. std::string encrypted_pem_pubkey4(encrypted_pem_pubkey.begin() + 160 + 8 + 742 + 5, encrypted_pem_pubkey.end());
  292. uint32_t imm1 = std::stoul(encrypted_pem_pubkey1.c_str());
  293. uint32_t imm3 = std::stoul(encrypted_pem_pubkey3.c_str());
  294. HANDLE hFile = CreateFile(libcc_dll_path, GENERIC_WRITE, NULL, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  295. if (hFile == INVALID_HANDLE_VALUE) {
  296. _tprintf_s(TEXT("Failed to open libcc.dll. CODE: 0x%08x @[patcher::Solution1::Do -> CreateFile]\r\n"), GetLastError());
  297. return FALSE;
  298. }
  299. // Start from win8, lpNumberOfBytesWritten parameter in WriteFile can be null if lpOverlapped is null.
  300. // But win7 is not. lpNumberOfBytesWritten cannot be null if lpOverlapped is null.
  301. // However MSDN does not mention that.
  302. DWORD WrittenBytes;
  303. // start patch 0
  304. _tprintf_s(TEXT("\r\nStart to do patch 0......\r\n"));
  305. if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[0], nullptr, FILE_BEGIN)) {
  306. _tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
  307. CloseHandle(hFile);
  308. return FALSE;
  309. }
  310. _tprintf_s(TEXT("At offset +0x%08x, write:\r\n\"%hs\"\r\n"), Patch_Offset[0], encrypted_pem_pubkey0.c_str());
  311. if (FALSE == WriteFile(hFile, encrypted_pem_pubkey0.c_str(), encrypted_pem_pubkey0.length(), &WrittenBytes, nullptr)) {
  312. _tprintf_s(TEXT("Failed to write patch 0. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
  313. CloseHandle(hFile);
  314. return FALSE;
  315. }
  316. _tprintf_s(TEXT("patch 0 done.....\r\n"));
  317. // start patch 1
  318. _tprintf_s(TEXT("\r\nStart to do patch 1.....\r\n"));
  319. if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[1], nullptr, FILE_BEGIN)) {
  320. _tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
  321. CloseHandle(hFile);
  322. return FALSE;
  323. }
  324. _tprintf_s(TEXT("At offset +0x%08x, write immediate value %d (type: uint32_t)\r\n"), Patch_Offset[1], imm1);
  325. if (FALSE == WriteFile(hFile, &imm1, sizeof(imm1), &WrittenBytes, nullptr)) {
  326. _tprintf_s(TEXT("Failed to write patch 1. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
  327. CloseHandle(hFile);
  328. return FALSE;
  329. }
  330. _tprintf_s(TEXT("patch 1 done.....\r\n"));
  331. // start patch 2
  332. _tprintf_s(TEXT("\r\nStart to do patch 2.....\r\n"));
  333. if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[2], nullptr, FILE_BEGIN)) {
  334. _tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
  335. CloseHandle(hFile);
  336. return FALSE;
  337. }
  338. _tprintf_s(TEXT("At offset +0x%08x, write:\r\n\"%hs\"\r\n"), Patch_Offset[2], encrypted_pem_pubkey2.c_str());
  339. if (FALSE == WriteFile(hFile, encrypted_pem_pubkey2.c_str(), encrypted_pem_pubkey2.length(), &WrittenBytes, nullptr)) {
  340. _tprintf_s(TEXT("Failed to write patch 2. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
  341. CloseHandle(hFile);
  342. return FALSE;
  343. }
  344. _tprintf_s(TEXT("patch 2 done.....\r\n"));
  345. // start patch 3
  346. _tprintf_s(TEXT("\r\nStart to do patch 3.....\r\n"));
  347. if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[3], nullptr, FILE_BEGIN)) {
  348. _tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
  349. CloseHandle(hFile);
  350. return FALSE;
  351. }
  352. _tprintf_s(TEXT("At offset +0x%08x, write immediate value %d (type: uint32_t)\r\n"), Patch_Offset[3], imm3);
  353. if (FALSE == WriteFile(hFile, &imm3, sizeof(imm3), &WrittenBytes, nullptr)) {
  354. _tprintf_s(TEXT("Failed to write patch 3. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
  355. CloseHandle(hFile);
  356. return FALSE;
  357. }
  358. _tprintf_s(TEXT("patch 3 done.....\r\n"));
  359. // start patch 4
  360. _tprintf_s(TEXT("\r\nStart to do patch 4.....\r\n"));
  361. if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[4], nullptr, FILE_BEGIN)) {
  362. _tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
  363. CloseHandle(hFile);
  364. return FALSE;
  365. }
  366. _tprintf_s(TEXT("At offset +0x%08x, write:\r\n\"%hs\"\r\n"), Patch_Offset[4], encrypted_pem_pubkey4.c_str());
  367. if (FALSE == WriteFile(hFile, encrypted_pem_pubkey4.c_str(), encrypted_pem_pubkey4.length(), &WrittenBytes, nullptr)) {
  368. _tprintf_s(TEXT("Failed to write patch 4. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
  369. CloseHandle(hFile);
  370. return FALSE;
  371. }
  372. _tprintf_s(TEXT("patch 4 done.....\r\n\r\n"));
  373. return TRUE;
  374. }
  375. }