amd64_emulator.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include "amd64_emulator.hpp"
  3. #include "exceptions/key_exception.hpp"
  4. #define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-patcher\\amd64_emulator.cpp"
  5. #define NKG_CURRENT_SOURCE_LINE() __LINE__
  6. namespace nkg {
  7. void amd64_emulator::_unicorn_hookcode_cb_stub(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
  8. auto hook_stub_ctx = reinterpret_cast<hook_stub_context_t*>(user_data);
  9. hook_stub_ctx->self->m_unicorn_hook_cbs_hookcode[hook_stub_ctx->unicorn_hook_handle](address, size);
  10. }
  11. void amd64_emulator::_unicorn_hookmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data) {
  12. auto hook_stub_ctx = reinterpret_cast<hook_stub_context_t*>(user_data);
  13. hook_stub_ctx->self->m_unicorn_hook_cbs_hookmem[hook_stub_ctx->unicorn_hook_handle](type, address, static_cast<unsigned int>(size), value);
  14. }
  15. bool amd64_emulator::_unicorn_eventmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data) {
  16. auto hook_stub_ctx = reinterpret_cast<hook_stub_context_t*>(user_data);
  17. return hook_stub_ctx->self->m_unicorn_hook_cbs_eventmem[hook_stub_ctx->unicorn_hook_handle](type, address, static_cast<unsigned int>(size), value);
  18. }
  19. amd64_emulator::amd64_emulator() {
  20. auto err = uc_open(UC_ARCH_X86, UC_MODE_64, m_unicorn_engine.unsafe_addressof());
  21. if (err != UC_ERR_OK) {
  22. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_open failed.");
  23. }
  24. }
  25. void amd64_emulator::reg_read(int regid, void* value) {
  26. auto err = uc_reg_read(m_unicorn_engine.get(), regid, value);
  27. if (err != UC_ERR_OK) {
  28. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_read failed.");
  29. }
  30. }
  31. void amd64_emulator::reg_write(int regid, const void* value) {
  32. auto err = uc_reg_write(m_unicorn_engine.get(), regid, value);
  33. if (err != UC_ERR_OK) {
  34. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_write failed.");
  35. }
  36. }
  37. uint64_t amd64_emulator::msr_read(uint32_t rid) {
  38. uc_x86_msr msr;
  39. msr.rid = rid;
  40. auto err = uc_reg_read(m_unicorn_engine.get(), UC_X86_REG_MSR, &msr);
  41. if (err != UC_ERR_OK) {
  42. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_write failed.");
  43. }
  44. return msr.value;
  45. }
  46. void amd64_emulator::msr_write(uint32_t rid, uint64_t value) {
  47. uc_x86_msr msr;
  48. msr.rid = rid;
  49. msr.value = value;
  50. auto err = uc_reg_write(m_unicorn_engine.get(), UC_X86_REG_MSR, &msr);
  51. if (err != UC_ERR_OK) {
  52. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_write failed.");
  53. }
  54. }
  55. void amd64_emulator::mem_map(uint64_t address, size_t size, uint32_t perms) {
  56. auto err = uc_mem_map(m_unicorn_engine.get(), address, size, perms);
  57. if (err) {
  58. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_map failed.");
  59. }
  60. }
  61. void amd64_emulator::mem_unmap(uint64_t address, size_t size) {
  62. auto err = uc_mem_unmap(m_unicorn_engine.get(), address, size);
  63. if (err) {
  64. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_unmap failed.");
  65. }
  66. }
  67. void amd64_emulator::mem_read(uint64_t address, void* buf, size_t size) {
  68. auto err = uc_mem_read(m_unicorn_engine.get(), address, buf, size);
  69. if (err) {
  70. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_read failed.");
  71. }
  72. }
  73. std::vector<uint8_t> amd64_emulator::mem_read(uint64_t address, size_t size) {
  74. std::vector<uint8_t> ret_buf(size);
  75. auto err = uc_mem_read(m_unicorn_engine.get(), address, ret_buf.data(), ret_buf.size());
  76. if (err) {
  77. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_read failed.");
  78. }
  79. return ret_buf;
  80. }
  81. void amd64_emulator::mem_write(uint64_t address, const void* buf, size_t size) {
  82. auto err = uc_mem_write(m_unicorn_engine.get(), address, buf, size);
  83. if (err) {
  84. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_write failed.");
  85. }
  86. }
  87. void amd64_emulator::mem_write(uint64_t address, const std::vector<uint8_t>& buf) {
  88. mem_write(address, buf.data(), buf.size());
  89. }
  90. void amd64_emulator::hook_del(uc_hook hook_handle) {
  91. auto iter_of_hook_stub_ctxs = m_unicorn_hook_stub_ctxs.find(hook_handle);
  92. if (iter_of_hook_stub_ctxs == m_unicorn_hook_stub_ctxs.end()) {
  93. throw exceptions::key_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Target hook is not found.");
  94. }
  95. auto iter_of_hook_cbs_hookcode = m_unicorn_hook_cbs_hookcode.find(hook_handle);
  96. if (iter_of_hook_cbs_hookcode != m_unicorn_hook_cbs_hookcode.end()) {
  97. auto err = uc_hook_del(m_unicorn_engine.get(), hook_handle);
  98. if (err) {
  99. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"hook_del failed.");
  100. }
  101. m_unicorn_hook_cbs_hookcode.erase(iter_of_hook_cbs_hookcode);
  102. m_unicorn_hook_stub_ctxs.erase(iter_of_hook_stub_ctxs);
  103. return;
  104. }
  105. auto iter_of_hook_cbs_hookmem = m_unicorn_hook_cbs_hookmem.find(hook_handle);
  106. if (iter_of_hook_cbs_hookmem != m_unicorn_hook_cbs_hookmem.end()) {
  107. auto err = uc_hook_del(m_unicorn_engine.get(), hook_handle);
  108. if (err) {
  109. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"hook_del failed.");
  110. }
  111. m_unicorn_hook_cbs_hookmem.erase(iter_of_hook_cbs_hookmem);
  112. m_unicorn_hook_stub_ctxs.erase(iter_of_hook_stub_ctxs);
  113. return;
  114. }
  115. auto iter_of_hook_cbs_eventmem = m_unicorn_hook_cbs_eventmem.find(hook_handle);
  116. if (iter_of_hook_cbs_eventmem != m_unicorn_hook_cbs_eventmem.end()) {
  117. auto err = uc_hook_del(m_unicorn_engine.get(), hook_handle);
  118. if (err) {
  119. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"hook_del failed.");
  120. }
  121. m_unicorn_hook_cbs_eventmem.erase(iter_of_hook_cbs_eventmem);
  122. m_unicorn_hook_stub_ctxs.erase(iter_of_hook_stub_ctxs);
  123. return;
  124. }
  125. __assume(false);
  126. }
  127. void amd64_emulator::emu_start(uint64_t begin_address, uint64_t end_address, uint64_t timeout, size_t count) {
  128. auto err = uc_emu_start(m_unicorn_engine.get(), begin_address, end_address, timeout, count);
  129. if (err) {
  130. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"emu_start failed.");
  131. }
  132. }
  133. void amd64_emulator::emu_stop() {
  134. auto err = uc_emu_stop(m_unicorn_engine.get());
  135. if (err) {
  136. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_emu_stop failed.");
  137. }
  138. }
  139. //void amd64_emulator::create_gdt_entry(uint64_t gdt_entry_address, uint32_t base, uint32_t limit, uint8_t access_byte, uint8_t flags) {
  140. // struct {
  141. // uint16_t limit0;
  142. // uint16_t base0;
  143. // uint8_t base1;
  144. // uint8_t access_byte;
  145. // uint8_t limit1 : 4;
  146. // uint8_t flags : 4;
  147. // uint8_t base2;
  148. // } segment_descriptor;
  149. // static_assert(sizeof(segment_descriptor) == 8);
  150. // segment_descriptor.limit0 = limit & 0xffff;
  151. // segment_descriptor.base0 = base & 0xffff;
  152. // segment_descriptor.base1 = (base >> 16) & 0xff;
  153. // segment_descriptor.access_byte = access_byte;
  154. // segment_descriptor.limit1 = (limit >> 16) & 0xf;
  155. // segment_descriptor.flags = flags & 0xf;
  156. // segment_descriptor.base2 = (base >> 24) & 0xff;
  157. // auto err = uc_mem_write(m_unicorn_engine.get(), gdt_entry_address, &segment_descriptor, sizeof(segment_descriptor));
  158. // if (err != UC_ERR_OK) {
  159. // throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_write failed.");
  160. // }
  161. //}
  162. }
  163. #undef NKG_CURRENT_SOURCE_LINE
  164. #undef NKG_CURRENT_SOURCE_FILE