Working unicorn

This commit is contained in:
momo5502
2024-08-16 21:56:05 +02:00
parent a154eb3ec9
commit aa047c6227
4 changed files with 103 additions and 36 deletions

View File

@@ -72,7 +72,7 @@ if(MSVC)
/GS
/Gy
/EHa
/guard:cf
#/guard:cf
)
momo_add_compile_options(CXX

View File

@@ -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);
}
}

40
src/emulator/unicorn.cpp Normal file
View File

@@ -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;
}
}

50
src/emulator/unicorn.hpp Normal file
View File

@@ -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_{};
};