PatchSolution0.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #include "PatchSolutions.hpp"
  2. #include "ExceptionGeneric.hpp"
  3. #include "Misc.hpp"
  4. #include <string.h>
  5. namespace nkg {
  6. PatchSolution0::PatchSolution0(const Elf64Interpreter& Image) :
  7. m_Image(Image),
  8. m_DisassemblyEngine(CS_ARCH_X86, CS_MODE_64),
  9. m_AssemblyEngine(KS_ARCH_X86, KS_MODE_64),
  10. m_RefSegment(nullptr)
  11. {
  12. m_DisassemblyEngine.Option(CS_OPT_DETAIL, CS_OPT_ON);
  13. }
  14. [[nodiscard]]
  15. bool PatchSolution0::FindPatchOffset() noexcept {
  16. try {
  17. const Elf64_Phdr* RefSegment = nullptr;
  18. std::optional<Elf64_Off> PatchMarkOffset;
  19. std::optional<Elf64_Addr> PatchMarkRva;
  20. std::optional<Elf64_Addr> MachineCodeRva;
  21. std::optional<size_t> MachineCodeSize;
  22. std::vector<uint8_t> MachineCodeNew;
  23. if (m_Image.ElfHeader()->e_machine != EM_X86_64) {
  24. throw ARL::Exception(__BASE_FILE__, __LINE__, "Not amd64 platform.");
  25. }
  26. for (size_t i = 0; i < m_Image.NumberOfElfProgramHeaders(); ++i) {
  27. auto seg_hdr = m_Image.ElfProgramHeader(i);
  28. if (seg_hdr->p_type != PT_NULL && seg_hdr->p_filesz >= sizeof(PatchMarkType)) {
  29. auto lpMark = m_Image.ElfOffset<const PatchMarkType*>(seg_hdr->p_offset + seg_hdr->p_filesz - sizeof(PatchMarkType));
  30. if (lpMark->Starter == PatchMarkStarter || lpMark->Terminator == PatchMarkTerminator) {
  31. throw ARL::Exception(__BASE_FILE__, __LINE__, "Already patched.");
  32. }
  33. }
  34. }
  35. {
  36. std::map<Elf64_Off, Elf64_Xword> SpaceMap{ { 0, m_Image.ElfSize() } };
  37. SearchFreeSpace(SpaceMap, m_Image);
  38. for (const auto& space : SpaceMap) {
  39. bool found = false;
  40. auto offset = space.first;
  41. auto size = space.second;
  42. if (size >= sizeof(PatchMarkType)) {
  43. for (size_t i = 0; i < m_Image.NumberOfElfProgramHeaders(); ++i) {
  44. auto seg_hdr = m_Image.ElfProgramHeader(i);
  45. if (seg_hdr->p_type == PT_LOAD && seg_hdr->p_offset + seg_hdr->p_filesz == offset) {
  46. RefSegment = seg_hdr;
  47. PatchMarkOffset = offset;
  48. PatchMarkRva = m_Image.ConvertOffsetToRva(offset - 1) + 1;
  49. found = true;
  50. break;
  51. }
  52. }
  53. }
  54. if (found) {
  55. break;
  56. }
  57. }
  58. }
  59. {
  60. auto Disassembler = m_DisassemblyEngine.CreateDisassembler();
  61. auto Assembler = m_AssemblyEngine.CreateAssembler();
  62. auto sec_hdr_text = m_Image.ElfSectionHeader(".text");
  63. auto sec_view_text = m_Image.ElfSectionView(sec_hdr_text);
  64. auto lpMachineCode = m_Image.SearchElfSectionView(sec_hdr_text, [](const void* base, size_t i, size_t size) {
  65. auto p = reinterpret_cast<const uint8_t*>(base) + i;
  66. return i + 16 <= size &&
  67. p[1] == 0x0f && p[2] == 0xb6 && // movzx xxx, yyy
  68. p[6] == 0x8b && // mov xxx, yyy
  69. p[10] == 0x8b && // mov xxx, yyy
  70. p[13] == 0x85 && // test xxx, yyy
  71. p[15] == 0x79; // jns xxx
  72. }
  73. );
  74. auto cbMachineCode = static_cast<size_t>(sec_hdr_text->sh_size - ARL::AddressDelta(lpMachineCode, sec_view_text));
  75. MachineCodeRva = m_Image.ConvertPtrToRva(lpMachineCode);
  76. Disassembler.SetContext({ lpMachineCode, cbMachineCode, MachineCodeRva.value() });
  77. int char_reg;
  78. int lpsz_reg;
  79. if (Disassembler.Next() && strcasecmp(Disassembler.GetInstruction()->mnemonic, "movzx") == 0) {
  80. auto lpInsn = Disassembler.GetInstruction();
  81. if (lpInsn->detail->x86.operands[0].type == X86_OP_REG) {
  82. char_reg = lpInsn->detail->x86.operands[0].reg;
  83. } else {
  84. throw ARL::AssertionError(__BASE_FILE__, __LINE__, "Something unexpected happened.");
  85. }
  86. } else {
  87. throw ARL::AssertionError(__BASE_FILE__, __LINE__, "Something unexpected happened.");
  88. }
  89. if (Disassembler.Next() && strcasecmp(Disassembler.GetInstruction()->mnemonic, "mov") == 0) {
  90. auto lpInsn = Disassembler.GetInstruction();
  91. if (lpInsn->detail->x86.operands[0].type == X86_OP_REG) {
  92. lpsz_reg = lpInsn->detail->x86.operands[0].reg;
  93. } else {
  94. throw ARL::AssertionError(__BASE_FILE__, __LINE__, "Something unexpected happened.");
  95. }
  96. } else {
  97. throw ARL::AssertionError(__BASE_FILE__, __LINE__, "Something unexpected happened.");
  98. }
  99. if (Disassembler.Next() && Disassembler.Next() && Disassembler.Next()) {
  100. MachineCodeSize = static_cast<size_t>(Disassembler.GetContext().Address - MachineCodeRva.value());
  101. MachineCodeNew = Assembler.GenerateMachineCode(
  102. [this, char_reg, lpsz_reg, &PatchMarkRva]() -> std::string {
  103. const char asm_template[] =
  104. "xor %1$s, %1$s;"
  105. "lea %2$s, byte ptr [0x%3$.16lx];";
  106. std::string asm_string;
  107. int l;
  108. l = snprintf(nullptr, 0,
  109. asm_template,
  110. this->m_DisassemblyEngine.GetRegisterName(char_reg),
  111. this->m_DisassemblyEngine.GetRegisterName(lpsz_reg),
  112. PatchMarkRva.value() + offsetof(PatchMarkType, Data)
  113. );
  114. if (l < 0) {
  115. std::terminate();
  116. }
  117. asm_string.resize(l + 1);
  118. l = snprintf(asm_string.data(), asm_string.length(),
  119. asm_template,
  120. this->m_DisassemblyEngine.GetRegisterName(char_reg),
  121. this->m_DisassemblyEngine.GetRegisterName(lpsz_reg),
  122. PatchMarkRva.value() + offsetof(PatchMarkType, Data)
  123. );
  124. if (l < 0) {
  125. std::terminate();
  126. }
  127. while (asm_string.back() == '\x00') {
  128. asm_string.pop_back();
  129. }
  130. return asm_string;
  131. }().c_str(),
  132. MachineCodeRva.value()
  133. );
  134. if (MachineCodeNew.size() <= MachineCodeSize.value()) {
  135. MachineCodeNew.insert(MachineCodeNew.end(), MachineCodeSize.value() - MachineCodeNew.size(), '\x90'); // \x90 -> nop
  136. } else {
  137. throw ARL::AssertionError(__BASE_FILE__, __LINE__, "Something unexpected happened.");
  138. }
  139. } else {
  140. throw ARL::AssertionError(__BASE_FILE__, __LINE__, "Something unexpected happened.");
  141. }
  142. }
  143. if (RefSegment && PatchMarkOffset.has_value() && MachineCodeRva.has_value() && MachineCodeSize.has_value()) {
  144. m_RefSegment = RefSegment;
  145. m_PatchMarkOffset = PatchMarkOffset;
  146. m_MachineCodeRva = MachineCodeRva;
  147. m_MachineCodeSize = MachineCodeSize;
  148. m_MachineCodeNew = std::move(MachineCodeNew);
  149. printf("[+] PatchSolution0 ...... Ready to apply\n");
  150. printf(" RefSegment = %zu\n", m_RefSegment - m_Image.ElfProgramHeader(0));
  151. printf(" MachineCodeRva = 0x%.16lx\n", m_MachineCodeRva.value());
  152. printf(" PatchMarkOffset = +0x%.16lx\n", PatchMarkOffset.value());
  153. } else {
  154. throw ARL::Exception(__BASE_FILE__, __LINE__, "Not found.");
  155. }
  156. return true;
  157. } catch (ARL::Exception& e) {
  158. printf("[-] PatchSolution0 ...... Omitted\n");
  159. return false;
  160. }
  161. }
  162. [[nodiscard]]
  163. bool PatchSolution0::CheckKey(const RSACipher& Cipher) const noexcept {
  164. return Cipher.Bits() == 2048;
  165. }
  166. void PatchSolution0::MakePatch(const RSACipher& Cipher) const {
  167. if (m_RefSegment && m_PatchMarkOffset.has_value() && m_MachineCodeRva.has_value() && m_MachineCodeSize.has_value()) {
  168. if (m_MachineCodeSize.value() == m_MachineCodeNew.size()) {
  169. auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
  170. for (auto pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----", pos)) {
  171. szPublicKey.erase(pos, strlen("-----BEGIN PUBLIC KEY-----"));
  172. }
  173. for (auto pos = szPublicKey.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----END PUBLIC KEY-----", pos)) {
  174. szPublicKey.erase(pos, strlen("-----END PUBLIC KEY-----"));
  175. }
  176. for (auto pos = szPublicKey.find("\n"); pos != std::string::npos; pos = szPublicKey.find("\n", pos)) {
  177. szPublicKey.erase(pos, strlen("\n"));
  178. }
  179. auto lpMark = m_Image.ElfOffset<PatchMarkType*>(m_PatchMarkOffset.value());
  180. puts("*******************************************************");
  181. puts("* PatchSolution0 *");
  182. puts("*******************************************************");
  183. if (lpMark->Starter != PatchMarkStarter || lpMark->Terminator != PatchMarkTerminator) {
  184. auto RefSegment = const_cast<Elf64_Phdr*>(m_RefSegment);
  185. printf("[*] Previous:\n");
  186. Misc::PrintMemory(RefSegment, sizeof(Elf64_Phdr), m_Image.ElfBase());
  187. RefSegment->p_filesz += sizeof(PatchMarkType);
  188. RefSegment->p_memsz += sizeof(PatchMarkType);
  189. printf("[*] After:\n");
  190. Misc::PrintMemory(RefSegment, sizeof(Elf64_Phdr), m_Image.ElfBase());
  191. printf("\n");
  192. printf("[*] Previous:\n");
  193. Misc::PrintMemory(lpMark, sizeof(PatchMarkType), m_Image.ElfBase());
  194. lpMark->Starter = PatchMarkStarter;
  195. memcpy(lpMark->Data, szPublicKey.data(), std::min(szPublicKey.size(), sizeof(lpMark->Data)));
  196. lpMark->Terminator = PatchMarkTerminator;
  197. printf("[*] After:\n");
  198. Misc::PrintMemory(lpMark, sizeof(PatchMarkType), m_Image.ElfBase());
  199. printf("\n");
  200. } else {
  201. if (strncmp(reinterpret_cast<char*>(lpMark->Data), szPublicKey.data(), sizeof(lpMark->Data)) != 0) {
  202. printf("[*] Previous:\n");
  203. Misc::PrintMemory(lpMark, sizeof(PatchMarkType), m_Image.ElfBase());
  204. memcpy(lpMark->Data, szPublicKey.data(), std::min(szPublicKey.size(), sizeof(lpMark->Data)));
  205. printf("[*] After:\n");
  206. Misc::PrintMemory(lpMark, sizeof(PatchMarkType), m_Image.ElfBase());
  207. printf("\n");
  208. }
  209. }
  210. {
  211. auto lpMachineCode = m_Image.ConvertRvaToPtr(m_MachineCodeRva.value());
  212. printf("[*] Previous:\n");
  213. Misc::PrintMemory(lpMachineCode, m_MachineCodeSize.value(), m_Image.ElfBase());
  214. memcpy(lpMachineCode, m_MachineCodeNew.data(), m_MachineCodeSize.value());
  215. printf("[*] After:\n");
  216. Misc::PrintMemory(lpMachineCode, m_MachineCodeSize.value(), m_Image.ElfBase());
  217. printf("\n");
  218. }
  219. } else {
  220. throw ARL::AssertionError(__BASE_FILE__, __LINE__, "Something unexpected happened.");
  221. }
  222. } else {
  223. throw ARL::Exception(__BASE_FILE__, __LINE__, "Not ready yet.");
  224. }
  225. }
  226. }