From aa047c6227ea32e322acbe33ff3074787b106226 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 16 Aug 2024 21:56:05 +0200 Subject: [PATCH] Working unicorn --- cmake/compiler-env.cmake | 2 +- src/emulator/main.cpp | 47 ++++++++++--------------------------- src/emulator/unicorn.cpp | 40 ++++++++++++++++++++++++++++++++ src/emulator/unicorn.hpp | 50 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 36 deletions(-) create mode 100644 src/emulator/unicorn.cpp create mode 100644 src/emulator/unicorn.hpp diff --git a/cmake/compiler-env.cmake b/cmake/compiler-env.cmake index 2dd73a23..82bd2b56 100644 --- a/cmake/compiler-env.cmake +++ b/cmake/compiler-env.cmake @@ -72,7 +72,7 @@ if(MSVC) /GS /Gy /EHa - /guard:cf + #/guard:cf ) momo_add_compile_options(CXX diff --git a/src/emulator/main.cpp b/src/emulator/main.cpp index b6842261..b1b54096 100644 --- a/src/emulator/main.cpp +++ b/src/emulator/main.cpp @@ -1,59 +1,36 @@ #include "std_include.hpp" -// code to be emulated #define X86_CODE32 "\x41\x4a" // INC ecx; DEC edx - -// memory address where emulation starts #define ADDRESS 0x1000000 +#include "unicorn.hpp" namespace { void run() { - uc_engine* uc; - uc_err err; - int r_ecx = 0x1234; // ECX register - int r_edx = 0x7890; // EDX register + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register printf("Emulate i386 code\n"); - // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return ; - } + const unicorn uc{UC_ARCH_X86, UC_MODE_32}; - // map 2MB memory for this emulation - uc_mem_map(uc, ADDRESS, 0x1000, UC_PROT_ALL); + e(uc_mem_map(uc, ADDRESS, 0x1000, UC_PROT_ALL)); + e(uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)); - // write machine code to be emulated to memory - if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) { - printf("Failed to write emulation code to memory, quit!\n"); - return; - } + e(uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx)); + e(uc_reg_write(uc, UC_X86_REG_EDX, &r_edx)); - // initialize machine registers - uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); + e(uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0)); - // emulate code in infinite time & unlimited instructions - err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); - if (err) { - printf("Failed on uc_emu_start() with error returned %u: %s\n", - err, uc_strerror(err)); - } - - // now print out some registers printf("Emulation done. Below is the CPU context\n"); - uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); + e(uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx)); + e(uc_reg_read(uc, UC_X86_REG_EDX, &r_edx)); + printf(">>> ECX = 0x%x\n", r_ecx); printf(">>> EDX = 0x%x\n", r_edx); - - uc_close(uc); } } diff --git a/src/emulator/unicorn.cpp b/src/emulator/unicorn.cpp new file mode 100644 index 00000000..c8ec7c50 --- /dev/null +++ b/src/emulator/unicorn.cpp @@ -0,0 +1,40 @@ +#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 new file mode 100644 index 00000000..3c211a92 --- /dev/null +++ b/src/emulator/unicorn.hpp @@ -0,0 +1,50 @@ +#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); + } +} + +inline void e(const uc_err error_code) +{ + ThrowIfUnicornError(error_code); +} + +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_; + } + +private: + uc_engine* uc_{}; +};