patch_solution_since_16.0.7.0.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. #include "patch_solution_since_16.0.7.0.hpp"
  2. #include <cstddef>
  3. #include <regex>
  4. #include "keystone_assembler.hpp"
  5. #include <fmt/format.h>
  6. namespace nkg {
  7. uint64_t patch_solution_since<16, 0, 7, 0>::_emulator_append_external_api_impl(amd64_emulator& x64_emulator, std::string_view api_name, const std::vector<uint8_t>& api_impl) {
  8. auto& external_api_impl = x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl");
  9. auto& external_api_impl_area_base = x64_emulator.context_get<uint64_t&>("external_api_impl_area_base");
  10. auto& external_api_impl_area_size = x64_emulator.context_get<size_t&>("external_api_impl_area_size");
  11. auto& external_api_impl_append_address = x64_emulator.context_get<uint64_t&>("external_api_impl_append_address");
  12. auto p = external_api_impl_append_address;
  13. if (p + api_impl.size() > external_api_impl_area_base + external_api_impl_area_size) {
  14. auto expand_size = ((p + api_impl.size()) - (external_api_impl_area_base + external_api_impl_area_size) + 0xfff) / 0x1000 * 0x1000;
  15. x64_emulator.mem_map(external_api_impl_area_base + external_api_impl_area_size, expand_size, UC_PROT_READ | UC_PROT_EXEC);
  16. external_api_impl_area_size += expand_size;
  17. }
  18. x64_emulator.mem_write(p, api_impl);
  19. external_api_impl[std::string(api_name)] = p;
  20. external_api_impl_append_address = (p + api_impl.size() + 0xf) / 0x10 * 0x10;
  21. return p;
  22. }
  23. uint64_t patch_solution_since<16, 0, 7, 0>::_emulator_malloc(amd64_emulator& x64_emulator, size_t alloc_size) {
  24. auto& heap_records = x64_emulator.context_get<std::map<uint64_t, uint64_t>&>("heap_records");
  25. auto predecessor_chunk =
  26. std::adjacent_find(heap_records.begin(), heap_records.end(), [alloc_size](auto& chunk0, auto& chunk1) { return chunk1.first - (chunk0.first + chunk0.second) >= alloc_size; });
  27. uint64_t alloc_p;
  28. if (predecessor_chunk != heap_records.end()) {
  29. alloc_p = predecessor_chunk->first + predecessor_chunk->second;
  30. } else {
  31. auto heap_base = x64_emulator.context_get<uint64_t>("heap_base");
  32. auto heap_size = x64_emulator.context_get<uint64_t>("heap_size");
  33. auto free_space_base = heap_records.empty() ? heap_base : heap_records.rbegin()->first + heap_records.rbegin()->second;
  34. auto free_space_size = heap_base + heap_size - free_space_base;
  35. if (free_space_size < alloc_size) {
  36. auto heap_expand_base = heap_base + heap_size;
  37. auto heap_expand_size = (alloc_size - free_space_size + 0xfff) / 0x1000 * 0x1000;
  38. x64_emulator.mem_map(heap_expand_base, heap_expand_size, UC_PROT_READ | UC_PROT_WRITE);
  39. }
  40. alloc_p = free_space_base;
  41. }
  42. heap_records[alloc_p] = alloc_size;
  43. return alloc_p;
  44. }
  45. void patch_solution_since<16, 0, 7, 0>::_emulator_free(amd64_emulator& x64_emulator, uint64_t alloc_p) {
  46. auto& heap_records = x64_emulator.context_get<std::map<uint64_t, uint64_t>&>("heap_records");
  47. auto chunk = heap_records.find(alloc_p);
  48. if (chunk != heap_records.end()) {
  49. heap_records.erase(chunk);
  50. } else {
  51. printf("[-] patch_solution_since<16, 0, 7, 0>: emulator tries to free 0x%016lx which is not allocated by malloc.\n", alloc_p);
  52. x64_emulator.emu_stop();
  53. }
  54. }
  55. bool patch_solution_since<16, 0, 7, 0>::_emulator_page_fault_handler(amd64_emulator& x64_emulator, uc_mem_type access, uint64_t address, size_t size, int64_t value) {
  56. try {
  57. auto fault_segment = m_libcc_interpreter.elf_program_header_from_va(address);
  58. auto page_base = address / 0x1000 * 0x1000;
  59. auto page_size = 0x1000;
  60. uint32_t page_perms = UC_PROT_NONE;
  61. if (fault_segment->p_flags & PF_R) {
  62. page_perms |= UC_PROT_READ;
  63. }
  64. if (fault_segment->p_flags & PF_W) {
  65. page_perms |= UC_PROT_WRITE;
  66. }
  67. if (fault_segment->p_flags & PF_X) {
  68. page_perms |= UC_PROT_EXEC;
  69. }
  70. x64_emulator.mem_map(page_base, page_size, page_perms);
  71. x64_emulator.mem_write(page_base, m_libcc_interpreter.convert_va_to_ptr<const void*>(page_base), page_size);
  72. auto dynamic_pltgot = m_libcc_interpreter.elf_dynamic_pltgot();
  73. if (dynamic_pltgot.has_value() && page_base <= dynamic_pltgot.value() + 0x8 && dynamic_pltgot.value() + 0x10 <= page_base + page_size) {
  74. uint64_t dead_address = x64_emulator.context_get<uint64_t>("dead_address");
  75. x64_emulator.mem_write(dynamic_pltgot.value() + 0x8, &dead_address, sizeof(dead_address));
  76. }
  77. if (dynamic_pltgot.has_value() && page_base <= dynamic_pltgot.value() + 0x10 && dynamic_pltgot.value() + 0x18 <= page_base + page_size) {
  78. uint64_t dl_runtime_resolve = x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["dl_runtime_resolve"];
  79. x64_emulator.mem_write(dynamic_pltgot.value() + 0x10, &dl_runtime_resolve, sizeof(dl_runtime_resolve));
  80. }
  81. return true;
  82. } catch (::nkg::exception&) {
  83. return false;
  84. }
  85. }
  86. void patch_solution_since<16, 0, 7, 0>::_emulator_dl_runtime_resolve_handler(amd64_emulator& x64_emulator, uint64_t address, size_t size) {
  87. uint64_t rsp;
  88. x64_emulator.reg_read(UC_X86_REG_RSP, &rsp);
  89. uint64_t reloc_idx;
  90. x64_emulator.mem_read(rsp + 0x8, &reloc_idx, sizeof(reloc_idx));
  91. uint64_t reloc_va;
  92. Elf64_Sym* reloc_sym;
  93. uint32_t reloc_type;
  94. char* reloc_sym_name;
  95. if (m_libcc_interpreter.elf_dynamic_pltrel().value() == DT_REL) {
  96. auto jmp_reloc_table = m_libcc_interpreter.convert_va_to_ptr<Elf64_Rel*>(m_libcc_interpreter.elf_dynamic_jmprel().value());
  97. auto symbol_table = m_libcc_interpreter.convert_va_to_ptr<Elf64_Sym*>(m_libcc_interpreter.elf_dynamic_symtab().value());
  98. auto string_table = m_libcc_interpreter.convert_va_to_ptr<char*>(m_libcc_interpreter.elf_dynamic_strtab().value());
  99. reloc_va = jmp_reloc_table[reloc_idx].r_offset;
  100. reloc_sym = &symbol_table[ELF64_R_SYM(jmp_reloc_table[reloc_idx].r_info)];
  101. reloc_type = ELF64_R_TYPE(jmp_reloc_table[reloc_idx].r_info);
  102. reloc_sym_name = &string_table[reloc_sym->st_name];
  103. } else { // m_libcc_interpreter.elf_dynamic_pltrel().value() == DT_RELA
  104. auto jmp_reloc_table = m_libcc_interpreter.convert_va_to_ptr<Elf64_Rela*>(m_libcc_interpreter.elf_dynamic_jmprel().value());
  105. auto symbol_table = m_libcc_interpreter.convert_va_to_ptr<Elf64_Sym*>(m_libcc_interpreter.elf_dynamic_symtab().value());
  106. auto string_table = m_libcc_interpreter.convert_va_to_ptr<char*>(m_libcc_interpreter.elf_dynamic_strtab().value());
  107. reloc_va = jmp_reloc_table[reloc_idx].r_offset;
  108. reloc_sym = &symbol_table[ELF64_R_SYM(jmp_reloc_table[reloc_idx].r_info)];
  109. reloc_type = ELF64_R_TYPE(jmp_reloc_table[reloc_idx].r_info);
  110. reloc_sym_name = &string_table[reloc_sym->st_name];
  111. }
  112. if (strcmp(reloc_sym_name, "strlen") == 0) {
  113. auto external_api_impl_va =
  114. x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["strlen"];
  115. x64_emulator.mem_write(reloc_va, &external_api_impl_va, sizeof(external_api_impl_va));
  116. // external api address is resolved, set `qword ptr [rsp] = external_api_impl_va` in order to jump there
  117. x64_emulator.mem_write(rsp, &external_api_impl_va, sizeof(external_api_impl_va));
  118. } else if (strcmp(reloc_sym_name, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm") == 0) {
  119. // std::string::_M_append(char const*, unsigned long)
  120. auto external_api_impl_va =
  121. x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm"];
  122. x64_emulator.mem_write(reloc_va, &external_api_impl_va, sizeof(external_api_impl_va));
  123. // external api address is resolved, set `qword ptr [rsp] = external_api_impl_va` in order to jump there
  124. x64_emulator.mem_write(rsp, &external_api_impl_va, sizeof(external_api_impl_va));
  125. } else if (strcmp(reloc_sym_name, "_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareEPKc") == 0) {
  126. // std::string::compare(char const*) const
  127. auto external_api_impl_va =
  128. x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareEPKc"];
  129. x64_emulator.mem_write(reloc_va, &external_api_impl_va, sizeof(external_api_impl_va));
  130. // external api address is resolved, set `qword ptr [rsp] = external_api_impl_va` in order to jump there
  131. x64_emulator.mem_write(rsp, &external_api_impl_va, sizeof(external_api_impl_va));
  132. } else if (strcmp(reloc_sym_name, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9push_backEc") == 0) {
  133. // std::string::push_back(char)
  134. auto external_api_impl_va =
  135. x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9push_backEc"];
  136. x64_emulator.mem_write(reloc_va, &external_api_impl_va, sizeof(external_api_impl_va));
  137. // external api address is resolved, set `qword ptr [rsp] = external_api_impl_va` in order to jump there
  138. x64_emulator.mem_write(rsp, &external_api_impl_va, sizeof(external_api_impl_va));
  139. } else if (strcmp(reloc_sym_name, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc") == 0) {
  140. // std::string::append(char const*)
  141. m_va_pltgot_std_string_append = reloc_va;
  142. auto external_api_impl_va =
  143. x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc"];
  144. x64_emulator.mem_write(reloc_va, &external_api_impl_va, sizeof(external_api_impl_va));
  145. // external api address is resolved, set `qword ptr [rsp] = external_api_impl_va` in order to jump there
  146. x64_emulator.mem_write(rsp, &external_api_impl_va, sizeof(external_api_impl_va));
  147. } else if (strcmp(reloc_sym_name, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKcm") == 0) {
  148. // std::string::append(char const*, unsigned long)
  149. // redirect to `std::string::_M_append(char const*, unsigned long)`
  150. auto external_api_impl_va =
  151. x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm"];
  152. x64_emulator.mem_write(reloc_va, &external_api_impl_va, sizeof(external_api_impl_va));
  153. // external api address is resolved, set `qword ptr [rsp] = external_api_impl_va` in order to jump there
  154. x64_emulator.mem_write(rsp, &external_api_impl_va, sizeof(external_api_impl_va));
  155. } else if (strcmp(reloc_sym_name, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv") == 0) {
  156. // std::string::_M_dispose()
  157. auto external_api_impl_va =
  158. x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv"];
  159. x64_emulator.mem_write(reloc_va, &external_api_impl_va, sizeof(external_api_impl_va));
  160. // external api address is resolved, set `qword ptr [rsp] = external_api_impl_va` in order to jump there
  161. x64_emulator.mem_write(rsp, &external_api_impl_va, sizeof(external_api_impl_va));
  162. } else {
  163. printf("[-] patch_solution_since<16, 0, 7, 0>: PLT GOT entry `%s` is not resolved.\n", reloc_sym_name);
  164. x64_emulator.emu_stop();
  165. }
  166. }
  167. void patch_solution_since<16, 0, 7, 0>::_emulator_malloc_handler(amd64_emulator& x64_emulator, uint64_t address, size_t size) {
  168. uint64_t rdi;
  169. x64_emulator.reg_read(UC_X86_REG_RDI, &rdi);
  170. uint64_t rax = _emulator_malloc(x64_emulator, rdi);
  171. x64_emulator.reg_write(UC_X86_REG_RAX, &rax);
  172. }
  173. void patch_solution_since<16, 0, 7, 0>::_emulator_free_handler(amd64_emulator& x64_emulator, uint64_t address, size_t size) {
  174. uint64_t rdi;
  175. x64_emulator.reg_read(UC_X86_REG_RDI, &rdi);
  176. _emulator_free(x64_emulator, rdi);
  177. }
  178. std::string patch_solution_since<16, 0, 7, 0>::_build_encoded_key(const rsa_cipher& cipher) {
  179. auto encoded_key = cipher.export_public_key_string_pem();
  180. encoded_key = std::regex_replace(encoded_key, std::regex("-----BEGIN PUBLIC KEY-----"), "");
  181. encoded_key = std::regex_replace(encoded_key, std::regex("-----END PUBLIC KEY-----"), "");
  182. encoded_key = std::regex_replace(encoded_key, std::regex("\n"), "");
  183. return encoded_key;
  184. }
  185. std::list<std::pair<elf64_interpreter::va_t, size_t>> patch_solution_since<16, 0, 7, 0>::_calculate_reliable_areas() const {
  186. std::list<std::pair<elf64_interpreter::va_t, size_t>> reliable_areas;
  187. for (const auto& [base, size] : m_tracing) {
  188. auto tracing_block_begin_va = base;
  189. auto tracing_block_end_va = base + size;
  190. auto va = tracing_block_begin_va;
  191. auto next_reloc = m_libcc_interpreter.relocation_distribute().lower_bound(va);
  192. while (va < tracing_block_end_va) {
  193. if (next_reloc == m_libcc_interpreter.relocation_distribute().end() || tracing_block_end_va <= next_reloc->first) {
  194. reliable_areas.emplace_back(std::make_pair(va, static_cast<size_t>(tracing_block_end_va - va)));
  195. break;
  196. } else {
  197. reliable_areas.emplace_back(std::make_pair(va, static_cast<size_t>(next_reloc->first - va)));
  198. va = next_reloc->first + next_reloc->second;
  199. ++next_reloc;
  200. }
  201. }
  202. }
  203. return reliable_areas;
  204. }
  205. patch_solution_since<16, 0, 7, 0>::patch_solution_since(elf64_interpreter& libcc_interpreter) :
  206. m_libcc_interpreter(libcc_interpreter),
  207. m_va_CSRegistrationInfoFetcher_LINUX_vtable(0),
  208. m_va_CSRegistrationInfoFetcher_LINUX_GenerateRegistrationKey(0),
  209. m_va_pltgot_std_string_append(0) {}
  210. bool patch_solution_since<16, 0, 7, 0>::find_patch() {
  211. if (m_libcc_interpreter.elf_header()->e_machine != EM_X86_64) {
  212. printf("[-] patch_solution_since<16, 0, 7, 0>: Not x86-64 elf binary.\n");
  213. printf("[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  214. return false;
  215. }
  216. auto CSRegistrationInfoFetcher_LINUX_typeinfo_name =
  217. m_libcc_interpreter.search_section<uint8_t*>(
  218. ".rodata",
  219. [](const uint8_t* base, size_t off, size_t size) {
  220. return (size - off) >= sizeof("31CSRegistrationInfoFetcher_LINUX") && strcmp(address_offset_cast<const char*>(base, off), "31CSRegistrationInfoFetcher_LINUX") == 0;
  221. }
  222. );
  223. if (CSRegistrationInfoFetcher_LINUX_typeinfo_name == nullptr) {
  224. printf("[-] patch_solution_since<16, 0, 7, 0>: RTTI info for CSRegistrationInfoFetcher_LINUX is not found. (failure label 0)\n");
  225. printf("[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  226. return false;
  227. }
  228. auto CSRegistrationInfoFetcher_LINUX_typeinfo_name_va =
  229. m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_LINUX_typeinfo_name);
  230. auto CSRegistrationInfoFetcher_LINUX_typeinfo =
  231. m_libcc_interpreter.search_section<uint8_t*>(
  232. ".data.rel.ro",
  233. [CSRegistrationInfoFetcher_LINUX_typeinfo_name_va](const uint8_t* base, size_t off, size_t size) {
  234. return off % 8 == 0 && (size - (off + 8)) >= 8 && *address_offset_cast<const uint64_t*>(base, off + 8) == CSRegistrationInfoFetcher_LINUX_typeinfo_name_va;
  235. }
  236. );
  237. if (CSRegistrationInfoFetcher_LINUX_typeinfo == nullptr) {
  238. printf("[-] patch_solution_since<16, 0, 7, 0>: RTTI info for CSRegistrationInfoFetcher_LINUX is not found. (failure label 1)\n");
  239. printf("[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  240. return false;
  241. }
  242. auto CSRegistrationInfoFetcher_LINUX_typeinfo_va =
  243. m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_LINUX_typeinfo);
  244. auto CSRegistrationInfoFetcher_LINUX_vftable_before =
  245. m_libcc_interpreter.search_section<uint64_t*>(
  246. ".data.rel.ro",
  247. [CSRegistrationInfoFetcher_LINUX_typeinfo_va](const uint8_t* base, size_t off, size_t size) {
  248. return off % 8 == 0 && (size - off) >= 8 && *address_offset_cast<const uint64_t*>(base, off) == CSRegistrationInfoFetcher_LINUX_typeinfo_va;
  249. }
  250. );
  251. if (CSRegistrationInfoFetcher_LINUX_vftable_before == nullptr) {
  252. printf("[-] patch_solution_since<16, 0, 7, 0>: Vftable for CSRegistrationInfoFetcher_LINUX is not found.\n");
  253. printf("[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  254. }
  255. auto CSRegistrationInfoFetcher_LINUX_vftable = CSRegistrationInfoFetcher_LINUX_vftable_before + 1;
  256. m_va_CSRegistrationInfoFetcher_LINUX_vtable = m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_LINUX_vftable);
  257. m_va_CSRegistrationInfoFetcher_LINUX_GenerateRegistrationKey = CSRegistrationInfoFetcher_LINUX_vftable[7];
  258. printf("[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_LINUX_vtable = 0x%016lx\n", m_va_CSRegistrationInfoFetcher_LINUX_vtable);
  259. printf("[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_LINUX_GenerateRegistrationKey = 0x%016lx\n", m_va_CSRegistrationInfoFetcher_LINUX_GenerateRegistrationKey);
  260. amd64_emulator x64_emulator;
  261. x64_emulator.context_set("heap_base", uint64_t{ 0x00007fff00000000 });
  262. x64_emulator.context_set("heap_size", size_t{ 0x1000 * 32 });
  263. x64_emulator.context_set("heap_records", std::map<uint64_t, uint64_t>{});
  264. x64_emulator.context_set("stack_base", uint64_t{ 0x00007fffffff0000 });
  265. x64_emulator.context_set("stack_size", size_t{ 0x1000 * 32 });
  266. x64_emulator.context_set("stack_top", uint64_t{ x64_emulator.context_get<uint64_t>("stack_base") - x64_emulator.context_get<size_t>("stack_size") });
  267. x64_emulator.context_set("dead_area_base", uint64_t{ 0xfffffffffffff000 });
  268. x64_emulator.context_set("dead_area_size", size_t{ 0x1000 });
  269. x64_emulator.context_set("external_api_impl", std::map<std::string, uint64_t>{});
  270. x64_emulator.context_set("external_api_impl_area_base", uint64_t{ 0xffff900000000000 });
  271. x64_emulator.context_set("external_api_impl_area_size", size_t{ 0 });
  272. x64_emulator.context_set("external_api_impl_append_address", x64_emulator.context_get<uint64_t>("external_api_impl_area_base"));
  273. x64_emulator.context_set("start_address", static_cast<uint64_t>(m_va_CSRegistrationInfoFetcher_LINUX_GenerateRegistrationKey));
  274. x64_emulator.context_set("dead_address", x64_emulator.context_get<uint64_t>("dead_area_base"));
  275. // allocate heap
  276. x64_emulator.mem_map(x64_emulator.context_get<uint64_t>("heap_base"), x64_emulator.context_get<size_t>("heap_size"), UC_PROT_READ | UC_PROT_WRITE);
  277. // allocate stack
  278. x64_emulator.mem_map(x64_emulator.context_get<uint64_t>("stack_top"), x64_emulator.context_get<size_t>("stack_size"), UC_PROT_READ | UC_PROT_WRITE);
  279. // allocate dead area
  280. x64_emulator.mem_map(x64_emulator.context_get<uint64_t>("dead_area_base"), x64_emulator.context_get<size_t>("dead_area_size"), UC_PROT_READ | UC_PROT_EXEC);
  281. // allocate and setup external api impl area
  282. {
  283. keystone_assembler x64_assembler{ KS_ARCH_X86, KS_MODE_64 };
  284. auto& external_api_impl = x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl");
  285. auto& external_api_impl_append_address = x64_emulator.context_get<uint64_t&>("external_api_impl_append_address");
  286. _emulator_append_external_api_impl
  287. (
  288. x64_emulator, "dl_runtime_resolve",
  289. x64_assembler.assemble
  290. (
  291. " nop;"
  292. " mov rax, qword ptr [rsp];"
  293. " add rsp, 0x10;"
  294. " cmp rax, 0;"
  295. " je just_ret;"
  296. " jmp rax;"
  297. "just_ret:"
  298. " ret;"
  299. )
  300. );
  301. _emulator_append_external_api_impl(x64_emulator, "malloc", x64_assembler.assemble("ret;"));
  302. _emulator_append_external_api_impl(x64_emulator, "free", x64_assembler.assemble("ret;"));
  303. _emulator_append_external_api_impl
  304. (
  305. x64_emulator, "strlen",
  306. x64_assembler.assemble
  307. (
  308. "xor rcx, rcx;"
  309. "dec rcx;"
  310. "xor rax, rax;"
  311. "repne scasb byte ptr [rdi];"
  312. "not rcx;"
  313. "dec rcx;"
  314. "mov rax, rcx;"
  315. "ret;"
  316. )
  317. );
  318. _emulator_append_external_api_impl
  319. (
  320. x64_emulator, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm",
  321. x64_assembler.assemble
  322. (
  323. fmt::format
  324. (
  325. " push r12;"
  326. " push r13;"
  327. " push r14;"
  328. " push r15;"
  329. " mov r12, qword ptr [rdi];"
  330. " mov r13, qword ptr [rdi + 0x8];"
  331. " mov r14, 15;"
  332. " lea rax, qword ptr [rdi + 0x10];"
  333. " cmp r12, rax;"
  334. " cmovne r14, qword ptr [rdi + 0x10];"
  335. " xor r15, r15;"
  336. " lea rax, qword ptr [r13 + rdx];"
  337. " cmp rax, r14;"
  338. " jbe append_string;"
  339. "reallocate:"
  340. " push rdi;"
  341. " push rsi;"
  342. " push rdx;"
  343. " lea r14, qword ptr [r13 + rdx];"
  344. " lea rdi, qword ptr [r14 + 0x1];"
  345. " mov rax, {malloc:#016x};"
  346. " call rax;"
  347. " mov rdi, rax;"
  348. " mov rsi, r12;"
  349. " mov rcx, r13;"
  350. " rep movs byte ptr [rdi], byte ptr [rsi];"
  351. " mov r12, rax;"
  352. " mov rdi, qword ptr [rsp + 0x10];"
  353. " lea rax, qword ptr [rdi + 0x10];"
  354. " mov rdi, qword ptr [rdi];"
  355. " cmp rdi, rax;"
  356. " je label_0;"
  357. " mov rax, {free:#016x};"
  358. " call rax;"
  359. "label_0:"
  360. " pop rdx;"
  361. " pop rsi;"
  362. " pop rdi;"
  363. " mov r15b, 0x1;"
  364. "append_string:"
  365. " push rdi;"
  366. " push rsi;"
  367. " lea rdi, qword ptr [r12 + r13];"
  368. " mov rcx, rdx;"
  369. " rep movs byte ptr [rdi], byte ptr [rsi];"
  370. " mov byte ptr [rdi], 0;"
  371. " pop rsi;"
  372. " pop rdi;"
  373. " add r13, rdx;"
  374. "update_string_struct:"
  375. " mov qword ptr [rdi + 0x8], r13;"
  376. " test r15, r15;"
  377. " jz final;"
  378. " mov qword ptr [rdi], r12;"
  379. " mov qword ptr [rdi + 0x10], r14;"
  380. "final:"
  381. " mov rax, rdi;"
  382. " pop r15;"
  383. " pop r14;"
  384. " pop r13;"
  385. " pop r12;"
  386. " ret;",
  387. fmt::arg("malloc", external_api_impl["malloc"]),
  388. fmt::arg("free", external_api_impl["free"])
  389. )
  390. )
  391. );
  392. _emulator_append_external_api_impl
  393. (
  394. x64_emulator, "_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareEPKc",
  395. x64_assembler.assemble
  396. (
  397. // rcx = strlen(rsi);
  398. " push rsi;"
  399. " xor rcx, rcx;"
  400. " dec rcx;"
  401. "strlen_loop:"
  402. " inc rcx;"
  403. " cmp byte ptr [rsi + rcx], 0x00;"
  404. " jne strlen_loop;"
  405. " pop rsi;"
  406. // rdx = rcx;
  407. // rcx = min(this->_M_string_length, rcx);
  408. " mov rdx, rcx;"
  409. " cmp qword ptr [rdi + 0x8], rcx;"
  410. " cmovb rcx, qword ptr [rdi + 0x8];"
  411. // if (rcx == 0 || memcmp(this->_M_dataplus, rsi, rcx) == 0) goto compare_length;
  412. " test rcx, rcx;"
  413. " jz compare_length;"
  414. "memcmp:"
  415. " push rdi;"
  416. " push rsi;"
  417. " mov rdi, qword ptr [rdi];"
  418. " xchg rsi, rdi;"
  419. " repe cmps byte ptr [rsi], byte ptr [rdi];"
  420. " pop rsi;"
  421. " pop rdi;"
  422. " jl return_negative;"
  423. " jg return_positive;"
  424. "compare_length:"
  425. " cmp qword ptr [rdi + 0x8], rdx;"
  426. " ja return_positive;"
  427. " jb return_negative;"
  428. "return_zero:"
  429. " xor eax, eax;"
  430. " ret;"
  431. "return_positive:"
  432. " mov eax, 1;"
  433. " ret;"
  434. "return_negative:"
  435. " mov eax, 0xffffffff;"
  436. " ret;"
  437. )
  438. );
  439. _emulator_append_external_api_impl
  440. (
  441. x64_emulator, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9push_backEc",
  442. x64_assembler.assemble
  443. (
  444. fmt::format
  445. (
  446. " push rsi;"
  447. " mov rsi, rsp;"
  448. " mov rdx, 0x1;"
  449. " mov rax, {_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm:#016x};"
  450. " call rax;"
  451. " pop rsi;"
  452. " ret;",
  453. fmt::arg("_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm", external_api_impl["_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm"])
  454. )
  455. )
  456. );
  457. _emulator_append_external_api_impl
  458. (
  459. x64_emulator, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc",
  460. x64_assembler.assemble
  461. (
  462. fmt::format
  463. (
  464. " push rsi;"
  465. " xor rdx, rdx;"
  466. " dec rdx;"
  467. "strlen_loop:"
  468. " inc rdx;"
  469. " cmp byte ptr [rsi + rdx], 0x00;"
  470. " jne strlen_loop;"
  471. " pop rsi;"
  472. " mov rax, {_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm:#016x};"
  473. " jmp rax;",
  474. fmt::arg("_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm", external_api_impl["_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm"])
  475. )
  476. )
  477. );
  478. _emulator_append_external_api_impl
  479. (
  480. x64_emulator, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv",
  481. x64_assembler.assemble
  482. (
  483. fmt::format
  484. (
  485. " mov rcx, qword ptr [rdi];"
  486. " lea rdx, qword ptr [rdi + 0x10];"
  487. " cmp rcx, rdx;"
  488. " je return;"
  489. " mov rdi, rcx;"
  490. " mov rax, {free:#016x};"
  491. " call rax;"
  492. "return:"
  493. " ret",
  494. fmt::arg("free", external_api_impl["free"])
  495. )
  496. )
  497. );
  498. x64_emulator.hook_add<UC_HOOK_CODE>
  499. (std::bind(&patch_solution_since::_emulator_dl_runtime_resolve_handler, this, std::ref(x64_emulator), std::placeholders::_1, std::placeholders::_2), external_api_impl["dl_runtime_resolve"], external_api_impl["dl_runtime_resolve"]);
  500. x64_emulator.hook_add<UC_HOOK_CODE>
  501. (std::bind(&patch_solution_since::_emulator_malloc_handler, this, std::ref(x64_emulator), std::placeholders::_1, std::placeholders::_2), external_api_impl["malloc"], external_api_impl["malloc"]);
  502. x64_emulator.hook_add<UC_HOOK_CODE>
  503. (std::bind(&patch_solution_since::_emulator_free_handler, this, std::ref(x64_emulator), std::placeholders::_1, std::placeholders::_2), external_api_impl["free"], external_api_impl["free"]);
  504. }
  505. // set page fault handler
  506. x64_emulator.hook_add<UC_HOOK_MEM_UNMAPPED>
  507. (std::bind(&patch_solution_since::_emulator_page_fault_handler, this, std::ref(x64_emulator), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
  508. // set rbp, rsp
  509. uint64_t init_rbp = x64_emulator.context_get<uint64_t>("stack_base") - x64_emulator.context_get<size_t>("stack_size") / 4;
  510. uint64_t init_rsp = x64_emulator.context_get<uint64_t>("stack_base") - x64_emulator.context_get<size_t>("stack_size") / 2;
  511. x64_emulator.reg_write(UC_X86_REG_RBP, &init_rbp);
  512. x64_emulator.reg_write(UC_X86_REG_RSP, &init_rsp);
  513. // set return address
  514. auto retaddr = x64_emulator.context_get<uint64_t>("dead_address");
  515. x64_emulator.mem_write(init_rsp, &retaddr, sizeof(retaddr));
  516. // set argument registers
  517. uint64_t init_rdi = init_rsp + 0x40; // a pointer to stack memory which stores return value
  518. x64_emulator.reg_write(UC_X86_REG_RDI, &init_rdi);
  519. std::list<std::pair<elf64_interpreter::va_t, size_t>> tracing;
  520. x64_emulator.hook_add<UC_HOOK_CODE>(
  521. [&x64_emulator, &tracing, stack_frame_index = 0](uint64_t address, size_t size) mutable {
  522. std::byte instruction_data[16]; // a x86-64 instruction is 16-bytes long at most
  523. x64_emulator.mem_read(address, instruction_data, size);
  524. if (stack_frame_index == 0) {
  525. if (tracing.size() > 0 && tracing.back().first + tracing.back().second == address) {
  526. tracing.back().second += size;
  527. } else {
  528. tracing.emplace_back(std::make_pair(address, size));
  529. }
  530. }
  531. bool is_near_call =
  532. instruction_data[0] == std::byte{ 0xe8 } ||
  533. instruction_data[0] == std::byte{ 0xff } && (instruction_data[1] & std::byte{ 0b00111000 }) == std::byte{ 0b00010000 }; // FF /2
  534. if (is_near_call) {
  535. ++stack_frame_index;
  536. return;
  537. }
  538. bool is_near_ret =
  539. instruction_data[0] == std::byte{ 0xc2 } ||
  540. instruction_data[0] == std::byte{ 0xc3 };
  541. if (is_near_ret) {
  542. --stack_frame_index;
  543. return;
  544. }
  545. }
  546. );
  547. // start emulate
  548. try {
  549. x64_emulator.emu_start(x64_emulator.context_get<uint64_t>("start_address"), x64_emulator.context_get<uint64_t>("dead_address"));
  550. } catch (amd64_emulator::backend_error& e) {
  551. printf("[-] patch_solution_since<16, 0, 7, 0>: Code emulation failed. %s\n", e.error_string().c_str());
  552. printf("[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  553. return false;
  554. }
  555. if (m_va_pltgot_std_string_append == 0) {
  556. if (m_libcc_interpreter.elf_dynamic_pltrel().value() == DT_REL) {
  557. auto jmp_reloc_table = m_libcc_interpreter.convert_va_to_ptr<Elf64_Rel*>(m_libcc_interpreter.elf_dynamic_jmprel().value());
  558. auto jmp_reloc_table_size = m_libcc_interpreter.elf_dynamic_pltrelsz().value() / sizeof(Elf64_Rel);
  559. auto symbol_table = m_libcc_interpreter.convert_va_to_ptr<Elf64_Sym*>(m_libcc_interpreter.elf_dynamic_symtab().value());
  560. auto string_table = m_libcc_interpreter.convert_va_to_ptr<char*>(m_libcc_interpreter.elf_dynamic_strtab().value());
  561. for (size_t i = 0; i < jmp_reloc_table_size; ++i) {
  562. auto reloc_va = jmp_reloc_table[i].r_offset;
  563. auto reloc_sym = &symbol_table[ELF64_R_SYM(jmp_reloc_table[i].r_info)];
  564. auto reloc_type = ELF64_R_TYPE(jmp_reloc_table[i].r_info);
  565. auto reloc_sym_name = &string_table[reloc_sym->st_name];
  566. if (strcmp(reloc_sym_name, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc") == 0) {
  567. m_va_pltgot_std_string_append = reloc_va;
  568. break;
  569. }
  570. }
  571. } else { // m_libcc_interpreter.elf_dynamic_pltrel().value() == DT_RELA
  572. auto jmp_reloc_table = m_libcc_interpreter.convert_va_to_ptr<Elf64_Rela*>(m_libcc_interpreter.elf_dynamic_jmprel().value());
  573. auto jmp_reloc_table_size = m_libcc_interpreter.elf_dynamic_pltrelsz().value() / sizeof(Elf64_Rela);
  574. auto symbol_table = m_libcc_interpreter.convert_va_to_ptr<Elf64_Sym*>(m_libcc_interpreter.elf_dynamic_symtab().value());
  575. auto string_table = m_libcc_interpreter.convert_va_to_ptr<char*>(m_libcc_interpreter.elf_dynamic_strtab().value());
  576. for (size_t i = 0; i < jmp_reloc_table_size; ++i) {
  577. auto reloc_va = jmp_reloc_table[i].r_offset;
  578. auto reloc_sym = &symbol_table[ELF64_R_SYM(jmp_reloc_table[i].r_info)];
  579. auto reloc_type = ELF64_R_TYPE(jmp_reloc_table[i].r_info);
  580. auto reloc_sym_name = &string_table[reloc_sym->st_name];
  581. if (strcmp(reloc_sym_name, "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc") == 0) {
  582. m_va_pltgot_std_string_append = reloc_va;
  583. break;
  584. }
  585. }
  586. }
  587. }
  588. if (m_va_pltgot_std_string_append) {
  589. printf("[*] patch_solution_since<16, 0, 7, 0>: m_va_pltgot_std_string_append = 0x%016lx\n", m_va_pltgot_std_string_append);
  590. } else {
  591. printf("[*] patch_solution_since<16, 0, 7, 0>: std::string::append(const char*) is not found.\n");
  592. printf("[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  593. return false;
  594. }
  595. m_tracing = std::move(tracing);
  596. //
  597. // get result
  598. //
  599. // on AMD64 platform, `std::string` has follow memory layout:
  600. // ------------------------------
  601. // | offset | size |
  602. // ------------------------------
  603. // | +0 | 0x8 | char*: raw string ptr
  604. // ------------------------------
  605. // | +0x8 | 0x8 | size_t: string length
  606. // ------------------------------
  607. // | +0x10 | 0x8 | `char[16]: a small string buffer` OR `size_t: capacity`
  608. // ------------------------------
  609. //
  610. uint64_t encoded_key_length;
  611. x64_emulator.mem_read(init_rdi + 0x8, &encoded_key_length, sizeof(encoded_key_length));
  612. if (encoded_key_length != official_encoded_key.length()) {
  613. printf("[-] patch_solution_since<16, 0, 7, 0>: unexpected encoded key length(%lu).\n", encoded_key_length);
  614. printf("[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  615. return false;
  616. }
  617. uint64_t encoded_key_ptr;
  618. x64_emulator.mem_read(init_rdi, &encoded_key_ptr, sizeof(encoded_key_ptr));
  619. auto encoded_key = x64_emulator.mem_read(encoded_key_ptr, encoded_key_length);
  620. if (memcmp(encoded_key.data(), official_encoded_key.data(), encoded_key.size()) == 0) {
  621. printf("[+] patch_solution_since<16, 0, 7, 0>: official encoded key is found.\n");
  622. return true;
  623. } else {
  624. printf("[-] patch_solution_since<16, 0, 7, 0>: official encoded key is not found.\n");
  625. printf("[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  626. return false;
  627. }
  628. }
  629. bool patch_solution_since<16, 0, 7, 0>::check_rsa_privkey(const rsa_cipher& cipher) {
  630. return cipher.bits() == 2048;
  631. }
  632. void patch_solution_since<16, 0, 7, 0>::make_patch(const rsa_cipher& cipher) {
  633. auto new_encoded_key = _build_encoded_key(cipher);
  634. auto CSRegistrationInfoFetcher_LINUX_GenerateRegistrationKey =
  635. m_libcc_interpreter.convert_va_to_ptr<uint8_t*>(m_va_CSRegistrationInfoFetcher_LINUX_GenerateRegistrationKey);
  636. std::vector<std::string> patch_code_chunks;
  637. patch_code_chunks.emplace_back("push rbp;");
  638. patch_code_chunks.emplace_back("mov rbp, rsp;");
  639. patch_code_chunks.emplace_back("lea rax, qword ptr [rdi + 0x10];");
  640. patch_code_chunks.emplace_back("mov qword ptr [rdi], rax;");
  641. patch_code_chunks.emplace_back("mov qword ptr [rdi + 0x8], 0;");
  642. {
  643. std::vector<uint64_t> push_values((new_encoded_key.length() + 1 + 7) / 8, 0);
  644. memcpy(push_values.data(), new_encoded_key.data(), new_encoded_key.length());
  645. std::for_each
  646. (
  647. push_values.crbegin(),
  648. push_values.crend(),
  649. [&patch_code_chunks](uint64_t x) {
  650. patch_code_chunks.emplace_back(fmt::format("mov rax, {:#016x};", x));
  651. patch_code_chunks.emplace_back("push rax;");
  652. }
  653. );
  654. }
  655. patch_code_chunks.emplace_back("mov rsi, rsp;");
  656. patch_code_chunks.emplace_back(fmt::format("call qword ptr [{:#016x}];", m_va_pltgot_std_string_append)); // keystone will emit `call qword ptr [rip+xxx]` here
  657. patch_code_chunks.emplace_back("leave;");
  658. patch_code_chunks.emplace_back("ret;");
  659. auto x86_assembler = keystone_assembler{ KS_ARCH_X86, KS_MODE_64 };
  660. auto reliable_areas = _calculate_reliable_areas();
  661. auto current_va = m_va_CSRegistrationInfoFetcher_LINUX_GenerateRegistrationKey;
  662. auto current_ptr = m_libcc_interpreter.convert_va_to_ptr<uint8_t*>(current_va);
  663. auto current_reliable_area = reliable_areas.begin();
  664. auto current_reliable_area_begin_va = current_reliable_area->first;
  665. auto current_reliable_area_end_va = current_reliable_area_begin_va + current_reliable_area->second;
  666. for (const auto& patch_code_chunk : patch_code_chunks) {
  667. while (true) {
  668. auto assembled_patch_code_chunk = x86_assembler.assemble(patch_code_chunk, current_va);
  669. constexpr size_t jmp_code_max_size = 1 + sizeof(uint32_t);
  670. if (current_reliable_area_begin_va <= current_va && current_va + assembled_patch_code_chunk.size() + jmp_code_max_size <= current_reliable_area_end_va) {
  671. memcpy(current_ptr, assembled_patch_code_chunk.data(), assembled_patch_code_chunk.size());
  672. current_va += assembled_patch_code_chunk.size();
  673. current_ptr += assembled_patch_code_chunk.size();
  674. break;
  675. } else {
  676. auto next_reliable_area = std::next(current_reliable_area);
  677. while (next_reliable_area->second < 0x10) {
  678. next_reliable_area = std::next(next_reliable_area);
  679. }
  680. auto assembled_jmp = x86_assembler.assemble(fmt::format("jmp {:#016x};", next_reliable_area->first), current_va);
  681. memcpy(current_ptr, assembled_jmp.data(), assembled_jmp.size());
  682. current_va = next_reliable_area->first;
  683. current_ptr = m_libcc_interpreter.convert_va_to_ptr<uint8_t*>(next_reliable_area->first);
  684. current_reliable_area = next_reliable_area;
  685. current_reliable_area_begin_va = current_reliable_area->first;
  686. current_reliable_area_end_va = current_reliable_area_begin_va + current_reliable_area->second;
  687. }
  688. }
  689. }
  690. printf("[*] patch_solution_since<16, 0, 7, 0>: Patch has been done.\n");
  691. }
  692. }