patch_solution_since_16.0.7.0.amd64.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include "amd64_emulator.hpp"
  3. #include "keystone_assembler.hpp"
  4. #include "patch_solution_since_16.0.7.0.hpp"
  5. #include <algorithm>
  6. #include <fmt/format.h>
  7. namespace nkg {
  8. patch_solution_since<16, 0, 7, 0>::patch_solution_since(image_interpreter& libcc_interpreter) :
  9. m_libcc_interpreter(libcc_interpreter),
  10. m_va_CSRegistrationInfoFetcher_WIN_vtable(0),
  11. m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey(0),
  12. m_va_iat_entry_malloc(0) {}
  13. bool patch_solution_since<16, 0, 7, 0>::find_patch() {
  14. auto CSRegistrationInfoFetcher_WIN_type_descriptor_name =
  15. m_libcc_interpreter.search_section<const uint8_t*>(
  16. ".data",
  17. [](const uint8_t* p, size_t s) {
  18. if (s < sizeof(".?AVCSRegistrationInfoFetcher_WIN@@")) {
  19. return false;
  20. }
  21. return strcmp(reinterpret_cast<const char*>(p), ".?AVCSRegistrationInfoFetcher_WIN@@") == 0;
  22. }
  23. );
  24. if (CSRegistrationInfoFetcher_WIN_type_descriptor_name == nullptr) {
  25. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: RTTI info for CSRegistrationInfoFetcher_WIN is not found. (failure label 0)\n");
  26. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  27. return false;
  28. }
  29. auto CSRegistrationInfoFetcher_WIN_rtti_type_descriptor = CSRegistrationInfoFetcher_WIN_type_descriptor_name - 0x10;
  30. auto CSRegistrationInfoFetcher_WIN_rtti_type_descriptor_rva = m_libcc_interpreter.convert_ptr_to_rva(CSRegistrationInfoFetcher_WIN_rtti_type_descriptor);
  31. auto CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_pTypeDescriptor =
  32. m_libcc_interpreter.search_section<const uint8_t*>(
  33. ".rdata",
  34. [this, CSRegistrationInfoFetcher_WIN_rtti_type_descriptor_rva](const uint8_t* p, size_t s) {
  35. if (reinterpret_cast<uintptr_t>(p) % sizeof(uint32_t) != 0) {
  36. return false;
  37. }
  38. if (s < sizeof(uint32_t)) {
  39. return false;
  40. }
  41. if (*reinterpret_cast<const uint32_t*>(p) != CSRegistrationInfoFetcher_WIN_rtti_type_descriptor_rva) {
  42. return false;
  43. }
  44. if (s < sizeof(uint32_t) * 2) {
  45. return false;
  46. }
  47. auto maybe_CSRegistrationInfoFetcher_WIN_rtti_class_hierarchy_descriptor_rva = reinterpret_cast<const uint32_t*>(p)[1];
  48. try {
  49. return memcmp(m_libcc_interpreter.image_section_header_from_rva(maybe_CSRegistrationInfoFetcher_WIN_rtti_class_hierarchy_descriptor_rva)->Name, ".rdata\x00\x00", 8) == 0;
  50. } catch (nkg::exception&) {
  51. return false;
  52. }
  53. }
  54. );
  55. if (CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_pTypeDescriptor == nullptr) {
  56. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: RTTI info for CSRegistrationInfoFetcher_WIN is not found. (failure label 1)\n");
  57. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  58. return false;
  59. }
  60. auto CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator = CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_pTypeDescriptor - 0xC;
  61. auto CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_va = m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator);
  62. auto CSRegistrationInfoFetcher_WIN_vtable_before =
  63. m_libcc_interpreter.search_section<const uint8_t*>(
  64. ".rdata",
  65. [CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_va](const uint8_t* p, size_t s) {
  66. if (reinterpret_cast<uintptr_t>(p) % sizeof(uint64_t) != 0) {
  67. return false;
  68. }
  69. if (s < sizeof(uint64_t)) {
  70. return false;
  71. }
  72. return *reinterpret_cast<const uint64_t*>(p) == CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_va;
  73. }
  74. );
  75. if (CSRegistrationInfoFetcher_WIN_vtable_before == nullptr) {
  76. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: Vftable for CSRegistrationInfoFetcher_WIN is not found.\n");
  77. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  78. return false;
  79. }
  80. auto CSRegistrationInfoFetcher_WIN_vtable =
  81. reinterpret_cast<const image_interpreter::va_t*>(CSRegistrationInfoFetcher_WIN_vtable_before + sizeof(image_interpreter::va_t));
  82. m_va_CSRegistrationInfoFetcher_WIN_vtable = m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_WIN_vtable);
  83. m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey = CSRegistrationInfoFetcher_WIN_vtable[6];
  84. wprintf(L"[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_vtable = 0x%016llx\n", m_va_CSRegistrationInfoFetcher_WIN_vtable);
  85. wprintf(L"[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey = 0x%016llx\n", m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey);
  86. amd64_emulator x64_emulator;
  87. x64_emulator.context_set("heap_base", uint64_t{ 0x00007fff00000000 });
  88. x64_emulator.context_set("heap_size", size_t{ 0x1000 * 32 });
  89. x64_emulator.context_set("heap_records", std::map<uint64_t, uint64_t>{});
  90. x64_emulator.context_set("stack_base", uint64_t{ 0x00007fffffff0000 });
  91. x64_emulator.context_set("stack_size", size_t{ 0x1000 * 32 });
  92. x64_emulator.context_set("stack_top", uint64_t{ x64_emulator.context_get<uint64_t>("stack_base") - x64_emulator.context_get<size_t>("stack_size") });
  93. x64_emulator.context_set("dead_area_base", uint64_t{ 0xfffffffffffff000 });
  94. x64_emulator.context_set("dead_area_size", size_t{ 0x1000 });
  95. x64_emulator.context_set("iat_base", uint64_t{ m_libcc_interpreter.convert_rva_to_va(m_libcc_interpreter.image_nt_headers()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) });
  96. x64_emulator.context_set("iat_size", size_t{ m_libcc_interpreter.image_nt_headers()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size });
  97. x64_emulator.context_set("external_api_stub_area_base", uint64_t{ 0xffff800000000000 });
  98. x64_emulator.context_set("external_api_stub_area_size", size_t{ (x64_emulator.context_get<size_t>("iat_size") / 8 + 0xfff) / 0x1000 * 0x1000 });
  99. x64_emulator.context_set("external_api_impl", std::map<std::string, uint64_t>{});
  100. x64_emulator.context_set("external_api_impl_area_base", uint64_t{ 0xffff900000000000 });
  101. x64_emulator.context_set("external_api_impl_area_size", size_t{ 0 });
  102. x64_emulator.context_set("gs_base", uint64_t{ 0xffffa00000000000 });
  103. x64_emulator.context_set("gs_size", size_t{ 0x1000 });
  104. x64_emulator.context_set("start_address", static_cast<uint64_t>(m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey));
  105. x64_emulator.context_set("dead_address", x64_emulator.context_get<uint64_t>("dead_area_base"));
  106. // allocate heap
  107. 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);
  108. // allocate stack
  109. 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);
  110. // allocate dead area
  111. 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);
  112. // allocate and hook read access to IAT
  113. {
  114. auto iat_base = x64_emulator.context_get<uint64_t>("iat_base");
  115. auto iat_size = x64_emulator.context_get<size_t>("iat_size");
  116. auto external_api_stub_area_base = x64_emulator.context_get<uint64_t>("external_api_stub_area_base");
  117. auto iat_page_base = iat_base / 0x1000 * 0x1000;
  118. auto iat_page_count = (iat_base - iat_page_base + iat_size + 0xfff) / 0x1000;
  119. x64_emulator.mem_map(iat_page_base, iat_page_count * 0x1000, UC_PROT_READ);
  120. x64_emulator.hook_add<UC_HOOK_MEM_READ>(
  121. [this, &x64_emulator, iat_base, external_api_stub_area_base](uc_mem_type type, uint64_t address, size_t size, int64_t value) {
  122. auto rva = m_libcc_interpreter.convert_va_to_rva(address);
  123. auto import_lookup_entry = m_libcc_interpreter.import_lookup_entry_from_rva(rva);
  124. if (import_lookup_entry && !IMAGE_SNAP_BY_ORDINAL(import_lookup_entry->u1.Ordinal)) {
  125. auto import_by_name_entry = m_libcc_interpreter.convert_rva_to_ptr<PIMAGE_IMPORT_BY_NAME>(import_lookup_entry->u1.AddressOfData);
  126. if (strcmp(import_by_name_entry->Name, "memcpy") == 0) {
  127. uint64_t impl_address = x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["memcpy"];
  128. x64_emulator.mem_write(address, &impl_address, sizeof(impl_address));
  129. } else if (strcmp(import_by_name_entry->Name, "memcmp") == 0) {
  130. uint64_t impl_address = x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["memcmp"];
  131. x64_emulator.mem_write(address, &impl_address, sizeof(impl_address));
  132. } else {
  133. uint64_t stub_address = external_api_stub_area_base + (address - iat_base) / sizeof(IMAGE_THUNK_DATA);
  134. x64_emulator.mem_write(address, &stub_address, sizeof(stub_address));
  135. }
  136. } else {
  137. x64_emulator.emu_stop();
  138. }
  139. },
  140. iat_base,
  141. iat_base + iat_size - 1
  142. );
  143. }
  144. // allocate and setup external api stub area
  145. {
  146. auto external_api_stub_area_base = x64_emulator.context_get<uint64_t>("external_api_stub_area_base");
  147. auto external_api_stub_area_size = x64_emulator.context_get<size_t>("external_api_stub_area_size");
  148. x64_emulator.mem_map(external_api_stub_area_base, external_api_stub_area_size, UC_PROT_READ | UC_PROT_EXEC);
  149. x64_emulator.mem_write(external_api_stub_area_base, std::vector<uint8_t>(external_api_stub_area_size, 0xc3)); // c3 -> ret
  150. x64_emulator.hook_add<UC_HOOK_CODE>(
  151. [this, &x64_emulator, external_api_stub_area_base](uint64_t address, size_t size) {
  152. auto iat_base = x64_emulator.context_get<uint64_t>("iat_base");
  153. auto from_va = iat_base + (address - external_api_stub_area_base) * sizeof(IMAGE_THUNK_DATA);
  154. auto from_rva = m_libcc_interpreter.convert_va_to_rva(from_va);
  155. auto import_lookup_entry = m_libcc_interpreter.import_lookup_entry_from_rva(from_rva);
  156. if (import_lookup_entry && !IMAGE_SNAP_BY_ORDINAL(import_lookup_entry->u1.Ordinal)) {
  157. auto import_by_name_entry = m_libcc_interpreter.convert_rva_to_ptr<PIMAGE_IMPORT_BY_NAME>(import_lookup_entry->u1.AddressOfData);
  158. if (strcmp(import_by_name_entry->Name, "malloc") == 0) {
  159. m_va_iat_entry_malloc = from_va;
  160. uint64_t alloc_size;
  161. x64_emulator.reg_read(UC_X86_REG_RCX, &alloc_size);
  162. auto& heap_records = x64_emulator.context_get<std::map<uint64_t, uint64_t>&>("heap_records");
  163. auto predecessor_chunk =
  164. std::adjacent_find(
  165. heap_records.begin(),
  166. heap_records.end(),
  167. [alloc_size](const auto& chunk0, const auto& chunk1) { return chunk1.first - (chunk0.first + chunk0.second) >= alloc_size; }
  168. );
  169. uint64_t alloc_p;
  170. if (predecessor_chunk != heap_records.end()) {
  171. alloc_p = predecessor_chunk->first + predecessor_chunk->second;
  172. } else {
  173. auto heap_base = x64_emulator.context_get<uint64_t>("heap_base");
  174. auto heap_size = x64_emulator.context_get<uint64_t>("heap_size");
  175. auto free_space_base = heap_records.size() > 0 ? heap_records.rbegin()->first + heap_records.rbegin()->second : heap_base;
  176. auto free_space_size = heap_base + heap_size - free_space_base;
  177. if (free_space_size < alloc_size) {
  178. auto heap_expand_base = heap_base + heap_size;
  179. auto heap_expand_size = (alloc_size - free_space_size + 0xfff) / 0x1000 * 0x1000;
  180. x64_emulator.mem_map(heap_expand_base, heap_expand_size, UC_PROT_READ | UC_PROT_WRITE);
  181. }
  182. alloc_p = free_space_base;
  183. }
  184. heap_records[alloc_p] = alloc_size;
  185. x64_emulator.reg_write(UC_X86_REG_RAX, &alloc_p);
  186. } else if (strcmp(import_by_name_entry->Name, "free") == 0) {
  187. uint64_t alloc_p;
  188. x64_emulator.reg_read(UC_X86_REG_RCX, &alloc_p);
  189. auto& heap_records = x64_emulator.context_get<std::map<uint64_t, uint64_t>&>("heap_records");
  190. auto chunk = heap_records.find(alloc_p);
  191. if (chunk != heap_records.end()) {
  192. heap_records.erase(chunk);
  193. } else {
  194. x64_emulator.emu_stop();
  195. }
  196. } else {
  197. x64_emulator.emu_stop();
  198. }
  199. } else {
  200. x64_emulator.emu_stop();
  201. }
  202. },
  203. external_api_stub_area_base,
  204. external_api_stub_area_base + external_api_stub_area_size - 1
  205. );
  206. }
  207. // allocate and setup external api impl area
  208. {
  209. keystone_assembler x64_assembler{ KS_ARCH_X86, KS_MODE_64 };
  210. std::map<std::string, std::vector<uint8_t>> machine_code_list =
  211. {
  212. std::make_pair(
  213. "memcpy",
  214. x64_assembler.assemble(
  215. "push rdi;"
  216. "push rsi;"
  217. "mov rdi, rcx;"
  218. "mov rsi, rdx;"
  219. "mov rcx, r8;"
  220. "rep movs byte ptr [rdi], byte ptr [rsi];"
  221. "pop rsi;"
  222. "pop rdi;"
  223. "ret;"
  224. )
  225. ),
  226. std::make_pair(
  227. "memcmp",
  228. x64_assembler.assemble(
  229. " push rdi;"
  230. " push rsi;"
  231. " mov rsi, rcx;"
  232. " mov rdi, rdx;"
  233. " mov rcx, r8;"
  234. " cmp rcx, rcx;"
  235. " repe cmps byte ptr [rsi], byte ptr [rdi];"
  236. " jz cmp_eq;"
  237. "cmp_not_eq:"
  238. " movsx eax, byte ptr [rsi - 1];"
  239. " movsx ecx, byte ptr [rdi - 1];"
  240. " sub eax, ecx;"
  241. " jmp final;"
  242. "cmp_eq:"
  243. " xor eax, eax;"
  244. "final:"
  245. " pop rsi;"
  246. " pop rdi;"
  247. " ret;"
  248. )
  249. ),
  250. std::make_pair(
  251. "memmove",
  252. x64_assembler.assemble(
  253. " push rdi;"
  254. " push rsi;"
  255. " cmp rdx, rcx;"
  256. " jb reverse_copy;"
  257. "copy:"
  258. " mov rdi, rcx;"
  259. " mov rsi, rdx;"
  260. " mov rcx, r8;"
  261. " rep movsb byte ptr[rdi], byte ptr[rsi];"
  262. " jmp final;"
  263. "reverse_copy:"
  264. " std;"
  265. " lea rdi, qword ptr[rcx + r8 - 1];"
  266. " lea rsi, qword ptr[rdx + r8 - 1];"
  267. " mov rcx, r8;"
  268. " rep movsb byte ptr[rdi], byte ptr[rsi];"
  269. " cld;"
  270. "final:"
  271. " pop rsi;"
  272. " pop rdi;"
  273. " ret;"
  274. )
  275. )
  276. };
  277. auto& external_api_impl = x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl");
  278. auto& external_api_impl_area_base = x64_emulator.context_get<uint64_t&>("external_api_impl_area_base");
  279. auto& external_api_impl_area_size = x64_emulator.context_get<size_t&>("external_api_impl_area_size");
  280. auto p = external_api_impl_area_base;
  281. for (const auto& name_code_pair : machine_code_list) {
  282. external_api_impl[name_code_pair.first] = p;
  283. p = (p + name_code_pair.second.size() + 0xf) / 0x10 * 0x10;
  284. }
  285. external_api_impl_area_size = (p + 0xfff) / 0x1000 * 0x1000 - external_api_impl_area_base;
  286. x64_emulator.mem_map(external_api_impl_area_base, external_api_impl_area_size, UC_PROT_READ | UC_PROT_EXEC);
  287. for (const auto& name_code_pair : machine_code_list) {
  288. x64_emulator.mem_write(external_api_impl[name_code_pair.first], name_code_pair.second);
  289. }
  290. }
  291. // allocate and hook access to gs area
  292. x64_emulator.mem_map(x64_emulator.context_get<uint64_t>("gs_base"), x64_emulator.context_get<size_t>("gs_size"), UC_PROT_READ | UC_PROT_WRITE);
  293. x64_emulator.msr_write(0xC0000101, x64_emulator.context_get<uint64_t>("gs_base")); // set gs base address
  294. x64_emulator.hook_add<UC_HOOK_MEM_READ>(
  295. [this, &x64_emulator](uc_mem_type access, uint64_t address, size_t size, int64_t value) {
  296. auto gs_base = x64_emulator.context_get<uint64_t>("gs_base");
  297. switch (address - gs_base) {
  298. case 0x10: // qword ptr gs:[0x10] -> Stack Limit / Ceiling of stack (low address)
  299. {
  300. uint64_t val = x64_emulator.context_get<uint64_t>("stack_top");
  301. x64_emulator.mem_write(address, &val, size);
  302. }
  303. break;
  304. default:
  305. x64_emulator.emu_stop();
  306. break;
  307. }
  308. },
  309. x64_emulator.context_get<uint64_t>("gs_base"),
  310. x64_emulator.context_get<uint64_t>("gs_base") + x64_emulator.context_get<size_t>("gs_size") - 1
  311. );
  312. // x64_emulator.hook_add<UC_HOOK_CODE>([](uint64_t address, size_t size) { wprintf_s(L"code_trace, address = 0x%016zx\n", address); });
  313. x64_emulator.hook_add<UC_HOOK_MEM_UNMAPPED>(
  314. [this, &x64_emulator](uc_mem_type access, uint64_t address, size_t size, int64_t value) -> bool {
  315. try {
  316. auto fault_section = m_libcc_interpreter.image_section_header_from_va(address);
  317. auto page_base = address / 0x1000 * 0x1000;
  318. auto page_size = 0x1000;
  319. uint32_t page_perms = UC_PROT_NONE;
  320. if (fault_section->Characteristics & IMAGE_SCN_MEM_READ) {
  321. page_perms |= UC_PROT_READ;
  322. }
  323. if (fault_section->Characteristics & IMAGE_SCN_MEM_WRITE) {
  324. page_perms |= UC_PROT_WRITE;
  325. }
  326. if (fault_section->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
  327. page_perms |= UC_PROT_EXEC;
  328. }
  329. x64_emulator.mem_map(page_base, page_size, page_perms);
  330. x64_emulator.mem_write(page_base, m_libcc_interpreter.convert_va_to_ptr<const void*>(page_base), page_size);
  331. return true;
  332. } catch (::nkg::exception&) {
  333. return false;
  334. }
  335. }
  336. );
  337. // set rbp, rsp
  338. uint64_t init_rbp = x64_emulator.context_get<uint64_t>("stack_base") - x64_emulator.context_get<size_t>("stack_size") / 4;
  339. uint64_t init_rsp = x64_emulator.context_get<uint64_t>("stack_base") - x64_emulator.context_get<size_t>("stack_size") / 2;
  340. x64_emulator.reg_write(UC_X86_REG_RBP, &init_rbp);
  341. x64_emulator.reg_write(UC_X86_REG_RSP, &init_rsp);
  342. // set return address
  343. auto retaddr = x64_emulator.context_get<uint64_t>("dead_address");
  344. x64_emulator.mem_write(init_rsp, &retaddr, sizeof(retaddr));
  345. // set argument registers
  346. uint64_t init_rcx = 0; // `this` pointer of CSRegistrationInfoFetcher_WIN, but we don't need it for now.
  347. uint64_t init_rdx = init_rsp + 0x40; // a pointer to stack memory which stores return value
  348. x64_emulator.reg_write(UC_X86_REG_RCX, &init_rcx);
  349. x64_emulator.reg_write(UC_X86_REG_RDX, &init_rdx);
  350. //
  351. // start emulate
  352. //
  353. try {
  354. x64_emulator.emu_start(x64_emulator.context_get<uint64_t>("start_address"), x64_emulator.context_get<uint64_t>("dead_address"));
  355. } catch (nkg::exception&) {
  356. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: Code emulation failed.\n");
  357. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  358. return false;
  359. }
  360. wprintf_s(L"[*] patch_solution_since<16, 0, 7, 0>: m_va_iat_entry_malloc = 0x%016llx\n", m_va_iat_entry_malloc);
  361. //
  362. // get result
  363. //
  364. // on AMD64 platform, `std::string` has follow memory layout:
  365. // ------------------------------
  366. // | offset | size |
  367. // ------------------------------
  368. // | +0 | 0x10 | `char[16]: a small string buffer` OR `char*: a large string buffer pointer`
  369. // ------------------------------
  370. // | +0x10 | 0x8 | size_t: string length
  371. // ------------------------------
  372. // | +0x18 | 0x8 | size_t: capacity
  373. // ------------------------------
  374. //
  375. uint64_t encoded_key_length;
  376. x64_emulator.mem_read(init_rdx + 0x10, &encoded_key_length, sizeof(encoded_key_length));
  377. if (encoded_key_length != official_encoded_key.length()) {
  378. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: unexpected encoded key length(%llu).\n", encoded_key_length);
  379. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  380. return false;
  381. }
  382. uint64_t encoded_key_ptr;
  383. x64_emulator.mem_read(init_rdx, &encoded_key_ptr, sizeof(encoded_key_ptr));
  384. auto encoded_key = x64_emulator.mem_read(encoded_key_ptr, encoded_key_length);
  385. if (memcmp(encoded_key.data(), official_encoded_key.data(), encoded_key.size()) == 0) {
  386. wprintf_s(L"[+] patch_solution_since<16, 0, 7, 0>: official encoded key is found.\n");
  387. return true;
  388. } else {
  389. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: official encoded key is not found.\n");
  390. wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
  391. return false;
  392. }
  393. }
  394. bool patch_solution_since<16, 0, 7, 0>::check_rsa_privkey(const rsa_cipher& cipher) {
  395. return true; // no requirements
  396. }
  397. void patch_solution_since<16, 0, 7, 0>::make_patch(const rsa_cipher& cipher) {
  398. auto encoded_key = _build_encoded_key(cipher);
  399. auto CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey =
  400. m_libcc_interpreter.convert_va_to_ptr<uint8_t*>(m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey);
  401. std::vector<std::string> patch_code_chunks;
  402. patch_code_chunks.emplace_back("push rdi;");
  403. patch_code_chunks.emplace_back("push rsi;");
  404. patch_code_chunks.emplace_back("push rbx;");
  405. patch_code_chunks.emplace_back("push rbp;");
  406. patch_code_chunks.emplace_back("mov rbp, rsp;");
  407. patch_code_chunks.emplace_back("mov rbx, rdx;");
  408. patch_code_chunks.emplace_back("sub rsp, 0x20;");
  409. patch_code_chunks.emplace_back(fmt::format("mov rcx, {:#x};", encoded_key.length() + 1));
  410. patch_code_chunks.emplace_back(fmt::format("call qword ptr [{:#016x}];", m_va_iat_entry_malloc));
  411. patch_code_chunks.emplace_back("add rsp, 0x20;");
  412. {
  413. std::vector<uint64_t> push_values((encoded_key.length() + 1 + 7) / 8, 0);
  414. memcpy(push_values.data(), encoded_key.data(), encoded_key.length());
  415. std::for_each(
  416. push_values.crbegin(),
  417. push_values.crend(),
  418. [&patch_code_chunks](uint64_t x) {
  419. patch_code_chunks.emplace_back(fmt::format("mov rdx, {:#016x};", x));
  420. patch_code_chunks.emplace_back("push rdx;");
  421. }
  422. );
  423. }
  424. patch_code_chunks.emplace_back("mov rdi, rax;");
  425. patch_code_chunks.emplace_back("mov rsi, rsp;");
  426. patch_code_chunks.emplace_back(fmt::format("mov rcx, {:#x};", encoded_key.length() + 1));
  427. patch_code_chunks.emplace_back("rep movs byte ptr [rdi], byte ptr [rsi];");
  428. patch_code_chunks.emplace_back("mov qword ptr [rbx], rax;");
  429. patch_code_chunks.emplace_back(fmt::format("mov qword ptr [rbx + 0x10], {:#x};", encoded_key.length()));
  430. patch_code_chunks.emplace_back(fmt::format("mov qword ptr [rbx + 0x18], {:#x};", encoded_key.length() + 1));
  431. patch_code_chunks.emplace_back("mov rax, rbx;");
  432. patch_code_chunks.emplace_back("leave;");
  433. patch_code_chunks.emplace_back("pop rbx;");
  434. patch_code_chunks.emplace_back("pop rsi;");
  435. patch_code_chunks.emplace_back("pop rdi;");
  436. patch_code_chunks.emplace_back("ret;");
  437. //auto patch_code = keystone_assembler{ KS_ARCH_X86, KS_MODE_64 }
  438. // .assemble(
  439. // fmt::format(
  440. // " push rdi;"
  441. // " push rsi;"
  442. // " push rbx;"
  443. // " mov rbx, rdx;"
  444. // "allocate_string_buf:"
  445. // " mov rcx, {encoded_key_length:#x} + 1;"
  446. // " sub rsp, 0x20;"
  447. // " call qword ptr [{m_va_iat_entry_malloc:#x}];"
  448. // " add rsp, 0x20;"
  449. // "write_our_own_key_to_string_buf:"
  450. // " mov rdi, rax;"
  451. // " lea rsi, qword ptr [end_of_code + rip];"
  452. // " mov rcx, 0x188;"
  453. // " rep movs byte ptr [rdi], byte ptr [rsi];"
  454. // " mov byte ptr [rdi], 0;"
  455. // "craft_std_string:"
  456. // " mov qword ptr [rbx], rax;"
  457. // " mov qword ptr [rbx + 0x10], {encoded_key_length:#x};"
  458. // " mov qword ptr [rbx + 0x18], {encoded_key_length:#x} + 1;"
  459. // "final:"
  460. // " mov rax, rbx;"
  461. // " pop rbx;"
  462. // " pop rsi;"
  463. // " pop rdi;"
  464. // " ret;"
  465. // "end_of_code:",
  466. // fmt::arg("encoded_key_length", encoded_key.length()),
  467. // fmt::arg("m_va_iat_entry_malloc", m_va_iat_entry_malloc)
  468. // ),
  469. // m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey
  470. // );
  471. std::vector<uint8_t> assembled_patch_code;
  472. {
  473. keystone_assembler x86_assembler{ KS_ARCH_X86, KS_MODE_64 };
  474. auto current_va = m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey;
  475. auto next_reloc = m_libcc_interpreter.relocation_distribute().lower_bound(m_libcc_interpreter.convert_va_to_rva(current_va));
  476. for (const auto& patch_code_chunk : patch_code_chunks) {
  477. auto assembled_patch_code_chunk = x86_assembler.assemble(patch_code_chunk, current_va);
  478. while (true) {
  479. auto next_reloc_va = m_libcc_interpreter.convert_rva_to_va(next_reloc->first);
  480. auto next_reloc_size = next_reloc->second;
  481. if (current_va + assembled_patch_code_chunk.size() + 2 <= next_reloc_va) { // 2 -> size of machine code "jmp rel8"
  482. assembled_patch_code.insert(assembled_patch_code.end(), assembled_patch_code_chunk.begin(), assembled_patch_code_chunk.end());
  483. current_va += assembled_patch_code_chunk.size();
  484. break;
  485. } else if (current_va + 2 <= next_reloc_va) {
  486. auto next_va = next_reloc_va + next_reloc_size;
  487. auto assembled_jmp = x86_assembler.assemble(fmt::format("jmp {:#016x};", next_va), current_va);
  488. auto assembled_padding = std::vector<uint8_t>(next_va - (current_va + assembled_jmp.size()), 0xcc); // 0xcc -> int3
  489. assembled_patch_code.insert(assembled_patch_code.end(), assembled_jmp.begin(), assembled_jmp.end());
  490. assembled_patch_code.insert(assembled_patch_code.end(), assembled_padding.begin(), assembled_padding.end());
  491. current_va = next_va;
  492. ++next_reloc;
  493. } else {
  494. __assume(false); // impossible to reach here
  495. }
  496. }
  497. }
  498. }
  499. memcpy(CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey, assembled_patch_code.data(), assembled_patch_code.size());
  500. wprintf_s(L"[*] patch_solution_since<16, 0, 7, 0>: Patch has been done.\n");
  501. }
  502. }