mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-19 03:33:56 +00:00
Separate application and emulator settings
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace
|
||||
|
||||
void run(const std::string_view application)
|
||||
{
|
||||
emulator_settings settings{
|
||||
application_settings settings{
|
||||
.application = application,
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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); //
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user