Solution2.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include "def.hpp"
  2. namespace Patcher {
  3. const char Solution2::KeywordsMeta[KeywordsCount + 1] =
  4. "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I"
  5. "qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv"
  6. "a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF"
  7. "R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2"
  8. "WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt"
  9. "YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ"
  10. "awIDAQAB";
  11. uint8_t Solution2::Keywords[KeywordsCount][5];
  12. void Solution2::BuildKeywords() noexcept {
  13. for (size_t i = 0; i < KeywordsCount; ++i) {
  14. Keywords[i][0] = 0x83; // Keywords[i] = asm('xor eax, KeywordsMeta[i]') +
  15. Keywords[i][1] = 0xf0;
  16. Keywords[i][2] = KeywordsMeta[i];
  17. Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxxxxxxxxxx, al')
  18. Keywords[i][4] = 0x05;
  19. }
  20. }
  21. bool Solution2::FindPatchOffset() noexcept {
  22. PIMAGE_SECTION_HEADER textSection = nullptr;
  23. uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
  24. uint8_t* ptextSectionData = nullptr;
  25. off_t Offsets[KeywordsCount];
  26. memset(Offsets, -1, sizeof(Offsets));
  27. textSection = Helper::ImageSectionHeader(pTargetFileView, ".text");
  28. if (textSection == nullptr)
  29. return false;
  30. ptextSectionData = pTargetFileView + textSection->PointerToRawData;
  31. BuildKeywords();
  32. // Find offsets
  33. {
  34. size_t FirstKeywordCounter = 0;
  35. uint32_t Hints[9];
  36. DWORD PossibleRangeStart = 0xffffffff;
  37. DWORD PossibleRangeEnd;
  38. for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) {
  39. if (memcmp(ptextSectionData + i, Keywords[0], 5) == 0) {
  40. Hints[FirstKeywordCounter++] =
  41. *reinterpret_cast<uint32_t*>(ptextSectionData + i + sizeof(Keywords[0])) +
  42. i + sizeof(Keywords[0]) + sizeof(uint32_t);
  43. if (i < PossibleRangeStart)
  44. PossibleRangeStart = i;
  45. }
  46. }
  47. PossibleRangeStart -= 0x1000;
  48. PossibleRangeEnd = PossibleRangeStart + 0x100000;
  49. // Keywords[0] should occur 9 times.
  50. // Because there's only 9 'M' chars in `KeywordsMeta`.
  51. if (FirstKeywordCounter != 9)
  52. return false;
  53. Helper::QuickSort(Hints, 0, _countof(Hints));
  54. // assert
  55. // if not satisfied, refuse to patch
  56. if (Hints[8] - Hints[0] != 0x18360F8F8 - 0x18360F7D0)
  57. return false;
  58. for (size_t i = 0; i < KeywordsCount; ++i) {
  59. if (Offsets[i] != -1)
  60. continue;
  61. for (DWORD j = PossibleRangeStart; j < PossibleRangeEnd; ++j) {
  62. if (memcmp(ptextSectionData + j, Keywords[i], sizeof(Keywords[i])) == 0) {
  63. off_t index =
  64. *reinterpret_cast<uint32_t*>(ptextSectionData + j + sizeof(Keywords[i])) +
  65. j + sizeof(Keywords[i]) + sizeof(uint32_t) - Hints[0];
  66. if (0 <= index && index < KeywordsCount && KeywordsMeta[index] == KeywordsMeta[i]) {
  67. Offsets[index] = textSection->PointerToRawData + j;
  68. }
  69. }
  70. }
  71. // if not found, refuse to patch
  72. if (Offsets[i] == -1)
  73. return false;
  74. }
  75. }
  76. static_assert(sizeof(PatchOffsets) == sizeof(Offsets), "static_assert failure!");
  77. memcpy(PatchOffsets, Offsets, sizeof(PatchOffsets));
  78. for (size_t i = 0; i < KeywordsCount; ++i)
  79. _tprintf_s(TEXT("MESSAGE: [Solution2] Keywords[%zu] has been found: offset = +0x%08lx.\n"),
  80. i, PatchOffsets[i]);
  81. return true;
  82. }
  83. bool Solution2::MakePatch(RSACipher* cipher) const {
  84. std::string RSAPublicKeyPEM;
  85. uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
  86. RSAPublicKeyPEM = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
  87. if (RSAPublicKeyPEM.empty()) {
  88. REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
  89. return false;
  90. }
  91. RSAPublicKeyPEM.erase(RSAPublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
  92. RSAPublicKeyPEM.erase(RSAPublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
  93. {
  94. std::string::size_type pos = 0;
  95. while ((pos = RSAPublicKeyPEM.find("\n", pos)) != std::string::npos) {
  96. RSAPublicKeyPEM.erase(pos, 1);
  97. }
  98. }
  99. if (RSAPublicKeyPEM.length() != KeywordsCount) {
  100. REPORT_ERROR("ERROR: Public key length does not match.");
  101. return false;
  102. }
  103. PRINT_MESSAGE("//");
  104. PRINT_MESSAGE("// Begin Solution2");
  105. PRINT_MESSAGE("//");
  106. for (size_t i = 0; i < KeywordsCount; ++i) {
  107. _tprintf_s(TEXT("@+0x%08X: %02X %02X %02X --> "),
  108. PatchOffsets[i],
  109. pTargetFileView[PatchOffsets[i]],
  110. pTargetFileView[PatchOffsets[i] + 1],
  111. pTargetFileView[PatchOffsets[i] + 2]);
  112. pTargetFileView[PatchOffsets[i] + 2] = RSAPublicKeyPEM[i];
  113. _tprintf_s(TEXT("%02X %02X %02X\n"),
  114. pTargetFileView[PatchOffsets[i]],
  115. pTargetFileView[PatchOffsets[i] + 1],
  116. pTargetFileView[PatchOffsets[i] + 2]);
  117. }
  118. PRINT_MESSAGE("");
  119. return true;
  120. }
  121. }