PatchSolution2.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #include "PatchSolution.hpp"
  2. #include "Exception.hpp"
  3. #include "Helper.hpp"
  4. #include <tchar.h>
  5. #undef __BASE_FILE__
  6. #define __BASE_FILE__ TEXT("PatchSolution2.cpp")
  7. const char PatchSolution2::KeywordsMeta[0x188 + 1] =
  8. "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I"
  9. "qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv"
  10. "a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF"
  11. "R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2"
  12. "WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt"
  13. "YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ"
  14. "awIDAQAB";
  15. uint8_t PatchSolution2::Keywords[0x188][5];
  16. PatchSolution2::PatchSolution2() {
  17. for (size_t i = 0; i < 0x188; ++i)
  18. _PatchOffsets[i] = -1;
  19. }
  20. void PatchSolution2::SetFile(void* pFile) {
  21. if (!_LibccDllInterpreter.ParseImage(pFile, true)) {
  22. throw Exception(__BASE_FILE__, __LINE__,
  23. TEXT("Invalid PE file."));
  24. }
  25. }
  26. #if defined(_M_X64)
  27. void PatchSolution2::BuildKeywords() noexcept {
  28. for (size_t i = 0; i < 0x188; ++i) {
  29. Keywords[i][0] = 0x83; // Keywords[i] = asm('xor eax, KeywordsMeta[i]') +
  30. Keywords[i][1] = 0xf0;
  31. Keywords[i][2] = KeywordsMeta[i];
  32. Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxxxxxxxxxx, al')
  33. Keywords[i][4] = 0x05;
  34. }
  35. }
  36. bool PatchSolution2::FindPatchOffset() noexcept {
  37. PIMAGE_SECTION_HEADER ptextSectionHeader = _LibccDllInterpreter.GetSectionHeader(".text");
  38. uint8_t* ptextSection = _LibccDllInterpreter.GetSectionView<uint8_t>(".text");
  39. off_t Offsets[0x188];
  40. for (size_t i = 0; i < 0x188; ++i)
  41. Offsets[i] = -1;
  42. if (ptextSectionHeader == nullptr)
  43. return false;
  44. if (ptextSection == nullptr)
  45. return false;
  46. BuildKeywords();
  47. // Find offsets
  48. {
  49. size_t FirstKeywordCounter = 0;
  50. uint32_t Hints[9];
  51. DWORD PossibleRangeStart = 0xffffffff;
  52. DWORD PossibleRangeEnd;
  53. for (DWORD i = 0; i < ptextSectionHeader->SizeOfRawData; ++i) {
  54. if (memcmp(ptextSection + i, Keywords[0], sizeof(Keywords[0])) == 0) {
  55. Hints[FirstKeywordCounter++] =
  56. *reinterpret_cast<uint32_t*>(ptextSection + i + sizeof(Keywords[0])) +
  57. i + sizeof(Keywords[0]) + sizeof(uint32_t);
  58. if (i < PossibleRangeStart)
  59. PossibleRangeStart = i;
  60. }
  61. }
  62. PossibleRangeStart -= 0x1000;
  63. PossibleRangeEnd = PossibleRangeStart + 0x100000;
  64. // Keywords[0] should occur 9 times.
  65. // Because there's only 9 'M' chars in `KeywordsMeta`.
  66. if (FirstKeywordCounter != 9)
  67. return false;
  68. Helper::QuickSort(Hints, 0, _countof(Hints));
  69. // assert
  70. // if not satisfied, refuse to patch
  71. if (Hints[8] - Hints[0] != 0x18360F8F8 - 0x18360F7D0)
  72. return false;
  73. for (size_t i = 0; i < 0x188; ++i) {
  74. if (Offsets[i] != -1)
  75. continue;
  76. for (DWORD j = PossibleRangeStart; j < PossibleRangeEnd; ++j) {
  77. if (memcmp(ptextSection + j, Keywords[i], sizeof(Keywords[i])) == 0) {
  78. off_t index =
  79. *reinterpret_cast<uint32_t*>(ptextSection + j + sizeof(Keywords[i])) +
  80. j + sizeof(Keywords[i]) + sizeof(uint32_t) - Hints[0];
  81. if (0 <= index && index < 0x188 && KeywordsMeta[index] == KeywordsMeta[i]) {
  82. Offsets[index] = ptextSectionHeader->PointerToRawData + j;
  83. }
  84. }
  85. }
  86. // if not found, refuse to patch
  87. if (Offsets[i] == -1)
  88. return false;
  89. }
  90. }
  91. _tprintf_s(TEXT("[*] PatchSolution2 ...... Ready to apply\n"));
  92. for (size_t i = 0; i < 0x188; ++i) {
  93. _PatchOffsets[i] = Offsets[i];
  94. _tprintf_s(TEXT(" |--[*] Keyword[%zu]\n"), i);
  95. _tprintf_s(TEXT(" | | - Offset = +0x%.8lx\n"), _PatchOffsets[i]);
  96. _tprintf_s(TEXT(" |\n"));
  97. }
  98. return true;
  99. }
  100. #else
  101. void PatchSolution2::BuildKeywords() noexcept {
  102. for (size_t i = 0; i < 0x188; ++i) {
  103. switch (i % 3) {
  104. case 0:
  105. Keywords[i][0] = 0x83; // Keywords[i] = asm('xor edx, KeywordsMeta[i]') +
  106. Keywords[i][1] = 0xf2;
  107. Keywords[i][2] = KeywordsMeta[i];
  108. Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxx, dl')
  109. Keywords[i][4] = 0x15;
  110. break;
  111. case 1:
  112. Keywords[i][0] = 0x83; // Keywords[i] = asm('xor eax, KeywordsMeta[i]') +
  113. Keywords[i][1] = 0xf0;
  114. Keywords[i][2] = KeywordsMeta[i];
  115. Keywords[i][3] = 0xa2; // asm_prefix('mov byte ptr ds:xxxxxxxx, al')
  116. break;
  117. default:
  118. Keywords[i][0] = 0x83; // Keywords[i] = asm('xor ecx, KeywordsMeta[i]') +
  119. Keywords[i][1] = 0xf1;
  120. Keywords[i][2] = KeywordsMeta[i];
  121. Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxx, cl')
  122. Keywords[i][4] = 0x0D;
  123. break;
  124. }
  125. }
  126. }
  127. bool PatchSolution2::FindPatchOffset() noexcept {
  128. PIMAGE_SECTION_HEADER ptextSectionHeader = _LibccDllInterpreter.GetSectionHeader(".text");
  129. uint8_t* ptextSection = _LibccDllInterpreter.GetSectionView<uint8_t>(".text");
  130. off_t Offsets[0x188];
  131. for (size_t i = 0; i < 0x188; ++i)
  132. Offsets[i] = -1;
  133. if (ptextSectionHeader == nullptr)
  134. return false;
  135. if (ptextSection == nullptr)
  136. return false;
  137. BuildKeywords();
  138. // Find offsets
  139. {
  140. size_t FirstKeywordCounter = 0;
  141. uint32_t Hints[3];
  142. DWORD PossibleRangeStart = 0xffffffff;
  143. DWORD PossibleRangeEnd;
  144. for (DWORD i = 0; i < ptextSectionHeader->SizeOfRawData; ++i) {
  145. if (memcmp(ptextSection + i, Keywords[0], sizeof(Keywords[0])) == 0) {
  146. Hints[FirstKeywordCounter++] =
  147. *reinterpret_cast<uint32_t*>(ptextSection + i + sizeof(Keywords[0]));
  148. if (i < PossibleRangeStart)
  149. PossibleRangeStart = i;
  150. }
  151. }
  152. PossibleRangeStart -= 0x1000;
  153. PossibleRangeEnd = PossibleRangeStart + 0x100000;
  154. // Keywords[0] should occur 3 times.
  155. if (FirstKeywordCounter != 3)
  156. return false;
  157. Helper::QuickSort(Hints, 0, _countof(Hints));
  158. // assert
  159. // if not satisfied, refuse to patch
  160. if (Hints[2] - Hints[0] != 0x127382BE - 0x12738210)
  161. return false;
  162. for (size_t i = 0; i < 0x188; ++i) {
  163. uint8_t CurrentKeyword[9];
  164. size_t CurrentKeywordSize = i % 3 == 1 ? 4 : 5;
  165. memcpy(CurrentKeyword, Keywords[i], CurrentKeywordSize);
  166. *reinterpret_cast<uint32_t*>(CurrentKeyword + CurrentKeywordSize) = Hints[0] + i;
  167. CurrentKeywordSize += sizeof(uint32_t);
  168. for (DWORD j = PossibleRangeStart; j < PossibleRangeEnd; ++j) {
  169. if (memcmp(ptextSection + j, CurrentKeyword, CurrentKeywordSize) == 0) {
  170. Offsets[i] = ptextSectionHeader->PointerToRawData + j;
  171. break;
  172. }
  173. }
  174. // if not found, refuse to patch
  175. if (Offsets[i] == -1)
  176. return false;
  177. }
  178. }
  179. _tprintf_s(TEXT("[*] PatchSolution2 ...... Ready to apply\n"));
  180. for (size_t i = 0; i < 0x188; ++i) {
  181. _PatchOffsets[i] = Offsets[i];
  182. _tprintf_s(TEXT(" |--[*] Keyword[%zu]\n"), i);
  183. _tprintf_s(TEXT(" | | - Offset = +0x%.8zx\n"), _PatchOffsets[i]);
  184. _tprintf_s(TEXT(" |"));
  185. }
  186. return true;
  187. }
  188. #endif
  189. bool PatchSolution2::CheckKey(RSACipher* pCipher) const {
  190. std::string PublicKeyString =
  191. pCipher->ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
  192. Helper::StringRemove<std::string>(PublicKeyString, "-----BEGIN PUBLIC KEY-----");
  193. Helper::StringRemove<std::string>(PublicKeyString, "-----END PUBLIC KEY-----");
  194. Helper::StringRemove<std::string>(PublicKeyString, "\n");
  195. return PublicKeyString.length() == 0x188;
  196. }
  197. void PatchSolution2::MakePatch(RSACipher* pCipher) const {
  198. uint8_t* pView = _LibccDllInterpreter.GetImageBase<uint8_t>();
  199. std::string PublicKeyString =
  200. pCipher->ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
  201. Helper::StringRemove<std::string>(PublicKeyString, "-----BEGIN PUBLIC KEY-----");
  202. Helper::StringRemove<std::string>(PublicKeyString, "-----END PUBLIC KEY-----");
  203. Helper::StringRemove<std::string>(PublicKeyString, "\n");
  204. _putts(TEXT("******************************************"));
  205. _putts(TEXT("* PatchSulution2 *"));
  206. _putts(TEXT("******************************************"));
  207. for (size_t i = 0; i < 0x188; ++i) {
  208. _tprintf_s(TEXT("@ +0x%.8lx: %.2X %.2X %.2X ---> "),
  209. _PatchOffsets[i],
  210. pView[_PatchOffsets[i]],
  211. pView[_PatchOffsets[i] + 1],
  212. pView[_PatchOffsets[i] + 2]);
  213. pView[_PatchOffsets[i] + 2] = PublicKeyString[i];
  214. _tprintf_s(TEXT("%.2X %.2X %.2X\n"),
  215. pView[_PatchOffsets[i]],
  216. pView[_PatchOffsets[i] + 1],
  217. pView[_PatchOffsets[i] + 2]);
  218. }
  219. }