Move more logging into callbacks

This commit is contained in:
momo5502
2025-06-06 19:27:50 +02:00
parent 24939583c4
commit bc77faec3d
18 changed files with 106 additions and 78 deletions

View File

@@ -2,7 +2,11 @@
#include "analysis.hpp"
#include "windows_emulator.hpp"
#include "utils/lazy_object.hpp"
#include <utils/lazy_object.hpp>
#ifdef OS_EMSCRIPTEN
#include <event_handler.hpp>
#endif
#define STR_VIEW_VA(str) static_cast<int>((str).size()), (str).data()
@@ -31,6 +35,34 @@ namespace
c.win_emu->log.print(color::pink, "Suspicious: %.*s (0x%" PRIx64 ")\n", STR_VIEW_VA(details), rip);
}
void handle_generic_activity(const analysis_context& c, const std::string_view details)
{
c.win_emu->log.print(color::dark_gray, "%.*s\n", STR_VIEW_VA(details));
}
void handle_generic_access(const analysis_context& c, const std::string_view type, const std::u16string_view name)
{
c.win_emu->log.print(color::dark_gray, "--> %.*s: %s\n", STR_VIEW_VA(type), u16_to_u8(name).c_str()); //
}
void handle_ioctrl(const analysis_context& c, const io_device&, const std::u16string_view device_name,
const ULONG code)
{
c.win_emu->log.print(color::dark_gray, "--> %s: 0x%X\n", u16_to_u8(device_name).c_str(),
static_cast<uint32_t>(code));
}
void handle_thread_switch(const analysis_context& c, const emulator_thread& current_thread,
const emulator_thread& new_thread)
{
c.win_emu->log.print(color::dark_gray, "Performing thread switch: %X -> %X\n", current_thread.id,
new_thread.id);
#ifdef OS_EMSCRIPTEN
debugger::event_context ec{.win_emu = *c.win_emu};
debugger::handle_events(ec);
#endif
}
void handle_instruction(analysis_context& c, const uint64_t address)
{
auto& win_emu = *c.win_emu;
@@ -167,6 +199,10 @@ void register_analysis_callbacks(analysis_context& c)
cb.on_stdout = make_callback(c, handle_stdout);
cb.on_syscall = make_callback(c, handle_syscall);
cb.on_ioctrl = make_callback(c, handle_ioctrl);
cb.on_instruction = make_callback(c, handle_instruction);
cb.on_thread_switch = make_callback(c, handle_thread_switch);
cb.on_generic_access = make_callback(c, handle_generic_access);
cb.on_generic_activity = make_callback(c, handle_generic_activity);
cb.on_suspicious_activity = make_callback(c, handle_suspicious_activity);
}

View File

@@ -8,10 +8,6 @@
#include "snapshot.hpp"
#include "analysis.hpp"
#ifdef OS_EMSCRIPTEN
#include <event_handler.hpp>
#endif
#include <utils/interupt_handler.hpp>
#include <cstdio>
@@ -268,14 +264,6 @@ namespace
win_emu->log.disable_output(options.concise_logging || options.silent);
context.win_emu = win_emu.get();
// TODO: Move to analysis
#ifdef OS_EMSCRIPTEN
win_emu->callbacks.on_thread_switch = [&] {
debugger::event_context c{.win_emu = *win_emu};
debugger::handle_events(c); //
};
#endif
win_emu->log.log("Using emulator: %s\n", win_emu->emu().get_name().c_str());
register_analysis_callbacks(context);

View File

@@ -525,9 +525,6 @@ namespace
const auto request = _AFD_REQUEST(c.io_control_code);
win_emu.log.print(color::dark_gray, "--> AFD IOCTL: 0x%X (%u)\n", static_cast<uint32_t>(c.io_control_code),
static_cast<uint32_t>(request));
switch (request)
{
case AFD_BIND:

View File

@@ -26,8 +26,6 @@ namespace
NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& c) override
{
win_emu.log.print(color::dark_gray, "--> KSEC IOCTL: 0x%X\n", static_cast<uint32_t>(c.io_control_code));
if (c.io_control_code != 0x390400)
{
return STATUS_NOT_SUPPORTED;

View File

@@ -1,5 +1,6 @@
#include "std_include.hpp"
#include "io_device.hpp"
#include "windows_emulator.hpp"
#include "devices/afd_endpoint.hpp"
#include "devices/mount_point_manager.hpp"
#include "devices/security_support_provider.hpp"
@@ -49,3 +50,31 @@ std::unique_ptr<io_device> create_device(const std::u16string_view device)
throw std::runtime_error("Unsupported device: " + u16_to_u8(device));
}
NTSTATUS io_device_container::io_control(windows_emulator& win_emu, const io_device_context& context)
{
this->assert_validity();
win_emu.callbacks.on_ioctrl(*this->device_, this->device_name_, context.io_control_code);
return this->device_->io_control(win_emu, context);
}
void io_device_container::work(windows_emulator& win_emu)
{
this->assert_validity();
this->device_->work(win_emu);
}
void io_device_container::serialize_object(utils::buffer_serializer& buffer) const
{
this->assert_validity();
buffer.write_string(this->device_name_);
this->device_->serialize(buffer);
}
void io_device_container::deserialize_object(utils::buffer_deserializer& buffer)
{
buffer.read_string(this->device_name_);
this->setup();
this->device_->deserialize(buffer);
}

View File

@@ -146,32 +146,11 @@ class io_device_container : public io_device
this->device_->create(win_emu, data);
}
NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& context) override
{
this->assert_validity();
return this->device_->io_control(win_emu, context);
}
void work(windows_emulator& win_emu) override;
NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& context) override;
void work(windows_emulator& win_emu) override
{
this->assert_validity();
this->device_->work(win_emu);
}
void serialize_object(utils::buffer_serializer& buffer) const override
{
this->assert_validity();
buffer.write_string(this->device_name_);
this->device_->serialize(buffer);
}
void deserialize_object(utils::buffer_deserializer& buffer) override
{
buffer.read_string(this->device_name_);
this->setup();
this->device_->deserialize(buffer);
}
void serialize_object(utils::buffer_serializer& buffer) const override;
void deserialize_object(utils::buffer_deserializer& buffer) override;
template <typename T = io_device>
requires(std::is_base_of_v<io_device, T> || std::is_same_v<io_device, T>)

View File

@@ -34,7 +34,7 @@ struct process_context
{
utils::optional_function<void(handle h, emulator_thread& thr)> on_create_thread{};
utils::optional_function<void(handle h, emulator_thread& thr)> on_thread_terminated{};
utils::optional_function<void()> on_thread_switch{};
utils::optional_function<void(emulator_thread& current_thread, emulator_thread& new_thread)> on_thread_switch{};
};
struct atom_entry

View File

@@ -40,6 +40,11 @@ struct registry_key : ref_counted_object
buffer.read(this->hive);
buffer.read(this->path);
}
std::u16string to_string() const
{
return this->hive.get().u16string() + u"\\" + this->path.get().u16string();
}
};
struct registry_value

View File

@@ -63,7 +63,7 @@ namespace syscalls
if (attributes.ObjectName)
{
name = read_unicode_string(c.emu, attributes.ObjectName);
c.win_emu.log.print(color::dark_gray, "--> Event name: %s\n", u16_to_u8(name).c_str());
c.win_emu.callbacks.on_generic_access("Opening event", name);
}
}
@@ -100,7 +100,7 @@ namespace syscalls
{
const auto attributes = object_attributes.read();
const auto name = read_unicode_string(c.emu, attributes.ObjectName);
c.win_emu.log.print(color::dark_gray, "--> Event name: %s\n", u16_to_u8(name).c_str());
c.win_emu.callbacks.on_generic_access("Opening event", name);
if (name == u"\\KernelObjects\\SystemErrorPortReady")
{

View File

@@ -236,16 +236,7 @@ namespace syscalls
if (!f->enumeration_state || query_flags & SL_RESTART_SCAN)
{
const auto mask = file_mask ? read_unicode_string(c.emu, file_mask) : u"";
if (!mask.empty())
{
c.win_emu.log.print(color::dark_gray, "--> Enumerating directory: %s (Mask: \"%s\")\n",
u16_to_u8(f->name).c_str(), u16_to_u8(mask).c_str());
}
else
{
c.win_emu.log.print(color::dark_gray, "--> Enumerating directory: %s\n", u16_to_u8(f->name).c_str());
}
c.win_emu.callbacks.on_generic_access("Enumerating directory", f->name);
f->enumeration_state.emplace(file_enumeration_state{});
f->enumeration_state->files = scan_directory(c.win_emu.file_sys, f->name, mask);
@@ -565,7 +556,7 @@ namespace syscalls
const auto attributes = object_attributes.read();
auto filename = read_unicode_string(c.emu, attributes.ObjectName);
c.win_emu.log.print(color::dark_gray, "--> Query file info: %s\n", u16_to_u8(filename).c_str()); //
c.win_emu.callbacks.on_generic_access("Query file info", filename);
const auto ret = [&](const NTSTATUS status) {
block.Status = status;
@@ -798,7 +789,7 @@ namespace syscalls
auto filename = read_unicode_string(c.emu, attributes.ObjectName);
auto printer = utils::finally([&] {
c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(filename).c_str()); //
c.win_emu.callbacks.on_generic_access("Opening file", filename); //
});
const auto io_device_name = get_io_device_name(filename);
@@ -849,7 +840,7 @@ namespace syscalls
if (is_directory || create_options & FILE_DIRECTORY_FILE)
{
c.win_emu.log.print(color::dark_gray, "--> Opening folder: %s\n", u16_to_u8(f.name).c_str());
c.win_emu.callbacks.on_generic_access("Opening folder", f.name);
if (create_disposition & FILE_CREATE)
{
@@ -871,7 +862,7 @@ namespace syscalls
return STATUS_SUCCESS;
}
c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(f.name).c_str());
c.win_emu.callbacks.on_generic_access("Opening file", f.name);
std::u16string mode = map_mode(desired_access, create_disposition);
@@ -924,7 +915,7 @@ namespace syscalls
filename = root->name + (has_separator ? u"" : u"\\") + filename;
}
c.win_emu.log.print(color::dark_gray, "--> Querying file attributes: %s\n", u16_to_u8(filename).c_str());
c.win_emu.callbacks.on_generic_access("Querying file attributes", filename);
const auto local_filename = c.win_emu.file_sys.translate(filename).u8string();
@@ -965,7 +956,7 @@ namespace syscalls
const auto filename = read_unicode_string(
c.emu, emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>>{c.emu, attributes.ObjectName});
c.win_emu.log.print(color::dark_gray, "--> Querying file attributes: %s\n", u16_to_u8(filename).c_str());
c.win_emu.callbacks.on_generic_access("Querying file attributes", filename);
const auto local_filename = c.win_emu.file_sys.translate(filename).u8string();

View File

@@ -192,8 +192,6 @@ namespace syscalls
if (!potential_base)
{
c.win_emu.log.print(color::dark_gray, "--> Not allocated\n");
return STATUS_MEMORY_NOT_ALLOCATED;
}

View File

@@ -44,7 +44,7 @@ namespace syscalls
{
name = read_unicode_string(
c.emu, emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>>{c.emu, attributes.ObjectName});
c.win_emu.log.print(color::dark_gray, "--> Mutant name: %s\n", u16_to_u8(name).c_str());
c.win_emu.callbacks.on_generic_access("Opening mutant", name);
}
}
@@ -78,7 +78,7 @@ namespace syscalls
if (attributes.ObjectName)
{
name = read_unicode_string(c.emu, attributes.ObjectName);
c.win_emu.log.print(color::dark_gray, "--> Mutant name: %s\n", u16_to_u8(name).c_str());
c.win_emu.callbacks.on_generic_access("Opening mutant", name);
}
}

View File

@@ -14,7 +14,7 @@ namespace syscalls
const emulator_object<ULONG> connection_info_length)
{
auto port_name = read_unicode_string(c.emu, server_port_name);
c.win_emu.log.print(color::dark_gray, "NtConnectPort: %s\n", u16_to_u8(port_name).c_str());
c.win_emu.callbacks.on_generic_access("Connecting port", port_name);
port p{};
p.name = std::move(port_name);

View File

@@ -25,7 +25,7 @@ namespace syscalls
key = full_path.u16string();
}
c.win_emu.log.print(color::dark_gray, "--> Registry key: %s\n", u16_to_u8(key).c_str());
c.win_emu.callbacks.on_generic_access("Registry key", key);
auto entry = c.win_emu.registry.get_key({key});
if (!entry.has_value())
@@ -129,8 +129,12 @@ namespace syscalls
}
const auto query_name = read_unicode_string(c.emu, value_name);
c.win_emu.log.print(color::dark_gray, "--> Query value key: %s (%s\\%s)\n", u16_to_u8(query_name).c_str(),
key->hive.get().string().c_str(), key->path.get().string().c_str());
if (c.win_emu.callbacks.on_generic_access)
{
// TODO: Find a better way to log this
c.win_emu.callbacks.on_generic_access("Querying value key", query_name + u" (" + key->to_string() + u")");
}
const auto value = c.win_emu.registry.get_value(*key, u16_to_u8(query_name));
if (!value)

View File

@@ -20,7 +20,7 @@ namespace syscalls
const auto* file = c.proc.files.get(file_handle);
if (file)
{
c.win_emu.log.print(color::dark_gray, "--> Section for file %s\n", u16_to_u8(file->name).c_str());
c.win_emu.callbacks.on_generic_access("Section for file", file->name);
s.file_name = file->name;
}
@@ -30,7 +30,7 @@ namespace syscalls
if (attributes.ObjectName)
{
auto name = read_unicode_string(c.emu, attributes.ObjectName);
c.win_emu.log.print(color::dark_gray, "--> Section with name %s\n", u16_to_u8(name).c_str());
c.win_emu.callbacks.on_generic_access("Section with name", name);
s.name = std::move(name);
}
}
@@ -60,7 +60,7 @@ namespace syscalls
const auto attributes = object_attributes.read();
auto filename = read_unicode_string(c.emu, attributes.ObjectName);
c.win_emu.log.print(color::dark_gray, "--> Opening section: %s\n", u16_to_u8(filename).c_str());
c.win_emu.callbacks.on_generic_access("Opening section", filename);
if (filename == u"\\Windows\\SharedSection")
{

View File

@@ -43,7 +43,7 @@ namespace syscalls
if (attributes.ObjectName)
{
name = read_unicode_string(c.emu, attributes.ObjectName);
c.win_emu.log.print(color::dark_gray, "--> Timer name: %s\n", u16_to_u8(name).c_str());
c.win_emu.callbacks.on_generic_access("Opening timer", name);
}
}

View File

@@ -107,7 +107,7 @@ namespace
return;
}
win_emu.log.print(color::dark_gray, "Dispatching APC...\n");
win_emu.callbacks.on_generic_activity("APC Dispatch");
const auto next_apx = apcs.front();
apcs.erase(apcs.begin());
@@ -165,8 +165,7 @@ namespace
{
if (active_thread)
{
win_emu.log.print(color::dark_gray, "Performing thread switch: %X -> %X\n", active_thread->id,
thread.id);
win_emu.callbacks.on_thread_switch(*active_thread, thread);
active_thread->save(emu);
}
@@ -184,7 +183,6 @@ namespace
}
thread.apc_alertable = false;
win_emu.callbacks.on_thread_switch();
return true;
}

View File

@@ -13,14 +13,19 @@
#include "module/module_manager.hpp"
#include "network/socket_factory.hpp"
struct io_device;
struct emulator_callbacks : module_manager::callbacks, process_context::callbacks
{
using continuation = instruction_hook_continuation;
utils::optional_function<continuation(uint32_t syscall_id, std::string_view syscall_name)> on_syscall{};
utils::optional_function<void(std::string_view data)> on_stdout{};
utils::optional_function<void(std::string_view type, std::u16string_view name)> on_generic_access{};
utils::optional_function<void(std::string_view description)> on_generic_activity{};
utils::optional_function<void(std::string_view description)> on_suspicious_activity{};
utils::optional_function<void(uint64_t address)> on_instruction{};
utils::optional_function<void(io_device& device, std::u16string_view device_name, ULONG code)> on_ioctrl{};
};
struct application_settings