i386_emulator.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include "i386_emulator.hpp"
  3. #include "exceptions/key_exception.hpp"
  4. #define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-patcher\\i386_emulator.cpp"
  5. #define NKG_CURRENT_SOURCE_LINE() __LINE__
  6. namespace nkg {
  7. void i386_emulator::_unicorn_hookcode_cb_stub(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
  8. auto hook_stub_ctx =
  9. reinterpret_cast<hook_stub_context_t*>(user_data);
  10. auto& hook_callback =
  11. std::any_cast<std::function<hookcode_cb_t>&>(hook_stub_ctx->self->m_unicorn_hook_callbacks[hook_stub_ctx->unicorn_hook_handle]);
  12. hook_callback(static_cast<uint32_t>(address), size);
  13. }
  14. void i386_emulator::_unicorn_hookmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data) {
  15. auto hook_stub_ctx =
  16. reinterpret_cast<hook_stub_context_t*>(user_data);
  17. auto& hook_callback =
  18. std::any_cast<std::function<hookmem_cb_t>&>(hook_stub_ctx->self->m_unicorn_hook_callbacks[hook_stub_ctx->unicorn_hook_handle]);
  19. hook_callback(type, static_cast<uint32_t>(address), static_cast<unsigned int>(size), static_cast<int32_t>(value));
  20. }
  21. bool i386_emulator::_unicorn_eventmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data) {
  22. auto hook_stub_ctx =
  23. reinterpret_cast<hook_stub_context_t*>(user_data);
  24. auto& hook_callback =
  25. std::any_cast<std::function<eventmem_cb_t>&>(hook_stub_ctx->self->m_unicorn_hook_callbacks[hook_stub_ctx->unicorn_hook_handle]);
  26. return hook_callback(type, static_cast<uint32_t>(address), static_cast<unsigned int>(size), static_cast<int32_t>(value));
  27. }
  28. i386_emulator::i386_emulator() {
  29. auto err = uc_open(UC_ARCH_X86, UC_MODE_32, m_unicorn_engine.unsafe_addressof());
  30. if (err != UC_ERR_OK) {
  31. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_open failed.");
  32. }
  33. }
  34. void i386_emulator::reg_read(int regid, void* value) {
  35. auto err = uc_reg_read(m_unicorn_engine.get(), regid, value);
  36. if (err != UC_ERR_OK) {
  37. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_read failed.");
  38. }
  39. }
  40. void i386_emulator::reg_write(int regid, const void* value) {
  41. auto err = uc_reg_write(m_unicorn_engine.get(), regid, value);
  42. if (err != UC_ERR_OK) {
  43. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_write failed.");
  44. }
  45. }
  46. void i386_emulator::mem_map(uint32_t address, size_t size, uint32_t perms) {
  47. auto err = uc_mem_map(m_unicorn_engine.get(), address, size, perms);
  48. if (err) {
  49. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_map failed.");
  50. }
  51. }
  52. void i386_emulator::mem_unmap(uint32_t address, size_t size) {
  53. auto err = uc_mem_unmap(m_unicorn_engine.get(), address, size);
  54. if (err) {
  55. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_unmap failed.");
  56. }
  57. }
  58. void i386_emulator::mem_read(uint32_t address, void* buf, size_t size) {
  59. auto err = uc_mem_read(m_unicorn_engine.get(), address, buf, size);
  60. if (err) {
  61. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_read failed.");
  62. }
  63. }
  64. std::vector<uint8_t> i386_emulator::mem_read(uint32_t address, size_t size) {
  65. std::vector<uint8_t> ret_buf(size);
  66. auto err = uc_mem_read(m_unicorn_engine.get(), address, ret_buf.data(), ret_buf.size());
  67. if (err) {
  68. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_read failed.");
  69. }
  70. return ret_buf;
  71. }
  72. void i386_emulator::mem_write(uint32_t address, const void* buf, size_t size) {
  73. auto err = uc_mem_write(m_unicorn_engine.get(), address, buf, size);
  74. if (err) {
  75. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_write failed.");
  76. }
  77. }
  78. void i386_emulator::mem_write(uint32_t address, const std::vector<uint8_t>& buf) {
  79. mem_write(address, buf.data(), buf.size());
  80. }
  81. void i386_emulator::hook_del(uc_hook hook_handle) {
  82. auto iter_of_hook_stub_ctxs = m_unicorn_hook_stub_ctxs.find(hook_handle);
  83. if (iter_of_hook_stub_ctxs == m_unicorn_hook_stub_ctxs.end()) {
  84. throw exceptions::key_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Target hook is not found.");
  85. }
  86. auto iter_of_hook_callbacks = m_unicorn_hook_callbacks.find(hook_handle);
  87. if (iter_of_hook_callbacks != m_unicorn_hook_callbacks.end()) {
  88. auto err = uc_hook_del(m_unicorn_engine.get(), hook_handle);
  89. if (err) {
  90. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"hook_del failed.");
  91. }
  92. m_unicorn_hook_callbacks.erase(iter_of_hook_callbacks);
  93. m_unicorn_hook_stub_ctxs.erase(iter_of_hook_stub_ctxs);
  94. return;
  95. }
  96. __assume(false);
  97. }
  98. void i386_emulator::create_gdt_entry(uint32_t gdt_entry_address, uint32_t base, uint32_t limit, uint8_t access_byte, uint8_t flags) {
  99. struct {
  100. uint64_t limit0 : 16;
  101. uint64_t base0 : 24;
  102. uint64_t access_byte : 8;
  103. uint64_t limit1 : 4;
  104. uint64_t flags : 4;
  105. uint64_t base1 : 8;
  106. } gdt_entry;
  107. gdt_entry.limit0 = limit & 0xffff;
  108. gdt_entry.base0 = base & 0xffffff;
  109. gdt_entry.access_byte = access_byte;
  110. gdt_entry.flags = flags & 0xf;
  111. gdt_entry.base1 = (base & 0xff000000) >> 24;
  112. mem_write(gdt_entry_address, &gdt_entry, sizeof(gdt_entry));
  113. }
  114. void i386_emulator::emu_start(uint32_t begin_address, uint32_t end_address, uint64_t timeout, size_t count) {
  115. auto err = uc_emu_start(m_unicorn_engine.get(), begin_address, end_address, timeout, count);
  116. if (err) {
  117. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"emu_start failed.");
  118. }
  119. }
  120. void i386_emulator::emu_stop() {
  121. auto err = uc_emu_stop(m_unicorn_engine.get());
  122. if (err) {
  123. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_emu_stop failed.");
  124. }
  125. }
  126. }
  127. #undef NKG_CURRENT_SOURCE_LINE
  128. #undef NKG_CURRENT_SOURCE_FILE