diff --git a/src/emulator/emulator.hpp b/src/emulator/emulator.hpp index 982c3415..e2100e57 100644 --- a/src/emulator/emulator.hpp +++ b/src/emulator/emulator.hpp @@ -1,15 +1,19 @@ #pragma once #include #include +#include +#include -#include "memory_permission.hpp" +#include "memory_region.hpp" -struct memory_region -{ - uint64_t start; - size_t length; - memory_permission pemissions; -}; +struct emulator_hook; + +using memory_operation = memory_permission; + +using instruction_hook_callback = std::function; + +using simple_memory_hook_callback = std::function; +using complex_memory_hook_callback = std::function; class emulator { @@ -39,54 +43,39 @@ public: virtual void protect_memory(uint64_t address, size_t size, memory_permission permissions) = 0; virtual std::vector get_memory_regions() = 0; -}; -template -class typed_emulator : public emulator -{ -public: - using registers = Register; - using pointer_type = PointerType; + virtual emulator_hook* hook_memory_access(uint64_t address, size_t size, memory_operation filter, + complex_memory_hook_callback callback) = 0; + virtual emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) = 0; - static constexpr size_t pointer_size = sizeof(pointer_type); - static constexpr registers stack_pointer = StackPointer; + virtual void delete_hook(emulator_hook* hook) = 0; - void write_register(registers reg, const void* value, const size_t size) + emulator_hook* hook_memory_read(const uint64_t address, const size_t size, simple_memory_hook_callback callback) { - this->write_raw_register(static_cast(reg), value, size); + return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::read); } - void read_register(registers reg, void* value, const size_t size) + emulator_hook* hook_memory_write(const uint64_t address, const size_t size, simple_memory_hook_callback callback) { - this->read_raw_register(static_cast(reg), value, size); + return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::write); } - template - T reg(const registers regid) const + emulator_hook* hook_memory_execution(const uint64_t address, const size_t size, + simple_memory_hook_callback callback) { - T value{}; - this->read_register(regid, &value, sizeof(value)); - return value; - } - - template - void reg(const registers regid, const S& maybe_value) const - { - T value = static_cast(maybe_value); - this->write_register(regid, &value, sizeof(value)); - } - - pointer_type read_stack(const size_t index) const - { - uint64_t result{}; - const auto sp = this->reg(stack_pointer); - - this->read_memory(sp + (index * pointer_size), &result, sizeof(result)); - - return result; + return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::exec); } private: - void read_raw_register(int reg, void* value, size_t size) override = 0; - void write_raw_register(int reg, const void* value, size_t size) override = 0; + emulator_hook* hook_simple_memory_access(const uint64_t address, const size_t size, + simple_memory_hook_callback callback, const memory_operation operation) + { + assert((static_cast(operation) & (static_cast(operation) - 1)) == 0); + return this->hook_memory_access(address, size, operation, + [c = std::move(callback)](const uint64_t a, const size_t s, + memory_operation) + { + c(a, s); + }); + } }; diff --git a/src/emulator/memory_region.hpp b/src/emulator/memory_region.hpp new file mode 100644 index 00000000..e166195d --- /dev/null +++ b/src/emulator/memory_region.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "memory_permission.hpp" + +struct memory_region +{ + uint64_t start; + size_t length; + memory_permission pemissions; +}; diff --git a/src/emulator/typed_emulator.hpp b/src/emulator/typed_emulator.hpp new file mode 100644 index 00000000..af2184fc --- /dev/null +++ b/src/emulator/typed_emulator.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include "emulator.hpp" + +using simple_instruction_hook_callback = std::function; + +template +class typed_emulator : public emulator +{ +public: + using registers = Register; + using pointer_type = PointerType; + using hookable_instructions = HookableInstructions; + + static constexpr size_t pointer_size = sizeof(pointer_type); + static constexpr registers stack_pointer = StackPointer; + static constexpr registers instruction_pointer = InstructionPointer; + + void write_register(registers reg, const void* value, const size_t size) + { + this->write_raw_register(static_cast(reg), value, size); + } + + void read_register(registers reg, void* value, const size_t size) + { + this->read_raw_register(static_cast(reg), value, size); + } + + template + T reg(const registers regid) + { + T value{}; + this->read_register(regid, &value, sizeof(value)); + return value; + } + + template + void reg(const registers regid, const S& maybe_value) + { + T value = static_cast(maybe_value); + this->write_register(regid, &value, sizeof(value)); + } + + pointer_type read_stack(const size_t index) + { + pointer_type result{}; + const auto sp = this->reg(stack_pointer); + + this->read_memory(sp + (index * pointer_size), &result, sizeof(result)); + + return result; + } + + emulator_hook* hook_instruction(hookable_instructions instruction_type, instruction_hook_callback callback) + { + return this->hook_instruction(instruction_type, [this, c = std::move(callback)] + { + const auto ip = static_cast(this->reg(instruction_pointer)); + c(ip); + }); + } + + virtual emulator_hook* hook_instruction(hookable_instructions instruction_type, + simple_instruction_hook_callback callback) = 0; + +private: + emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override + { + return this->hook_instruction(static_cast(instruction_type), std::move(callback)); + } + + void read_raw_register(int reg, void* value, size_t size) override = 0; + void write_raw_register(int reg, const void* value, size_t size) override = 0; +}; diff --git a/src/emulator/x64_emulator.hpp b/src/emulator/x64_emulator.hpp index 882c2559..13146e87 100644 --- a/src/emulator/x64_emulator.hpp +++ b/src/emulator/x64_emulator.hpp @@ -1,248 +1,12 @@ #pragma once -#include "emulator.hpp" +#include "typed_emulator.hpp" +#include "x64_register.hpp" -enum class x64_register +enum class x64_hookable_instructions { - invalid = 0, - ah, - al, - ax, - bh, - bl, - bp, - bpl, - bx, - ch, - cl, - cs, - cx, - dh, - di, - dil, - dl, - ds, - dx, - eax, - ebp, - ebx, - ecx, - edi, - edx, - eflags, - eip, - es = eip + 2, - esi, - esp, - fpsw, - fs, - gs, - ip, - rax, - rbp, - rbx, - rcx, - rdi, - rdx, - rip, - rsi = rip + 2, - rsp, - si, - sil, - sp, - spl, - ss, - cr0, - cr1, - cr2, - cr3, - cr4, - cr8 = cr4 + 4, - dr0 = cr8 + 8, - dr1, - dr2, - dr3, - dr4, - dr5, - dr6, - dr7, - fp0 = dr7 + 9, - fp1, - fp2, - fp3, - fp4, - fp5, - fp6, - fp7, - k0, - k1, - k2, - k3, - k4, - k5, - k6, - k7, - mm0, - mm1, - mm2, - mm3, - mm4, - mm5, - mm6, - mm7, - r8, - r9, - r10, - r11, - r12, - r13, - r14, - r15, - st0, - st1, - st2, - st3, - st4, - st5, - st6, - st7, - xmm0, - xmm1, - xmm2, - xmm3, - xmm4, - xmm5, - xmm6, - xmm7, - xmm8, - xmm9, - xmm10, - xmm11, - xmm12, - xmm13, - xmm14, - xmm15, - xmm16, - xmm17, - xmm18, - xmm19, - xmm20, - xmm21, - xmm22, - xmm23, - xmm24, - xmm25, - xmm26, - xmm27, - xmm28, - xmm29, - xmm30, - xmm31, - ymm0, - ymm1, - ymm2, - ymm3, - ymm4, - ymm5, - ymm6, - ymm7, - ymm8, - ymm9, - ymm10, - ymm11, - ymm12, - ymm13, - ymm14, - ymm15, - ymm16, - ymm17, - ymm18, - ymm19, - ymm20, - ymm21, - ymm22, - ymm23, - ymm24, - ymm25, - ymm26, - ymm27, - ymm28, - ymm29, - ymm30, - ymm31, - zmm0, - zmm1, - zmm2, - zmm3, - zmm4, - zmm5, - zmm6, - zmm7, - zmm8, - zmm9, - zmm10, - zmm11, - zmm12, - zmm13, - zmm14, - zmm15, - zmm16, - zmm17, - zmm18, - zmm19, - zmm20, - zmm21, - zmm22, - zmm23, - zmm24, - zmm25, - zmm26, - zmm27, - zmm28, - zmm29, - zmm30, - zmm31, - r8b, - r9b, - r10b, - r11b, - r12b, - r13b, - r14b, - r15b, - r8d, - r9d, - r10d, - r11d, - r12d, - r13d, - r14d, - r15d, - r8w, - r9w, - r10w, - r11w, - r12w, - r13w, - r14w, - r15w, - idtr, - gdtr, - ldtr, - tr, - fpcw, - fptag, - msr, - mxcsr, - fs_base, - gs_base, - flags, - rflags, - fip, - fcs, - fdp, - fds, - fop, - end, // Must be last + syscall, + cpuid, }; -using x64_emulator = typed_emulator; +using x64_emulator = typed_emulator; diff --git a/src/emulator/x64_register.hpp b/src/emulator/x64_register.hpp new file mode 100644 index 00000000..520e1d78 --- /dev/null +++ b/src/emulator/x64_register.hpp @@ -0,0 +1,245 @@ +#pragma once + +enum class x64_register +{ + invalid = 0, + ah, + al, + ax, + bh, + bl, + bp, + bpl, + bx, + ch, + cl, + cs, + cx, + dh, + di, + dil, + dl, + ds, + dx, + eax, + ebp, + ebx, + ecx, + edi, + edx, + eflags, + eip, + es = eip + 2, + esi, + esp, + fpsw, + fs, + gs, + ip, + rax, + rbp, + rbx, + rcx, + rdi, + rdx, + rip, + rsi = rip + 2, + rsp, + si, + sil, + sp, + spl, + ss, + cr0, + cr1, + cr2, + cr3, + cr4, + cr8 = cr4 + 4, + dr0 = cr8 + 8, + dr1, + dr2, + dr3, + dr4, + dr5, + dr6, + dr7, + fp0 = dr7 + 9, + fp1, + fp2, + fp3, + fp4, + fp5, + fp6, + fp7, + k0, + k1, + k2, + k3, + k4, + k5, + k6, + k7, + mm0, + mm1, + mm2, + mm3, + mm4, + mm5, + mm6, + mm7, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + st0, + st1, + st2, + st3, + st4, + st5, + st6, + st7, + xmm0, + xmm1, + xmm2, + xmm3, + xmm4, + xmm5, + xmm6, + xmm7, + xmm8, + xmm9, + xmm10, + xmm11, + xmm12, + xmm13, + xmm14, + xmm15, + xmm16, + xmm17, + xmm18, + xmm19, + xmm20, + xmm21, + xmm22, + xmm23, + xmm24, + xmm25, + xmm26, + xmm27, + xmm28, + xmm29, + xmm30, + xmm31, + ymm0, + ymm1, + ymm2, + ymm3, + ymm4, + ymm5, + ymm6, + ymm7, + ymm8, + ymm9, + ymm10, + ymm11, + ymm12, + ymm13, + ymm14, + ymm15, + ymm16, + ymm17, + ymm18, + ymm19, + ymm20, + ymm21, + ymm22, + ymm23, + ymm24, + ymm25, + ymm26, + ymm27, + ymm28, + ymm29, + ymm30, + ymm31, + zmm0, + zmm1, + zmm2, + zmm3, + zmm4, + zmm5, + zmm6, + zmm7, + zmm8, + zmm9, + zmm10, + zmm11, + zmm12, + zmm13, + zmm14, + zmm15, + zmm16, + zmm17, + zmm18, + zmm19, + zmm20, + zmm21, + zmm22, + zmm23, + zmm24, + zmm25, + zmm26, + zmm27, + zmm28, + zmm29, + zmm30, + zmm31, + r8b, + r9b, + r10b, + r11b, + r12b, + r13b, + r14b, + r15b, + r8d, + r9d, + r10d, + r11d, + r12d, + r13d, + r14d, + r15d, + r8w, + r9w, + r10w, + r11w, + r12w, + r13w, + r14w, + r15w, + idtr, + gdtr, + ldtr, + tr, + fpcw, + fptag, + msr, + mxcsr, + fs_base, + gs_base, + flags, + rflags, + fip, + fcs, + fdp, + fds, + fop, + end, // Must be last +}; diff --git a/src/unicorn_emulator/unicorn_x64_emulator.cpp b/src/unicorn_emulator/unicorn_x64_emulator.cpp index d3af2410..965fe519 100644 --- a/src/unicorn_emulator/unicorn_x64_emulator.cpp +++ b/src/unicorn_emulator/unicorn_x64_emulator.cpp @@ -1,6 +1,7 @@ #define UNICORN_EMULATOR_IMPL #include "unicorn_x64_emulator.hpp" +#define NOMINMAX #include #include @@ -39,6 +40,32 @@ namespace unicorn throw_if_unicorn_error(error_code); } + uc_x86_insn map_hookable_instruction(const x64_hookable_instructions instruction) + { + switch (instruction) + { + case x64_hookable_instructions::syscall: + return UC_X86_INS_SYSCALL; + case x64_hookable_instructions::cpuid: + return UC_X86_INS_CPUID; + } + + throw std::runtime_error("Bad instruction for mapping"); + } + + memory_operation map_memory_operation(const uc_mem_type mem_type) + { + switch (mem_type) + { + case UC_MEM_READ: + return memory_permission::read; + case UC_MEM_WRITE: + return memory_permission::write; + default: + return memory_permission::none; + } + } + class unicorn_memory_regions { public: @@ -70,6 +97,151 @@ namespace unicorn uc_mem_region* regions_{}; }; + struct object + { + object() = default; + virtual ~object() = default; + + object(object&&) = default; + object(const object&) = default; + object& operator=(object&&) = default; + object& operator=(const object&) = default; + }; + + struct hook_object : object + { + emulator_hook* as_opaque_hook() + { + return reinterpret_cast(this); + } + }; + + class unicorn_hook + { + public: + unicorn_hook() = default; + + unicorn_hook(uc_engine* uc) + : unicorn_hook(uc, {}) + { + } + + unicorn_hook(uc_engine* uc, const uc_hook hook) + : uc_(uc) + , hook_(hook) + { + } + + ~unicorn_hook() + { + release(); + } + + unicorn_hook(const unicorn_hook&) = delete; + unicorn_hook& operator=(const unicorn_hook&) = delete; + + + unicorn_hook(unicorn_hook&& obj) noexcept + { + this->operator=(std::move(obj)); + } + + uc_hook* make_reference() + { + if (!this->uc_) + { + throw std::runtime_error("Cannot make reference on default constructed hook"); + } + + this->release(); + return &this->hook_; + } + + unicorn_hook& operator=(unicorn_hook&& obj) noexcept + { + if (this != &obj) + { + this->release(); + + this->uc_ = obj.uc_; + this->hook_ = obj.hook_; + obj.uc_ = {}; + } + + + return *this; + } + + void release() + { + if (this->hook_ && this->uc_) + { + uc_hook_del(this->uc_, this->hook_); + this->hook_ = {}; + } + } + + private: + uc_engine* uc_{}; + uc_hook hook_{}; + }; + + template + class function_wrapper : public object + { + public: + using user_data_pointer = void*; + using c_function_type = ReturnType(Args..., user_data_pointer); + using functor_type = std::function; + + function_wrapper(functor_type functor) + : functor_(std::make_unique(std::move(functor))) + { + } + + c_function_type* get_function() + { + return +[](Args... args, user_data_pointer user_data) -> ReturnType + { + return (*static_cast(user_data))(std::forward(args)...); + }; + } + + user_data_pointer get_user_data() const + { + return this->functor_.get(); + } + + private: + std::unique_ptr functor_{}; + }; + + class hook_container : public hook_object + { + public: + template + requires(std::is_base_of_v + && std::is_move_constructible_v) + void add(T data, unicorn_hook hook) + { + hook_entry entry{}; + + entry.data = std::make_unique(std::move(data)); + entry.hook = std::move(hook); + + this->hooks_.emplace_back(std::move(entry)); + } + + private: + struct hook_entry + { + std::unique_ptr data{}; + unicorn_hook hook{}; + }; + + std::vector hooks_; + }; + class unicorn_x64_emulator : public x64_emulator { public: @@ -169,6 +341,121 @@ namespace unicorn return result; } + emulator_hook* hook_instruction(x64_hookable_instructions instruction_type, + simple_instruction_hook_callback callback) + { + const auto uc_instruction = map_hookable_instruction(instruction_type); + + function_wrapper wrapper([c = std::move(callback)](uc_engine*) + { + c(); + }); + + unicorn_hook hook{*this}; + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_INSN, wrapper.get_function(), + wrapper.get_user_data(), 0, std::numeric_limits::max(), uc_instruction)); + + auto container = std::make_unique(); + container->add(std::move(wrapper), std::move(hook)); + + auto* result = container->as_opaque_hook(); + + this->hooks_.push_back(std::move(container)); + + return result; + } + + emulator_hook* hook_memory_access(uint64_t address, size_t size, memory_operation filter, + complex_memory_hook_callback callback) override + { + if (filter == memory_permission::none) + { + return nullptr; + } + + const auto shared_callback = std::make_shared(std::move(callback)); + + auto container = std::make_unique(); + + if ((filter & memory_operation::read) != memory_operation::none) + { + function_wrapper wrapper( + [shared_callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, + const int64_t) + { + const auto operation = map_memory_operation(type); + if (operation != memory_permission::none) + { + (*shared_callback)(address, static_cast(size), operation); + } + }); + + unicorn_hook hook{*this}; + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_READ, wrapper.get_function(), + wrapper.get_user_data(), address, address + size)); + + container->add(std::move(wrapper), std::move(hook)); + } + + if ((filter & memory_operation::write) != memory_operation::none) + { + function_wrapper wrapper( + [shared_callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, + const int64_t) + { + const auto operation = map_memory_operation(type); + if (operation != memory_permission::none) + { + (*shared_callback)(address, static_cast(size), operation); + } + }); + + unicorn_hook hook{*this}; + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_WRITE, wrapper.get_function(), + wrapper.get_user_data(), address, address + size)); + + container->add(std::move(wrapper), std::move(hook)); + } + + if ((filter & memory_operation::exec) != memory_operation::none) + { + function_wrapper wrapper( + [shared_callback](uc_engine*, const uint64_t address, const uint32_t size) + { + (*shared_callback)(address, static_cast(size), memory_permission::exec); + }); + + unicorn_hook hook{*this}; + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(), + wrapper.get_user_data(), address, address + size)); + + container->add(std::move(wrapper), std::move(hook)); + } + + auto* result = container->as_opaque_hook(); + + this->hooks_.push_back(std::move(container)); + + return result; + } + + void delete_hook(emulator_hook* hook) override + { + const auto entry = std::ranges::find_if(this->hooks_, [&](const std::unique_ptr& hook_ptr) + { + return hook_ptr->as_opaque_hook() == hook; + }); + + if (entry != this->hooks_.end()) + { + this->hooks_.erase(entry); + } + } + operator uc_engine*() const { return this->uc_; @@ -176,6 +463,7 @@ namespace unicorn private: uc_engine* uc_{}; + std::vector> hooks_{}; }; } diff --git a/src/windows_emulator/emulator_utils.hpp b/src/windows_emulator/emulator_utils.hpp index 8f2621de..20a7e3b2 100644 --- a/src/windows_emulator/emulator_utils.hpp +++ b/src/windows_emulator/emulator_utils.hpp @@ -1,8 +1,6 @@ #pragma once #include "memory_utils.hpp" -#include - template class emulator_object { @@ -137,96 +135,3 @@ private: uint64_t size_{}; uint64_t active_address_{0}; }; - -/* -class unicorn_hook -{ -public: - using function = std::function; - - template - unicorn_hook(const unicorn& uc, const int type, const uint64_t begin, const uint64_t end, function callback, - Args... args) - : uc_(&uc) - { - this->function_ = std::make_unique( - [c = std::move(callback), &uc](const uint64_t address, const uint32_t size) - { - c(uc, address, size); - }); - - void* handler = +[](uc_engine*, const uint64_t address, const uint32_t size, - void* user_data) - { - (*static_cast(user_data))(address, size); - }; - - if (type == UC_HOOK_INSN) - { - handler = +[](uc_engine* uc, void* user_data) - { - uint64_t rip{}; - uc_reg_read(uc, UC_X86_REG_RIP, &rip); - (*static_cast(user_data))(rip, 0); - }; - } - - if (type == UC_HOOK_MEM_READ) - { - handler = +[](uc_engine*, const uc_mem_type, const uint64_t address, const int size, - const int64_t, void* user_data) - { - (*static_cast(user_data))(address, size); - }; - } - uce(uc_hook_add(*this->uc_, &this->hook_, type, handler, this->function_.get(), begin, end, args...)); - } - - unicorn_hook(const unicorn_hook&) = delete; - unicorn_hook& operator=(const unicorn_hook&) = delete; - - unicorn_hook(unicorn_hook&& obj) noexcept - { - this->operator=(std::move(obj)); - } - - unicorn_hook& operator=(unicorn_hook&& obj) noexcept - { - if (this != &obj) - { - this->remove(); - - this->uc_ = obj.uc_; - this->hook_ = obj.hook_; - this->function_ = std::move(obj.function_); - - obj.hook_ = {}; - } - - return *this; - } - - ~unicorn_hook() - { - this->remove(); - } - - void remove() - { - if (this->hook_) - { - uc_hook_del(*this->uc_, this->hook_); - this->hook_ = {}; - } - - this->function_ = {}; - } - -private: - using internal_function = std::function; - - const unicorn* uc_{}; - uc_hook hook_{}; - std::unique_ptr function_{}; -}; -*/ \ No newline at end of file diff --git a/src/windows_emulator/main.cpp b/src/windows_emulator/main.cpp index bb2565cb..777271db 100644 --- a/src/windows_emulator/main.cpp +++ b/src/windows_emulator/main.cpp @@ -270,24 +270,21 @@ namespace std::map members_{}; }; - /* + template - unicorn_hook watch_object(const unicorn& uc, emulator_object object) + void watch_object(x64_emulator& emu, emulator_object object) { type_info info{}; - return { - uc, UC_HOOK_MEM_READ, object.value(), object.end(), - [i = std::move(info), o = std::move(object)](const unicorn&, const uint64_t address, - const uint32_t ) - { - const auto offset = address - o.value(); - printf("%s: %llX (%s)\n", i.get_type_name().c_str(), offset, - i.get_member_name(offset).c_str()); - } - }; + emu.hook_memory_read(object.value(), object.size(), + [i = std::move(info), object](const uint64_t address, size_t) + { + const auto offset = address - object.value(); + printf("%s: %llX (%s)\n", i.get_type_name().c_str(), offset, + i.get_member_name(offset).c_str()); + }); } - */ + void run() { const auto emu = unicorn::create_x64_emulator(); @@ -309,10 +306,6 @@ namespace (void)entry1; (void)entry2; - /* - std::vector export_hooks{}; - - std::unordered_map export_remap{}; for (const auto& exp : context.ntdll.exports) { @@ -322,53 +315,49 @@ namespace for (const auto& exp : export_remap) { auto name = exp.second; - unicorn_hook hook(uc, UC_HOOK_CODE, exp.first, exp.first, - [n = std::move(name)](const unicorn& uc, const uint64_t address, const uint32_t) - { - printf("Executing function: %s (%llX)\n", n.c_str(), address); + emu->hook_memory_execution(exp.first, exp.first, + [&emu, n = std::move(name)](const uint64_t address, const size_t) + { + printf("Executing function: %s (%llX)\n", n.c_str(), address); - if (n == "RtlImageNtHeaderEx") - { - printf("Base: %llX\n", uc.reg(UC_X86_REG_RDX)); - } - }); - - export_hooks.emplace_back(std::move(hook)); + if (n == "RtlImageNtHeaderEx") + { + printf("Base: %llX\n", emu->reg(x64_register::rdx)); + } + }); } - unicorn_hook hook(uc, UC_HOOK_INSN, 0, std::numeric_limits::max(), - [&](const unicorn&, const uint64_t, const uint32_t) - { - handle_syscall(uc, context); - }, UC_X86_INS_SYSCALL); + emu->hook_instruction(x64_hookable_instructions::syscall, [&] + { + handle_syscall(*emu, context); + }); - //export_hooks.emplace_back(watch_object(uc, context.teb)); - //export_hooks.emplace_back(watch_object(uc, context.peb)); - //export_hooks.emplace_back(watch_object(uc, context.process_params)); - //export_hooks.emplace_back(watch_object(uc, context.kusd)); + watch_object(*emu, context.teb); + watch_object(*emu, context.peb); + watch_object(*emu, context.process_params); + watch_object(*emu, context.kusd); - unicorn_hook hook2(uc, UC_HOOK_CODE, 0, std::numeric_limits::max(), - [](const unicorn& uc, const uint64_t address, const uint32_t ) - { - static bool hit = false; - // if (address == 0x1800D3C80) - if (address == 0x1800D4420) - { - //hit = true; - //uc.stop(); - } + emu->hook_memory_execution(0, std::numeric_limits::max(), [&](const uint64_t address, const size_t) + { + static bool hit = false; + // if (address == 0x1800D3C80) + if (address == 0x1800D4420) + { + //hit = true; + //uc.stop(); + } + + if (hit) + { + printf( + "Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX - R8: %16llX - R9: %16llX - RDI: %16llX - RSI: %16llX\n", + address, + emu->reg(x64_register::rax), emu->reg(x64_register::rbx), emu->reg(x64_register::rcx), + emu->reg(x64_register::rdx), emu->reg(x64_register::r8), emu->reg(x64_register::r9), + emu->reg(x64_register::rdi), emu->reg(x64_register::rsi)); + } + }); - if (hit) - { - printf( - "Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX - R8: %16llX - R9: %16llX - RDI: %16llX - RSI: %16llX\n", - address, - uc.reg(UC_X86_REG_RAX), uc.reg(UC_X86_REG_RBX), uc.reg(UC_X86_REG_RCX), - uc.reg(UC_X86_REG_RDX), uc.reg(UC_X86_REG_R8), uc.reg(UC_X86_REG_R9), - uc.reg(UC_X86_REG_RDI), uc.reg(UC_X86_REG_RSI)); - } - }); -*/ const auto execution_context = context.gs_segment.reserve(); emu->reg(x64_register::rcx, execution_context.value()); diff --git a/src/windows_emulator/memory_utils.hpp b/src/windows_emulator/memory_utils.hpp index d0d95419..43b09839 100644 --- a/src/windows_emulator/memory_utils.hpp +++ b/src/windows_emulator/memory_utils.hpp @@ -59,7 +59,7 @@ inline bool is_memory_allocated(emulator& emu, const uint64_t address) return false; } -inline memory_permission map_nt_to_unicorn_protection(const uint32_t nt_protection) +inline memory_permission map_nt_to_emulator_protection(const uint32_t nt_protection) { switch (nt_protection) { @@ -80,7 +80,7 @@ inline memory_permission map_nt_to_unicorn_protection(const uint32_t nt_protecti } } -inline uint32_t map_unicorn_to_nt_protection(const memory_permission permission) +inline uint32_t map_emulator_to_nt_protection(const memory_permission permission) { const bool has_exec = (permission & memory_permission::exec) != memory_permission::none; const bool has_read = (permission & memory_permission::read) != memory_permission::none; diff --git a/src/windows_emulator/process_context.hpp b/src/windows_emulator/process_context.hpp index 21f6bb05..51e68cdb 100644 --- a/src/windows_emulator/process_context.hpp +++ b/src/windows_emulator/process_context.hpp @@ -1,5 +1,5 @@ #pragma once -#include "unicorn_utils.hpp" +#include "emulator_utils.hpp" struct mapped_binary { diff --git a/src/windows_emulator/std_include.hpp b/src/windows_emulator/std_include.hpp index 74d1372b..f6b0eadf 100644 --- a/src/windows_emulator/std_include.hpp +++ b/src/windows_emulator/std_include.hpp @@ -56,8 +56,6 @@ #include -#include - #define NTDDI_WIN11_GE 0 #define PHNT_VERSION PHNT_WIN11 #include diff --git a/src/windows_emulator/syscalls.cpp b/src/windows_emulator/syscalls.cpp index 60d74cd6..7c4d87b1 100644 --- a/src/windows_emulator/syscalls.cpp +++ b/src/windows_emulator/syscalls.cpp @@ -3,10 +3,10 @@ namespace { - void handle_NtQueryPerformanceCounter(const unicorn& uc) + void handle_NtQueryPerformanceCounter(x64_emulator& emu) { - const emulator_object performance_counter{uc, uc.reg(UC_X86_REG_R10)}; - const emulator_object performance_frequency{uc, uc.reg(UC_X86_REG_RDX)}; + const emulator_object performance_counter{emu, emu.reg(x64_register::r10)}; + const emulator_object performance_frequency{emu, emu.reg(x64_register::rdx)}; try { @@ -26,45 +26,45 @@ namespace }); } - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); } catch (...) { - uc.reg(UC_X86_REG_RAX, STATUS_ACCESS_VIOLATION); + emu.reg(x64_register::rax, STATUS_ACCESS_VIOLATION); } } - void handle_NtManageHotPatch(const unicorn& uc) + void handle_NtManageHotPatch(x64_emulator& emu) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED); + emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); } - void handle_NtOpenKey(const unicorn& uc) + void handle_NtOpenKey(x64_emulator& emu) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED); + emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); } - void handle_NtCreateIoCompletion(const unicorn& uc) + void handle_NtCreateIoCompletion(x64_emulator& emu) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED); + emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); } - void handle_NtTraceEvent(const unicorn& uc) + void handle_NtTraceEvent(x64_emulator& emu) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED); + emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); } - void handle_NtCreateEvent(const unicorn& uc, process_context& context) + void handle_NtCreateEvent(x64_emulator& emu, process_context& context) { - const emulator_object event_handle{uc, uc.reg(UC_X86_REG_R10)}; - const auto object_attributes = uc.reg(UC_X86_REG_R8); - const auto event_type = uc.reg(UC_X86_REG_R9D); - const auto initial_state = static_cast(uc.read_stack(5)); + const emulator_object event_handle{emu, emu.reg(x64_register::r10)}; + const auto object_attributes = emu.reg(x64_register::r8); + const auto event_type = emu.reg(x64_register::r9d); + const auto initial_state = static_cast(emu.read_stack(5)); if (object_attributes) { puts("Unsupported object attributes"); - uc.stop(); + emu.stop(); return; } @@ -75,34 +75,34 @@ namespace static_assert(sizeof(EVENT_TYPE) == sizeof(uint32_t)); - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); } - void handle_NtQueryVirtualMemory(const unicorn& uc, const process_context& context) + void handle_NtQueryVirtualMemory(x64_emulator& emu, const process_context& context) { - const auto process_handle = uc.reg(UC_X86_REG_R10); - const auto base_address = uc.reg(UC_X86_REG_RDX); - const auto info_class = uc.reg(UC_X86_REG_R8D); - const auto memory_information = uc.reg(UC_X86_REG_R9); - const auto memory_information_length = static_cast(uc.read_stack(5)); - const emulator_object return_length{uc, uc.read_stack(6)}; + const auto process_handle = emu.reg(x64_register::r10); + const auto base_address = emu.reg(x64_register::rdx); + const auto info_class = emu.reg(x64_register::r8d); + const auto memory_information = emu.reg(x64_register::r9); + const auto memory_information_length = static_cast(emu.read_stack(5)); + const emulator_object return_length{emu, emu.read_stack(6)}; if (process_handle != ~0ULL) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED); + emu.reg(x64_register::rax, STATUS_NOT_IMPLEMENTED); return; } if (info_class == MemoryWorkingSetExInformation) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED); + emu.reg(x64_register::rax, STATUS_NOT_IMPLEMENTED); return; } if (info_class != MemoryImageInformation) { printf("Unsupported memory info class: %X\n", info_class); - uc.stop(); + emu.stop(); return; } @@ -113,18 +113,18 @@ namespace if (memory_information_length != sizeof(MEMORY_IMAGE_INFORMATION)) { - uc.reg(UC_X86_REG_RAX, STATUS_BUFFER_OVERFLOW); + emu.reg(x64_register::rax, STATUS_BUFFER_OVERFLOW); return; } if (!is_within_start_and_length(base_address, context.ntdll.image_base, context.ntdll.size_of_image)) { puts("Bad image request"); - uc.stop(); + emu.stop(); return; } - const emulator_object info{uc, memory_information}; + const emulator_object info{emu, memory_information}; info.access([&](MEMORY_IMAGE_INFORMATION& image_info) { @@ -132,20 +132,20 @@ namespace image_info.SizeOfImage = context.ntdll.size_of_image; }); - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); } - void handle_NtQuerySystemInformation(const unicorn& uc) + void handle_NtQuerySystemInformation(x64_emulator& emu) { - const auto info_class = uc.reg(UC_X86_REG_R10D); - const auto system_information = uc.reg(UC_X86_REG_RDX); - const auto system_information_length = uc.reg(UC_X86_REG_R8D); - const emulator_object return_length{uc, uc.reg(UC_X86_REG_R9)}; + const auto info_class = emu.reg(x64_register::r10d); + const auto system_information = emu.reg(x64_register::rdx); + const auto system_information_length = emu.reg(x64_register::r8d); + const emulator_object return_length{emu, emu.reg(x64_register::r9)}; if (info_class == SystemFlushInformation || info_class == SystemHypervisorSharedPageInformation) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED); + emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); return; } @@ -158,11 +158,11 @@ namespace if (system_information_length != sizeof(SYSTEM_NUMA_INFORMATION)) { - uc.reg(UC_X86_REG_RAX, STATUS_BUFFER_TOO_SMALL); + emu.reg(x64_register::rax, STATUS_BUFFER_TOO_SMALL); return; } - const emulator_object info_obj{uc, system_information}; + const emulator_object info_obj{emu, system_information}; info_obj.access([&](SYSTEM_NUMA_INFORMATION& info) { @@ -172,14 +172,14 @@ namespace info.Pad[0] = 0xFFF; }); - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); return; } if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) { printf("Unsupported system info class: %X\n", info_class); - uc.stop(); + emu.stop(); return; } @@ -190,11 +190,11 @@ namespace if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION)) { - uc.reg(UC_X86_REG_RAX, STATUS_BUFFER_TOO_SMALL); + emu.reg(x64_register::rax, STATUS_BUFFER_TOO_SMALL); return; } - const emulator_object info{uc, system_information}; + const emulator_object info{emu, system_information}; info.access([&](SYSTEM_BASIC_INFORMATION& basic_info) { @@ -210,23 +210,23 @@ namespace basic_info.NumberOfProcessors = 1; }); - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); } - void handle_NtQuerySystemInformationEx(const unicorn& uc) + void handle_NtQuerySystemInformationEx(x64_emulator& emu) { - const auto info_class = uc.reg(UC_X86_REG_R10D); - const auto input_buffer = uc.reg(UC_X86_REG_RDX); - const auto input_buffer_length = uc.reg(UC_X86_REG_R8D); - const auto system_information = uc.reg(UC_X86_REG_R9); - const auto system_information_length = static_cast(uc.read_stack(5)); - const emulator_object return_length{uc, uc.read_stack(6)}; + const auto info_class = emu.reg(x64_register::r10d); + const auto input_buffer = emu.reg(x64_register::rdx); + const auto input_buffer_length = emu.reg(x64_register::r8d); + const auto system_information = emu.reg(x64_register::r9); + const auto system_information_length = static_cast(emu.read_stack(5)); + const emulator_object return_length{emu, emu.read_stack(6)}; if (info_class == SystemFlushInformation || info_class == SystemFeatureConfigurationInformation || info_class == SystemFeatureConfigurationSectionInformation) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED); + emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); return; } @@ -234,7 +234,7 @@ namespace { void* buffer = calloc(1, input_buffer_length); void* res_buff = calloc(1, system_information_length); - uc_mem_read(uc, input_buffer, buffer, input_buffer_length); + emu.read_memory(input_buffer, buffer, input_buffer_length); uint64_t code = 0; @@ -247,20 +247,20 @@ namespace if (code == 0) { - uc_mem_write(uc, system_information, res_buff, return_length.read()); + emu.write_memory(system_information, res_buff, return_length.read()); } free(buffer); free(res_buff); - uc.reg(UC_X86_REG_RAX, code); + emu.reg(x64_register::rax, code); return; } if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) { printf("Unsupported system info ex class: %X\n", info_class); - uc.stop(); + emu.stop(); return; } @@ -271,11 +271,11 @@ namespace if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION)) { - uc.reg(UC_X86_REG_RAX, STATUS_BUFFER_TOO_SMALL); + emu.reg(x64_register::rax, STATUS_BUFFER_TOO_SMALL); return; } - const emulator_object info{uc, system_information}; + const emulator_object info{emu, system_information}; info.access([&](SYSTEM_BASIC_INFORMATION& basic_info) { @@ -291,27 +291,27 @@ namespace basic_info.NumberOfProcessors = 1; }); - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); } - void handle_NtQueryProcessInformation(const unicorn& uc) + void handle_NtQueryProcessInformation(x64_emulator& emu) { - const auto process_handle = uc.reg(UC_X86_REG_R10); - const auto info_class = uc.reg(UC_X86_REG_EDX); - const auto process_information = uc.reg(UC_X86_REG_R8); - const auto process_information_length = uc.reg(UC_X86_REG_R9D); - const emulator_object return_length{uc, uc.read_stack(5)}; + const auto process_handle = emu.reg(x64_register::r10); + const auto info_class = emu.reg(x64_register::edx); + const auto process_information = emu.reg(x64_register::r8); + const auto process_information_length = emu.reg(x64_register::r9d); + const emulator_object return_length{emu, emu.read_stack(5)}; if (process_handle != ~0ULL) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED); + emu.reg(x64_register::rax, STATUS_NOT_IMPLEMENTED); return; } if (info_class != ProcessCookie) { printf("Unsupported process info class: %X\n", info_class); - uc.stop(); + emu.stop(); return; } @@ -322,27 +322,27 @@ namespace if (process_information_length != sizeof(uint32_t)) { - uc.reg(UC_X86_REG_RAX, STATUS_BUFFER_OVERFLOW); + emu.reg(x64_register::rax, STATUS_BUFFER_OVERFLOW); return; } - const emulator_object info{uc, process_information}; + const emulator_object info{emu, process_information}; info.write(0x01234567); - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); } - void handle_NtProtectVirtualMemory(const unicorn& uc) + void handle_NtProtectVirtualMemory(x64_emulator& emu) { - const auto process_handle = uc.reg(UC_X86_REG_R10); - const emulator_object base_address{uc, uc.reg(UC_X86_REG_RDX)}; - const emulator_object bytes_to_protect{uc, uc.reg(UC_X86_REG_R8)}; - const auto protection = uc.reg(UC_X86_REG_R9D); - const emulator_object old_protection{uc, uc.read_stack(5)}; + const auto process_handle = emu.reg(x64_register::r10); + const emulator_object base_address{emu, emu.reg(x64_register::rdx)}; + const emulator_object bytes_to_protect{emu, emu.reg(x64_register::r8)}; + const auto protection = emu.reg(x64_register::r9d); + const emulator_object old_protection{emu, emu.read_stack(5)}; if (process_handle != ~0ULL) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED); + emu.reg(x64_register::rax, STATUS_NOT_IMPLEMENTED); return; } @@ -352,27 +352,27 @@ namespace const auto size = page_align_up(bytes_to_protect.read()); bytes_to_protect.write(static_cast(size)); - const auto current_uc_protection = get_memory_protection(uc, address); - const auto current_protection = map_unicorn_to_nt_protection(current_uc_protection); + const auto current_uc_protection = get_memory_protection(emu, address); + const auto current_protection = map_emulator_to_nt_protection(current_uc_protection); old_protection.write(current_protection); - const auto requested_protection = map_nt_to_unicorn_protection(protection); - uce(uc_mem_protect(uc, address, size, requested_protection)); + const auto requested_protection = map_nt_to_emulator_protection(protection); + emu.protect_memory(address, size, requested_protection); - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); } - void handle_NtAllocateVirtualMemory(const unicorn& uc) + void handle_NtAllocateVirtualMemory(x64_emulator& emu) { - const auto process_handle = uc.reg(UC_X86_REG_R10); - const emulator_object base_address{uc, uc.reg(UC_X86_REG_RDX)}; - const emulator_object bytes_to_allocate{uc, uc.reg(UC_X86_REG_R9)}; - //const auto allocation_type = uc.reg(UC_X86_REG_R9D); - const auto page_protection = static_cast(uc.read_stack(6)); + const auto process_handle = emu.reg(x64_register::r10); + const emulator_object base_address{emu, emu.reg(x64_register::rdx)}; + const emulator_object bytes_to_allocate{emu, emu.reg(x64_register::r9)}; + //const auto allocation_type =emu.reg(x64_register::r9d); + const auto page_protection = static_cast(emu.read_stack(6)); if (process_handle != ~0ULL) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED); + emu.reg(x64_register::rax, STATUS_NOT_IMPLEMENTED); return; } @@ -381,7 +381,7 @@ namespace //allocation_bytes = align_up(allocation_bytes, allocation_granularity); //bytes_to_allocate.write(allocation_bytes); - const auto protection = map_nt_to_unicorn_protection(page_protection); + const auto protection = map_nt_to_emulator_protection(page_protection); auto allocate_anywhere = false; auto allocation_base = base_address.read(); @@ -390,9 +390,9 @@ namespace allocate_anywhere = true; allocation_base = allocation_granularity; } - else if (is_memory_allocated(uc, allocation_base)) + else if (is_memory_allocated(emu, allocation_base)) { - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); return; } @@ -400,34 +400,42 @@ namespace while (true) { - succeeded = uc_mem_map(uc, allocation_base, allocation_bytes, protection) == UC_ERR_OK; - if (succeeded || !allocate_anywhere) + try { + emu.map_memory(allocation_base, allocation_bytes, protection); + succeeded = true; break; } + catch (...) + { + if (!allocate_anywhere) + { + break; + } - allocation_base += allocation_granularity; + allocation_base += allocation_granularity; + } } base_address.write(allocation_base); - uc.reg(UC_X86_REG_RAX, succeeded - ? STATUS_SUCCESS - : STATUS_NOT_SUPPORTED // No idea what the correct code is + emu.reg(x64_register::rax, succeeded + ? STATUS_SUCCESS + : STATUS_NOT_SUPPORTED // No idea what the correct code is ); } - void handle_NtAllocateVirtualMemoryEx(const unicorn& uc) + void handle_NtAllocateVirtualMemoryEx(x64_emulator& emu) { - const auto process_handle = uc.reg(UC_X86_REG_R10); - const emulator_object base_address{uc, uc.reg(UC_X86_REG_RDX)}; - const emulator_object bytes_to_allocate{uc, uc.reg(UC_X86_REG_R8)}; - //const auto allocation_type = uc.reg(UC_X86_REG_R9D); - const auto page_protection = static_cast(uc.read_stack(5)); + const auto process_handle = emu.reg(x64_register::r10); + const emulator_object base_address{emu, emu.reg(x64_register::rdx)}; + const emulator_object bytes_to_allocate{emu, emu.reg(x64_register::r8)}; + //const auto allocation_type =emu.reg(x64_register::r9d); + const auto page_protection = static_cast(emu.read_stack(5)); if (process_handle != ~0ULL) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED); + emu.reg(x64_register::rax, STATUS_NOT_IMPLEMENTED); return; } @@ -436,7 +444,7 @@ namespace //allocation_bytes = align_up(allocation_bytes, allocation_granularity); //bytes_to_allocate.write(allocation_bytes); - const auto protection = map_nt_to_unicorn_protection(page_protection); + const auto protection = map_nt_to_emulator_protection(page_protection); auto allocate_anywhere = false; auto allocation_base = base_address.read(); @@ -445,9 +453,9 @@ namespace allocate_anywhere = true; allocation_base = allocation_granularity; } - else if (is_memory_allocated(uc, allocation_base)) + else if (is_memory_allocated(emu, allocation_base)) { - uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + emu.reg(x64_register::rax, STATUS_SUCCESS); return; } @@ -455,51 +463,69 @@ namespace while (true) { - succeeded = uc_mem_map(uc, allocation_base, allocation_bytes, protection) == UC_ERR_OK; - if (succeeded || !allocate_anywhere) + try { + emu.map_memory(allocation_base, allocation_bytes, protection); + succeeded = true; break; } + catch (...) + { + succeeded = false; + if (!allocate_anywhere) + { + break; + } - allocation_base += allocation_granularity; + allocation_base += allocation_granularity; + } } base_address.write(allocation_base); - uc.reg(UC_X86_REG_RAX, succeeded - ? STATUS_SUCCESS - : STATUS_NOT_SUPPORTED // No idea what the correct code is + emu.reg(x64_register::rax, succeeded + ? STATUS_SUCCESS + : STATUS_NOT_SUPPORTED // No idea what the correct code is ); } - void handle_NtFreeVirtualMemory(const unicorn& uc) + void handle_NtFreeVirtualMemory(x64_emulator& emu) { - const auto process_handle = uc.reg(UC_X86_REG_R10); - const emulator_object base_address{uc, uc.reg(UC_X86_REG_RDX)}; - const emulator_object bytes_to_allocate{uc, uc.reg(UC_X86_REG_R8)}; + const auto process_handle = emu.reg(x64_register::r10); + const emulator_object base_address{emu, emu.reg(x64_register::rdx)}; + const emulator_object bytes_to_allocate{emu, emu.reg(x64_register::r8)}; if (process_handle != ~0ULL) { - uc.reg(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED); + emu.reg(x64_register::rax, STATUS_NOT_IMPLEMENTED); return; } const auto allocation_base = base_address.read(); const auto allocation_size = bytes_to_allocate.read(); - const auto succeeded = uc_mem_unmap(uc, allocation_base, allocation_size) == UC_ERR_OK; + bool succeeded = false; + try + { + emu.unmap_memory(allocation_base, allocation_size); + succeeded = true; + } + catch (...) + { + succeeded = false; + } - uc.reg(UC_X86_REG_RAX, succeeded - ? STATUS_SUCCESS - : STATUS_NOT_SUPPORTED // No idea what the correct code is + emu.reg(x64_register::rax, succeeded + ? STATUS_SUCCESS + : STATUS_NOT_SUPPORTED // No idea what the correct code is ); } } void handle_syscall(x64_emulator& emu, process_context& context) { - const auto address = uc.reg(UC_X86_REG_RIP); - const auto syscall_id = uc.reg(UC_X86_REG_EAX); + const auto address = emu.reg(x64_register::rip); + const auto syscall_id = emu.reg(x64_register::eax); printf("Handling syscall: %X (%llX)\n", syscall_id, address); @@ -508,56 +534,56 @@ void handle_syscall(x64_emulator& emu, process_context& context) switch (syscall_id) { case 0x12: - handle_NtOpenKey(uc); + handle_NtOpenKey(emu); break; case 0x18: - handle_NtAllocateVirtualMemory(uc); + handle_NtAllocateVirtualMemory(emu); break; case 0x1E: - handle_NtFreeVirtualMemory(uc); + handle_NtFreeVirtualMemory(emu); break; case 0x19: - handle_NtQueryProcessInformation(uc); + handle_NtQueryProcessInformation(emu); break; case 0x23: - handle_NtQueryVirtualMemory(uc, context); + handle_NtQueryVirtualMemory(emu, context); break; case 0x31: - handle_NtQueryPerformanceCounter(uc); + handle_NtQueryPerformanceCounter(emu); break; case 0x36: - handle_NtQuerySystemInformation(uc); + handle_NtQuerySystemInformation(emu); break; case 0x48: - handle_NtCreateEvent(uc, context); + handle_NtCreateEvent(emu, context); break; case 0x50: - handle_NtProtectVirtualMemory(uc); + handle_NtProtectVirtualMemory(emu); break; case 0x5E: - handle_NtTraceEvent(uc); + handle_NtTraceEvent(emu); break; case 0x78: - handle_NtAllocateVirtualMemoryEx(uc); + handle_NtAllocateVirtualMemoryEx(emu); break; case 0xB2: - handle_NtCreateIoCompletion(uc); + handle_NtCreateIoCompletion(emu); break; case 0x11A: - handle_NtManageHotPatch(uc); + handle_NtManageHotPatch(emu); break; case 0x16E: - handle_NtQuerySystemInformationEx(uc); + handle_NtQuerySystemInformationEx(emu); break; default: printf("Unhandled syscall: %X\n", syscall_id); - uc.reg(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED); - uc.stop(); + emu.reg(x64_register::rax, STATUS_NOT_IMPLEMENTED); + emu.stop(); break; } } catch (...) { - uc.reg(UC_X86_REG_RAX, STATUS_UNSUCCESSFUL); + emu.reg(x64_register::rax, STATUS_UNSUCCESSFUL); } }