patch_solution_since_16.0.7.0.cpp 36 KB

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