Separate application and emulator settings

This commit is contained in:
Maurice Heumann
2025-02-10 15:46:38 +01:00
parent a5bae30e00
commit a28be3049b
7 changed files with 115 additions and 60 deletions

View File

@@ -113,18 +113,21 @@ namespace
return false;
}
const emulator_settings settings{
application_settings app_settings{
.application = args[0],
.arguments = parse_arguments(args),
};
const emulator_settings settings{
.registry_directory = options.registry_path,
.emulation_root = options.emulation_root,
.arguments = parse_arguments(args),
.verbose_calls = options.verbose_logging,
.disable_logging = options.silent,
.silent_until_main = options.concise_logging,
.modules = options.modules,
};
windows_emulator win_emu{settings};
windows_emulator win_emu{std::move(app_settings), settings};
(void)&watch_system_objects;
watch_system_objects(win_emu, options.modules, options.concise_logging);

View File

@@ -137,7 +137,7 @@ namespace
void run(const std::string_view application)
{
emulator_settings settings{
application_settings settings{
.application = application,
};

View File

@@ -38,7 +38,30 @@ namespace test
return env;
}
inline windows_emulator create_sample_emulator(emulator_settings settings, const bool reproducible = false,
struct sample_configuration
{
bool reproducible{false};
bool print_time{false};
};
inline application_settings get_sample_app_settings(const sample_configuration& config)
{
application_settings settings{.application = "C:\\test-sample.exe"};
if (config.print_time)
{
settings.arguments.emplace_back(u"-time");
}
if (config.reproducible)
{
settings.arguments.emplace_back(u"-reproducible");
}
return settings;
}
inline windows_emulator create_sample_emulator(emulator_settings settings, const sample_configuration& config = {},
emulator_callbacks callbacks = {})
{
const auto is_verbose = enable_verbose_logging();
@@ -49,29 +72,27 @@ namespace test
// settings.verbose_calls = true;
}
if (reproducible)
{
settings.arguments = {u"-reproducible"};
}
settings.application = "c:/test-sample.exe";
settings.emulation_root = get_emulator_root();
settings.port_mappings[28970] = static_cast<uint16_t>(getpid());
settings.path_mappings["C:\\a.txt"] =
std::filesystem::temp_directory_path() / ("emulator-test-file-" + std::to_string(getpid()) + ".txt");
return windows_emulator{std::move(settings), std::move(callbacks)};
return windows_emulator{
get_sample_app_settings(config),
settings,
std::move(callbacks),
};
}
inline windows_emulator create_sample_emulator(const bool reproducible = false)
inline windows_emulator create_sample_emulator(const sample_configuration& config = {})
{
emulator_settings settings{
.disable_logging = true,
.use_relative_time = true,
};
return create_sample_emulator(std::move(settings), reproducible);
return create_sample_emulator(std::move(settings), config);
}
inline void bisect_emulation(windows_emulator& emu)

View File

@@ -2,9 +2,17 @@
namespace test
{
namespace
{
auto create_reproducible_sample_emulator()
{
return create_sample_emulator({.reproducible = true});
}
}
TEST(SerializationTest, ResettingEmulatorWorks)
{
auto emu = create_sample_emulator(true);
auto emu = create_reproducible_sample_emulator();
utils::buffer_serializer start_state{};
emu.serialize(start_state);
@@ -31,7 +39,7 @@ namespace test
TEST(SerializationTest, SerializedDataIsReproducible)
{
auto emu1 = create_sample_emulator(true);
auto emu1 = create_reproducible_sample_emulator();
emu1.start();
ASSERT_TERMINATED_SUCCESSFULLY(emu1);
@@ -55,7 +63,7 @@ namespace test
TEST(SerializationTest, EmulationIsReproducible)
{
auto emu1 = create_sample_emulator(true);
auto emu1 = create_reproducible_sample_emulator();
emu1.start();
ASSERT_TERMINATED_SUCCESSFULLY(emu1);
@@ -63,7 +71,7 @@ namespace test
utils::buffer_serializer serializer1{};
emu1.serialize(serializer1);
auto emu2 = create_sample_emulator(true);
auto emu2 = create_reproducible_sample_emulator();
emu2.start();
ASSERT_TERMINATED_SUCCESSFULLY(emu2);
@@ -76,7 +84,7 @@ namespace test
TEST(SerializationTest, DeserializedEmulatorBehavesLikeSource)
{
auto emu = create_sample_emulator(true);
auto emu = create_reproducible_sample_emulator();
emu.start({}, 100);
utils::buffer_serializer serializer{};

View File

@@ -7,16 +7,18 @@ namespace test
std::string output_buffer{};
emulator_callbacks callbacks{
.stdout_callback = [&output_buffer](const std::string_view data) { output_buffer.append(data); },
.stdout_callback =
[&output_buffer](const std::string_view data) {
output_buffer.append(data); //
},
};
const emulator_settings settings{
.arguments = {u"-time"},
.disable_logging = true,
.use_relative_time = false,
};
auto emu = create_sample_emulator(settings, false, callbacks);
auto emu = create_sample_emulator(settings, {.print_time = true}, std::move(callbacks));
emu.start();
constexpr auto prefix = "Time: "sv;

View File

@@ -18,6 +18,38 @@ constexpr auto MAX_INSTRUCTIONS_PER_TIME_SLICE = 100000;
namespace
{
void adjust_working_directory(application_settings& app_settings)
{
if (!app_settings.working_directory.empty())
{
// Do nothing
}
#ifdef OS_WINDOWS
else if (app_settings.application.is_relative())
{
app_settings.working_directory = std::filesystem::current_path();
}
#endif
else
{
app_settings.working_directory = app_settings.application.parent();
}
}
void adjust_application(application_settings& app_settings)
{
if (app_settings.application.is_relative())
{
app_settings.application = app_settings.working_directory / app_settings.application;
}
}
void fixup_application_settings(application_settings& app_settings)
{
adjust_working_directory(app_settings);
adjust_application(app_settings);
}
uint64_t copy_string(x64_emulator& emu, emulator_allocator& allocator, const void* base_ptr, const uint64_t offset,
const size_t length)
{
@@ -177,8 +209,8 @@ namespace
emu.reg<uint16_t>(x64_register::ss, 0x2B);
}
void setup_context(windows_emulator& win_emu, const emulator_settings& settings, const windows_path& application,
const windows_path& working_dir)
void setup_context(windows_emulator& win_emu, const application_settings& app_settings,
const emulator_settings& emu_settings)
{
auto& emu = win_emu.emu();
auto& context = win_emu.process();
@@ -186,11 +218,12 @@ namespace
setup_gdt(emu, memory);
// TODO: Move that out
context.registry =
registry_manager(win_emu.get_emulation_root().empty() ? settings.registry_directory
registry_manager(win_emu.get_emulation_root().empty() ? emu_settings.registry_directory
: win_emu.get_emulation_root() / "registry");
context.kusd.setup(settings.use_relative_time);
context.kusd.setup(emu_settings.use_relative_time);
context.base_allocator = create_allocator(memory, PEB_SEGMENT_SIZE);
auto& allocator = context.base_allocator;
@@ -228,18 +261,19 @@ namespace
allocator.copy_string(u"SystemRoot=C:\\WINDOWS");
allocator.copy_string(u"");
const auto application_str = application.u16string();
const auto application_str = app_settings.application.u16string();
std::u16string command_line = u"\"" + application_str + u"\"";
for (const auto& arg : settings.arguments)
for (const auto& arg : app_settings.arguments)
{
command_line.push_back(u' ');
command_line.append(arg);
}
allocator.make_unicode_string(proc_params.CommandLine, command_line);
allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, working_dir.u16string() + u"\\", 1024);
allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath,
app_settings.working_directory.u16string() + u"\\", 1024);
allocator.make_unicode_string(proc_params.ImagePathName, application_str);
const auto total_length = allocator.get_next_address() - context.process_params.value();
@@ -403,26 +437,11 @@ std::unique_ptr<x64_emulator> create_default_x64_emulator()
return unicorn::create_x64_emulator();
}
windows_emulator::windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks,
std::unique_ptr<x64_emulator> emu)
windows_emulator::windows_emulator(application_settings app_settings, const emulator_settings& settings,
emulator_callbacks callbacks, std::unique_ptr<x64_emulator> emu)
: windows_emulator(settings.emulation_root, std::move(emu))
{
windows_path working_dir{};
if (!settings.working_directory.empty())
{
working_dir = settings.working_directory;
}
#ifdef OS_WINDOWS
else if (settings.application.is_relative())
{
working_dir = std::filesystem::current_path();
}
#endif
else
{
working_dir = settings.application.parent();
}
fixup_application_settings(app_settings);
for (const auto& mapping : settings.path_mappings)
{
@@ -441,7 +460,7 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c
this->callbacks_ = std::move(callbacks);
this->modules_ = settings.modules;
this->setup_process(settings, working_dir);
this->setup_process(app_settings, settings);
}
windows_emulator::windows_emulator(const std::filesystem::path& emulation_root, std::unique_ptr<x64_emulator> emu)
@@ -463,20 +482,16 @@ windows_emulator::windows_emulator(const std::filesystem::path& emulation_root,
windows_emulator::~windows_emulator() = default;
void windows_emulator::setup_process(const emulator_settings& settings, const windows_path& working_directory)
void windows_emulator::setup_process(const application_settings& app_settings, const emulator_settings& emu_settings)
{
auto& emu = this->emu();
auto& context = this->process();
context.mod_manager = module_manager(this->memory(), this->file_sys()); // TODO: Cleanup module manager
const auto application = settings.application.is_absolute() //
? settings.application
: (working_directory / settings.application);
setup_context(*this, app_settings, emu_settings);
setup_context(*this, settings, application, working_directory);
context.executable = context.mod_manager.map_module(application, this->log, true);
context.executable = context.mod_manager.map_module(app_settings.application, this->log, true);
context.peb.access([&](PEB64& peb) {
peb.ImageBaseAddress = reinterpret_cast<std::uint64_t*>(context.executable->image_base); //

View File

@@ -25,18 +25,23 @@ struct emulator_callbacks
outofline_syscall{};
};
// TODO: Split up into application and emulator settings
struct emulator_settings
struct application_settings
{
windows_path application{};
windows_path working_directory{};
std::vector<std::u16string> arguments{};
};
struct emulator_settings
{
std::filesystem::path registry_directory{"./registry"};
std::filesystem::path emulation_root{};
std::vector<std::u16string> arguments{};
bool verbose_calls{false};
bool disable_logging{false};
bool silent_until_main{false};
bool use_relative_time{false};
std::unordered_map<uint16_t, uint16_t> port_mappings{};
std::unordered_map<windows_path, std::filesystem::path> path_mappings{};
std::set<std::string, std::less<>> modules{};
@@ -55,7 +60,8 @@ class windows_emulator
public:
windows_emulator(const std::filesystem::path& emulation_root,
std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks = {},
windows_emulator(application_settings app_settings, const emulator_settings& settings = {},
emulator_callbacks callbacks = {},
std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
windows_emulator(windows_emulator&&) = delete;
@@ -227,6 +233,6 @@ class windows_emulator
// std::optional<process_context> process_snapshot_{};
void setup_hooks();
void setup_process(const emulator_settings& settings, const windows_path& working_directory);
void setup_process(const application_settings& app_settings, const emulator_settings& emu_settings);
void on_instruction_execution(uint64_t address);
};