From 024e837ad932a0a1ec75e2b8484d06f5df6a73b2 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 21 Aug 2024 13:31:17 +0200 Subject: [PATCH] Prepare unicorn isolation --- src/CMakeLists.txt | 4 +- src/emulator/CMakeLists.txt | 17 +- src/emulator/empty.cpp | 0 src/emulator/emulator.hpp | 92 +++++++ src/emulator/memory_permission.hpp | 64 +++++ src/emulator/memory_utils.hpp | 130 --------- src/emulator/syscalls.hpp | 6 - src/emulator/unicorn.cpp | 40 --- src/emulator/unicorn.hpp | 76 ------ src/emulator/x64_emulator.hpp | 248 ++++++++++++++++++ src/unicorn_emulator/CMakeLists.txt | 16 ++ src/unicorn_emulator/unicorn_x64_emulator.cpp | 186 +++++++++++++ src/unicorn_emulator/unicorn_x64_emulator.hpp | 16 ++ src/windows_emulator/CMakeLists.txt | 24 ++ .../emulator_utils.hpp} | 87 +++--- src/{emulator => windows_emulator}/main.cpp | 136 +++++----- src/windows_emulator/memory_utils.hpp | 110 ++++++++ .../process_context.hpp | 10 +- .../reflect_extension.hpp | 0 .../resource.rc | 0 .../resources/icon.ico | Bin .../std_include.hpp | 0 .../syscalls.cpp | 44 ++-- src/windows_emulator/syscalls.hpp | 6 + 24 files changed, 908 insertions(+), 404 deletions(-) create mode 100644 src/emulator/empty.cpp create mode 100644 src/emulator/emulator.hpp create mode 100644 src/emulator/memory_permission.hpp delete mode 100644 src/emulator/memory_utils.hpp delete mode 100644 src/emulator/syscalls.hpp delete mode 100644 src/emulator/unicorn.cpp delete mode 100644 src/emulator/unicorn.hpp create mode 100644 src/emulator/x64_emulator.hpp create mode 100644 src/unicorn_emulator/CMakeLists.txt create mode 100644 src/unicorn_emulator/unicorn_x64_emulator.cpp create mode 100644 src/unicorn_emulator/unicorn_x64_emulator.hpp create mode 100644 src/windows_emulator/CMakeLists.txt rename src/{emulator/unicorn_utils.hpp => windows_emulator/emulator_utils.hpp} (72%) rename src/{emulator => windows_emulator}/main.cpp (73%) create mode 100644 src/windows_emulator/memory_utils.hpp rename src/{emulator => windows_emulator}/process_context.hpp (71%) rename src/{emulator => windows_emulator}/reflect_extension.hpp (100%) rename src/{emulator => windows_emulator}/resource.rc (100%) rename src/{emulator => windows_emulator}/resources/icon.ico (100%) rename src/{emulator => windows_emulator}/std_include.hpp (100%) rename src/{emulator => windows_emulator}/syscalls.cpp (89%) create mode 100644 src/windows_emulator/syscalls.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index daa5563f..c57578e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,2 +1,4 @@ add_subdirectory(common) -add_subdirectory(emulator) \ No newline at end of file +add_subdirectory(emulator) +add_subdirectory(unicorn_emulator) +add_subdirectory(windows_emulator) diff --git a/src/emulator/CMakeLists.txt b/src/emulator/CMakeLists.txt index 15a6cc79..f4990045 100644 --- a/src/emulator/CMakeLists.txt +++ b/src/emulator/CMakeLists.txt @@ -6,19 +6,8 @@ file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS list(SORT SRC_FILES) -add_executable(emulator ${SRC_FILES}) +add_library(emulator ${SRC_FILES}) -momo_assign_source_group(${SRC_FILES}) - -target_precompile_headers(emulator PRIVATE std_include.hpp) - -target_link_libraries(emulator PRIVATE - common - unicorn - phnt::phnt - reflect +target_include_directories(emulator INTERFACE + "${CMAKE_CURRENT_LIST_DIR}" ) - -set_property(GLOBAL PROPERTY VS_STARTUP_PROJECT emulator) - -momo_strip_target(emulator) diff --git a/src/emulator/empty.cpp b/src/emulator/empty.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/emulator/emulator.hpp b/src/emulator/emulator.hpp new file mode 100644 index 00000000..982c3415 --- /dev/null +++ b/src/emulator/emulator.hpp @@ -0,0 +1,92 @@ +#pragma once +#include +#include + +#include "memory_permission.hpp" + +struct memory_region +{ + uint64_t start; + size_t length; + memory_permission pemissions; +}; + +class emulator +{ +public: + emulator() = default; + + emulator(const emulator&) = delete; + emulator& operator=(const emulator&) = delete; + + emulator(emulator&&) = delete; + emulator& operator=(emulator&&) = delete; + + virtual ~emulator() = default; + + virtual void start(uint64_t start, uint64_t end = 0, std::chrono::microseconds timeout = {}, size_t count = 0) = 0; + virtual void stop() = 0; + + virtual void read_raw_register(int reg, void* value, size_t size) = 0; + virtual void write_raw_register(int reg, const void* value, size_t size) = 0; + + virtual void map_memory(uint64_t address, size_t size, memory_permission permissions) = 0; + virtual void unmap_memory(uint64_t address, size_t size) = 0; + + virtual void read_memory(uint64_t address, void* data, size_t size) = 0; + virtual void write_memory(uint64_t address, const void* data, size_t size) = 0; + + 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; + + static constexpr size_t pointer_size = sizeof(pointer_type); + static constexpr registers stack_pointer = StackPointer; + + 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) const + { + 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; + } + +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; +}; diff --git a/src/emulator/memory_permission.hpp b/src/emulator/memory_permission.hpp new file mode 100644 index 00000000..4eca4171 --- /dev/null +++ b/src/emulator/memory_permission.hpp @@ -0,0 +1,64 @@ +#pragma once +#include + +enum class memory_permission : uint8_t +{ + none = 0, + read = 1 << 0, + write = 1 << 1, + exec = 1 << 2, + read_write = read | write, + all = read | write | exec +}; + +/***************************************************************************** + * + ****************************************************************************/ + +inline constexpr memory_permission +operator&(const memory_permission x, const memory_permission y) +{ + return static_cast + (static_cast(x) & static_cast(y)); +} + +inline constexpr memory_permission +operator|(const memory_permission x, const memory_permission y) +{ + return static_cast + (static_cast(x) | static_cast(y)); +} + +inline constexpr memory_permission +operator^(const memory_permission x, const memory_permission y) +{ + return static_cast + (static_cast(x) ^ static_cast(y)); +} + +inline constexpr memory_permission +operator~(memory_permission x) +{ + return static_cast(~static_cast(x)); +} + +inline memory_permission& +operator&=(memory_permission& x, const memory_permission y) +{ + x = x & y; + return x; +} + +inline memory_permission& +operator|=(memory_permission& x, const memory_permission y) +{ + x = x | y; + return x; +} + +inline memory_permission& +operator^=(memory_permission& x, const memory_permission y) +{ + x = x ^ y; + return x; +} diff --git a/src/emulator/memory_utils.hpp b/src/emulator/memory_utils.hpp deleted file mode 100644 index af905b1f..00000000 --- a/src/emulator/memory_utils.hpp +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once -#include -#include - -inline bool is_within_start_and_end(const uint64_t value, const uint64_t start, const uint64_t end) -{ - return value >= start && value < end; -} - -inline bool is_within_start_and_length(const uint64_t value, const uint64_t start, const uint64_t length) -{ - return is_within_start_and_end(value, start, start + length); -} - -inline uint64_t align_down(const uint64_t value, const uint64_t alignment) -{ - return value & ~(alignment - 1); -} - -inline uint64_t align_up(const uint64_t value, const uint64_t alignment) -{ - return align_down(value + (alignment - 1), alignment); -} - -inline uint64_t page_align_down(const uint64_t value) -{ - return align_down(value, 0x1000); -} - -inline uint64_t page_align_up(const uint64_t value) -{ - return align_up(value, 0x1000); -} - -template -T access_memory_regions(const unicorn& uc, const F& accessor) -{ - uint32_t count{}; - uc_mem_region* regions{}; - - uce(uc_mem_regions(uc, ®ions, &count)); - const auto _ = utils::finally([&] - { - uc_free(regions); - }); - - return accessor(std::span(regions, count)); -} - -inline uint32_t get_memory_protection(const unicorn& uc, const uint64_t address) -{ - return access_memory_regions(uc, [&](const std::span regions) -> uint32_t - { - for (const auto& region : regions) - { - if (is_within_start_and_end(address, region.begin, region.end)) - { - return region.perms; - } - } - - return UC_PROT_NONE; - }); -} - -inline bool is_memory_allocated(const unicorn& uc, const uint64_t address) -{ - return access_memory_regions(uc, [&](const std::span regions) - { - for (const auto& region : regions) - { - if (is_within_start_and_end(address, region.begin, region.end)) - { - return true; - } - } - - return false; - }); -} - -inline uint32_t map_nt_to_unicorn_protection(const uint32_t nt_protection) -{ - switch (nt_protection) - { - case PAGE_NOACCESS: - return UC_PROT_NONE; - case PAGE_READONLY: - return UC_PROT_READ; - case PAGE_READWRITE: - case PAGE_WRITECOPY: - return UC_PROT_READ | UC_PROT_WRITE; - case PAGE_EXECUTE: - case PAGE_EXECUTE_READ: - return UC_PROT_READ | UC_PROT_EXEC; - case PAGE_EXECUTE_READWRITE: - case PAGE_EXECUTE_WRITECOPY: - default: - return UC_PROT_ALL; - } -} - -inline uint32_t map_unicorn_to_nt_protection(const uint32_t unicorn_protection) -{ - const bool has_exec = unicorn_protection & UC_PROT_EXEC; - const bool has_read = unicorn_protection & UC_PROT_READ; - const bool has_write = unicorn_protection & UC_PROT_WRITE; - - if (!has_read) - { - return PAGE_NOACCESS; - } - - if (has_exec && has_write) - { - return PAGE_EXECUTE_READWRITE; - } - - if (has_exec) - { - return PAGE_EXECUTE_READ; - } - - if (has_write) - { - return PAGE_READWRITE; - } - - return PAGE_READONLY; -} diff --git a/src/emulator/syscalls.hpp b/src/emulator/syscalls.hpp deleted file mode 100644 index cefaccdd..00000000 --- a/src/emulator/syscalls.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "unicorn.hpp" -#include "process_context.hpp" - -void handle_syscall(const unicorn& uc, process_context& context); diff --git a/src/emulator/unicorn.cpp b/src/emulator/unicorn.cpp deleted file mode 100644 index c8ec7c50..00000000 --- a/src/emulator/unicorn.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "std_include.hpp" -#include "unicorn.hpp" - -unicorn::unicorn(const uc_arch arch, const uc_mode mode) -{ - const auto error = uc_open(arch, mode, &this->uc_); - ThrowIfUnicornError(error); -} - -unicorn::unicorn(unicorn&& obj) noexcept -{ - this->operator=(std::move(obj)); -} - -unicorn& unicorn::operator=(unicorn&& obj) noexcept -{ - if (this != &obj) - { - this->close(); - - this->uc_ = obj.uc_; - obj.uc_ = nullptr; - } - - return *this; -} - -unicorn::~unicorn() -{ - this->close(); -} - -void unicorn::close() -{ - if (this->uc_) - { - uc_close(this->uc_); - this->uc_ = nullptr; - } -} diff --git a/src/emulator/unicorn.hpp b/src/emulator/unicorn.hpp deleted file mode 100644 index 7b2cba81..00000000 --- a/src/emulator/unicorn.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -struct unicorn_error : std::runtime_error -{ - unicorn_error(const uc_err error_code) - : std::runtime_error(uc_strerror(error_code)) - , code(error_code) - { - } - - uc_err code{}; -}; - -inline void ThrowIfUnicornError(const uc_err error_code) -{ - if (error_code != UC_ERR_OK) - { - throw unicorn_error(error_code); - } -} - -#define uce ThrowIfUnicornError - -class unicorn -{ -public: - unicorn() = default; - unicorn(uc_arch arch, uc_mode mode); - - unicorn(const unicorn& obj) = delete; - unicorn& operator=(const unicorn& obj) = delete; - - unicorn(unicorn&& obj) noexcept; - unicorn& operator=(unicorn&& obj) noexcept; - - ~unicorn(); - - void close(); - - operator uc_engine*() const - { - return this->uc_; - } - - template - T reg(const int regid) const - { - T value{}; - uce(uc_reg_read(this->uc_, regid, &value)); - return value; - } - - template - void reg(const int regid, const S& maybe_value) const - { - T value = static_cast(maybe_value); - uce(uc_reg_write(this->uc_, regid, &value)); - } - - void stop() const - { - uce(uc_emu_stop(this->uc_)); - } - - uint64_t read_stack(const size_t index) const - { - uint64_t result{}; - const auto rsp = this->reg(UC_X86_REG_RSP); - - uce(uc_mem_read(this->uc_, rsp + (index * sizeof(result)), &result, sizeof(result))); - return result; - } - -private: - uc_engine* uc_{}; -}; diff --git a/src/emulator/x64_emulator.hpp b/src/emulator/x64_emulator.hpp new file mode 100644 index 00000000..882c2559 --- /dev/null +++ b/src/emulator/x64_emulator.hpp @@ -0,0 +1,248 @@ +#pragma once +#include "emulator.hpp" + +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 +}; + +using x64_emulator = typed_emulator; diff --git a/src/unicorn_emulator/CMakeLists.txt b/src/unicorn_emulator/CMakeLists.txt new file mode 100644 index 00000000..fee62097 --- /dev/null +++ b/src/unicorn_emulator/CMakeLists.txt @@ -0,0 +1,16 @@ +file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS + *.cpp + *.hpp + *.rc +) + +list(SORT SRC_FILES) + +add_library(unicorn_emulator SHARED ${SRC_FILES}) + +target_include_directories(unicorn_emulator INTERFACE + "${CMAKE_CURRENT_LIST_DIR}" +) + +target_link_libraries(unicorn_emulator PUBLIC emulator) +target_link_libraries(unicorn_emulator PRIVATE unicorn) diff --git a/src/unicorn_emulator/unicorn_x64_emulator.cpp b/src/unicorn_emulator/unicorn_x64_emulator.cpp new file mode 100644 index 00000000..d3af2410 --- /dev/null +++ b/src/unicorn_emulator/unicorn_x64_emulator.cpp @@ -0,0 +1,186 @@ +#define UNICORN_EMULATOR_IMPL +#include "unicorn_x64_emulator.hpp" + +#include +#include + +namespace unicorn +{ + namespace + { + static_assert(static_cast(memory_permission::none) == UC_PROT_NONE); + static_assert(static_cast(memory_permission::read) == UC_PROT_READ); + static_assert(static_cast(memory_permission::exec) == UC_PROT_EXEC); + static_assert(static_cast(memory_permission::all) == UC_PROT_ALL); + + static_assert(static_cast(x64_register::end) == UC_X86_REG_ENDING); + + struct unicorn_error : std::runtime_error + { + unicorn_error(const uc_err error_code) + : std::runtime_error(uc_strerror(error_code)) + , code(error_code) + { + } + + uc_err code{}; + }; + + void throw_if_unicorn_error(const uc_err error_code) + { + if (error_code != UC_ERR_OK) + { + throw unicorn_error(error_code); + } + } + + void uce(const uc_err error_code) + { + throw_if_unicorn_error(error_code); + } + + class unicorn_memory_regions + { + public: + unicorn_memory_regions(uc_engine* uc) + { + uce(uc_mem_regions(uc, &this->regions_, &this->count_)); + } + + unicorn_memory_regions(unicorn_memory_regions&&) = delete; + unicorn_memory_regions(const unicorn_memory_regions&) = delete; + unicorn_memory_regions& operator=(unicorn_memory_regions&&) = delete; + unicorn_memory_regions& operator=(const unicorn_memory_regions&) = delete; + + ~unicorn_memory_regions() + { + if (regions_) + { + uc_free(regions_); + } + } + + std::span get_span() const + { + return {this->regions_, this->count_}; + } + + private: + uint32_t count_{}; + uc_mem_region* regions_{}; + }; + + class unicorn_x64_emulator : public x64_emulator + { + public: + unicorn_x64_emulator() + { + uce(uc_open(UC_ARCH_X86, UC_MODE_64, &this->uc_)); + } + + ~unicorn_x64_emulator() override + { + uc_close(this->uc_); + } + + void start(const uint64_t start, const uint64_t end, std::chrono::microseconds timeout, + const size_t count) override + { + if (timeout.count() < 0) + { + timeout = {}; + } + + uce(uc_emu_start(*this, start, end, static_cast(timeout.count()), count)); + } + + void stop() override + { + uce(uc_emu_stop(*this)); + } + + void write_raw_register(const int reg, const void* value, const size_t size) override + { + size_t result_size = size; + uce(uc_reg_write2(*this, reg, value, &result_size)); + + if (size != result_size) + { + throw std::runtime_error( + "Register size mismatch: " + std::to_string(size) + " != " + std::to_string(result_size)); + } + } + + void read_raw_register(const int reg, void* value, const size_t size) override + { + size_t result_size = size; + uce(uc_reg_read2(*this, reg, value, &result_size)); + + if (size != result_size) + { + throw std::runtime_error( + "Register size mismatch: " + std::to_string(size) + " != " + std::to_string(result_size)); + } + } + + void map_memory(const uint64_t address, const size_t size, memory_permission permissions) override + { + uce(uc_mem_map(*this, address, size, static_cast(permissions))); + } + + void unmap_memory(const uint64_t address, const size_t size) override + { + uce(uc_mem_unmap(*this, address, size)); + } + + void read_memory(const uint64_t address, void* data, const size_t size) override + { + uce(uc_mem_read(*this, address, data, size)); + } + + void write_memory(const uint64_t address, const void* data, const size_t size) override + { + uce(uc_mem_write(*this, address, data, size)); + } + + void protect_memory(const uint64_t address, const size_t size, memory_permission permissions) override + { + uce(uc_mem_protect(*this, address, size, static_cast(permissions))); + } + + std::vector get_memory_regions() override + { + const unicorn_memory_regions regions{*this}; + const auto region_span = regions.get_span(); + + std::vector result{}; + result.reserve(region_span.size()); + + for (const auto region : region_span) + { + memory_region reg{}; + reg.start = region.begin; + reg.length = region.end - region.begin; + reg.pemissions = static_cast(region.perms) & memory_permission::all; + + result.push_back(reg); + } + + return result; + } + + operator uc_engine*() const + { + return this->uc_; + } + + private: + uc_engine* uc_{}; + }; + } + + std::unique_ptr create_x64_emulator() + { + return std::make_unique(); + } +} diff --git a/src/unicorn_emulator/unicorn_x64_emulator.hpp b/src/unicorn_emulator/unicorn_x64_emulator.hpp new file mode 100644 index 00000000..f349cf53 --- /dev/null +++ b/src/unicorn_emulator/unicorn_x64_emulator.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#ifdef UNICORN_EMULATOR_IMPL +#define UNICORN_EMULATOR_DLL_STORAGE __declspec(dllexport) +#else +#define UNICORN_EMULATOR_DLL_STORAGE __declspec(dllimport) +#endif + +namespace unicorn +{ + UNICORN_EMULATOR_DLL_STORAGE + std::unique_ptr create_x64_emulator(); +} diff --git a/src/windows_emulator/CMakeLists.txt b/src/windows_emulator/CMakeLists.txt new file mode 100644 index 00000000..de2bb40f --- /dev/null +++ b/src/windows_emulator/CMakeLists.txt @@ -0,0 +1,24 @@ +file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS + *.cpp + *.hpp + *.rc +) + +list(SORT SRC_FILES) + +add_executable(windows_emulator ${SRC_FILES}) + +momo_assign_source_group(${SRC_FILES}) + +target_precompile_headers(windows_emulator PRIVATE std_include.hpp) + +target_link_libraries(windows_emulator PRIVATE + common + phnt::phnt + reflect + unicorn_emulator +) + +set_property(GLOBAL PROPERTY VS_STARTUP_PROJECT windows_emulator) + +momo_strip_target(windows_emulator) diff --git a/src/emulator/unicorn_utils.hpp b/src/windows_emulator/emulator_utils.hpp similarity index 72% rename from src/emulator/unicorn_utils.hpp rename to src/windows_emulator/emulator_utils.hpp index a5d1429a..8f2621de 100644 --- a/src/emulator/unicorn_utils.hpp +++ b/src/windows_emulator/emulator_utils.hpp @@ -1,16 +1,17 @@ #pragma once -#include "unicorn.hpp" #include "memory_utils.hpp" +#include + template -class unicorn_object +class emulator_object { public: - unicorn_object() = default; + emulator_object() = default; - unicorn_object(const unicorn& uc, uint64_t address) - : uc_(&uc) - , address_(address) + emulator_object(emulator& emu, const uint64_t address) + : emu_(&emu) + , address_(address) { } @@ -42,22 +43,20 @@ public: T read() const { T obj{}; - - uce(uc_mem_read(*this->uc_, this->address_, &obj, sizeof(obj))); - + this->emu_->read_memory(this->address_, &obj, sizeof(obj)); return obj; } void write(const T& value) const { - uce(uc_mem_write(*this->uc_, this->address_, &value, sizeof(value))); + this->emu_->write_memory(this->address_, &value, sizeof(value)); } template void access(const F& accessor) const { T obj{}; - uce(uc_mem_read(*this->uc_, this->address_, &obj, sizeof(obj))); + this->emu_->read_memory(this->address_, &obj, sizeof(obj)); accessor(obj); @@ -65,20 +64,20 @@ public: } private: - const unicorn* uc_{}; + emulator* emu_{}; uint64_t address_{}; }; -class unicorn_allocator +class emulator_allocator { public: - unicorn_allocator() = default; + emulator_allocator() = default; - unicorn_allocator(const unicorn& uc, const uint64_t address, const uint64_t size) - : uc_(&uc) - , address_(address) - , size_(size) - , active_address_(address) + emulator_allocator(emulator& emu, const uint64_t address, const uint64_t size) + : emu_(&emu) + , address_(address) + , size_(size) + , active_address_(address) { } @@ -99,10 +98,10 @@ public: } template - unicorn_object reserve() + emulator_object reserve() { const auto potential_start = this->reserve(sizeof(T), alignof(T)); - return unicorn_object(*this->uc_, potential_start); + return emulator_object(*this->emu_, potential_start); } void make_unicode_string(UNICODE_STRING& result, const std::wstring_view str) @@ -113,32 +112,33 @@ public: const auto string_buffer = this->reserve(total_length, required_alignment); - uce(uc_mem_write(*this->uc_, string_buffer, str.data(), total_length)); + this->emu_->write_memory(string_buffer, str.data(), total_length); result.Buffer = reinterpret_cast(string_buffer); result.Length = static_cast(total_length); result.MaximumLength = result.Length; } - unicorn_object make_unicode_string(const std::wstring_view str) + emulator_object make_unicode_string(const std::wstring_view str) { const auto unicode_string = this->reserve(); unicode_string.access([&](UNICODE_STRING& unicode_str) - { - this->make_unicode_string(unicode_str, str); - }); + { + this->make_unicode_string(unicode_str, str); + }); return unicode_string; } private: - const unicorn* uc_{}; + emulator* emu_{}; uint64_t address_{}; uint64_t size_{}; - uint64_t active_address_{ 0 }; + uint64_t active_address_{0}; }; +/* class unicorn_hook { public: @@ -146,7 +146,7 @@ public: template unicorn_hook(const unicorn& uc, const int type, const uint64_t begin, const uint64_t end, function callback, - Args... args) + Args... args) : uc_(&uc) { this->function_ = std::make_unique( @@ -156,28 +156,28 @@ public: }); void* handler = +[](uc_engine*, const uint64_t address, const uint32_t size, - void* user_data) - { - (*static_cast(user_data))(address, 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); - }; + { + 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 /*type*/, const uint64_t address, const int size, - const int64_t /*value*/, void* user_data) - { - (*static_cast(user_data))(address, size); - }; + 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...)); } @@ -229,3 +229,4 @@ private: uc_hook hook_{}; std::unique_ptr function_{}; }; +*/ \ No newline at end of file diff --git a/src/emulator/main.cpp b/src/windows_emulator/main.cpp similarity index 73% rename from src/emulator/main.cpp rename to src/windows_emulator/main.cpp index 58e655e8..bb2565cb 100644 --- a/src/emulator/main.cpp +++ b/src/windows_emulator/main.cpp @@ -1,14 +1,14 @@ #include "std_include.hpp" -#include "unicorn.hpp" -#include "memory_utils.hpp" -#include "unicorn_utils.hpp" +#include "emulator_utils.hpp" #include "process_context.hpp" #include "syscalls.hpp" #include "reflect_extension.hpp" #include +#include + #define GS_SEGMENT_ADDR 0x6000000ULL #define GS_SEGMENT_SIZE (20 << 20) // 20 MB @@ -21,32 +21,32 @@ namespace { - void setup_stack(const unicorn& uc, uint64_t stack_base, size_t stack_size) + void setup_stack(x64_emulator& emu, const uint64_t stack_base, const size_t stack_size) { - uce(uc_mem_map(uc, stack_base, stack_size, UC_PROT_READ | UC_PROT_WRITE)); + emu.map_memory(stack_base, stack_size, memory_permission::read_write); const uint64_t stack_end = stack_base + stack_size; - uce(uc_reg_write(uc, UC_X86_REG_RSP, &stack_end)); + emu.reg(x64_register::rsp, stack_end); } - unicorn_allocator setup_gs_segment(const unicorn& uc, const uint64_t segment_base, const uint64_t size) + emulator_allocator setup_gs_segment(x64_emulator& emu, const uint64_t segment_base, const uint64_t size) { const std::array value = { IA32_GS_BASE_MSR, segment_base }; - uce(uc_reg_write(uc, UC_X86_REG_MSR, value.data())); - uce(uc_mem_map(uc, segment_base, size, UC_PROT_READ | UC_PROT_WRITE)); + emu.write_register(x64_register::msr, value.data(), value.size()); + emu.map_memory(segment_base, size, memory_permission::read_write); - return {uc, segment_base, size}; + return {emu, segment_base, size}; } - unicorn_object setup_kusd(const unicorn& uc) + emulator_object setup_kusd(x64_emulator& emu) { - uce(uc_mem_map(uc, KUSD_ADDRESS, page_align_up(sizeof(KUSER_SHARED_DATA)), UC_PROT_READ)); + emu.map_memory(KUSD_ADDRESS, page_align_up(sizeof(KUSER_SHARED_DATA)), memory_permission::read); - const unicorn_object kusd_object{uc, KUSD_ADDRESS}; + const emulator_object kusd_object{emu, KUSD_ADDRESS}; kusd_object.access([](KUSER_SHARED_DATA& kusd) { const auto& real_kusd = *reinterpret_cast(KUSD_ADDRESS); @@ -64,7 +64,7 @@ namespace return kusd_object; } - mapped_binary map_module(const unicorn& uc, const std::vector& module_data, + mapped_binary map_module(x64_emulator& emu, const std::vector& module_data, const std::string& name) { mapped_binary binary{}; @@ -80,24 +80,26 @@ namespace while (true) { - const auto res = uc_mem_map(uc, binary.image_base, binary.size_of_image, UC_PROT_READ); - if (res == UC_ERR_OK) + try { + emu.map_memory(binary.image_base, binary.size_of_image, memory_permission::read); break; } - - binary.image_base += 0x10000; - - if (binary.image_base < optional_header.ImageBase || (optional_header.DllCharacteristics & - IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0) + catch (...) { - throw std::runtime_error("Failed to map range"); + binary.image_base += 0x10000; + + if (binary.image_base < optional_header.ImageBase || (optional_header.DllCharacteristics & + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0) + { + throw std::runtime_error("Failed to map range"); + } } } printf("Mapping %s at %llX\n", name.c_str(), binary.image_base); - uce(uc_mem_write(uc, binary.image_base, ptr, optional_header.SizeOfHeaders)); + emu.write_memory(binary.image_base, ptr, optional_header.SizeOfHeaders); const std::span sections(IMAGE_FIRST_SECTION(nt_headers), nt_headers->FileHeader.NumberOfSections); @@ -110,28 +112,28 @@ namespace const void* source_ptr = ptr + section.PointerToRawData; const auto size_of_data = std::min(section.SizeOfRawData, section.Misc.VirtualSize); - uce(uc_mem_write(uc, target_ptr, source_ptr, size_of_data)); + emu.write_memory(target_ptr, source_ptr, size_of_data); } - uint32_t permissions = UC_PROT_NONE; + auto permissions = memory_permission::none; if (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) { - permissions |= UC_PROT_EXEC; + permissions |= memory_permission::exec; } if (section.Characteristics & IMAGE_SCN_MEM_READ) { - permissions |= UC_PROT_READ; + permissions |= memory_permission::read; } if (section.Characteristics & IMAGE_SCN_MEM_WRITE) { - permissions |= UC_PROT_WRITE; + permissions |= memory_permission::write; } const auto size_of_section = page_align_up(std::max(section.SizeOfRawData, section.Misc.VirtualSize)); - uce(uc_mem_protect(uc, target_ptr, size_of_section, permissions)); + emu.protect_memory(target_ptr, size_of_section, permissions); } auto& export_directory_entry = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; @@ -162,14 +164,14 @@ namespace return binary; } - process_context setup_context(const unicorn& uc) + process_context setup_context(x64_emulator& emu) { - setup_stack(uc, STACK_ADDRESS, STACK_SIZE); + setup_stack(emu, STACK_ADDRESS, STACK_SIZE); process_context context{}; - context.kusd = setup_kusd(uc); + context.kusd = setup_kusd(emu); - context.gs_segment = setup_gs_segment(uc, GS_SEGMENT_ADDR, GS_SEGMENT_SIZE); + context.gs_segment = setup_gs_segment(emu, GS_SEGMENT_ADDR, GS_SEGMENT_SIZE); auto& gs = context.gs_segment; @@ -210,10 +212,10 @@ namespace return {(std::istreambuf_iterator(stream)), std::istreambuf_iterator()}; } - mapped_binary map_file(const unicorn& uc, const std::filesystem::path& file) + mapped_binary map_file(x64_emulator& emu, const std::filesystem::path& file) { const auto data = load_file(file); - return map_module(uc, data, file.generic_string()); + return map_module(emu, data, file.generic_string()); } template @@ -268,15 +270,16 @@ namespace std::map members_{}; }; + /* template - unicorn_hook watch_object(const unicorn& uc, unicorn_object object) + unicorn_hook watch_object(const unicorn& uc, 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 /*size*/) + const uint32_t ) { const auto offset = address - o.value(); printf("%s: %llX (%s)\n", i.get_type_name().c_str(), offset, @@ -284,21 +287,21 @@ namespace } }; } - + */ void run() { - const unicorn uc{UC_ARCH_X86, UC_MODE_64}; + const auto emu = unicorn::create_x64_emulator(); - auto context = setup_context(uc); + auto context = setup_context(*emu); - context.executable = map_file(uc, R"(C:\Users\mauri\Desktop\ConsoleApplication6.exe)"); + context.executable = map_file(*emu, R"(C:\Users\mauri\Desktop\ConsoleApplication6.exe)"); context.peb.access([&](PEB& peb) { peb.ImageBaseAddress = reinterpret_cast(context.executable.image_base); }); - context.ntdll = map_file(uc, R"(C:\Windows\System32\ntdll.dll)"); + context.ntdll = map_file(*emu, R"(C:\Windows\System32\ntdll.dll)"); const auto entry1 = context.ntdll.exports.at("LdrInitializeThunk"); const auto entry2 = context.ntdll.exports.at("RtlUserThreadStart"); @@ -306,6 +309,7 @@ namespace (void)entry1; (void)entry2; + /* std::vector export_hooks{}; @@ -338,21 +342,23 @@ namespace handle_syscall(uc, context); }, UC_X86_INS_SYSCALL); - 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)); + //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)); unicorn_hook hook2(uc, UC_HOOK_CODE, 0, std::numeric_limits::max(), - [](const unicorn& uc, const uint64_t address, const uint32_t /*size*/) + [](const unicorn& uc, const uint64_t address, const uint32_t ) { - //static bool hit = false; - /*if (address == 0x01800D46DD) + static bool hit = false; + // if (address == 0x1800D3C80) + if (address == 0x1800D4420) { - hit = true; - }*/ + //hit = true; + //uc.stop(); + } - //if (hit) + if (hit) { printf( "Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX - R8: %16llX - R9: %16llX - RDI: %16llX - RSI: %16llX\n", @@ -362,27 +368,23 @@ namespace uc.reg(UC_X86_REG_RDI), uc.reg(UC_X86_REG_RSI)); } }); - +*/ const auto execution_context = context.gs_segment.reserve(); - uc.reg(UC_X86_REG_RCX, execution_context.value()); - uc.reg(UC_X86_REG_RDX, context.ntdll.image_base); + emu->reg(x64_register::rcx, execution_context.value()); + emu->reg(x64_register::rdx, context.ntdll.image_base); - const auto err = uc_emu_start(uc, entry1, 0, 0, 0); - if (err != UC_ERR_OK) + try { - uint64_t rip{}; - uc_reg_read(uc, UC_X86_REG_RIP, &rip); - printf("Emulation failed at: %llX\n", rip); - uce(err); + emu->start(entry1); + } + catch (...) + { + printf("Emulation failed at: %llX\n", emu->reg(x64_register::rip)); + throw; } - printf("Emulation done. Below is the CPU context\n"); - - uint64_t rax{}; - uce(uc_reg_read(uc, UC_X86_REG_RAX, &rax)); - - printf(">>> RAX = 0x%llX\n", rax); + printf("Emulation done.\n"); } } diff --git a/src/windows_emulator/memory_utils.hpp b/src/windows_emulator/memory_utils.hpp new file mode 100644 index 00000000..d0d95419 --- /dev/null +++ b/src/windows_emulator/memory_utils.hpp @@ -0,0 +1,110 @@ +#pragma once +#include +#include + +inline bool is_within_start_and_end(const uint64_t value, const uint64_t start, const uint64_t end) +{ + return value >= start && value < end; +} + +inline bool is_within_start_and_length(const uint64_t value, const uint64_t start, const uint64_t length) +{ + return is_within_start_and_end(value, start, start + length); +} + +inline uint64_t align_down(const uint64_t value, const uint64_t alignment) +{ + return value & ~(alignment - 1); +} + +inline uint64_t align_up(const uint64_t value, const uint64_t alignment) +{ + return align_down(value + (alignment - 1), alignment); +} + +inline uint64_t page_align_down(const uint64_t value) +{ + return align_down(value, 0x1000); +} + +inline uint64_t page_align_up(const uint64_t value) +{ + return align_up(value, 0x1000); +} + + +inline memory_permission get_memory_protection(emulator& emu, const uint64_t address) +{ + for (const auto& region : emu.get_memory_regions()) + { + if (is_within_start_and_length(address, region.start, region.length)) + { + return region.pemissions; + } + } + + return memory_permission::none; +} + +inline bool is_memory_allocated(emulator& emu, const uint64_t address) +{ + for (const auto& region : emu.get_memory_regions()) + { + if (is_within_start_and_length(address, region.start, region.length)) + { + return true; + } + } + + return false; +} + +inline memory_permission map_nt_to_unicorn_protection(const uint32_t nt_protection) +{ + switch (nt_protection) + { + case PAGE_NOACCESS: + return memory_permission::none; + case PAGE_READONLY: + return memory_permission::read; + case PAGE_READWRITE: + case PAGE_WRITECOPY: + return memory_permission::read | memory_permission::write; + case PAGE_EXECUTE: + case PAGE_EXECUTE_READ: + return memory_permission::read | memory_permission::exec; + case PAGE_EXECUTE_READWRITE: + case PAGE_EXECUTE_WRITECOPY: + default: + return memory_permission::all; + } +} + +inline uint32_t map_unicorn_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; + const bool has_write = (permission & memory_permission::write) != memory_permission::none; + + if (!has_read) + { + return PAGE_NOACCESS; + } + + if (has_exec && has_write) + { + return PAGE_EXECUTE_READWRITE; + } + + if (has_exec) + { + return PAGE_EXECUTE_READ; + } + + if (has_write) + { + return PAGE_READWRITE; + } + + return PAGE_READONLY; +} diff --git a/src/emulator/process_context.hpp b/src/windows_emulator/process_context.hpp similarity index 71% rename from src/emulator/process_context.hpp rename to src/windows_emulator/process_context.hpp index f41cfa73..21f6bb05 100644 --- a/src/emulator/process_context.hpp +++ b/src/windows_emulator/process_context.hpp @@ -28,14 +28,14 @@ struct event struct process_context { - unicorn_object teb{}; - unicorn_object peb{}; - unicorn_object process_params{}; - unicorn_object kusd{}; + emulator_object teb{}; + emulator_object peb{}; + emulator_object process_params{}; + emulator_object kusd{}; mapped_binary executable{}; mapped_binary ntdll{}; std::vector events{}; - unicorn_allocator gs_segment{}; + emulator_allocator gs_segment{}; }; diff --git a/src/emulator/reflect_extension.hpp b/src/windows_emulator/reflect_extension.hpp similarity index 100% rename from src/emulator/reflect_extension.hpp rename to src/windows_emulator/reflect_extension.hpp diff --git a/src/emulator/resource.rc b/src/windows_emulator/resource.rc similarity index 100% rename from src/emulator/resource.rc rename to src/windows_emulator/resource.rc diff --git a/src/emulator/resources/icon.ico b/src/windows_emulator/resources/icon.ico similarity index 100% rename from src/emulator/resources/icon.ico rename to src/windows_emulator/resources/icon.ico diff --git a/src/emulator/std_include.hpp b/src/windows_emulator/std_include.hpp similarity index 100% rename from src/emulator/std_include.hpp rename to src/windows_emulator/std_include.hpp diff --git a/src/emulator/syscalls.cpp b/src/windows_emulator/syscalls.cpp similarity index 89% rename from src/emulator/syscalls.cpp rename to src/windows_emulator/syscalls.cpp index 2a5dedc8..60d74cd6 100644 --- a/src/emulator/syscalls.cpp +++ b/src/windows_emulator/syscalls.cpp @@ -5,8 +5,8 @@ namespace { void handle_NtQueryPerformanceCounter(const unicorn& uc) { - const unicorn_object performance_counter{uc, uc.reg(UC_X86_REG_R10)}; - const unicorn_object performance_frequency{uc, uc.reg(UC_X86_REG_RDX)}; + const emulator_object performance_counter{uc, uc.reg(UC_X86_REG_R10)}; + const emulator_object performance_frequency{uc, uc.reg(UC_X86_REG_RDX)}; try { @@ -56,7 +56,7 @@ namespace void handle_NtCreateEvent(const unicorn& uc, process_context& context) { - const unicorn_object event_handle{uc, uc.reg(UC_X86_REG_R10)}; + 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)); @@ -85,7 +85,7 @@ namespace 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 unicorn_object return_length{uc, uc.read_stack(6)}; + const emulator_object return_length{uc, uc.read_stack(6)}; if (process_handle != ~0ULL) { @@ -124,7 +124,7 @@ namespace return; } - const unicorn_object info{uc, memory_information}; + const emulator_object info{uc, memory_information}; info.access([&](MEMORY_IMAGE_INFORMATION& image_info) { @@ -140,7 +140,7 @@ namespace 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 unicorn_object return_length{uc, uc.reg(UC_X86_REG_R9)}; + const emulator_object return_length{uc, uc.reg(UC_X86_REG_R9)}; if (info_class == SystemFlushInformation || info_class == SystemHypervisorSharedPageInformation) @@ -162,7 +162,7 @@ namespace return; } - const unicorn_object info_obj{uc, system_information}; + const emulator_object info_obj{uc, system_information}; info_obj.access([&](SYSTEM_NUMA_INFORMATION& info) { @@ -194,7 +194,7 @@ namespace return; } - const unicorn_object info{uc, system_information}; + const emulator_object info{uc, system_information}; info.access([&](SYSTEM_BASIC_INFORMATION& basic_info) { @@ -220,7 +220,7 @@ namespace 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 unicorn_object return_length{uc, uc.read_stack(6)}; + const emulator_object return_length{uc, uc.read_stack(6)}; if (info_class == SystemFlushInformation || info_class == SystemFeatureConfigurationInformation @@ -275,7 +275,7 @@ namespace return; } - const unicorn_object info{uc, system_information}; + const emulator_object info{uc, system_information}; info.access([&](SYSTEM_BASIC_INFORMATION& basic_info) { @@ -300,7 +300,7 @@ namespace 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 unicorn_object return_length{uc, uc.read_stack(5)}; + const emulator_object return_length{uc, uc.read_stack(5)}; if (process_handle != ~0ULL) { @@ -326,7 +326,7 @@ namespace return; } - const unicorn_object info{uc, process_information}; + const emulator_object info{uc, process_information}; info.write(0x01234567); uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); @@ -335,10 +335,10 @@ namespace void handle_NtProtectVirtualMemory(const unicorn& uc) { const auto process_handle = uc.reg(UC_X86_REG_R10); - const unicorn_object base_address{uc, uc.reg(UC_X86_REG_RDX)}; - const unicorn_object bytes_to_protect{uc, uc.reg(UC_X86_REG_R8)}; + 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 unicorn_object old_protection{uc, uc.read_stack(5)}; + const emulator_object old_protection{uc, uc.read_stack(5)}; if (process_handle != ~0ULL) { @@ -365,8 +365,8 @@ namespace void handle_NtAllocateVirtualMemory(const unicorn& uc) { const auto process_handle = uc.reg(UC_X86_REG_R10); - const unicorn_object base_address{uc, uc.reg(UC_X86_REG_RDX)}; - const unicorn_object bytes_to_allocate{uc, uc.reg(UC_X86_REG_R9)}; + 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)); @@ -420,8 +420,8 @@ namespace void handle_NtAllocateVirtualMemoryEx(const unicorn& uc) { const auto process_handle = uc.reg(UC_X86_REG_R10); - const unicorn_object base_address{uc, uc.reg(UC_X86_REG_RDX)}; - const unicorn_object bytes_to_allocate{uc, uc.reg(UC_X86_REG_R8)}; + 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)); @@ -475,8 +475,8 @@ namespace void handle_NtFreeVirtualMemory(const unicorn& uc) { const auto process_handle = uc.reg(UC_X86_REG_R10); - const unicorn_object base_address{uc, uc.reg(UC_X86_REG_RDX)}; - const unicorn_object bytes_to_allocate{uc, uc.reg(UC_X86_REG_R8)}; + 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)}; if (process_handle != ~0ULL) { @@ -496,7 +496,7 @@ namespace } } -void handle_syscall(const unicorn& uc, process_context& context) +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); diff --git a/src/windows_emulator/syscalls.hpp b/src/windows_emulator/syscalls.hpp new file mode 100644 index 00000000..8990ffca --- /dev/null +++ b/src/windows_emulator/syscalls.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include +#include "process_context.hpp" + +void handle_syscall(x64_emulator& emu, process_context& context);