mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Simplify hooking interface
This commit is contained in:
@@ -42,13 +42,15 @@ namespace
|
|||||||
|
|
||||||
win_emu.emu().hook_memory_write(
|
win_emu.emu().hook_memory_write(
|
||||||
win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters), 0x8,
|
win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters), 0x8,
|
||||||
[&win_emu, cache_logging, params_hook, modules](const uint64_t address, size_t,
|
[&win_emu, cache_logging, params_hook, modules](const uint64_t address, const void*, size_t) mutable {
|
||||||
const uint64_t value) mutable {
|
|
||||||
const auto target_address = win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters);
|
const auto target_address = win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters);
|
||||||
|
|
||||||
if (address == target_address)
|
if (address == target_address)
|
||||||
{
|
{
|
||||||
const emulator_object<RTL_USER_PROCESS_PARAMETERS64> obj{win_emu.emu(), value};
|
const emulator_object<RTL_USER_PROCESS_PARAMETERS64> obj{
|
||||||
|
win_emu.emu(),
|
||||||
|
win_emu.emu().read_memory<uint64_t>(address),
|
||||||
|
};
|
||||||
|
|
||||||
win_emu.emu().delete_hook(params_hook);
|
win_emu.emu().delete_hook(params_hook);
|
||||||
params_hook = watch_object(win_emu, modules, obj, cache_logging);
|
params_hook = watch_object(win_emu, modules, obj, cache_logging);
|
||||||
@@ -236,7 +238,7 @@ namespace
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto read_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) {
|
auto read_handler = [&, section, concise_logging](const uint64_t address, const void*, size_t) {
|
||||||
const auto rip = win_emu->emu().read_instruction_pointer();
|
const auto rip = win_emu->emu().read_instruction_pointer();
|
||||||
if (!win_emu->mod_manager.executable->is_within(rip))
|
if (!win_emu->mod_manager.executable->is_within(rip))
|
||||||
{
|
{
|
||||||
@@ -258,7 +260,7 @@ namespace
|
|||||||
section.name.c_str(), address, rip);
|
section.name.c_str(), address, rip);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto write_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) {
|
const auto write_handler = [&, section, concise_logging](const uint64_t address, const void*, size_t) {
|
||||||
const auto rip = win_emu->emu().read_instruction_pointer();
|
const auto rip = win_emu->emu().read_instruction_pointer();
|
||||||
if (!win_emu->mod_manager.executable->is_within(rip))
|
if (!win_emu->mod_manager.executable->is_within(rip))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ emulator_hook* watch_object(windows_emulator& emu, const std::set<std::string, s
|
|||||||
|
|
||||||
return emu.emu().hook_memory_read(
|
return emu.emu().hook_memory_read(
|
||||||
object.value(), object.size(),
|
object.value(), object.size(),
|
||||||
[i = std::move(info), object, &emu, cache_logging, modules](const uint64_t address, size_t, uint64_t) {
|
[i = std::move(info), object, &emu, cache_logging, modules](const uint64_t address, const void*, size_t) {
|
||||||
const auto rip = emu.emu().read_instruction_pointer();
|
const auto rip = emu.emu().read_instruction_pointer();
|
||||||
const auto* mod = emu.mod_manager.find_by_address(rip);
|
const auto* mod = emu.mod_manager.find_by_address(rip);
|
||||||
const auto is_main_access = mod == emu.mod_manager.executable || modules.contains(mod->name);
|
const auto is_main_access = mod == emu.mod_manager.executable || modules.contains(mod->name);
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ using edge_generation_hook_callback =
|
|||||||
using basic_block_hook_callback = std::function<void(const basic_block& block)>;
|
using basic_block_hook_callback = std::function<void(const basic_block& block)>;
|
||||||
|
|
||||||
using instruction_hook_callback = std::function<instruction_hook_continuation()>;
|
using instruction_hook_callback = std::function<instruction_hook_continuation()>;
|
||||||
|
|
||||||
using interrupt_hook_callback = std::function<void(int interrupt)>;
|
using interrupt_hook_callback = std::function<void(int interrupt)>;
|
||||||
using simple_memory_hook_callback = std::function<void(uint64_t address, size_t size, uint64_t value)>;
|
|
||||||
using complex_memory_hook_callback =
|
using memory_access_hook_callback = std::function<void(uint64_t address, const void* data, size_t size)>;
|
||||||
std::function<void(uint64_t address, size_t size, uint64_t value, memory_operation operation)>;
|
using memory_execution_hook_callback = std::function<void(uint64_t address)>;
|
||||||
|
|
||||||
using memory_violation_hook_callback = std::function<memory_violation_continuation(
|
using memory_violation_hook_callback = std::function<memory_violation_continuation(
|
||||||
uint64_t address, size_t size, memory_operation operation, memory_violation_type type)>;
|
uint64_t address, size_t size, memory_operation operation, memory_violation_type type)>;
|
||||||
|
|
||||||
@@ -53,43 +53,18 @@ class hook_interface
|
|||||||
public:
|
public:
|
||||||
virtual ~hook_interface() = default;
|
virtual ~hook_interface() = default;
|
||||||
|
|
||||||
virtual emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) = 0;
|
virtual emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) = 0;
|
||||||
|
virtual emulator_hook* hook_memory_execution(uint64_t address, memory_execution_hook_callback callback) = 0;
|
||||||
|
virtual emulator_hook* hook_memory_read(uint64_t address, size_t size, memory_access_hook_callback callback) = 0;
|
||||||
|
virtual emulator_hook* hook_memory_write(uint64_t address, size_t size, memory_access_hook_callback callback) = 0;
|
||||||
|
|
||||||
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;
|
virtual emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) = 0;
|
||||||
|
|
||||||
virtual emulator_hook* hook_interrupt(interrupt_hook_callback callback) = 0;
|
virtual emulator_hook* hook_interrupt(interrupt_hook_callback callback) = 0;
|
||||||
|
virtual emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) = 0;
|
||||||
|
|
||||||
virtual emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) = 0;
|
virtual emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) = 0;
|
||||||
virtual emulator_hook* hook_basic_block(basic_block_hook_callback callback) = 0;
|
virtual emulator_hook* hook_basic_block(basic_block_hook_callback callback) = 0;
|
||||||
|
|
||||||
virtual void delete_hook(emulator_hook* hook) = 0;
|
virtual void delete_hook(emulator_hook* hook) = 0;
|
||||||
|
|
||||||
emulator_hook* hook_memory_read(const uint64_t address, const size_t size, simple_memory_hook_callback callback)
|
|
||||||
{
|
|
||||||
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::read);
|
|
||||||
}
|
|
||||||
|
|
||||||
emulator_hook* hook_memory_write(const uint64_t address, const size_t size, simple_memory_hook_callback callback)
|
|
||||||
{
|
|
||||||
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::write);
|
|
||||||
}
|
|
||||||
|
|
||||||
emulator_hook* hook_memory_execution(const uint64_t address, const size_t size,
|
|
||||||
simple_memory_hook_callback callback)
|
|
||||||
{
|
|
||||||
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::exec);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
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<uint8_t>(operation) & (static_cast<uint8_t>(operation) - 1)) == 0);
|
|
||||||
return this->hook_memory_access(address, size, operation,
|
|
||||||
[c = std::move(callback)](const uint64_t a, const size_t s,
|
|
||||||
const uint64_t value,
|
|
||||||
memory_operation) { c(a, s, value); });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,8 +7,13 @@ class scoped_hook
|
|||||||
scoped_hook() = default;
|
scoped_hook() = default;
|
||||||
|
|
||||||
scoped_hook(emulator& emu, emulator_hook* hook)
|
scoped_hook(emulator& emu, emulator_hook* hook)
|
||||||
|
: scoped_hook(emu, std::vector{hook})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_hook(emulator& emu, std::vector<emulator_hook*> hooks)
|
||||||
: emu_(&emu),
|
: emu_(&emu),
|
||||||
hook_(hook)
|
hooks_(std::move(hooks))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,9 +36,9 @@ class scoped_hook
|
|||||||
{
|
{
|
||||||
this->remove();
|
this->remove();
|
||||||
this->emu_ = obj.emu_;
|
this->emu_ = obj.emu_;
|
||||||
this->hook_ = obj.hook_;
|
this->hooks_ = std::move(obj.hooks_);
|
||||||
|
|
||||||
obj.hook_ = {};
|
obj.hooks_ = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@@ -41,14 +46,22 @@ class scoped_hook
|
|||||||
|
|
||||||
void remove()
|
void remove()
|
||||||
{
|
{
|
||||||
if (this->hook_)
|
auto hooks = std::move(this->hooks_);
|
||||||
|
this->hooks_ = {};
|
||||||
|
|
||||||
|
for (auto* hook : hooks_)
|
||||||
{
|
{
|
||||||
this->emu_->delete_hook(this->hook_);
|
try
|
||||||
this->hook_ = {};
|
{
|
||||||
|
this->emu_->delete_hook(hook);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
emulator* emu_{};
|
emulator* emu_{};
|
||||||
emulator_hook* hook_{};
|
std::vector<emulator_hook*> hooks_{};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ namespace
|
|||||||
void forward_emulator(windows_emulator& win_emu)
|
void forward_emulator(windows_emulator& win_emu)
|
||||||
{
|
{
|
||||||
const auto target = win_emu.mod_manager.executable->find_export("vulnerable");
|
const auto target = win_emu.mod_manager.executable->find_export("vulnerable");
|
||||||
win_emu.emu().hook_memory_execution(target, 1, [&](uint64_t, size_t, uint64_t) { win_emu.emu().stop(); });
|
win_emu.emu().hook_memory_execution(target, [&](uint64_t) {
|
||||||
|
win_emu.emu().stop(); //
|
||||||
|
});
|
||||||
|
|
||||||
run_emulation(win_emu);
|
run_emulation(win_emu);
|
||||||
}
|
}
|
||||||
@@ -64,7 +66,9 @@ namespace
|
|||||||
|
|
||||||
const auto ret = emu.emu().read_stack(0);
|
const auto ret = emu.emu().read_stack(0);
|
||||||
|
|
||||||
emu.emu().hook_memory_execution(ret, 1, [&](uint64_t, size_t, uint64_t) { emu.emu().stop(); });
|
emu.emu().hook_memory_execution(ret, [&](uint64_t) {
|
||||||
|
emu.emu().stop(); //
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore_emulator()
|
void restore_emulator()
|
||||||
|
|||||||
@@ -298,36 +298,46 @@ namespace icicle
|
|||||||
return wrap_hook(id);
|
return wrap_hook(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter,
|
emulator_hook* hook_memory_execution(const uint64_t address, memory_execution_hook_callback callback) override
|
||||||
complex_memory_hook_callback callback) override
|
|
||||||
{
|
{
|
||||||
if (filter == memory_permission::none)
|
// TODO
|
||||||
{
|
(void)address;
|
||||||
return nullptr;
|
throw std::runtime_error("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto shared_callback = std::make_shared<complex_memory_hook_callback>(std::move(callback));
|
emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) override
|
||||||
|
{
|
||||||
|
auto wrapper = make_function_object(std::move(callback));
|
||||||
|
auto* ptr = wrapper.get();
|
||||||
|
auto* func = +[](void* user, const uint64_t addr) {
|
||||||
|
auto& func = *static_cast<memory_execution_hook_callback*>(user);
|
||||||
|
(func)(addr);
|
||||||
|
};
|
||||||
|
|
||||||
if ((filter & memory_permission::exec) == memory_permission::exec)
|
const auto id = icicle_add_execution_hook(this->emu_, func, ptr);
|
||||||
{
|
this->hooks_[id] = std::move(wrapper);
|
||||||
if (address != 0 || size != std::numeric_limits<size_t>::max())
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Not supported!");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* ptr = shared_callback.get();
|
return wrap_hook(id);
|
||||||
auto wrapper = wrap_shared(shared_callback);
|
}
|
||||||
auto* func = +[](void* user, const uint64_t ptr) {
|
|
||||||
(*static_cast<complex_memory_hook_callback*>(user))(ptr, 0, 0, memory_permission::exec);
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto id = icicle_add_execution_hook(this->emu_, func, ptr);
|
emulator_hook* hook_memory_read(const uint64_t address, const size_t size,
|
||||||
this->hooks_[id] = std::move(wrapper);
|
memory_access_hook_callback callback) override
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
(void)address;
|
||||||
|
(void)size;
|
||||||
|
(void)callback;
|
||||||
|
throw std::runtime_error("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
return wrap_hook(id);
|
emulator_hook* hook_memory_write(const uint64_t address, const size_t size,
|
||||||
}
|
const memory_access_hook_callback callback) override
|
||||||
|
{
|
||||||
return nullptr;
|
// TODO
|
||||||
|
(void)address;
|
||||||
|
(void)size;
|
||||||
|
(void)callback;
|
||||||
|
throw std::runtime_error("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete_hook(emulator_hook* hook) override
|
void delete_hook(emulator_hook* hook) override
|
||||||
|
|||||||
@@ -175,63 +175,6 @@ namespace unicorn
|
|||||||
size_t size_{};
|
size_t size_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
void add_read_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container,
|
|
||||||
const std::shared_ptr<complex_memory_hook_callback>& callback)
|
|
||||||
{
|
|
||||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
|
||||||
[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)
|
|
||||||
{
|
|
||||||
(*callback)(address, static_cast<uint64_t>(size), 0, operation);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
unicorn_hook hook{uc};
|
|
||||||
|
|
||||||
uce(uc_hook_add(uc, 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_write_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container,
|
|
||||||
const std::shared_ptr<complex_memory_hook_callback>& callback)
|
|
||||||
{
|
|
||||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
|
||||||
[callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size,
|
|
||||||
const uint64_t value) {
|
|
||||||
const auto operation = map_memory_operation(type);
|
|
||||||
if (operation != memory_permission::none)
|
|
||||||
{
|
|
||||||
(*callback)(address, static_cast<uint64_t>(size), value, operation);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
unicorn_hook hook{uc};
|
|
||||||
|
|
||||||
uce(uc_hook_add(uc, 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_exec_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container,
|
|
||||||
const std::shared_ptr<complex_memory_hook_callback>& callback)
|
|
||||||
{
|
|
||||||
function_wrapper<void, uc_engine*, uint64_t, uint32_t> wrapper(
|
|
||||||
[callback](uc_engine*, const uint64_t address, const uint32_t size) {
|
|
||||||
(*callback)(address, size, 0, memory_permission::exec);
|
|
||||||
});
|
|
||||||
|
|
||||||
unicorn_hook hook{uc};
|
|
||||||
|
|
||||||
uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(), wrapper.get_user_data(),
|
|
||||||
address, address + size));
|
|
||||||
|
|
||||||
container.add(std::move(wrapper), std::move(hook));
|
|
||||||
}
|
|
||||||
|
|
||||||
basic_block map_block(const uc_tb& translation_block)
|
basic_block map_block(const uc_tb& translation_block)
|
||||||
{
|
{
|
||||||
basic_block block{};
|
basic_block block{};
|
||||||
@@ -581,38 +524,94 @@ namespace unicorn
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter,
|
emulator_hook* hook_memory_execution(uint64_t address, uint64_t size,
|
||||||
complex_memory_hook_callback callback) override
|
memory_execution_hook_callback callback)
|
||||||
{
|
{
|
||||||
if (filter == memory_permission::none)
|
auto exec_wrapper = [c = std::move(callback)](uc_engine*, const uint64_t address,
|
||||||
{
|
const uint32_t /*size*/) {
|
||||||
return nullptr;
|
c(address); //
|
||||||
}
|
};
|
||||||
|
|
||||||
const auto shared_callback = std::make_shared<complex_memory_hook_callback>(std::move(callback));
|
function_wrapper<void, uc_engine*, uint64_t, uint32_t> wrapper(std::move(exec_wrapper));
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
auto* container = this->create_hook_container();
|
||||||
|
container->add(std::move(wrapper), std::move(hook));
|
||||||
|
return container->as_opaque_hook();
|
||||||
|
}
|
||||||
|
|
||||||
|
emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) override
|
||||||
|
{
|
||||||
|
return this->hook_memory_execution(0, std::numeric_limits<uint64_t>::max(), std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
emulator_hook* hook_memory_execution(const uint64_t address,
|
||||||
|
memory_execution_hook_callback callback) override
|
||||||
|
{
|
||||||
|
return this->hook_memory_execution(address, 1, std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
emulator_hook* hook_memory_read(uint64_t address, size_t size,
|
||||||
|
memory_access_hook_callback callback) override
|
||||||
|
{
|
||||||
|
auto read_wrapper = [c = std::move(callback)](uc_engine*, const uc_mem_type type,
|
||||||
|
const uint64_t address, const int size,
|
||||||
|
const uint64_t value) {
|
||||||
|
const auto operation = map_memory_operation(type);
|
||||||
|
if (operation != memory_permission::none && size > 0)
|
||||||
|
{
|
||||||
|
c(address, &value, std::min(static_cast<size_t>(size), sizeof(value)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||||
|
std::move(read_wrapper));
|
||||||
|
|
||||||
|
unicorn_hook hook{*this};
|
||||||
|
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_READ_AFTER, wrapper.get_function(),
|
||||||
|
wrapper.get_user_data(), address, address + size));
|
||||||
|
|
||||||
|
auto* container = this->create_hook_container();
|
||||||
|
container->add(std::move(wrapper), std::move(hook));
|
||||||
|
return container->as_opaque_hook();
|
||||||
|
}
|
||||||
|
|
||||||
|
emulator_hook* hook_memory_write(uint64_t address, size_t size,
|
||||||
|
memory_access_hook_callback callback) override
|
||||||
|
{
|
||||||
|
auto write_wrapper = [c = std::move(callback)](uc_engine*, const uc_mem_type type,
|
||||||
|
const uint64_t address, const int size,
|
||||||
|
const uint64_t value) {
|
||||||
|
const auto operation = map_memory_operation(type);
|
||||||
|
if (operation != memory_permission::none && size > 0)
|
||||||
|
{
|
||||||
|
c(address, &value, std::min(static_cast<size_t>(size), sizeof(value)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||||
|
std::move(write_wrapper));
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
auto* container = this->create_hook_container();
|
||||||
|
container->add(std::move(wrapper), std::move(hook));
|
||||||
|
return container->as_opaque_hook();
|
||||||
|
}
|
||||||
|
|
||||||
|
hook_container* create_hook_container()
|
||||||
|
{
|
||||||
auto container = std::make_unique<hook_container>();
|
auto container = std::make_unique<hook_container>();
|
||||||
|
auto* ptr = container.get();
|
||||||
if ((filter & memory_operation::read) != memory_operation::none)
|
|
||||||
{
|
|
||||||
add_read_hook(*this, address, size, *container, shared_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((filter & memory_operation::write) != memory_operation::none)
|
|
||||||
{
|
|
||||||
add_write_hook(*this, address, size, *container, shared_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((filter & memory_operation::exec) != memory_operation::none)
|
|
||||||
{
|
|
||||||
add_exec_hook(*this, address, size, *container, shared_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* result = container->as_opaque_hook();
|
|
||||||
|
|
||||||
this->hooks_.push_back(std::move(container));
|
this->hooks_.push_back(std::move(container));
|
||||||
|
return ptr;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete_hook(emulator_hook* hook) override
|
void delete_hook(emulator_hook* hook) override
|
||||||
|
|||||||
@@ -517,9 +517,9 @@ void windows_emulator::setup_hooks()
|
|||||||
return memory_violation_continuation::resume;
|
return memory_violation_continuation::resume;
|
||||||
});
|
});
|
||||||
|
|
||||||
this->emu().hook_memory_execution(
|
this->emu().hook_memory_execution([&](const uint64_t address) {
|
||||||
0, std::numeric_limits<size_t>::max(),
|
this->on_instruction_execution(address); //
|
||||||
[&](const uint64_t address, const size_t, const uint64_t) { this->on_instruction_execution(address); });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void windows_emulator::start(size_t count)
|
void windows_emulator::start(size_t count)
|
||||||
|
|||||||
@@ -8,26 +8,6 @@
|
|||||||
#include "x64_register_mapping.hpp"
|
#include "x64_register_mapping.hpp"
|
||||||
#include "x64_target_descriptions.hpp"
|
#include "x64_target_descriptions.hpp"
|
||||||
|
|
||||||
inline memory_operation map_breakpoint_type(const gdb_stub::breakpoint_type type)
|
|
||||||
{
|
|
||||||
using enum gdb_stub::breakpoint_type;
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case software:
|
|
||||||
case hardware_exec:
|
|
||||||
return memory_operation::exec;
|
|
||||||
case hardware_read:
|
|
||||||
return memory_permission::read;
|
|
||||||
case hardware_write:
|
|
||||||
return memory_permission::write;
|
|
||||||
case hardware_read_write:
|
|
||||||
return memory_permission::read_write;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Bad bp type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct breakpoint_key
|
struct breakpoint_key
|
||||||
{
|
{
|
||||||
size_t addr{};
|
size_t addr{};
|
||||||
@@ -196,11 +176,9 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
return this->hooks_.access<bool>([&](hook_map& hooks) {
|
return this->hooks_.access<bool>([&](hook_map& hooks) {
|
||||||
hooks[{addr, size, type}] = scoped_hook(
|
auto hook_vector = this->create_hook(type, addr, size);
|
||||||
*this->emu_, this->emu_->hook_memory_access(addr, size, map_breakpoint_type(type),
|
|
||||||
[this](uint64_t, size_t, uint64_t, memory_operation) {
|
hooks[{addr, size, type}] = scoped_hook(*this->emu_, std::move(hook_vector));
|
||||||
this->on_interrupt(); //
|
|
||||||
}));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -264,4 +242,64 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler
|
|||||||
|
|
||||||
using hook_map = std::unordered_map<breakpoint_key, scoped_hook>;
|
using hook_map = std::unordered_map<breakpoint_key, scoped_hook>;
|
||||||
utils::concurrency::container<hook_map> hooks_{};
|
utils::concurrency::container<hook_map> hooks_{};
|
||||||
|
|
||||||
|
std::vector<emulator_hook*> create_execute_hook(const uint64_t addr, const size_t size)
|
||||||
|
{
|
||||||
|
std::vector<emulator_hook*> hooks{};
|
||||||
|
hooks.reserve(size);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
auto* hook = this->emu_->hook_memory_execution(addr + i, [this](const uint64_t) {
|
||||||
|
this->on_interrupt(); //
|
||||||
|
});
|
||||||
|
|
||||||
|
hooks.push_back(hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<emulator_hook*> create_read_hook(const uint64_t addr, const size_t size)
|
||||||
|
{
|
||||||
|
auto* hook = this->emu_->hook_memory_read(addr, size, [this](const uint64_t, const void*, const size_t) {
|
||||||
|
this->on_interrupt(); //
|
||||||
|
});
|
||||||
|
|
||||||
|
return {hook};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<emulator_hook*> create_write_hook(const uint64_t addr, const size_t size)
|
||||||
|
{
|
||||||
|
auto* hook = this->emu_->hook_memory_write(addr, size, [this](const uint64_t, const void*, const size_t) {
|
||||||
|
this->on_interrupt(); //
|
||||||
|
});
|
||||||
|
|
||||||
|
return {hook};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<emulator_hook*> create_hook(const gdb_stub::breakpoint_type type, const uint64_t addr,
|
||||||
|
const size_t size)
|
||||||
|
{
|
||||||
|
using enum gdb_stub::breakpoint_type;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case software:
|
||||||
|
case hardware_exec:
|
||||||
|
return this->create_execute_hook(addr, size);
|
||||||
|
case hardware_read:
|
||||||
|
return this->create_read_hook(addr, size);
|
||||||
|
case hardware_write:
|
||||||
|
return this->create_write_hook(addr, size);
|
||||||
|
case hardware_read_write: {
|
||||||
|
auto hooks1 = this->create_hook(hardware_read, addr, size);
|
||||||
|
auto hooks2 = this->create_hook(hardware_write, addr, size);
|
||||||
|
hooks1.insert(hooks1.end(), hooks2.begin(), hooks2.end());
|
||||||
|
return hooks1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Bad bp type");
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user