Cleanup emulation root handling

This fixes #103
This fixes #105
This commit is contained in:
momo5502
2025-01-25 08:30:43 +01:00
parent 4cd098626e
commit a3c6e9a5c0
6 changed files with 70 additions and 33 deletions

View File

@@ -12,7 +12,8 @@ namespace
bool use_gdb{false};
bool concise_logging{false};
bool verbose_logging{false};
std::string root_filesystem{"./root"};
std::string registry_path{"./registry"};
std::string emulation_root{};
};
void watch_system_objects(windows_emulator& win_emu, const bool cache_logging)
@@ -107,7 +108,8 @@ namespace
emulator_settings settings{
.application = args[0],
.root_filesystem = options.root_filesystem,
.registry_directory = options.registry_path,
.emulation_root = options.emulation_root,
.arguments = parse_arguments(args),
.silent_until_main = options.concise_logging,
};
@@ -209,14 +211,23 @@ namespace
{
options.concise_logging = true;
}
else if (arg == "-e")
{
if (args.size() < 2)
{
throw std::runtime_error("No emulation root path provided after -e");
}
arg_it = args.erase(arg_it);
options.emulation_root = args[0];
}
else if (arg == "-r")
{
if (args.size() < 2)
{
throw std::runtime_error("No root path provided after -r");
throw std::runtime_error("No registry path provided after -r");
}
arg_it = args.erase(arg_it);
options.root_filesystem = args[0];
options.registry_path = args[0];
}
else
{

View File

@@ -35,7 +35,7 @@ namespace test
inline windows_emulator create_sample_emulator(emulator_settings settings, emulator_callbacks callbacks = {})
{
settings.application = "c:/test-sample.exe";
settings.root_filesystem = get_emulator_root();
settings.emulation_root = get_emulator_root();
return windows_emulator{std::move(settings), std::move(callbacks)};
}

View File

@@ -7,7 +7,7 @@
class file_system
{
public:
file_system(std::filesystem::path root, windows_path working_dir)
file_system(std::filesystem::path root, windows_path working_dir = "C:\\")
: root_(std::move(root)),
working_dir_(std::move(working_dir))
{
@@ -26,6 +26,7 @@ class file_system
}
#endif
// TODO: Sanitize path to prevent traversal!
return this->root_ / full_path.to_portable_path();
}

View File

@@ -1530,7 +1530,7 @@ namespace
if (!f->enumeration_state || query_flags & SL_RESTART_SCAN)
{
f->enumeration_state.emplace(file_enumeration_state{});
f->enumeration_state->files = scan_directory(c.win_emu.file_sys.translate(f->name));
f->enumeration_state->files = scan_directory(c.win_emu.file_sys().translate(f->name));
}
auto& enum_state = *f->enumeration_state;
@@ -2586,7 +2586,7 @@ namespace
const emulator_object<LARGE_INTEGER> /*default_casing_table_size*/)
{
const auto locale_file =
utils::io::read_file(c.win_emu.file_sys.translate(R"(C:\Windows\System32\locale.nls)"));
utils::io::read_file(c.win_emu.file_sys().translate(R"(C:\Windows\System32\locale.nls)"));
if (locale_file.empty())
{
return STATUS_FILE_INVALID;
@@ -2826,14 +2826,14 @@ namespace
if (create_disposition & FILE_CREATE)
{
std::error_code ec{};
std::filesystem::create_directory(c.win_emu.file_sys.translate(f.name), ec);
create_directory(c.win_emu.file_sys().translate(f.name), ec);
if (ec)
{
return STATUS_ACCESS_DENIED;
}
}
else if (!std::filesystem::is_directory(c.win_emu.file_sys.translate(f.name)))
else if (!std::filesystem::is_directory(c.win_emu.file_sys().translate(f.name)))
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
@@ -2855,7 +2855,7 @@ namespace
FILE* file{};
const auto error = open_unicode(&file, c.win_emu.file_sys.translate(f.name), mode);
const auto error = open_unicode(&file, c.win_emu.file_sys().translate(f.name), mode);
if (!file)
{
@@ -2900,7 +2900,7 @@ namespace
c.win_emu.log.print(color::dark_gray, "--> Querying file attributes: %s\n", u16_to_u8(filename).c_str());
const auto local_filename = c.win_emu.file_sys.translate(filename).string();
const auto local_filename = c.win_emu.file_sys().translate(filename).string();
struct _stat64 file_stat{};
if (_stat64(local_filename.c_str(), &file_stat) != 0)

View File

@@ -216,7 +216,9 @@ namespace
setup_gdt(emu);
context.registry = registry_manager(win_emu.root_directory / "registry");
context.registry =
registry_manager(win_emu.get_emulation_root().empty() ? settings.registry_directory
: win_emu.get_emulation_root() / "registry");
context.kusd.setup(settings.use_relative_time);
@@ -268,7 +270,7 @@ namespace
allocator.make_unicode_string(proc_params.CommandLine, command_line);
allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath,
win_emu.file_sys.get_working_directory().u16string());
win_emu.file_sys().get_working_directory().u16string());
allocator.make_unicode_string(proc_params.ImagePathName, application_str);
const auto total_length = allocator.get_next_address() - context.process_params.value();
@@ -280,7 +282,7 @@ namespace
apiset_location apiset_loc = apiset_location::file;
if (win_emu.root_directory.empty())
if (win_emu.get_emulation_root().empty())
{
#ifdef OS_WINDOWS
apiset_loc = apiset_location::host;
@@ -292,7 +294,7 @@ namespace
context.peb.access([&](PEB64& peb) {
peb.ImageBaseAddress = nullptr;
peb.ProcessParameters = context.process_params.ptr();
peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc, win_emu.root_directory).ptr();
peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc, win_emu.get_emulation_root()).ptr();
peb.ProcessHeap = nullptr;
peb.ProcessHeaps = nullptr;
@@ -825,15 +827,15 @@ std::unique_ptr<x64_emulator> create_default_x64_emulator()
windows_emulator::windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks,
std::unique_ptr<x64_emulator> emu)
: windows_emulator(settings.root_filesystem, std::move(emu))
: windows_emulator(settings.emulation_root, std::move(emu))
{
if (!settings.working_directory.empty())
{
this->file_sys.set_working_directory(settings.working_directory);
this->file_sys().set_working_directory(settings.working_directory);
}
else
{
this->file_sys.set_working_directory(settings.application.parent());
this->file_sys().set_working_directory(settings.application.parent());
}
this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging;
@@ -843,12 +845,19 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c
this->setup_process(settings);
}
windows_emulator::windows_emulator(const std::filesystem::path& root_path, std::unique_ptr<x64_emulator> emu)
: root_directory{absolute(root_path)},
file_sys(root_directory / "filesys", u"C:\\"),
windows_emulator::windows_emulator(const std::filesystem::path& emulation_root, std::unique_ptr<x64_emulator> emu)
: emulation_root_{emulation_root.empty() ? emulation_root : absolute(emulation_root)},
file_sys_(emulation_root_.empty() ? emulation_root_ : emulation_root_ / "filesys"),
emu_(std::move(emu)),
process_(*emu_, file_sys)
process_(*emu_, file_sys_)
{
#ifndef OS_WINDOWS
if (this->get_emulation_root().empty())
{
throw std::runtime_error("Emulation root directory can not be empty!");
}
#endif
this->setup_hooks();
}
@@ -857,7 +866,7 @@ void windows_emulator::setup_process(const emulator_settings& settings)
auto& emu = this->emu();
auto& context = this->process();
context.mod_manager = module_manager(emu, this->file_sys); // TODO: Cleanup module manager
context.mod_manager = module_manager(emu, this->file_sys()); // TODO: Cleanup module manager
setup_context(*this, settings);
@@ -1119,7 +1128,7 @@ void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count)
void windows_emulator::serialize(utils::buffer_serializer& buffer) const
{
buffer.write(this->use_relative_time_);
this->file_sys.serialize(buffer);
this->file_sys().serialize(buffer);
this->emu().serialize(buffer);
this->process_.serialize(buffer);
this->dispatcher_.serialize(buffer);
@@ -1136,7 +1145,7 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer)
});
buffer.read(this->use_relative_time_);
this->file_sys.deserialize(buffer);
this->file_sys().deserialize(buffer);
this->emu().deserialize(buffer);
this->process_.deserialize(buffer);
@@ -1148,7 +1157,7 @@ void windows_emulator::save_snapshot()
this->emu().save_snapshot();
utils::buffer_serializer serializer{};
this->file_sys.serialize(serializer);
this->file_sys().serialize(serializer);
this->process_.serialize(serializer);
this->process_snapshot_ = serializer.move_buffer();
@@ -1168,7 +1177,7 @@ void windows_emulator::restore_snapshot()
this->emu().restore_snapshot();
utils::buffer_deserializer deserializer{this->process_snapshot_};
this->file_sys.deserialize(deserializer);
this->file_sys().deserialize(deserializer);
this->process_.deserialize(deserializer);
// this->process_ = *this->process_snapshot_;
}

View File

@@ -29,14 +29,15 @@ struct emulator_settings
{
windows_path application{};
windows_path working_directory{};
std::filesystem::path root_filesystem{};
std::filesystem::path registry_directory{"./registry"};
std::filesystem::path emulation_root{};
std::vector<std::u16string> arguments{};
bool disable_logging{false};
bool silent_until_main{false};
bool use_relative_time{false};
};
enum class apiset_location
enum class apiset_location : uint8_t
{
host,
file,
@@ -47,7 +48,7 @@ enum class apiset_location
class windows_emulator
{
public:
windows_emulator(const std::filesystem::path& root_path,
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 = {},
std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
@@ -133,10 +134,25 @@ class windows_emulator
return this->callbacks_;
}
std::filesystem::path root_directory{};
file_system file_sys;
file_system& file_sys()
{
return this->file_sys_;
}
const file_system& file_sys() const
{
return this->file_sys_;
}
const std::filesystem::path& get_emulation_root()
{
return this->emulation_root_;
}
private:
std::filesystem::path emulation_root_{};
file_system file_sys_;
emulator_callbacks callbacks_{};
bool use_relative_time_{false};
bool silent_until_main_{false};