diff --git a/src/analyzer/analysis.cpp b/src/analyzer/analysis.cpp new file mode 100644 index 00000000..aaf4d9d9 --- /dev/null +++ b/src/analyzer/analysis.cpp @@ -0,0 +1,273 @@ +#include "std_include.hpp" + +#include "analysis.hpp" +#include "windows_emulator.hpp" +#include + +#ifdef OS_EMSCRIPTEN +#include +#endif + +#define STR_VIEW_VA(str) static_cast((str).size()), (str).data() + +namespace +{ + template + std::function make_callback(analysis_context& c, Return (*callback)(analysis_context&, Args...)) + { + return [&c, callback](Args... args) { + return callback(c, std::forward(args)...); // + }; + } + + template + std::function make_callback(analysis_context& c, + Return (*callback)(const analysis_context&, Args...)) + { + return [&c, callback](Args... args) { + return callback(c, std::forward(args)...); // + }; + } + + void handle_suspicious_activity(const analysis_context& c, const std::string_view details) + { + const auto rip = c.win_emu->emu().read_instruction_pointer(); + c.win_emu->log.print(color::pink, "Suspicious: %.*s at 0x%" PRIx64 " (via 0x%" PRIx64 ")\n", + STR_VIEW_VA(details), rip, c.win_emu->process.previous_ip); + } + + 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_memory_allocate(const analysis_context& c, const uint64_t address, const uint64_t length, + const memory_permission permission, const bool commit) + { + const auto* action = commit ? "Committed" : "Allocated"; + + c.win_emu->log.print(is_executable(permission) ? color::gray : color::dark_gray, + "--> %s 0x%" PRIx64 " - 0x%" PRIx64 " (%s)\n", action, address, address + length, + get_permission_string(permission).c_str()); + } + + void handle_memory_protect(const analysis_context& c, const uint64_t address, const uint64_t length, + const memory_permission permission) + { + c.win_emu->log.print(color::dark_gray, "--> Changing protection at 0x%" PRIx64 "-0x%" PRIx64 " to %s\n", + address, address + length, get_permission_string(permission).c_str()); + } + + void handle_memory_violate(const analysis_context& c, const uint64_t address, const uint64_t size, + const memory_operation operation, const memory_violation_type type) + { + const auto permission = get_permission_string(operation); + const auto ip = c.win_emu->emu().read_instruction_pointer(); + const char* name = c.win_emu->mod_manager.find_name(ip); + + if (type == memory_violation_type::protection) + { + c.win_emu->log.print(color::gray, + "Protection violation: 0x%" PRIx64 " (%" PRIx64 ") - %s at 0x%" PRIx64 " (%s)\n", + address, size, permission.c_str(), ip, name); + } + else if (type == memory_violation_type::unmapped) + { + c.win_emu->log.print(color::gray, + "Mapping violation: 0x%" PRIx64 " (%" PRIx64 ") - %s at 0x%" PRIx64 " (%s)\n", address, + size, permission.c_str(), ip, name); + } + } + + 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(code)); + } + + void handle_thread_set_name(const analysis_context& c, const emulator_thread& t) + { + c.win_emu->log.print(color::blue, "Setting thread (%d) name: %s\n", t.id, u16_to_u8(t.name).c_str()); + } + + 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_module_load(const analysis_context& c, const mapped_module& mod) + { + c.win_emu->log.log("Mapped %s at 0x%" PRIx64 "\n", mod.path.generic_string().c_str(), mod.image_base); + } + + void handle_module_unload(const analysis_context& c, const mapped_module& mod) + { + c.win_emu->log.log("Unmapping %s (0x%" PRIx64 ")\n", mod.path.generic_string().c_str(), mod.image_base); + } + + void handle_instruction(analysis_context& c, const uint64_t address) + { + auto& win_emu = *c.win_emu; + + const auto is_main_exe = win_emu.mod_manager.executable->is_within(address); + const auto is_previous_main_exe = win_emu.mod_manager.executable->is_within(c.win_emu->process.previous_ip); + + const auto binary = utils::make_lazy([&] { + if (is_main_exe) + { + return win_emu.mod_manager.executable; + } + + return win_emu.mod_manager.find_by_address(address); // + }); + + const auto previous_binary = utils::make_lazy([&] { + if (is_previous_main_exe) + { + return win_emu.mod_manager.executable; + } + + return win_emu.mod_manager.find_by_address(win_emu.process.previous_ip); // + }); + + const auto is_in_interesting_module = [&] { + if (c.settings->modules.empty()) + { + return false; + } + + return (binary && c.settings->modules.contains(binary->name)) || + (previous_binary && c.settings->modules.contains(previous_binary->name)); + }; + + const auto is_interesting_call = is_previous_main_exe // + || is_main_exe // + || is_in_interesting_module(); + + if (!c.has_reached_main && c.settings->concise_logging && !c.settings->silent && is_main_exe) + { + c.has_reached_main = true; + win_emu.log.disable_output(false); + } + + if ((!c.settings->verbose_logging && !is_interesting_call) || !binary) + { + return; + } + + const auto export_entry = binary->address_names.find(address); + if (export_entry != binary->address_names.end() && + !c.settings->ignored_functions.contains(export_entry->second)) + { + const auto rsp = win_emu.emu().read_stack_pointer(); + + uint64_t return_address{}; + win_emu.emu().try_read_memory(rsp, &return_address, sizeof(return_address)); + + const auto* mod_name = win_emu.mod_manager.find_name(return_address); + + win_emu.log.print(is_interesting_call ? color::yellow : color::dark_gray, + "Executing function: %s - %s (0x%" PRIx64 ") via (0x%" PRIx64 ") %s\n", + binary->name.c_str(), export_entry->second.c_str(), address, return_address, mod_name); + } + else if (address == binary->entry_point) + { + win_emu.log.print(is_interesting_call ? color::yellow : color::gray, + "Executing entry point: %s (0x%" PRIx64 ")\n", binary->name.c_str(), address); + } + } + + emulator_callbacks::continuation handle_syscall(const analysis_context& c, const uint32_t syscall_id, + const std::string_view syscall_name) + { + auto& win_emu = *c.win_emu; + auto& emu = win_emu.emu(); + + const auto address = emu.read_instruction_pointer(); + const auto* mod = win_emu.mod_manager.find_by_address(address); + const auto is_sus_module = mod != win_emu.mod_manager.ntdll && mod != win_emu.mod_manager.win32u; + + if (is_sus_module) + { + win_emu.log.print(color::blue, "Executing inline syscall: %.*s (0x%X) at 0x%" PRIx64 " (%s)\n", + STR_VIEW_VA(syscall_name), syscall_id, address, mod ? mod->name.c_str() : ""); + } + else if (mod->is_within(win_emu.process.previous_ip)) + { + const auto rsp = emu.read_stack_pointer(); + + uint64_t return_address{}; + emu.try_read_memory(rsp, &return_address, sizeof(return_address)); + + const auto* caller_mod_name = win_emu.mod_manager.find_name(return_address); + + win_emu.log.print(color::dark_gray, + "Executing syscall: %.*s (0x%X) at 0x%" PRIx64 " via 0x%" PRIx64 " (%s)\n", + STR_VIEW_VA(syscall_name), syscall_id, address, return_address, caller_mod_name); + } + else + { + const auto* previous_mod = win_emu.mod_manager.find_by_address(win_emu.process.previous_ip); + + win_emu.log.print(color::blue, + "Crafted out-of-line syscall: %.*s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64 " (%s)\n", + STR_VIEW_VA(syscall_name), syscall_id, address, mod ? mod->name.c_str() : "", + win_emu.process.previous_ip, previous_mod ? previous_mod->name.c_str() : ""); + } + + return instruction_hook_continuation::run_instruction; + } + + void handle_stdout(analysis_context& c, const std::string_view data) + { + if (c.settings->silent) + { + (void)fwrite(data.data(), 1, data.size(), stdout); + } + else if (c.settings->buffer_stdout) + { + c.output.append(data); + } + else + { + c.win_emu->log.info("%.*s%s", static_cast(data.size()), data.data(), data.ends_with("\n") ? "" : "\n"); + } + } +} + +void register_analysis_callbacks(analysis_context& c) +{ + auto& cb = c.win_emu->callbacks; + + 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_memory_protect = make_callback(c, handle_memory_protect); + cb.on_memory_violate = make_callback(c, handle_memory_violate); + cb.on_memory_allocate = make_callback(c, handle_memory_allocate); + + cb.on_module_load = make_callback(c, handle_module_load); + cb.on_module_unload = make_callback(c, handle_module_unload); + + cb.on_thread_switch = make_callback(c, handle_thread_switch); + cb.on_thread_set_name = make_callback(c, handle_thread_set_name); + + cb.on_instruction = make_callback(c, handle_instruction); + 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); +} diff --git a/src/analyzer/analysis.hpp b/src/analyzer/analysis.hpp new file mode 100644 index 00000000..072e8503 --- /dev/null +++ b/src/analyzer/analysis.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +class windows_emulator; + +struct analysis_settings +{ + bool concise_logging{false}; + bool verbose_logging{false}; + bool silent{false}; + bool buffer_stdout{false}; + + std::set> modules{}; + std::set> ignored_functions{}; +}; + +struct analysis_context +{ + const analysis_settings* settings{}; + windows_emulator* win_emu{}; + + std::string output{}; + bool has_reached_main{false}; +}; + +void register_analysis_callbacks(analysis_context& c); diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 9a6a23f1..88b3b08d 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -6,10 +6,7 @@ #include "object_watching.hpp" #include "snapshot.hpp" - -#ifdef OS_EMSCRIPTEN -#include -#endif +#include "analysis.hpp" #include @@ -17,18 +14,12 @@ namespace { - struct analysis_options + struct analysis_options : analysis_settings { mutable bool use_gdb{false}; - bool concise_logging{false}; - bool verbose_logging{false}; - bool silent{false}; - bool buffer_stdout{false}; std::filesystem::path dump{}; std::string registry_path{"./registry"}; std::string emulation_root{}; - std::set> modules{}; - std::set> ignored_functions{}; std::unordered_map path_mappings{}; }; @@ -59,23 +50,25 @@ namespace } void watch_system_objects(windows_emulator& win_emu, const std::set>& modules, - const bool cache_logging) + const bool verbose) { + win_emu.setup_process_if_necessary(); + (void)win_emu; (void)modules; - (void)cache_logging; + (void)verbose; #if !defined(__GNUC__) || defined(__clang__) - watch_object(win_emu, modules, *win_emu.current_thread().teb, cache_logging); - watch_object(win_emu, modules, win_emu.process.peb, cache_logging); + watch_object(win_emu, modules, *win_emu.current_thread().teb, verbose); + watch_object(win_emu, modules, win_emu.process.peb, verbose); watch_object(win_emu, modules, emulator_object{win_emu.emu(), kusd_mmio::address()}, - cache_logging); + verbose); - auto* params_hook = watch_object(win_emu, modules, win_emu.process.process_params, cache_logging); + auto* params_hook = watch_object(win_emu, modules, win_emu.process.process_params, verbose); win_emu.emu().hook_memory_write( win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters), 0x8, - [&win_emu, cache_logging, params_hook, modules](const uint64_t address, const void*, size_t) mutable { + [&win_emu, verbose, params_hook, modules](const uint64_t address, const void*, size_t) mutable { const auto target_address = win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters); if (address == target_address) @@ -86,7 +79,7 @@ namespace }; 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, verbose); } }); #endif @@ -109,8 +102,19 @@ namespace } } - bool run_emulation(windows_emulator& win_emu, const analysis_options& options) + void do_post_emulation_work(const analysis_context& c) { + if (c.settings->buffer_stdout) + { + c.win_emu->log.info("%.*s%s", static_cast(c.output.size()), c.output.data(), + c.output.ends_with("\n") ? "" : "\n"); + } + } + + bool run_emulation(const analysis_context& c, const analysis_options& options) + { + auto& win_emu = *c.win_emu; + std::atomic_uint32_t signals_received{0}; utils::interupt_handler _{[&] { const auto value = signals_received++; @@ -158,12 +162,14 @@ namespace } catch (const std::exception& e) { + do_post_emulation_work(c); win_emu.log.error("Emulation failed at: 0x%" PRIx64 " - %s\n", win_emu.emu().read_instruction_pointer(), e.what()); throw; } catch (...) { + do_post_emulation_work(c); win_emu.log.error("Emulation failed at: 0x%" PRIx64 "\n", win_emu.emu().read_instruction_pointer()); throw; } @@ -171,6 +177,7 @@ namespace const auto exit_status = win_emu.process.exit_status; if (!exit_status.has_value()) { + do_post_emulation_work(c); win_emu.log.error("Emulation terminated without status!\n"); return false; } @@ -179,6 +186,7 @@ namespace if (!options.silent) { + do_post_emulation_work(c); win_emu.log.disable_output(false); win_emu.log.print(success ? color::green : color::red, "Emulation terminated with status: %X\n", *exit_status); @@ -206,12 +214,7 @@ namespace return { .emulation_root = options.emulation_root, .registry_directory = options.registry_path, - .verbose_calls = options.verbose_logging, - .disable_logging = options.silent, - .silent_until_main = options.concise_logging, .path_mappings = options.path_mappings, - .modules = options.modules, - .ignored_functions = options.ignored_functions, }; } @@ -253,28 +256,18 @@ namespace bool run(const analysis_options& options, const std::span args) { - const auto win_emu = setup_emulator(options, args); - -#ifdef OS_EMSCRIPTEN - win_emu->callbacks.on_thread_switch = [&] { - debugger::event_context c{.win_emu = *win_emu}; - debugger::handle_events(c); // + analysis_context context{ + .settings = &options, }; -#endif + + const auto win_emu = setup_emulator(options, args); + win_emu->log.disable_output(options.concise_logging || options.silent); + context.win_emu = win_emu.get(); win_emu->log.log("Using emulator: %s\n", win_emu->emu().get_name().c_str()); - (void)&watch_system_objects; - watch_system_objects(*win_emu, options.modules, !options.verbose_logging); - win_emu->buffer_stdout = options.buffer_stdout; - - if (options.silent) - { - win_emu->buffer_stdout = false; - win_emu->callbacks.on_stdout = [](const std::string_view data) { - (void)fwrite(data.data(), 1, data.size(), stdout); - }; - } + register_analysis_callbacks(context); + watch_system_objects(*win_emu, options.modules, options.verbose_logging); const auto& exe = *win_emu->mod_manager.executable; @@ -334,7 +327,7 @@ namespace win_emu->emu().hook_memory_write(section.region.start, section.region.length, std::move(write_handler)); } - return run_emulation(*win_emu, options); + return run_emulation(context, options); } std::vector bundle_arguments(const int argc, char** argv) diff --git a/src/analyzer/object_watching.hpp b/src/analyzer/object_watching.hpp index dd77c4b3..3ba81167 100644 --- a/src/analyzer/object_watching.hpp +++ b/src/analyzer/object_watching.hpp @@ -6,23 +6,23 @@ template emulator_hook* watch_object(windows_emulator& emu, const std::set>& modules, - emulator_object object, const bool cache_logging = false) + emulator_object object, const auto verbose) { const reflect_type_info info{}; return emu.emu().hook_memory_read( object.value(), static_cast(object.size()), - [i = std::move(info), object, &emu, cache_logging, modules](const uint64_t address, const void*, size_t) { + [i = std::move(info), object, &emu, verbose, modules](const uint64_t address, const void*, size_t) { const auto rip = emu.emu().read_instruction_pointer(); const auto* mod = emu.mod_manager.find_by_address(rip); const auto is_main_access = mod == emu.mod_manager.executable || modules.contains(mod->name); - if (!emu.verbose_calls && !is_main_access) + if (!verbose && !is_main_access) { return; } - if (cache_logging) + if (!verbose) { static std::unordered_set logged_addresses{}; if (is_main_access && !logged_addresses.insert(address).second) diff --git a/src/common/platform/primitives.hpp b/src/common/platform/primitives.hpp index ad5fa657..419e61d9 100644 --- a/src/common/platform/primitives.hpp +++ b/src/common/platform/primitives.hpp @@ -66,4 +66,8 @@ using USHORT = WORD; #define FALSE 0 #endif +static_assert(sizeof(DWORD) == 4); +static_assert(sizeof(ULONG) == 4); +static_assert(sizeof(int) == 4); + // NOLINTEND(modernize-use-using) diff --git a/src/emulator/arch_emulator.hpp b/src/emulator/arch_emulator.hpp index ef218374..f20283a1 100644 --- a/src/emulator/arch_emulator.hpp +++ b/src/emulator/arch_emulator.hpp @@ -45,7 +45,7 @@ struct arm_emulator : arch_emulator enum class x86_hookable_instructions { - invalid, + invalid, // TODO: Get rid of that syscall, cpuid, rdtsc, diff --git a/src/fuzzer/main.cpp b/src/fuzzer/main.cpp index 7af4ba2d..78033fc7 100644 --- a/src/fuzzer/main.cpp +++ b/src/fuzzer/main.cpp @@ -28,12 +28,22 @@ namespace void run_emulation(windows_emulator& win_emu) { + bool has_exception = false; + const auto _ = utils::finally([&] { + win_emu.callbacks.on_exception = {}; // + }); + try { + win_emu.callbacks.on_exception = [&] { + has_exception = true; + win_emu.stop(); + }; + win_emu.log.disable_output(true); win_emu.start(); - if (win_emu.process.exception_rip.has_value()) + if (has_exception) { throw std::runtime_error("Exception!"); } @@ -68,7 +78,6 @@ namespace fuzzer_executer(const std::span data) : emulator_data(data) { - emu.fuzzing = true; emu.emu().hook_basic_block([&](const basic_block& block) { if (this->handler && visited_blocks.emplace(block.address).second) { diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index d7d2cdd2..8285600f 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -68,7 +68,9 @@ namespace test if (is_verbose) { - settings.disable_logging = false; + callbacks.on_stdout = [](const std::string_view data) { + std::cout << data; // + }; } settings.emulation_root = get_emulator_root(); @@ -93,8 +95,9 @@ namespace test if (is_verbose) { - settings.disable_logging = false; - // settings.verbose_calls = true; + callbacks.on_stdout = [](const std::string_view data) { + std::cout << data; // + }; } settings.emulation_root = get_emulator_root(); @@ -116,7 +119,6 @@ namespace test inline windows_emulator create_sample_emulator(const sample_configuration& config = {}) { emulator_settings settings{ - .disable_logging = true, .use_relative_time = true, }; @@ -126,7 +128,6 @@ namespace test inline windows_emulator create_empty_emulator() { emulator_settings settings{ - .disable_logging = true, .use_relative_time = true, }; diff --git a/src/windows-emulator-test/time_test.cpp b/src/windows-emulator-test/time_test.cpp index d82b2520..b71f111a 100644 --- a/src/windows-emulator-test/time_test.cpp +++ b/src/windows-emulator-test/time_test.cpp @@ -12,7 +12,6 @@ namespace test }; const emulator_settings settings{ - .disable_logging = true, .use_relative_time = false, }; diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index bc1ab997..72adae17 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -519,14 +519,12 @@ namespace { if (_AFD_BASE(c.io_control_code) != FSCTL_AFD_BASE) { - win_emu.log.print(color::cyan, "Bad AFD IOCTL: 0x%X\n", c.io_control_code); + win_emu.log.error("Bad AFD IOCTL: 0x%X\n", static_cast(c.io_control_code)); return STATUS_NOT_SUPPORTED; } const auto request = _AFD_REQUEST(c.io_control_code); - win_emu.log.print(color::dark_gray, "--> AFD IOCTL: 0x%X (%d)\n", c.io_control_code, request); - switch (request) { case AFD_BIND: @@ -562,7 +560,8 @@ namespace case AFD_TRANSPORT_IOCTL: return STATUS_SUCCESS; default: - win_emu.log.print(color::gray, "Unsupported AFD IOCTL: 0x%X (%d)\n", c.io_control_code, request); + win_emu.log.error("Unsupported AFD IOCTL: 0x%X (%u)\n", static_cast(c.io_control_code), + static_cast(request)); return STATUS_NOT_SUPPORTED; } } @@ -995,8 +994,8 @@ namespace { const auto timeout_callback = [](windows_emulator& win_emu, const io_device_context& c) { const emulator_object info_obj{win_emu.emu(), c.input_buffer}; - info_obj.access([&](AFD_POLL_INFO64& info) { - info.NumberOfHandles = 0; // + info_obj.access([&](AFD_POLL_INFO64& poll_info) { + poll_info.NumberOfHandles = 0; // }); }; @@ -1275,4 +1274,4 @@ std::unique_ptr create_afd_endpoint() std::unique_ptr create_afd_async_connect_hlp() { return std::make_unique(); -} \ No newline at end of file +} diff --git a/src/windows-emulator/devices/security_support_provider.cpp b/src/windows-emulator/devices/security_support_provider.cpp index 9796246f..58b2a9f6 100644 --- a/src/windows-emulator/devices/security_support_provider.cpp +++ b/src/windows-emulator/devices/security_support_provider.cpp @@ -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", c.io_control_code); - if (c.io_control_code != 0x390400) { return STATUS_NOT_SUPPORTED; diff --git a/src/windows-emulator/generic_logger.hpp b/src/windows-emulator/generic_logger.hpp new file mode 100644 index 00000000..d212dc4c --- /dev/null +++ b/src/windows-emulator/generic_logger.hpp @@ -0,0 +1,28 @@ +#pragma once +#include + +#if (defined(__clang__) || defined(__GNUC__)) && !defined(__MINGW64__) +#define FORMAT_ATTRIBUTE(fmt_pos, var_pos) __attribute__((format(printf, fmt_pos, var_pos))) +#else +#define FORMAT_ATTRIBUTE(fmt_pos, var_pos) +#endif + +enum class color +{ + black, + red, + green, + yellow, + blue, + cyan, + pink, + white, + gray, + dark_gray, +}; + +struct generic_logger : utils::object +{ + virtual void print(color c, std::string_view message) = 0; + virtual void print(color c, const char* message, ...) FORMAT_ATTRIBUTE(3, 4) = 0; +}; diff --git a/src/windows-emulator/io_device.cpp b/src/windows-emulator/io_device.cpp index b1803824..cefc0a15 100644 --- a/src/windows-emulator/io_device.cpp +++ b/src/windows-emulator/io_device.cpp @@ -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 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); +} diff --git a/src/windows-emulator/io_device.hpp b/src/windows-emulator/io_device.hpp index 970b5053..c55ca84d 100644 --- a/src/windows-emulator/io_device.hpp +++ b/src/windows-emulator/io_device.hpp @@ -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 requires(std::is_base_of_v || std::is_same_v) diff --git a/src/windows-emulator/logger.cpp b/src/windows-emulator/logger.cpp index 292bdfb6..3ad989cb 100644 --- a/src/windows-emulator/logger.cpp +++ b/src/windows-emulator/logger.cpp @@ -116,8 +116,13 @@ void logger::print_message(const color c, const std::string_view message, const print_colored(message, get_color_type(c)); } +void logger::print(const color c, const std::string_view message) +{ + this->print_message(c, message); +} + // NOLINTNEXTLINE(cert-dcl50-cpp) -void logger::print(const color c, const char* message, ...) const +void logger::print(const color c, const char* message, ...) { format_to_string(message, data); this->print_message(c, data); diff --git a/src/windows-emulator/logger.hpp b/src/windows-emulator/logger.hpp index aafcbb9c..f91be95e 100644 --- a/src/windows-emulator/logger.hpp +++ b/src/windows-emulator/logger.hpp @@ -1,29 +1,11 @@ #pragma once +#include "generic_logger.hpp" -#ifdef OS_WINDOWS -#define FORMAT_ATTRIBUTE(fmt_pos, var_pos) -#else -#define FORMAT_ATTRIBUTE(fmt_pos, var_pos) __attribute__((format(printf, fmt_pos, var_pos))) -#endif - -enum class color -{ - black, - red, - green, - yellow, - blue, - cyan, - pink, - white, - gray, - dark_gray, -}; - -class logger +class logger : public generic_logger { public: - void print(color c, const char* message, ...) const FORMAT_ATTRIBUTE(3, 4); + void print(color c, std::string_view message) override; + void print(color c, const char* message, ...) override FORMAT_ATTRIBUTE(3, 4); void info(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); void warn(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); void error(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 6e20e135..00eb45ab 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -122,8 +122,6 @@ mapped_module* module_manager::map_local_module(const std::filesystem::path& fil auto mod = map_module_from_file(*this->memory_, std::move(local_file)); mod.is_static = is_static; - logger.log("Mapped %s at 0x%" PRIx64 "\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)); this->callbacks_->on_module_load(entry.first->second); @@ -145,9 +143,9 @@ void module_manager::serialize(utils::buffer_serializer& buffer) const { buffer.write_map(this->modules_); - buffer.write(this->executable->image_base); - buffer.write(this->ntdll->image_base); - buffer.write(this->win32u->image_base); + buffer.write(this->executable ? this->executable->image_base : 0); + buffer.write(this->ntdll ? this->ntdll->image_base : 0); + buffer.write(this->win32u ? this->win32u->image_base : 0); } void module_manager::deserialize(utils::buffer_deserializer& buffer) @@ -158,12 +156,12 @@ void module_manager::deserialize(utils::buffer_deserializer& buffer) const auto ntdll_base = buffer.read(); const auto win32u_base = buffer.read(); - this->executable = this->find_by_address(executable_base); - this->ntdll = this->find_by_address(ntdll_base); - this->win32u = this->find_by_address(win32u_base); + this->executable = executable_base ? this->find_by_address(executable_base) : nullptr; + this->ntdll = ntdll_base ? this->find_by_address(ntdll_base) : nullptr; + this->win32u = win32u_base ? this->find_by_address(win32u_base) : nullptr; } -bool module_manager::unmap(const uint64_t address, const logger& logger) +bool module_manager::unmap(const uint64_t address) { const auto mod = this->modules_.find(address); if (mod == this->modules_.end()) @@ -176,8 +174,6 @@ bool module_manager::unmap(const uint64_t address, const logger& logger) return true; } - logger.log("Unmapping %s (0x%" PRIx64 ")\n", mod->second.path.generic_string().c_str(), mod->second.image_base); - this->callbacks_->on_module_unload(mod->second); unmap_module(*this->memory_, mod->second); this->modules_.erase(mod); diff --git a/src/windows-emulator/module/module_manager.hpp b/src/windows-emulator/module/module_manager.hpp index 7a789d9d..4123f733 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -51,7 +51,7 @@ class module_manager void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); - bool unmap(uint64_t address, const logger& logger); + bool unmap(uint64_t address); const module_map& modules() const { return modules_; diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 936ec373..8a07e0ba 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -251,7 +251,6 @@ void process_context::serialize(utils::buffer_serializer& buffer) const buffer.write(this->shared_section_size); buffer.write(this->dbwin_buffer); buffer.write(this->dbwin_buffer_size); - buffer.write_optional(this->exception_rip); buffer.write_optional(this->exit_status); buffer.write(this->base_allocator); buffer.write(this->peb); @@ -291,7 +290,6 @@ void process_context::deserialize(utils::buffer_deserializer& buffer) buffer.read(this->shared_section_size); buffer.read(this->dbwin_buffer); buffer.read(this->dbwin_buffer_size); - buffer.read_optional(this->exception_rip); buffer.read_optional(this->exit_status); buffer.read(this->base_allocator); buffer.read(this->peb); @@ -361,7 +359,7 @@ handle process_context::create_thread(memory_manager& memory, const uint64_t sta { emulator_thread t{memory, *this, start_address, argument, stack_size, suspended, ++this->spawned_thread_count}; auto [h, thr] = this->threads.store_and_get(std::move(t)); - this->callbacks_->on_create_thread(h, *thr); + this->callbacks_->on_thread_create(h, *thr); return h; } diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 6fad5508..b25c3e8b 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -32,9 +32,10 @@ struct process_context { struct callbacks { - utils::optional_function on_create_thread{}; + utils::optional_function on_thread_create{}; utils::optional_function on_thread_terminated{}; - utils::optional_function on_thread_switch{}; + utils::optional_function on_thread_switch{}; + utils::optional_function on_thread_set_name{}; }; struct atom_entry @@ -92,7 +93,6 @@ struct process_context uint64_t dbwin_buffer{0}; uint64_t dbwin_buffer_size{0}; - std::optional exception_rip{}; std::optional exit_status{}; emulator_allocator base_allocator; diff --git a/src/windows-emulator/registry/registry_manager.hpp b/src/windows-emulator/registry/registry_manager.hpp index 809713aa..81e0cb79 100644 --- a/src/windows-emulator/registry/registry_manager.hpp +++ b/src/windows-emulator/registry/registry_manager.hpp @@ -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 diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index 164da74b..c25ad547 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -24,8 +24,8 @@ void syscall_dispatcher::deserialize(utils::buffer_deserializer& buffer) this->add_handlers(); } -void syscall_dispatcher::setup(const exported_symbols& ntdll_exports, std::span ntdll_data, - const exported_symbols& win32u_exports, std::span win32u_data) +void syscall_dispatcher::setup(const exported_symbols& ntdll_exports, const std::span ntdll_data, + const exported_symbols& win32u_exports, const std::span win32u_data) { this->handlers_ = {}; @@ -76,8 +76,6 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) try { - const auto* mod = win_emu.mod_manager.find_by_address(address); - const auto entry = this->handlers_.find(syscall_id); if (entry == this->handlers_.end()) { @@ -87,8 +85,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) return; } - const std::string_view mod_name = mod ? mod->name : std::string_view{}; - const auto res = win_emu.callbacks.on_syscall(syscall_id, address, mod_name, entry->second.name); + const auto res = win_emu.callbacks.on_syscall(syscall_id, entry->second.name); if (res == instruction_hook_continuation::skip_instruction) { return; @@ -102,38 +99,6 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) return; } - if (mod != win_emu.mod_manager.ntdll && mod != win_emu.mod_manager.win32u) - { - 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() : ""); - } - else - { - if (mod->is_within(context.previous_ip)) - { - const auto rsp = c.emu.read_stack_pointer(); - - uint64_t return_address{}; - c.emu.try_read_memory(rsp, &return_address, sizeof(return_address)); - - const auto* caller_mod_name = win_emu.mod_manager.find_name(return_address); - - win_emu.log.print(color::dark_gray, - "Executing syscall: %s (0x%X) at 0x%" PRIx64 " via 0x%" PRIx64 " (%s)\n", - entry->second.name.c_str(), syscall_id, address, return_address, caller_mod_name); - } - else - { - const auto* previous_mod = win_emu.mod_manager.find_by_address(context.previous_ip); - - win_emu.log.print(color::blue, - "Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64 - " (%s)\n", - entry->second.name.c_str(), syscall_id, address, mod ? mod->name.c_str() : "", - context.previous_ip, previous_mod ? previous_mod->name.c_str() : ""); - } - } - entry->second.handler(c); } catch (std::exception& e) @@ -150,8 +115,10 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } } -syscall_dispatcher::syscall_dispatcher(const exported_symbols& ntdll_exports, std::span ntdll_data, - const exported_symbols& win32u_exports, std::span win32u_data) +syscall_dispatcher::syscall_dispatcher(const exported_symbols& ntdll_exports, + const std::span ntdll_data, + const exported_symbols& win32u_exports, + const std::span win32u_data) { this->setup(ntdll_exports, ntdll_data, win32u_exports, win32u_data); } diff --git a/src/windows-emulator/syscalls/event.cpp b/src/windows-emulator/syscalls/event.cpp index b53c0910..40b7a8a7 100644 --- a/src/windows-emulator/syscalls/event.cpp +++ b/src/windows-emulator/syscalls/event.cpp @@ -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") { diff --git a/src/windows-emulator/syscalls/exception.cpp b/src/windows-emulator/syscalls/exception.cpp index 42362bc3..4705dbf2 100644 --- a/src/windows-emulator/syscalls/exception.cpp +++ b/src/windows-emulator/syscalls/exception.cpp @@ -18,7 +18,7 @@ namespace syscalls } c.proc.exit_status = error_status; - c.proc.exception_rip = c.emu.read_instruction_pointer(); + c.win_emu.callbacks.on_exception(); c.emu.stop(); return STATUS_SUCCESS; @@ -27,7 +27,7 @@ namespace syscalls NTSTATUS handle_NtRaiseException( const syscall_context& c, const emulator_object>> /*exception_record*/, - const emulator_object thread_context, const BOOLEAN handle_exception) + const emulator_object /*thread_context*/, const BOOLEAN handle_exception) { if (handle_exception) { @@ -36,9 +36,9 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } - c.proc.exception_rip = thread_context.read().Rip; + c.win_emu.callbacks.on_exception(); c.emu.stop(); return STATUS_SUCCESS; } -} \ No newline at end of file +} diff --git a/src/windows-emulator/syscalls/file.cpp b/src/windows-emulator/syscalls/file.cpp index e79bd581..0d9abfd2 100644 --- a/src/windows-emulator/syscalls/file.cpp +++ b/src/windows-emulator/syscalls/file.cpp @@ -141,19 +141,19 @@ namespace syscalls switch (fs_information_class) { case FileFsDeviceInformation: - return handle_query( - c.emu, fs_information, length, io_status_block, [&](FILE_FS_DEVICE_INFORMATION& info) { - if (file_handle == STDOUT_HANDLE && !c.win_emu.buffer_stdout) - { - info.DeviceType = FILE_DEVICE_CONSOLE; - info.Characteristics = 0x20000; - } - else - { - info.DeviceType = FILE_DEVICE_DISK; - info.Characteristics = 0x20020; - } - }); + return handle_query(c.emu, fs_information, length, io_status_block, + [&](FILE_FS_DEVICE_INFORMATION& info) { + if (file_handle == STDOUT_HANDLE) + { + info.DeviceType = FILE_DEVICE_CONSOLE; + info.Characteristics = 0x20000; + } + else + { + info.DeviceType = FILE_DEVICE_DISK; + info.Characteristics = 0x20020; + } + }); case FileFsSizeInformation: return handle_query(c.emu, fs_information, length, io_status_block, @@ -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; @@ -689,13 +680,6 @@ namespace syscalls c.win_emu.callbacks.on_stdout(temp_buffer); - if (!temp_buffer.ends_with("\n")) - { - temp_buffer.push_back('\n'); - } - - c.win_emu.log.info("%.*s", static_cast(temp_buffer.size()), temp_buffer.data()); - return STATUS_SUCCESS; } @@ -805,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); @@ -856,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) { @@ -878,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); @@ -931,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(); @@ -972,7 +956,7 @@ namespace syscalls const auto filename = read_unicode_string( c.emu, emulator_object>>{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(); diff --git a/src/windows-emulator/syscalls/locale.cpp b/src/windows-emulator/syscalls/locale.cpp index 0cf09022..504f543c 100644 --- a/src/windows-emulator/syscalls/locale.cpp +++ b/src/windows-emulator/syscalls/locale.cpp @@ -34,14 +34,13 @@ namespace syscalls return STATUS_SUCCESS; } - NTSTATUS handle_NtGetNlsSectionPtr(const syscall_context& c, ULONG section_type, ULONG section_data, - emulator_pointer /*context_data*/, emulator_object section_pointer, - emulator_object section_size) + NTSTATUS handle_NtGetNlsSectionPtr(const syscall_context& c, const ULONG section_type, const ULONG section_data, + emulator_pointer /*context_data*/, + const emulator_object section_pointer, + const emulator_object section_size) { if (section_type == 11) { - c.win_emu.log.print(color::dark_gray, "--> Code Page: %d\n", section_data); - const auto file_path = R"(C:\Windows\System32\C_)" + std::to_string(section_data) + ".NLS"; const auto locale_file = utils::io::read_file(c.win_emu.file_sys.translate(file_path)); if (locale_file.empty()) @@ -59,7 +58,7 @@ namespace syscalls return STATUS_SUCCESS; } - c.win_emu.log.print(color::gray, "Unsupported section type: %X\n", section_type); + c.win_emu.log.warn("Unsupported section type: %X\n", static_cast(section_type)); return STATUS_NOT_SUPPORTED; } @@ -78,13 +77,13 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtQueryDefaultUILanguage(const syscall_context&, emulator_object language_id) + NTSTATUS handle_NtQueryDefaultUILanguage(const syscall_context&, const emulator_object language_id) { language_id.write(0x407); return STATUS_SUCCESS; } - NTSTATUS handle_NtQueryInstallUILanguage(const syscall_context&, emulator_object language_id) + NTSTATUS handle_NtQueryInstallUILanguage(const syscall_context&, const emulator_object language_id) { language_id.write(0x407); return STATUS_SUCCESS; diff --git a/src/windows-emulator/syscalls/memory.cpp b/src/windows-emulator/syscalls/memory.cpp index be5af2fb..efd5e2f2 100644 --- a/src/windows-emulator/syscalls/memory.cpp +++ b/src/windows-emulator/syscalls/memory.cpp @@ -146,9 +146,7 @@ namespace syscalls const auto requested_protection = map_nt_to_emulator_protection(protection); - c.win_emu.log.print(color::dark_gray, "--> Changing protection at 0x%" PRIx64 "-0x%" PRIx64 " to %s\n", - aligned_start, aligned_start + aligned_length, - get_permission_string(requested_protection).c_str()); + c.win_emu.callbacks.on_memory_protect(aligned_start, aligned_length, requested_protection); memory_permission old_protection_value{}; @@ -192,8 +190,6 @@ namespace syscalls if (!potential_base) { - c.win_emu.log.print(color::dark_gray, "--> Not allocated\n"); - return STATUS_MEMORY_NOT_ALLOCATED; } @@ -210,16 +206,11 @@ namespace syscalls if (commit && !reserve && c.win_emu.memory.commit_memory(potential_base, static_cast(allocation_bytes), protection)) { - c.win_emu.log.print(is_executable(protection) ? color::gray : color::dark_gray, - "--> Committed 0x%" PRIx64 " - 0x%" PRIx64 " (%s)\n", potential_base, - potential_base + allocation_bytes, get_permission_string(protection).c_str()); - + c.win_emu.callbacks.on_memory_allocate(potential_base, allocation_bytes, protection, true); return STATUS_SUCCESS; } - c.win_emu.log.print(is_executable(protection) ? color::gray : color::dark_gray, - "--> Allocated 0x%" PRIx64 " - 0x%" PRIx64 " (%s)\n", potential_base, - potential_base + allocation_bytes, get_permission_string(protection).c_str()); + c.win_emu.callbacks.on_memory_allocate(potential_base, allocation_bytes, protection, false); return c.win_emu.memory.allocate_memory(potential_base, static_cast(allocation_bytes), protection, !commit) diff --git a/src/windows-emulator/syscalls/mutant.cpp b/src/windows-emulator/syscalls/mutant.cpp index 1adb21d2..306c3474 100644 --- a/src/windows-emulator/syscalls/mutant.cpp +++ b/src/windows-emulator/syscalls/mutant.cpp @@ -44,7 +44,7 @@ namespace syscalls { name = read_unicode_string( c.emu, emulator_object>>{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); } } diff --git a/src/windows-emulator/syscalls/object.cpp b/src/windows-emulator/syscalls/object.cpp index 71ab7b28..5d17be4a 100644 --- a/src/windows-emulator/syscalls/object.cpp +++ b/src/windows-emulator/syscalls/object.cpp @@ -158,8 +158,7 @@ namespace syscalls if (!is_awaitable_object_type(h)) { - c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForMultipleObjects: %d!\n", - h.value.type); + c.win_emu.log.warn("Unsupported handle type for NtWaitForMultipleObjects: %d!\n", h.value.type); return STATUS_NOT_SUPPORTED; } @@ -180,7 +179,7 @@ namespace syscalls { if (!is_awaitable_object_type(h)) { - c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForSingleObject: %d!\n", h.value.type); + c.win_emu.log.warn("Unsupported handle type for NtWaitForSingleObject: %d!\n", h.value.type); return STATUS_NOT_SUPPORTED; } diff --git a/src/windows-emulator/syscalls/port.cpp b/src/windows-emulator/syscalls/port.cpp index 50072d50..46fa7a03 100644 --- a/src/windows-emulator/syscalls/port.cpp +++ b/src/windows-emulator/syscalls/port.cpp @@ -14,7 +14,7 @@ namespace syscalls const emulator_object 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); diff --git a/src/windows-emulator/syscalls/registry.cpp b/src/windows-emulator/syscalls/registry.cpp index 969a0d70..7ec1c034 100644 --- a/src/windows-emulator/syscalls/registry.cpp +++ b/src/windows-emulator/syscalls/registry.cpp @@ -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()) @@ -111,7 +111,7 @@ namespace syscalls return STATUS_SUCCESS; } - c.win_emu.log.print(color::gray, "Unsupported registry class: %X\n", key_information_class); + c.win_emu.log.warn("Unsupported registry class: %X\n", key_information_class); c.emu.stop(); return STATUS_NOT_SUPPORTED; } @@ -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) @@ -224,7 +228,7 @@ namespace syscalls return STATUS_SUCCESS; } - c.win_emu.log.print(color::gray, "Unsupported registry value class: %X\n", key_value_information_class); + c.win_emu.log.warn("Unsupported registry value class: %X\n", key_value_information_class); c.emu.stop(); return STATUS_NOT_SUPPORTED; } @@ -332,7 +336,7 @@ namespace syscalls return STATUS_SUCCESS; } - c.win_emu.log.print(color::gray, "Unsupported registry enumeration class: %X\n", key_information_class); + c.win_emu.log.warn("Unsupported registry enumeration class: %X\n", key_information_class); return STATUS_NOT_SUPPORTED; } @@ -443,8 +447,7 @@ namespace syscalls return STATUS_SUCCESS; } - c.win_emu.log.print(color::gray, "Unsupported registry value enumeration class: %X\n", - key_value_information_class); + c.win_emu.log.warn("Unsupported registry value enumeration class: %X\n", key_value_information_class); return STATUS_NOT_SUPPORTED; } } diff --git a/src/windows-emulator/syscalls/section.cpp b/src/windows-emulator/syscalls/section.cpp index 27f3cb2e..753db3c6 100644 --- a/src/windows-emulator/syscalls/section.cpp +++ b/src/windows-emulator/syscalls/section.cpp @@ -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") { @@ -287,7 +287,7 @@ namespace syscalls const auto* mod = c.win_emu.mod_manager.find_by_address(base_address); if (mod != nullptr) { - if (c.win_emu.mod_manager.unmap(base_address, c.win_emu.log)) + if (c.win_emu.mod_manager.unmap(base_address)) { return STATUS_SUCCESS; } diff --git a/src/windows-emulator/syscalls/system.cpp b/src/windows-emulator/syscalls/system.cpp index 2cee38e8..02b73402 100644 --- a/src/windows-emulator/syscalls/system.cpp +++ b/src/windows-emulator/syscalls/system.cpp @@ -109,7 +109,7 @@ namespace syscalls return STATUS_NOT_SUPPORTED; case SystemControlFlowTransition: - c.win_emu.log.print(color::pink, "Warbird control flow transition!\n"); + c.win_emu.callbacks.on_suspicious_activity("Warbird control flow transition"); return STATUS_NOT_SUPPORTED; case SystemTimeOfDayInformation: diff --git a/src/windows-emulator/syscalls/thread.cpp b/src/windows-emulator/syscalls/thread.cpp index d8c24a66..39098480 100644 --- a/src/windows-emulator/syscalls/thread.cpp +++ b/src/windows-emulator/syscalls/thread.cpp @@ -26,7 +26,7 @@ namespace syscalls if (info_class == ThreadHideFromDebugger) { - c.win_emu.log.print(color::pink, "--> Hiding thread %X from debugger!\n", thread->id); + c.win_emu.callbacks.on_suspicious_activity("Hiding thread from debugger"); return STATUS_SUCCESS; } @@ -41,8 +41,7 @@ namespace syscalls const auto i = info.read(); thread->name = read_unicode_string(c.emu, i.ThreadName); - c.win_emu.log.print(color::blue, "Setting thread (%d) name: %s\n", thread->id, - u16_to_u8(thread->name).c_str()); + c.win_emu.callbacks.on_thread_set_name(*thread); return STATUS_SUCCESS; } @@ -325,14 +324,15 @@ namespace syscalls } NTSTATUS handle_NtAlertThreadByThreadIdEx(const syscall_context& c, const uint64_t thread_id, - const emulator_object>> lock) + const emulator_object>> /*lock*/) { - if (lock.value()) + // TODO: Support lock + /*if (lock.value()) { - c.win_emu.log.print(color::gray, "NtAlertThreadByThreadIdEx with lock not supported yet!"); - // c.emu.stop(); - // return STATUS_NOT_SUPPORTED; - } + c.win_emu.log.warn("NtAlertThreadByThreadIdEx with lock not supported yet!\n"); + // c.emu.stop(); + // return STATUS_NOT_SUPPORTED; + }*/ return handle_NtAlertThreadByThreadId(c, thread_id); } @@ -425,7 +425,7 @@ namespace syscalls if (flags != 0) { - c.win_emu.log.error("NtGetNextThread flags %X not supported\n", flags); + c.win_emu.log.error("NtGetNextThread flags %X not supported\n", static_cast(flags)); c.emu.stop(); return STATUS_NOT_SUPPORTED; } @@ -470,7 +470,7 @@ namespace syscalls thread_context.access([&](CONTEXT64& context) { if ((context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) == CONTEXT_DEBUG_REGISTERS_64) { - c.win_emu.log.print(color::pink, "--> Reading debug registers!\n"); + c.win_emu.callbacks.on_suspicious_activity("Reading debug registers"); } cpu_context::save(c.emu, context); @@ -509,7 +509,7 @@ namespace syscalls if ((context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) == CONTEXT_DEBUG_REGISTERS_64) { - c.win_emu.log.print(color::pink, "--> Setting debug registers!\n"); + c.win_emu.callbacks.on_suspicious_activity("Setting debug registers"); } return STATUS_SUCCESS; diff --git a/src/windows-emulator/syscalls/timer.cpp b/src/windows-emulator/syscalls/timer.cpp index a154e27f..cc320fa1 100644 --- a/src/windows-emulator/syscalls/timer.cpp +++ b/src/windows-emulator/syscalls/timer.cpp @@ -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); } } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 76cf20ba..9433e08a 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -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; } @@ -289,7 +287,7 @@ windows_emulator::windows_emulator(std::unique_ptr emu, applica : windows_emulator(std::move(emu), settings, std::move(callbacks), std::move(interfaces)) { fixup_application_settings(app_settings); - this->setup_process(app_settings); + this->application_settings_ = std::move(app_settings); } windows_emulator::windows_emulator(std::unique_ptr emu, const emulator_settings& settings, @@ -304,8 +302,7 @@ windows_emulator::windows_emulator(std::unique_ptr emu, const e registry(emulation_root.empty() ? settings.registry_directory : emulation_root / "registry"), mod_manager(memory, file_sys, this->callbacks), process(*this->emu_, memory, *this->clock_, this->callbacks), - modules_(settings.modules), - ignored_functions_(settings.ignored_functions) + use_relative_time_(settings.use_relative_time) { #ifndef OS_WINDOWS if (this->emulation_root.empty()) @@ -324,16 +321,24 @@ windows_emulator::windows_emulator(std::unique_ptr emu, const e this->map_port(mapping.first, mapping.second); } - this->verbose_calls = settings.verbose_calls; - this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging; - this->use_relative_time_ = settings.use_relative_time; - this->log.disable_output(settings.disable_logging || this->silent_until_main_); - this->setup_hooks(); } windows_emulator::~windows_emulator() = default; +void windows_emulator::setup_process_if_necessary() +{ + if (!this->application_settings_) + { + return; + } + + auto app_settings = std::move(*this->application_settings_); + this->application_settings_ = {}; + + this->setup_process(app_settings); +} + void windows_emulator::setup_process(const application_settings& app_settings) { const auto& emu = this->emu(); @@ -418,89 +423,7 @@ void windows_emulator::on_instruction_execution(const uint64_t address) this->process.previous_ip = this->process.current_ip; this->process.current_ip = this->emu().read_instruction_pointer(); - const auto is_main_exe = this->mod_manager.executable->is_within(address); - const auto is_previous_main_exe = this->mod_manager.executable->is_within(this->process.previous_ip); - - const auto binary = utils::make_lazy([&] { - if (is_main_exe) - { - return this->mod_manager.executable; - } - - return this->mod_manager.find_by_address(address); // - }); - - const auto previous_binary = utils::make_lazy([&] { - if (is_previous_main_exe) - { - return this->mod_manager.executable; - } - - return this->mod_manager.find_by_address(this->process.previous_ip); // - }); - - const auto is_in_interesting_module = [&] { - if (this->modules_.empty()) - { - return false; - } - - return (binary && this->modules_.contains(binary->name)) || - (previous_binary && this->modules_.contains(previous_binary->name)); - }; - - const auto is_interesting_call = is_previous_main_exe // - || is_main_exe // - || is_in_interesting_module(); - - if (this->silent_until_main_ && is_main_exe) - { - this->silent_until_main_ = false; - this->log.disable_output(false); - } - - if (!this->verbose && !this->verbose_calls && !is_interesting_call) - { - return; - } - - if (binary) - { - const auto export_entry = binary->address_names.find(address); - if (export_entry != binary->address_names.end() && !this->ignored_functions_.contains(export_entry->second)) - { - const auto rsp = this->emu().read_stack_pointer(); - - uint64_t return_address{}; - this->emu().try_read_memory(rsp, &return_address, sizeof(return_address)); - - const auto* mod_name = this->mod_manager.find_name(return_address); - - log.print(is_interesting_call ? color::yellow : color::dark_gray, - "Executing function: %s - %s (0x%" PRIx64 ") via (0x%" PRIx64 ") %s\n", binary->name.c_str(), - export_entry->second.c_str(), address, return_address, mod_name); - } - else if (address == binary->entry_point) - { - log.print(is_interesting_call ? color::yellow : color::gray, "Executing entry point: %s (0x%" PRIx64 ")\n", - binary->name.c_str(), address); - } - } - - if (!this->verbose) - { - return; - } - - auto& emu = this->emu(); - - // TODO: Remove or cleanup - log.print(color::gray, - "Inst: %16" PRIx64 " - RAX: %16" PRIx64 " - RBX: %16" PRIx64 " - RCX: %16" PRIx64 " - RDX: %16" PRIx64 - " - R8: %16" PRIx64 " - R9: %16" PRIx64 " - RDI: %16" PRIx64 " - RSI: %16" PRIx64 " - %s\n", - address, emu.reg(x86_register::rax), emu.reg(x86_register::rbx), emu.reg(x86_register::rcx), - emu.reg(x86_register::rdx), emu.reg(x86_register::r8), emu.reg(x86_register::r9), - emu.reg(x86_register::rdi), emu.reg(x86_register::rsi), binary ? binary->name.c_str() : ""); + this->callbacks.on_instruction(address); } void windows_emulator::setup_hooks() @@ -529,17 +452,13 @@ void windows_emulator::setup_hooks() return instruction_hook_continuation::skip_instruction; }); + // TODO: Unicorn needs this - This should be handled in the backend this->emu().hook_instruction(x86_hookable_instructions::invalid, [&] { - const auto ip = this->emu().read_instruction_pointer(); - - this->log.print(color::gray, "Invalid instruction at: 0x%" PRIx64 " (via 0x%" PRIx64 ")\n", ip, - this->process.previous_ip); - - return instruction_hook_continuation::skip_instruction; + return instruction_hook_continuation::skip_instruction; // }); this->emu().hook_interrupt([&](const int interrupt) { - const auto rip = this->emu().read_instruction_pointer(); + this->callbacks.on_exception(); const auto eflags = this->emu().reg(x86_register::eflags); switch (interrupt) @@ -550,63 +469,37 @@ void windows_emulator::setup_hooks() case 1: if ((eflags & 0x100) != 0) { - this->log.print(color::pink, "Singlestep (Trap Flag): 0x%" PRIx64 "\n", rip); this->emu().reg(x86_register::eflags, eflags & ~0x100); } - else - { - this->log.print(color::pink, "Singlestep: 0x%" PRIx64 "\n", rip); - } + + this->callbacks.on_suspicious_activity("Singlestep"); dispatch_single_step(this->emu(), this->process); return; case 3: - this->log.print(color::pink, "Breakpoint: 0x%" PRIx64 "\n", rip); + this->callbacks.on_suspicious_activity("Breakpoint"); dispatch_breakpoint(this->emu(), this->process); return; case 6: + this->callbacks.on_suspicious_activity("Illegal instruction"); dispatch_illegal_instruction_violation(this->emu(), this->process); return; case 45: - this->log.print(color::pink, "DbgPrint: 0x%" PRIx64 "\n", rip); + this->callbacks.on_suspicious_activity("DbgPrint"); dispatch_breakpoint(this->emu(), this->process); return; default: + if (this->callbacks.on_generic_activity) + { + this->callbacks.on_generic_activity("Interrupt " + std::to_string(interrupt)); + } + break; } - - this->log.print(color::gray, "Interrupt: %i 0x%" PRIx64 "\n", interrupt, rip); - - if (this->fuzzing || true) // TODO: Fix - { - this->process.exception_rip = rip; - this->emu().stop(); - } }); this->emu().hook_memory_violation([&](const uint64_t address, const size_t size, const memory_operation operation, const memory_violation_type type) { - const auto permission = get_permission_string(operation); - const auto ip = this->emu().read_instruction_pointer(); - const char* name = this->mod_manager.find_name(ip); - - if (type == memory_violation_type::protection) - { - this->log.print(color::gray, "Protection violation: 0x%" PRIx64 " (%zX) - %s at 0x%" PRIx64 " (%s)\n", - address, size, permission.c_str(), ip, name); - } - else if (type == memory_violation_type::unmapped) - { - this->log.print(color::gray, "Mapping violation: 0x%" PRIx64 " (%zX) - %s at 0x%" PRIx64 " (%s)\n", address, - size, permission.c_str(), ip, name); - } - - if (this->fuzzing) - { - this->process.exception_rip = ip; - this->emu().stop(); - return memory_violation_continuation::stop; - } - + this->callbacks.on_memory_violate(address, size, operation, type); dispatch_access_violation(this->emu(), this->process, address, operation); return memory_violation_continuation::resume; }); @@ -619,6 +512,7 @@ void windows_emulator::setup_hooks() void windows_emulator::start(size_t count) { this->should_stop = false; + this->setup_process_if_necessary(); const auto use_count = count > 0; const auto start_instructions = this->executed_instructions_; @@ -690,9 +584,11 @@ void windows_emulator::register_factories(utils::buffer_deserializer& buffer) void windows_emulator::serialize(utils::buffer_serializer& buffer) const { + buffer.write_optional(this->application_settings_); buffer.write(this->executed_instructions_); buffer.write(this->switch_thread_); buffer.write(this->use_relative_time_); + this->emu().serialize_state(buffer, false); this->memory.serialize_memory_state(buffer, false); this->mod_manager.serialize(buffer); @@ -704,6 +600,7 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) { this->register_factories(buffer); + buffer.read_optional(this->application_settings_); buffer.read(this->executed_instructions_); buffer.read(this->switch_thread_); @@ -726,13 +623,18 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) void windows_emulator::save_snapshot() { - utils::buffer_serializer serializer{}; - this->emu().serialize_state(serializer, true); - this->memory.serialize_memory_state(serializer, true); - this->mod_manager.serialize(serializer); - this->process.serialize(serializer); + utils::buffer_serializer buffer{}; - this->process_snapshot_ = serializer.move_buffer(); + buffer.write_optional(this->application_settings_); + buffer.write(this->executed_instructions_); + buffer.write(this->switch_thread_); + + this->emu().serialize_state(buffer, true); + this->memory.serialize_memory_state(buffer, true); + this->mod_manager.serialize(buffer); + this->process.serialize(buffer); + + this->process_snapshot_ = buffer.move_buffer(); // TODO: Make process copyable // this->process_snapshot_ = this->process; @@ -746,13 +648,17 @@ void windows_emulator::restore_snapshot() return; } - utils::buffer_deserializer deserializer{this->process_snapshot_}; + utils::buffer_deserializer buffer{this->process_snapshot_}; - this->register_factories(deserializer); + this->register_factories(buffer); - this->emu().deserialize_state(deserializer, true); - this->memory.deserialize_memory_state(deserializer, true); - this->mod_manager.deserialize(deserializer); - this->process.deserialize(deserializer); + buffer.read_optional(this->application_settings_); + buffer.read(this->executed_instructions_); + buffer.read(this->switch_thread_); + + this->emu().deserialize_state(buffer, true); + this->memory.deserialize_memory_state(buffer, true); + this->mod_manager.deserialize(buffer); + this->process.deserialize(buffer); // this->process = *this->process_snapshot_; } diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index a1fae00e..c6732a30 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -13,13 +13,27 @@ #include "module/module_manager.hpp" #include "network/socket_factory.hpp" +struct io_device; + +#define opt_func utils::optional_function + struct emulator_callbacks : module_manager::callbacks, process_context::callbacks { - utils::optional_function - on_syscall{}; + using continuation = instruction_hook_continuation; - utils::optional_function on_stdout{}; + opt_func on_exception{}; + + opt_func on_memory_protect{}; + opt_func on_memory_allocate{}; + opt_func on_memory_violate{}; + + opt_func on_syscall{}; + opt_func on_stdout{}; + opt_func on_generic_access{}; + opt_func on_generic_activity{}; + opt_func on_suspicious_activity{}; + opt_func on_instruction{}; + opt_func on_ioctrl{}; }; struct application_settings @@ -27,22 +41,32 @@ struct application_settings windows_path application{}; windows_path working_directory{}; std::vector arguments{}; + + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->application); + buffer.write(this->working_directory); + buffer.write_vector(this->arguments); + } + + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->application); + buffer.read(this->working_directory); + buffer.read_vector(this->arguments); + } }; struct emulator_settings { + bool disable_logging{false}; + bool use_relative_time{false}; + std::filesystem::path emulation_root{}; std::filesystem::path registry_directory{"./registry"}; - bool verbose_calls{false}; - bool disable_logging{false}; - bool silent_until_main{false}; - bool use_relative_time{false}; - std::unordered_map port_mappings{}; std::unordered_map path_mappings{}; - std::set> modules{}; - std::set> ignored_functions{}; }; struct emulator_interfaces @@ -54,6 +78,7 @@ struct emulator_interfaces class windows_emulator { uint64_t executed_instructions_{0}; + std::optional application_settings_{}; std::unique_ptr emu_{}; std::unique_ptr clock_{}; @@ -128,6 +153,8 @@ class windows_emulator return this->executed_instructions_; } + void setup_process_if_necessary(); + void start(size_t count = 0); void stop(); @@ -176,25 +203,17 @@ class windows_emulator } } - bool verbose{false}; - bool verbose_calls{false}; - bool buffer_stdout{false}; - bool fuzzing{false}; - void yield_thread(bool alertable = false); bool perform_thread_switch(); bool activate_thread(uint32_t id); private: bool switch_thread_{false}; - bool use_relative_time_{false}; - bool silent_until_main_{false}; + bool use_relative_time_{false}; // TODO: Get rid of that std::atomic_bool should_stop{false}; std::unordered_map port_mappings_{}; - std::set> modules_{}; - std::set> ignored_functions_{}; std::vector process_snapshot_{}; // std::optional process_snapshot_{}; diff --git a/src/windows-emulator/windows_path.hpp b/src/windows-emulator/windows_path.hpp index e2b10ba0..82315d91 100644 --- a/src/windows-emulator/windows_path.hpp +++ b/src/windows-emulator/windows_path.hpp @@ -75,7 +75,8 @@ class windows_path template requires(!std::is_same_v, windows_path> && - !std::is_same_v, std::filesystem::path>) + !std::is_same_v, std::filesystem::path> && + !std::is_same_v, utils::buffer_deserializer>) windows_path(T&& path_like) : windows_path(std::filesystem::path(std::forward(path_like))) {