mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-29 07:51:01 +00:00
Better output
This commit is contained in:
@@ -40,10 +40,11 @@ namespace
|
||||
{
|
||||
if (use_gdb)
|
||||
{
|
||||
puts("Launching gdb stub...");
|
||||
const auto* address = "0.0.0.0:28960";
|
||||
win_emu.logger.print(color::pink, "Waiting for GDB connection on %s...\n", address);
|
||||
|
||||
x64_gdb_stub_handler handler{win_emu.emu()};
|
||||
run_gdb_stub(handler, "i386:x86-64", gdb_registers.size(), "0.0.0.0:28960");
|
||||
run_gdb_stub(handler, "i386:x86-64", gdb_registers.size(), address);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -52,11 +53,9 @@ namespace
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
printf("Emulation failed at: %llX\n", win_emu.emu().read_instruction_pointer());
|
||||
printf("Emulation failed at: 0x%llX\n", win_emu.emu().read_instruction_pointer());
|
||||
throw;
|
||||
}
|
||||
|
||||
printf("Emulation done.\n");
|
||||
}
|
||||
|
||||
void run(std::string_view application)
|
||||
@@ -65,14 +64,14 @@ namespace
|
||||
application, {}
|
||||
};
|
||||
|
||||
watch_system_objects(win_emu);
|
||||
//watch_system_objects(win_emu);
|
||||
|
||||
|
||||
const auto& exe = *win_emu.process().executable;
|
||||
|
||||
const auto text_start = exe.image_base + 0x1000;
|
||||
const auto text_end = exe.image_base + 0x52000;
|
||||
const auto scan_size = 0x1000;
|
||||
const auto scan_size = 0x100;
|
||||
|
||||
win_emu.emu().hook_memory_read(text_start, scan_size, [&](uint64_t address, size_t, uint64_t)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ emulator_hook* watch_object(windows_emulator& emu, emulator_object<T> object)
|
||||
const auto rip = emu.emu().read_instruction_pointer();
|
||||
|
||||
const auto offset = address - object.value();
|
||||
emu.logger.log("Object access: %s - %llX (%s) at %llX (%s)\n", i.get_type_name().c_str(),
|
||||
emu.logger.log("Object access: %s - 0x%llX (%s) at 0x%llX (%s)\n", i.get_type_name().c_str(),
|
||||
offset,
|
||||
i.get_member_name(offset).c_str(), rip,
|
||||
emu.process().module_manager.find_name(rip));
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace
|
||||
case cyan: return COLOR(0xB, "\033[0;96m");
|
||||
case pink: return COLOR(0xD, "\033[0;95m");
|
||||
case white: return COLOR(0xF, "\033[0;97m");
|
||||
case dark_gray: return COLOR(0x8, "\033[0;97m");
|
||||
case gray:
|
||||
default: return get_reset_color();
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ enum class color
|
||||
pink,
|
||||
white,
|
||||
gray,
|
||||
dark_gray,
|
||||
};
|
||||
|
||||
class logger
|
||||
|
||||
@@ -22,4 +22,9 @@ struct mapped_module
|
||||
|
||||
exported_symbols exports{};
|
||||
address_name_mapping address_names{};
|
||||
|
||||
bool is_within(const uint64_t address) const
|
||||
{
|
||||
return address >= this->image_base && address < (this->image_base + this->size_of_image);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -66,7 +66,7 @@ mapped_module* module_manager::map_module(const std::filesystem::path& file)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
printf("Mapped %s at %llX\n", mod->path.generic_string().c_str(), mod->image_base);
|
||||
printf("Mapped %s at 0x%llX\n", mod->path.generic_string().c_str(), mod->image_base);
|
||||
|
||||
const auto image_base = mod->image_base;
|
||||
const auto entry = this->modules_.try_emplace(image_base, std::move(*mod));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "emulator_utils.hpp"
|
||||
#include "handles.hpp"
|
||||
|
||||
@@ -119,6 +120,9 @@ struct process_context
|
||||
}
|
||||
|
||||
uint64_t executed_instructions{0};
|
||||
uint64_t current_ip{0};
|
||||
uint64_t previous_ip{0};
|
||||
|
||||
emulator_object<TEB> teb;
|
||||
emulator_object<PEB> peb;
|
||||
emulator_object<RTL_USER_PROCESS_PARAMETERS> process_params;
|
||||
@@ -144,6 +148,8 @@ struct process_context
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->executed_instructions);
|
||||
buffer.write(this->current_ip);
|
||||
buffer.write(this->previous_ip);
|
||||
buffer.write(this->teb);
|
||||
buffer.write(this->peb);
|
||||
buffer.write(this->process_params);
|
||||
@@ -168,6 +174,8 @@ struct process_context
|
||||
void deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read(this->executed_instructions);
|
||||
buffer.read(this->current_ip);
|
||||
buffer.read(this->previous_ip);
|
||||
buffer.read(this->teb);
|
||||
buffer.read(this->peb);
|
||||
buffer.read(this->process_params);
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
|
||||
#include "context_frame.hpp"
|
||||
#include "emulator_utils.hpp"
|
||||
#include "windows_emulator.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
|
||||
|
||||
struct syscall_context
|
||||
{
|
||||
windows_emulator& win_emu;
|
||||
x64_emulator& emu;
|
||||
process_context& proc;
|
||||
mutable bool write_status;
|
||||
@@ -71,10 +74,6 @@ namespace
|
||||
{
|
||||
syscalls.push_back(std::move(syscall.second));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Skipping %s\n", syscall.second.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return syscalls;
|
||||
@@ -334,8 +333,8 @@ namespace
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtOpenEvent(const syscall_context& c, const emulator_object<uint64_t> event_handle,
|
||||
const ACCESS_MASK /*desired_access*/,
|
||||
const emulator_object<OBJECT_ATTRIBUTES> object_attributes)
|
||||
const ACCESS_MASK /*desired_access*/,
|
||||
const emulator_object<OBJECT_ATTRIBUTES> object_attributes)
|
||||
{
|
||||
const auto attributes = object_attributes.read();
|
||||
const auto name = read_unicode_string(c.emu, attributes.ObjectName);
|
||||
@@ -420,7 +419,7 @@ namespace
|
||||
const auto attributes = object_attributes.read();
|
||||
|
||||
auto filename = read_unicode_string(c.emu, attributes.ObjectName);
|
||||
printf("Open section: %S\n", filename.c_str());
|
||||
printf("Opening section: %S\n", filename.c_str());
|
||||
|
||||
if (filename == L"\\Windows\\SharedSection")
|
||||
{
|
||||
@@ -622,7 +621,7 @@ namespace
|
||||
const auto mod = c.proc.module_manager.find_by_address(base_address);
|
||||
if (!mod)
|
||||
{
|
||||
printf("Bad address for memory image request: %llX\n", base_address);
|
||||
printf("Bad address for memory image request: 0x%llX\n", base_address);
|
||||
return STATUS_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
@@ -842,7 +841,7 @@ namespace
|
||||
|| info_class == SystemFeatureConfigurationInformation
|
||||
|| info_class == SystemFeatureConfigurationSectionInformation)
|
||||
{
|
||||
printf("Unsupported, but allowed system info class: %X\n", info_class);
|
||||
//printf("Unsupported, but allowed system info class: %X\n", info_class);
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@@ -1030,6 +1029,40 @@ namespace
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (info_class == ProcessImageFileNameWin32)
|
||||
{
|
||||
const auto peb = c.proc.peb.read();
|
||||
emulator_object<RTL_USER_PROCESS_PARAMETERS> proc_params{c.emu, peb.ProcessParameters};
|
||||
const auto params = proc_params.read();
|
||||
|
||||
const auto length = params.ImagePathName.Length + sizeof(UNICODE_STRING) + 2;
|
||||
|
||||
if (return_length)
|
||||
{
|
||||
return_length.write(static_cast<uint32_t>(length));
|
||||
}
|
||||
|
||||
if (process_information_length < length)
|
||||
{
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
const emulator_object<UNICODE_STRING> info{c.emu, process_information};
|
||||
info.access([&](UNICODE_STRING& str)
|
||||
{
|
||||
const auto buffer_start = static_cast<uint64_t>(process_information) + sizeof(UNICODE_STRING);
|
||||
const auto string = read_unicode_string(c.emu, params.ImagePathName);
|
||||
|
||||
c.emu.write_memory(buffer_start, string.c_str(), (string.size() + 1) * 2);
|
||||
|
||||
str.Length = params.ImagePathName.Length;
|
||||
str.MaximumLength = str.Length;
|
||||
str.Buffer = reinterpret_cast<wchar_t*>(buffer_start);
|
||||
});
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Unsupported process info class: %X\n", info_class);
|
||||
c.emu.stop();
|
||||
|
||||
@@ -1125,8 +1158,8 @@ namespace
|
||||
|
||||
const auto requested_protection = map_nt_to_emulator_protection(protection);
|
||||
|
||||
printf("Changing protection at %llX-%llX to %s\n", aligned_start, aligned_start + aligned_length,
|
||||
get_permission_string(requested_protection).c_str());
|
||||
c.win_emu.logger.print(color::dark_gray, "--> Changing protection at 0x%llX-0x%llX to %s\n", aligned_start,
|
||||
aligned_start + aligned_length, get_permission_string(requested_protection).c_str());
|
||||
|
||||
memory_permission old_protection_value{};
|
||||
c.emu.protect_memory(aligned_start, aligned_length, requested_protection, &old_protection_value);
|
||||
@@ -1297,7 +1330,7 @@ namespace
|
||||
const ULONG /*section_page_protection*/, const ULONG /*allocation_attributes*/,
|
||||
const uint64_t /*file_handle*/)
|
||||
{
|
||||
puts("NtCreateSection not supported");
|
||||
//puts("NtCreateSection not supported");
|
||||
section_handle.write(SHARED_SECTION.bits);
|
||||
|
||||
maximum_size.access([&c](ULARGE_INTEGER& large_int)
|
||||
@@ -1365,62 +1398,62 @@ namespace
|
||||
|
||||
NTSTATUS handle_NtDeviceIoControlFile()
|
||||
{
|
||||
puts("NtDeviceIoControlFile not supported");
|
||||
//puts("NtDeviceIoControlFile not supported");
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryWnfStateData()
|
||||
{
|
||||
puts("NtQueryWnfStateData not supported");
|
||||
//puts("NtQueryWnfStateData not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryWnfStateNameInformation()
|
||||
{
|
||||
puts("NtQueryWnfStateNameInformation not supported");
|
||||
//puts("NtQueryWnfStateNameInformation not supported");
|
||||
//return STATUS_NOT_SUPPORTED;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtOpenProcessToken()
|
||||
{
|
||||
puts("NtOpenProcessToken not supported");
|
||||
//puts("NtOpenProcessToken not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQuerySecurityAttributesToken()
|
||||
{
|
||||
puts("NtQuerySecurityAttributesToken not supported");
|
||||
//puts("NtQuerySecurityAttributesToken not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryLicenseValue()
|
||||
{
|
||||
puts("NtQueryLicenseValue not supported");
|
||||
//puts("NtQueryLicenseValue not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtTestAlert()
|
||||
{
|
||||
puts("NtTestAlert not supported");
|
||||
//puts("NtTestAlert not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryInformationToken()
|
||||
{
|
||||
puts("NtQueryInformationToken not supported");
|
||||
//puts("NtQueryInformationToken not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtDxgkIsFeatureEnabled()
|
||||
{
|
||||
puts("NtDxgkIsFeatureEnabled not supported");
|
||||
//puts("NtDxgkIsFeatureEnabled not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtUserDisplayConfigGetDeviceInfo()
|
||||
{
|
||||
puts("NtUserDisplayConfigGetDeviceInfo not supported");
|
||||
//puts("NtUserDisplayConfigGetDeviceInfo not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@@ -1439,7 +1472,7 @@ namespace
|
||||
|
||||
NTSTATUS handle_NtUserGetThreadState()
|
||||
{
|
||||
puts("NtUserGetThreadState not supported");
|
||||
//puts("NtUserGetThreadState not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@@ -1538,13 +1571,12 @@ namespace
|
||||
temp_buffer.resize(length);
|
||||
c.emu.read_memory(buffer, temp_buffer.data(), temp_buffer.size());
|
||||
|
||||
(void)fwrite(temp_buffer.data(), 1, temp_buffer.size(), stdout);
|
||||
(void)fflush(stdout);
|
||||
c.win_emu.logger.info("%.*s", static_cast<int>(temp_buffer.size()), temp_buffer.data());
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
puts("NtWriteFile not supported");
|
||||
//puts("NtWriteFile not supported");
|
||||
c.emu.stop();
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
@@ -1831,20 +1863,23 @@ void syscall_dispatcher::deserialize(utils::buffer_deserializer& buffer)
|
||||
this->add_handlers();
|
||||
}
|
||||
|
||||
void syscall_dispatcher::dispatch(x64_emulator& emu, process_context& context)
|
||||
void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
||||
{
|
||||
auto& emu = win_emu.emu();
|
||||
auto& context = win_emu.process();
|
||||
|
||||
const auto address = emu.read_instruction_pointer();
|
||||
const auto syscall_id = emu.reg<uint32_t>(x64_register::eax);
|
||||
|
||||
|
||||
const syscall_context c{emu, context, true};
|
||||
const syscall_context c{win_emu, emu, context, true};
|
||||
|
||||
try
|
||||
{
|
||||
const auto entry = this->handlers_.find(syscall_id);
|
||||
if (entry == this->handlers_.end())
|
||||
{
|
||||
printf("Unknown syscall: %X\n", syscall_id);
|
||||
printf("Unknown syscall: 0x%X\n", syscall_id);
|
||||
c.emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_SUPPORTED);
|
||||
c.emu.stop();
|
||||
return;
|
||||
@@ -1852,24 +1887,25 @@ void syscall_dispatcher::dispatch(x64_emulator& emu, process_context& context)
|
||||
|
||||
if (!entry->second.handler)
|
||||
{
|
||||
printf("Unimplemented syscall: %s - %X\n", entry->second.name.c_str(), syscall_id);
|
||||
printf("Unimplemented syscall: %s - 0x%X\n", entry->second.name.c_str(), syscall_id);
|
||||
c.emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_SUPPORTED);
|
||||
c.emu.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Handling syscall: %s with id %X at %llX \n", entry->second.name.c_str(), syscall_id, address);
|
||||
win_emu.logger.print(color::dark_gray, "Syscall: %s (0x%X) at 0x%llX\n", entry->second.name.c_str(), syscall_id,
|
||||
address);
|
||||
entry->second.handler(c);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
printf("Syscall threw an exception: %X (%llX) - %s\n", syscall_id, address, e.what());
|
||||
printf("Syscall threw an exception: %X (0x%llX) - %s\n", syscall_id, address, e.what());
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_UNSUCCESSFUL);
|
||||
emu.stop();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
printf("Syscall threw an unknown exception: %X (%llX)\n", syscall_id, address);
|
||||
printf("Syscall threw an unknown exception: %X (0x%llX)\n", syscall_id, address);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_UNSUCCESSFUL);
|
||||
emu.stop();
|
||||
}
|
||||
|
||||
@@ -13,13 +13,15 @@ struct syscall_handler_entry
|
||||
std::string name{};
|
||||
};
|
||||
|
||||
class windows_emulator;
|
||||
|
||||
class syscall_dispatcher
|
||||
{
|
||||
public:
|
||||
syscall_dispatcher() = default;
|
||||
syscall_dispatcher(const exported_symbols& ntdll_exports, const exported_symbols& win32u_exports);
|
||||
|
||||
void dispatch(x64_emulator& emu, process_context& context);
|
||||
void dispatch(windows_emulator& win_emu);
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const;
|
||||
void deserialize(utils::buffer_deserializer& buffer);
|
||||
|
||||
@@ -437,9 +437,6 @@ namespace
|
||||
frame.cs = pointers.ContextRecord->SegCs;
|
||||
frame.eflags = pointers.ContextRecord->EFlags;
|
||||
});
|
||||
|
||||
printf("ContextRecord: %llX\n", context_record_obj.value());
|
||||
printf("ExceptionRecord: %llX\n", exception_record_obj.value());
|
||||
}
|
||||
|
||||
void dispatch_access_violation(x64_emulator& emu, const uint64_t dispatcher, const uint64_t address,
|
||||
@@ -543,20 +540,20 @@ void windows_emulator::setup_hooks()
|
||||
}
|
||||
}
|
||||
|
||||
this->dispatcher_.dispatch(this->emu(), this->process());
|
||||
this->dispatcher_.dispatch(*this);
|
||||
return instruction_hook_continuation::skip_instruction;
|
||||
});
|
||||
|
||||
this->emu().hook_instruction(x64_hookable_instructions::invalid, [&]
|
||||
{
|
||||
const auto ip = this->emu().read_instruction_pointer();
|
||||
printf("Invalid instruction at: %llX\n", ip);
|
||||
printf("Invalid instruction at: 0x%llX\n", ip);
|
||||
return instruction_hook_continuation::skip_instruction;
|
||||
});
|
||||
|
||||
this->emu().hook_interrupt([&](const int interrupt)
|
||||
{
|
||||
printf("Interrupt: %i %llX\n", interrupt, this->emu().read_instruction_pointer());
|
||||
printf("Interrupt: %i 0x%llX\n", interrupt, this->emu().read_instruction_pointer());
|
||||
});
|
||||
|
||||
this->emu().hook_memory_violation([&](const uint64_t address, const size_t size, const memory_operation operation,
|
||||
@@ -568,11 +565,11 @@ void windows_emulator::setup_hooks()
|
||||
|
||||
if (type == memory_violation_type::protection)
|
||||
{
|
||||
printf("Protection violation: %llX (%zX) - %s at %llX (%s)\n", address, size, permission.c_str(), ip, name);
|
||||
printf("Protection violation: 0x%llX (%zX) - %s at 0x%llX (%s)\n", address, size, permission.c_str(), ip, name);
|
||||
}
|
||||
else if (type == memory_violation_type::unmapped)
|
||||
{
|
||||
printf("Mapping violation: %llX (%zX) - %s at %llX (%s)\n", address, size, permission.c_str(), ip, name);
|
||||
printf("Mapping violation: 0x%llX (%zX) - %s at 0x%llX (%s)\n", address, size, permission.c_str(), ip, name);
|
||||
}
|
||||
|
||||
dispatch_access_violation(this->emu(), this->process().ki_user_exception_dispatcher, address, operation);
|
||||
@@ -582,9 +579,17 @@ void windows_emulator::setup_hooks()
|
||||
this->emu().hook_memory_execution(0, std::numeric_limits<size_t>::max(),
|
||||
[&](const uint64_t address, const size_t, const uint64_t)
|
||||
{
|
||||
++this->process().executed_instructions;
|
||||
auto& process = this->process();
|
||||
|
||||
if (address == 0x180038B65)
|
||||
++process.executed_instructions;
|
||||
|
||||
process.previous_ip = process.current_ip;
|
||||
process.current_ip = this->emu().read_instruction_pointer();
|
||||
|
||||
const auto is_interesting_call = process.executable->is_within(
|
||||
process.previous_ip) || process.executable->is_within(address);
|
||||
|
||||
/*if (address == 0x180038B65)
|
||||
{
|
||||
puts("!!! DLL init failed");
|
||||
}
|
||||
@@ -593,7 +598,13 @@ void windows_emulator::setup_hooks()
|
||||
const auto* name = this->process().module_manager.find_name(
|
||||
this->emu().reg(x64_register::rcx));
|
||||
printf("!!! DLL init: %s\n", name);
|
||||
}*/
|
||||
|
||||
if (!this->verbose_ && !this->verbose_calls_ && !is_interesting_call)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* binary = this->process().module_manager.find_by_address(address);
|
||||
|
||||
if (binary)
|
||||
@@ -601,13 +612,13 @@ void windows_emulator::setup_hooks()
|
||||
const auto export_entry = binary->address_names.find(address);
|
||||
if (export_entry != binary->address_names.end())
|
||||
{
|
||||
printf("Executing function: %s - %s (%llX)\n", binary->name.c_str(),
|
||||
export_entry->second.c_str(), address);
|
||||
logger.print(is_interesting_call ? color::yellow : color::gray, "Executing function: %s - %s (0x%llX)\n", binary->name.c_str(),
|
||||
export_entry->second.c_str(), address);
|
||||
}
|
||||
else if (address == binary->entry_point)
|
||||
{
|
||||
printf("Executing entry point: %s (%llX)\n", binary->name.c_str(),
|
||||
address);
|
||||
logger.print(is_interesting_call ? color::yellow : color::gray, "Executing entry point: %s (0x%llX)\n", binary->name.c_str(),
|
||||
address);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,11 @@ public:
|
||||
this->verbose_ = verbose;
|
||||
}
|
||||
|
||||
void set_verbose_calls(const bool verbose)
|
||||
{
|
||||
this->verbose_calls_ = verbose;
|
||||
}
|
||||
|
||||
void add_syscall_hook(instruction_hook_callback callback)
|
||||
{
|
||||
this->syscall_hooks_.push_back(std::move(callback));
|
||||
@@ -69,6 +74,7 @@ public:
|
||||
|
||||
private:
|
||||
bool verbose_{false};
|
||||
bool verbose_calls_{false};
|
||||
std::unique_ptr<x64_emulator> emu_{};
|
||||
|
||||
std::vector<instruction_hook_callback> syscall_hooks_{};
|
||||
|
||||
Reference in New Issue
Block a user