some refactoring with optional_function (#96)

- wrapped std::function into utils::optional_function 
  - cleaned the code accordingly in windows_emulator
- using the 'emulator'/'windows_emulator' dependency implies the
emulator_common as well.
This commit is contained in:
Maurice Heumann
2025-01-23 18:07:27 +01:00
committed by GitHub
7 changed files with 75 additions and 50 deletions

View File

@@ -0,0 +1,54 @@
#pragma once
#include <functional>
namespace utils
{
template <typename Signature>
class optional_function;
template <typename Ret, typename... Args>
class optional_function<Ret(Args...)>
{
private:
std::function<Ret(Args...)> func;
public:
optional_function() = default;
optional_function(std::function<Ret(Args...)> f)
: func(std::move(f))
{
}
template <typename F, typename = std::enable_if_t<std::is_invocable_r_v<Ret, F, Args...>>>
optional_function(F&& f)
: func(std::forward<F>(f))
{
}
optional_function& operator=(std::function<Ret(Args...)> f)
{
func = std::move(f);
return *this;
}
Ret operator()(Args... args) const
{
if (func)
{
return func(std::forward<Args>(args)...);
}
if constexpr (!std::is_void_v<Ret>)
{
return Ret();
}
}
explicit operator bool() const noexcept
{
return static_cast<bool>(func);
}
};
}

View File

@@ -8,4 +8,5 @@ list(SORT SRC_FILES)
add_library(emulator ${SRC_FILES})
target_link_libraries(emulator PUBLIC emulator-common)
target_include_directories(emulator INTERFACE "${CMAKE_CURRENT_LIST_DIR}")

View File

@@ -16,10 +16,7 @@ target_link_libraries(windows-emulator PRIVATE
unicorn-emulator
)
target_link_libraries(windows-emulator PUBLIC
emulator-common
emulator
)
target_link_libraries(windows-emulator PUBLIC emulator)
target_include_directories(windows-emulator INTERFACE "${CMAKE_CURRENT_LIST_DIR}")

View File

@@ -91,8 +91,8 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
const auto* mod = context.mod_manager.find_by_address(address);
if (mod != context.ntdll && mod != context.win32u)
{
win_emu.on_inline_syscall(syscall_id, address, mod ? mod->name.c_str() : "<N/A>",
entry->second.name.c_str());
win_emu.callbacks().inline_syscall(syscall_id, address, mod ? mod->name.c_str() : "<N/A>",
entry->second.name.c_str());
win_emu.log.print(color::blue, "Executing inline syscall: %s (0x%X) at 0x%" PRIx64 " (%s)\n",
entry->second.name.c_str(), syscall_id, address, mod ? mod->name.c_str() : "<N/A>");
}
@@ -111,9 +111,9 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
else
{
const auto* previous_mod = context.mod_manager.find_by_address(context.previous_ip);
win_emu.on_outofline_syscall(syscall_id, address, mod ? mod->name.c_str() : "<N/A>",
entry->second.name.c_str(), context.previous_ip,
previous_mod ? previous_mod->name.c_str() : "<N/A>");
win_emu.callbacks().outofline_syscall(syscall_id, address, mod ? mod->name.c_str() : "<N/A>",
entry->second.name.c_str(), context.previous_ip,
previous_mod ? previous_mod->name.c_str() : "<N/A>");
win_emu.log.print(color::blue,
"Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64
" (%s)\n",

View File

@@ -2681,7 +2681,7 @@ namespace
temp_buffer.push_back('\n');
}
c.win_emu.on_stdout(temp_buffer);
c.win_emu.callbacks().stdout_callback(temp_buffer);
c.win_emu.log.info("%.*s", static_cast<int>(temp_buffer.size()), temp_buffer.data());
return STATUS_SUCCESS;

View File

@@ -1141,30 +1141,3 @@ void windows_emulator::restore_snapshot()
this->process_.deserialize(deserializer);
// this->process_ = *this->process_snapshot_;
}
void windows_emulator::on_stdout(const std::string_view data) const
{
if (this->callbacks_.stdout_callback)
{
this->callbacks_.stdout_callback(data);
}
}
void windows_emulator::on_inline_syscall(uint32_t syscall_id, const x64_emulator::pointer_type address,
const std::string_view mod_name, const std::string_view name)
{
if (this->callbacks_.inline_syscall)
{
this->callbacks_.inline_syscall(syscall_id, address, mod_name, name);
}
}
void windows_emulator::on_outofline_syscall(uint32_t syscall_id, x64_emulator::pointer_type address,
std::string_view mod_name, std::string_view syscall_name,
x64_emulator::pointer_type prev_address, std::string_view prev_mod_name)
{
if (this->callbacks_.outofline_syscall)
{
this->callbacks_.outofline_syscall(syscall_id, address, mod_name, syscall_name, prev_address, prev_mod_name);
}
}

View File

@@ -3,6 +3,8 @@
#include <x64_emulator.hpp>
#include <utils/function.hpp>
#include "syscall_dispatcher.hpp"
#include "process_context.hpp"
#include "logger.hpp"
@@ -11,13 +13,13 @@ std::unique_ptr<x64_emulator> create_default_x64_emulator();
struct emulator_callbacks
{
std::function<void(std::string_view)> stdout_callback{};
std::function<void(uint32_t syscall_id, x64_emulator::pointer_type address, std::string_view mod_name,
std::string_view syscall_name)>
utils::optional_function<void(std::string_view)> stdout_callback{};
utils::optional_function<void(uint32_t syscall_id, x64_emulator::pointer_type address, std::string_view mod_name,
std::string_view syscall_name)>
inline_syscall{};
std::function<void(uint32_t syscall_id, x64_emulator::pointer_type address, std::string_view mod_name,
std::string_view syscall_name, x64_emulator::pointer_type prev_address,
std::string_view prev_mod_name)>
utils::optional_function<void(uint32_t syscall_id, x64_emulator::pointer_type address, std::string_view mod_name,
std::string_view syscall_name, x64_emulator::pointer_type prev_address,
std::string_view prev_mod_name)>
outofline_syscall{};
};
@@ -108,13 +110,6 @@ class windows_emulator
this->syscall_hooks_.push_back(std::move(callback));
}
void on_stdout(const std::string_view data) const;
void on_inline_syscall(uint32_t syscall_id, const x64_emulator::pointer_type address,
const std::string_view mod_name, const std::string_view name);
void on_outofline_syscall(uint32_t syscall_id, x64_emulator::pointer_type address, std::string_view mod_name,
std::string_view syscall_name, x64_emulator::pointer_type prev_address,
std::string_view prev_mod_name);
logger log{};
bool verbose{false};
bool verbose_calls{false};
@@ -131,6 +126,11 @@ class windows_emulator
return this->use_relative_time_;
}
emulator_callbacks& callbacks()
{
return this->callbacks_;
}
private:
emulator_callbacks callbacks_{};
bool use_relative_time_{false};