mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 19:23:56 +00:00
Fix a lot of path I/O operations (#132)
This commit is contained in:
@@ -12,6 +12,7 @@ namespace
|
||||
bool use_gdb{false};
|
||||
bool concise_logging{false};
|
||||
bool verbose_logging{false};
|
||||
bool silent{false};
|
||||
std::string registry_path{"./registry"};
|
||||
std::string emulation_root{};
|
||||
};
|
||||
@@ -113,6 +114,7 @@ namespace
|
||||
.emulation_root = options.emulation_root,
|
||||
.arguments = parse_arguments(args),
|
||||
.verbose_calls = options.verbose_logging,
|
||||
.disable_logging = options.silent,
|
||||
.silent_until_main = options.concise_logging,
|
||||
};
|
||||
|
||||
@@ -122,6 +124,14 @@ namespace
|
||||
watch_system_objects(win_emu, options.concise_logging);
|
||||
win_emu.buffer_stdout = true;
|
||||
|
||||
if (options.silent)
|
||||
{
|
||||
win_emu.buffer_stdout = false;
|
||||
win_emu.callbacks().stdout_callback = [](const std::string_view data) {
|
||||
(void)fwrite(data.data(), 1, data.size(), stdout);
|
||||
};
|
||||
}
|
||||
|
||||
const auto& exe = *win_emu.process().executable;
|
||||
|
||||
const auto concise_logging = options.concise_logging;
|
||||
@@ -204,6 +214,10 @@ namespace
|
||||
{
|
||||
options.use_gdb = true;
|
||||
}
|
||||
else if (arg == "-s")
|
||||
{
|
||||
options.silent = true;
|
||||
}
|
||||
else if (arg == "-v")
|
||||
{
|
||||
options.verbose_logging = true;
|
||||
|
||||
@@ -11,6 +11,11 @@ struct UNICODE_STRING
|
||||
EMULATOR_CAST(typename Traits::PVOID, char16_t*) Buffer;
|
||||
};
|
||||
|
||||
inline std::u16string u8_to_u16(const std::string_view view)
|
||||
{
|
||||
return std::u16string(view.begin(), view.end());
|
||||
}
|
||||
|
||||
inline std::string u16_to_u8(const std::u16string_view u16_view)
|
||||
{
|
||||
std::string utf8_str;
|
||||
|
||||
@@ -33,6 +33,13 @@ namespace utils
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(!std::is_same_v<std::remove_cvref_t<T>, std::function<Ret(Args...)>>)
|
||||
optional_function& operator=(T&& t)
|
||||
{
|
||||
return this->operator=(std::function<Ret(Args...)>(std::forward<T>(t)));
|
||||
}
|
||||
|
||||
Ret operator()(Args... args) const
|
||||
{
|
||||
if (func)
|
||||
|
||||
@@ -125,12 +125,35 @@ bool test_env()
|
||||
return !computername.empty() && blub == "LUL";
|
||||
}
|
||||
|
||||
bool test_file_path_io(const std::filesystem::path& filename)
|
||||
{
|
||||
std::error_code ec{};
|
||||
const auto absolute_file = std::filesystem::absolute(filename, ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
puts("Getting absolute path failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto canonical_file = std::filesystem::canonical(filename, ec);
|
||||
(void)canonical_file;
|
||||
|
||||
if (ec)
|
||||
{
|
||||
puts("Getting canonical path failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_io()
|
||||
{
|
||||
const auto* filename = "a.txt";
|
||||
const std::filesystem::path filename = "a.txt";
|
||||
|
||||
FILE* fp{};
|
||||
(void)fopen_s(&fp, filename, "wb");
|
||||
(void)fopen_s(&fp, filename.string().c_str(), "wb");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
@@ -143,6 +166,11 @@ bool test_io()
|
||||
(void)fwrite(text.data(), 1, text.size(), fp);
|
||||
(void)fclose(fp);
|
||||
|
||||
if (!test_file_path_io(filename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream t(filename);
|
||||
t.seekg(0, std::ios::end);
|
||||
const size_t size = t.tellg();
|
||||
@@ -153,6 +181,43 @@ bool test_io()
|
||||
return text == buffer;
|
||||
}
|
||||
|
||||
bool test_working_directory()
|
||||
{
|
||||
std::error_code ec{};
|
||||
|
||||
const auto current_dir = std::filesystem::current_path(ec);
|
||||
if (ec)
|
||||
{
|
||||
puts("Failed to get current path");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::filesystem::path sys32 = "C:/windows/system32";
|
||||
current_path(sys32, ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
puts("Failed to update working directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto new_current_dir = std::filesystem::current_path();
|
||||
if (sys32 != new_current_dir)
|
||||
{
|
||||
puts("Updated directory is wrong!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!std::ifstream("ntdll.dll"))
|
||||
{
|
||||
puts("Working directory is not active!");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::current_path(current_dir);
|
||||
return std::filesystem::current_path() == current_dir;
|
||||
}
|
||||
|
||||
bool test_dir_io()
|
||||
{
|
||||
size_t count = 0;
|
||||
@@ -350,6 +415,7 @@ int main(const int argc, const char* argv[])
|
||||
|
||||
RUN_TEST(test_io, "I/O")
|
||||
RUN_TEST(test_dir_io, "Dir I/O")
|
||||
RUN_TEST(test_working_directory, "Working Directory")
|
||||
RUN_TEST(test_registry, "Registry")
|
||||
RUN_TEST(test_threads, "Threads")
|
||||
RUN_TEST(test_env, "Environment")
|
||||
|
||||
69
src/windows-emulator/devices/mount_point_manager.cpp
Normal file
69
src/windows-emulator/devices/mount_point_manager.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "mount_point_manager.hpp"
|
||||
|
||||
#include "../windows_emulator.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct mount_point_manager : stateless_device
|
||||
{
|
||||
NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& c) override
|
||||
{
|
||||
if (c.io_control_code != 0x6D0030)
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (c.input_buffer_length < 2)
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
const auto data = win_emu.emu().read_memory(c.input_buffer, c.input_buffer_length);
|
||||
|
||||
const std::u16string_view file(reinterpret_cast<const char16_t*>(data.data()), (data.size() / 2) - 1);
|
||||
|
||||
constexpr std::u16string_view volume_prefix = u".\\Device\\HarddiskVolume";
|
||||
if (!file.starts_with(volume_prefix))
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
const auto drive_number = file.substr(volume_prefix.size());
|
||||
const auto drive_number_u8 = u16_to_u8(drive_number);
|
||||
const auto drive_letter = static_cast<char>('A' + atoi(drive_number_u8.c_str()) - 1);
|
||||
|
||||
std::string response{};
|
||||
response.push_back(drive_letter);
|
||||
response.push_back(':');
|
||||
response.push_back(0);
|
||||
response.push_back(0);
|
||||
|
||||
const auto u16_response = u8_to_u16(response);
|
||||
|
||||
const auto length = static_cast<uint32_t>(u16_response.size() * 2);
|
||||
const auto total_length = sizeof(length) + length;
|
||||
|
||||
if (c.io_status_block)
|
||||
{
|
||||
IO_STATUS_BLOCK<EmulatorTraits<Emu64>> block{};
|
||||
block.Information = total_length;
|
||||
c.io_status_block.write(block);
|
||||
}
|
||||
|
||||
if (c.output_buffer_length < total_length)
|
||||
{
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
win_emu.emu().write_memory(c.output_buffer, length);
|
||||
win_emu.emu().write_memory(c.output_buffer + sizeof(length), u16_response.data(), length);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<io_device> create_mount_point_manager()
|
||||
{
|
||||
return std::make_unique<mount_point_manager>();
|
||||
}
|
||||
4
src/windows-emulator/devices/mount_point_manager.hpp
Normal file
4
src/windows-emulator/devices/mount_point_manager.hpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include "../io_device.hpp"
|
||||
|
||||
std::unique_ptr<io_device> create_mount_point_manager();
|
||||
@@ -187,13 +187,17 @@ class emulator_allocator
|
||||
return reinterpret_cast<char16_t*>(uc_str.Buffer);
|
||||
}
|
||||
|
||||
void make_unicode_string(UNICODE_STRING<EmulatorTraits<Emu64>>& result, const std::u16string_view str)
|
||||
void make_unicode_string(UNICODE_STRING<EmulatorTraits<Emu64>>& result, const std::u16string_view str,
|
||||
const std::optional<size_t> maximum_length = std::nullopt)
|
||||
{
|
||||
constexpr auto element_size = sizeof(str[0]);
|
||||
constexpr auto required_alignment = alignof(decltype(str[0]));
|
||||
const auto total_length = str.size() * element_size;
|
||||
const auto total_buffer_length = total_length + element_size;
|
||||
|
||||
const auto string_buffer = this->reserve(total_length + element_size, required_alignment);
|
||||
const auto max_length = std::max(maximum_length.value_or(total_buffer_length), total_buffer_length);
|
||||
|
||||
const auto string_buffer = this->reserve(max_length, required_alignment);
|
||||
|
||||
this->emu_->write_memory(string_buffer, str.data(), total_length);
|
||||
|
||||
@@ -202,15 +206,17 @@ class emulator_allocator
|
||||
|
||||
result.Buffer = string_buffer;
|
||||
result.Length = static_cast<USHORT>(total_length);
|
||||
result.MaximumLength = static_cast<USHORT>(total_length + element_size);
|
||||
result.MaximumLength = static_cast<USHORT>(max_length);
|
||||
}
|
||||
|
||||
emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> make_unicode_string(const std::u16string_view str)
|
||||
emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> make_unicode_string(
|
||||
const std::u16string_view str, const std::optional<size_t> maximum_length = std::nullopt)
|
||||
{
|
||||
const auto unicode_string = this->reserve<UNICODE_STRING<EmulatorTraits<Emu64>>>();
|
||||
|
||||
unicode_string.access(
|
||||
[&](UNICODE_STRING<EmulatorTraits<Emu64>>& unicode_str) { this->make_unicode_string(unicode_str, str); });
|
||||
unicode_string.access([&](UNICODE_STRING<EmulatorTraits<Emu64>>& unicode_str) {
|
||||
this->make_unicode_string(unicode_str, str, maximum_length); //
|
||||
});
|
||||
|
||||
return unicode_string;
|
||||
}
|
||||
|
||||
@@ -7,19 +7,19 @@
|
||||
class file_system
|
||||
{
|
||||
public:
|
||||
file_system(std::filesystem::path root, windows_path working_dir = "C:\\")
|
||||
file_system(std::filesystem::path root)
|
||||
: root_(std::move(root))
|
||||
{
|
||||
this->set_working_directory(std::move(working_dir));
|
||||
}
|
||||
|
||||
std::filesystem::path translate(const windows_path& win_path) const
|
||||
{
|
||||
const auto& full_path = win_path.is_absolute() //
|
||||
? win_path
|
||||
: (this->working_dir_ / win_path);
|
||||
if (!win_path.is_absolute())
|
||||
{
|
||||
throw std::runtime_error("Only absolute paths can be translated!");
|
||||
}
|
||||
|
||||
const auto mapping = this->mappings_.find(full_path);
|
||||
const auto mapping = this->mappings_.find(win_path);
|
||||
if (mapping != this->mappings_.end())
|
||||
{
|
||||
return mapping->second;
|
||||
@@ -28,27 +28,12 @@ class file_system
|
||||
#ifdef OS_WINDOWS
|
||||
if (this->root_.empty())
|
||||
{
|
||||
return full_path.u16string();
|
||||
return win_path.u16string();
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: Sanitize path to prevent traversal!
|
||||
return this->root_ / full_path.to_portable_path();
|
||||
}
|
||||
|
||||
void set_working_directory(windows_path working_dir)
|
||||
{
|
||||
if (!working_dir.is_absolute())
|
||||
{
|
||||
throw std::runtime_error("Working directory is not an absolute path: " + working_dir.string());
|
||||
}
|
||||
|
||||
this->working_dir_ = std::move(working_dir);
|
||||
}
|
||||
|
||||
const windows_path& get_working_directory() const
|
||||
{
|
||||
return this->working_dir_;
|
||||
return this->root_ / win_path.to_portable_path();
|
||||
}
|
||||
|
||||
windows_path local_to_windows_path(const std::filesystem::path& local_path) const
|
||||
@@ -81,16 +66,6 @@ class file_system
|
||||
return windows_path{drive, std::move(folders)};
|
||||
}
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->working_dir_);
|
||||
}
|
||||
|
||||
void deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read(this->working_dir_);
|
||||
}
|
||||
|
||||
void map(windows_path src, std::filesystem::path dest)
|
||||
{
|
||||
this->mappings_[std::move(src)] = std::move(dest);
|
||||
@@ -98,6 +73,5 @@ class file_system
|
||||
|
||||
private:
|
||||
std::filesystem::path root_{};
|
||||
windows_path working_dir_{};
|
||||
std::unordered_map<windows_path, std::filesystem::path> mappings_{};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "io_device.hpp"
|
||||
#include "devices/afd_endpoint.hpp"
|
||||
#include "devices/mount_point_manager.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -28,5 +29,10 @@ std::unique_ptr<io_device> create_device(const std::u16string_view device)
|
||||
return create_afd_endpoint();
|
||||
}
|
||||
|
||||
if (device == u"MountPointManager")
|
||||
{
|
||||
return create_mount_point_manager();
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unsupported device: " + u16_to_u8(device));
|
||||
}
|
||||
|
||||
@@ -1749,51 +1749,58 @@ namespace
|
||||
const emulator_object<IO_STATUS_BLOCK<EmulatorTraits<Emu64>>> io_status_block, const uint64_t file_information,
|
||||
const uint32_t length, const uint32_t info_class)
|
||||
{
|
||||
IO_STATUS_BLOCK<EmulatorTraits<Emu64>> block{};
|
||||
block.Status = STATUS_SUCCESS;
|
||||
block.Information = 0;
|
||||
|
||||
const auto _ = utils::finally([&] {
|
||||
if (io_status_block)
|
||||
{
|
||||
io_status_block.write(block);
|
||||
}
|
||||
});
|
||||
|
||||
const auto ret = [&](const NTSTATUS status) {
|
||||
block.Status = status;
|
||||
return status;
|
||||
};
|
||||
|
||||
const auto* f = c.proc.files.get(file_handle);
|
||||
if (!f)
|
||||
{
|
||||
return STATUS_INVALID_HANDLE;
|
||||
return ret(STATUS_INVALID_HANDLE);
|
||||
}
|
||||
|
||||
if (info_class == FileNameInformation)
|
||||
if (info_class == FileNameInformation || info_class == FileNormalizedNameInformation)
|
||||
{
|
||||
const auto required_length = sizeof(FILE_NAME_INFORMATION) + (f->name.size() * 2);
|
||||
const auto relative_path = u"\\" + windows_path(f->name).without_drive().u16string();
|
||||
const auto required_length = sizeof(FILE_NAME_INFORMATION) + (relative_path.size() * 2);
|
||||
|
||||
if (io_status_block)
|
||||
{
|
||||
IO_STATUS_BLOCK<EmulatorTraits<Emu64>> block{};
|
||||
block.Information = sizeof(FILE_NAME_INFORMATION) + required_length;
|
||||
io_status_block.write(block);
|
||||
}
|
||||
block.Information = required_length;
|
||||
|
||||
if (length != required_length)
|
||||
if (length < block.Information)
|
||||
{
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
return ret(STATUS_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
c.emu.write_memory(file_information, FILE_NAME_INFORMATION{
|
||||
.FileNameLength = static_cast<ULONG>(f->name.size() * 2),
|
||||
.FileNameLength = static_cast<ULONG>(relative_path.size() * 2),
|
||||
.FileName = {},
|
||||
});
|
||||
|
||||
c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), f->name.c_str(),
|
||||
(f->name.size() + 1) * 2);
|
||||
c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), relative_path.c_str(),
|
||||
(relative_path.size() + 1) * 2);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return ret(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
if (info_class == FileStandardInformation)
|
||||
{
|
||||
if (io_status_block)
|
||||
{
|
||||
IO_STATUS_BLOCK<EmulatorTraits<Emu64>> block{};
|
||||
block.Information = sizeof(FILE_STANDARD_INFORMATION);
|
||||
io_status_block.write(block);
|
||||
}
|
||||
block.Information = sizeof(FILE_STANDARD_INFORMATION);
|
||||
|
||||
if (length != sizeof(FILE_STANDARD_INFORMATION))
|
||||
if (length < block.Information)
|
||||
{
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
return ret(STATUS_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
const emulator_object<FILE_STANDARD_INFORMATION> info{c.emu, file_information};
|
||||
@@ -1807,26 +1814,21 @@ namespace
|
||||
|
||||
info.write(i);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return ret(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
if (info_class == FilePositionInformation)
|
||||
{
|
||||
if (!f->handle)
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
return ret(STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
if (io_status_block)
|
||||
{
|
||||
IO_STATUS_BLOCK<EmulatorTraits<Emu64>> block{};
|
||||
block.Information = sizeof(FILE_POSITION_INFORMATION);
|
||||
io_status_block.write(block);
|
||||
}
|
||||
block.Information = sizeof(FILE_POSITION_INFORMATION);
|
||||
|
||||
if (length != sizeof(FILE_POSITION_INFORMATION))
|
||||
if (length < block.Information)
|
||||
{
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
return ret(STATUS_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
const emulator_object<FILE_POSITION_INFORMATION> info{c.emu, file_information};
|
||||
@@ -1836,13 +1838,13 @@ namespace
|
||||
|
||||
info.write(i);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return ret(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
c.win_emu.log.error("Unsupported query file info class: %X\n", info_class);
|
||||
c.emu.stop();
|
||||
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
return ret(STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtSetInformationProcess(const syscall_context& c, const handle process_handle,
|
||||
@@ -2868,6 +2870,22 @@ namespace
|
||||
return mode;
|
||||
}
|
||||
|
||||
std::optional<std::u16string_view> get_io_device_name(const std::u16string_view filename)
|
||||
{
|
||||
constexpr std::u16string_view device_prefix = u"\\Device\\";
|
||||
if (filename.starts_with(device_prefix))
|
||||
{
|
||||
return filename.substr(device_prefix.size());
|
||||
}
|
||||
|
||||
if (filename.starts_with(u"\\??\\MountPointManager"))
|
||||
{
|
||||
return u"MountPointManager";
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtCreateFile(const syscall_context& c, const emulator_object<handle> file_handle,
|
||||
ACCESS_MASK desired_access,
|
||||
const emulator_object<OBJECT_ATTRIBUTES<EmulatorTraits<Emu64>>> object_attributes,
|
||||
@@ -2883,16 +2901,15 @@ namespace
|
||||
auto printer = utils::finally(
|
||||
[&] { c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(filename).c_str()); });
|
||||
|
||||
constexpr std::u16string_view device_prefix = u"\\Device\\";
|
||||
if (filename.starts_with(device_prefix))
|
||||
const auto io_device_name = get_io_device_name(filename);
|
||||
if (io_device_name.has_value())
|
||||
{
|
||||
const io_device_creation_data data{
|
||||
.buffer = ea_buffer,
|
||||
.length = ea_length,
|
||||
};
|
||||
|
||||
auto device_name = filename.substr(device_prefix.size());
|
||||
io_device_container container{std::move(device_name), c.win_emu, data};
|
||||
io_device_container container{std::u16string(*io_device_name), c.win_emu, data};
|
||||
|
||||
const auto handle = c.proc.devices.store(std::move(container));
|
||||
file_handle.write(handle);
|
||||
@@ -2919,7 +2936,8 @@ namespace
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
f.name = root->name + f.name;
|
||||
const auto has_separator = root->name.ends_with(u"\\") || root->name.ends_with(u"/");
|
||||
f.name = root->name + (has_separator ? u"" : u"\\") + f.name;
|
||||
}
|
||||
|
||||
printer.cancel();
|
||||
@@ -3034,12 +3052,44 @@ namespace
|
||||
share_access, FILE_OPEN, open_options, 0, 0);
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryObject(const syscall_context&, const handle /*handle*/,
|
||||
const OBJECT_INFORMATION_CLASS /*object_information_class*/,
|
||||
const emulator_pointer /*object_information*/,
|
||||
const ULONG /*object_information_length*/,
|
||||
const emulator_object<ULONG> /*return_length*/)
|
||||
NTSTATUS handle_NtQueryObject(const syscall_context& c, const handle handle,
|
||||
const OBJECT_INFORMATION_CLASS object_information_class,
|
||||
const emulator_pointer object_information, const ULONG object_information_length,
|
||||
const emulator_object<ULONG> return_length)
|
||||
{
|
||||
if (object_information_class == ObjectNameInformation)
|
||||
{
|
||||
if (handle.value.type != handle_types::file)
|
||||
{
|
||||
c.win_emu.log.error("Unsupported handle type for name information query: %X\n", handle.value.type);
|
||||
c.emu.stop();
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
const auto file = c.proc.files.get(handle);
|
||||
if (!file)
|
||||
{
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
const auto device_path = windows_path(file->name).to_device_path();
|
||||
|
||||
const auto required_size = sizeof(UNICODE_STRING<EmulatorTraits<Emu64>>) + (device_path.size() + 1) * 2;
|
||||
return_length.write(static_cast<ULONG>(required_size));
|
||||
|
||||
if (required_size > object_information_length)
|
||||
{
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
emulator_allocator allocator(c.emu, object_information, object_information_length);
|
||||
allocator.make_unicode_string(device_path);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
c.win_emu.log.error("Unsupported object info class: %X\n", object_information_class);
|
||||
c.emu.stop();
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +209,8 @@ namespace
|
||||
emu.reg<uint16_t>(x64_register::ss, 0x2B);
|
||||
}
|
||||
|
||||
void setup_context(windows_emulator& win_emu, const emulator_settings& settings)
|
||||
void setup_context(windows_emulator& win_emu, const emulator_settings& settings, const windows_path& application,
|
||||
const windows_path& working_dir)
|
||||
{
|
||||
auto& emu = win_emu.emu();
|
||||
auto& context = win_emu.process();
|
||||
@@ -258,7 +259,7 @@ namespace
|
||||
allocator.copy_string(u"SystemRoot=C:\\WINDOWS");
|
||||
allocator.copy_string(u"");
|
||||
|
||||
const auto application_str = settings.application.u16string();
|
||||
const auto application_str = application.u16string();
|
||||
|
||||
std::u16string command_line = u"\"" + application_str + u"\"";
|
||||
|
||||
@@ -269,8 +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());
|
||||
allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, working_dir.u16string() + u"\\", 1024);
|
||||
allocator.make_unicode_string(proc_params.ImagePathName, application_str);
|
||||
|
||||
const auto total_length = allocator.get_next_address() - context.process_params.value();
|
||||
@@ -829,19 +829,21 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c
|
||||
std::unique_ptr<x64_emulator> emu)
|
||||
: windows_emulator(settings.emulation_root, std::move(emu))
|
||||
{
|
||||
windows_path working_dir{};
|
||||
|
||||
if (!settings.working_directory.empty())
|
||||
{
|
||||
this->file_sys().set_working_directory(settings.working_directory);
|
||||
working_dir = settings.working_directory;
|
||||
}
|
||||
#ifdef OS_WINDOWS
|
||||
else if (settings.application.is_relative())
|
||||
{
|
||||
this->file_sys().set_working_directory(std::filesystem::current_path());
|
||||
working_dir = std::filesystem::current_path();
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
this->file_sys().set_working_directory(settings.application.parent());
|
||||
working_dir = settings.application.parent();
|
||||
}
|
||||
|
||||
for (const auto& mapping : settings.path_mappings)
|
||||
@@ -859,7 +861,7 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c
|
||||
this->use_relative_time_ = settings.use_relative_time;
|
||||
this->log.disable_output(settings.disable_logging || this->silent_until_main_);
|
||||
this->callbacks_ = std::move(callbacks);
|
||||
this->setup_process(settings);
|
||||
this->setup_process(settings, working_dir);
|
||||
}
|
||||
|
||||
windows_emulator::windows_emulator(const std::filesystem::path& emulation_root, std::unique_ptr<x64_emulator> emu)
|
||||
@@ -878,16 +880,22 @@ windows_emulator::windows_emulator(const std::filesystem::path& emulation_root,
|
||||
this->setup_hooks();
|
||||
}
|
||||
|
||||
void windows_emulator::setup_process(const emulator_settings& settings)
|
||||
windows_emulator::~windows_emulator() = default;
|
||||
|
||||
void windows_emulator::setup_process(const emulator_settings& settings, const windows_path& working_directory)
|
||||
{
|
||||
auto& emu = this->emu();
|
||||
|
||||
auto& context = this->process();
|
||||
context.mod_manager = module_manager(emu, this->file_sys()); // TODO: Cleanup module manager
|
||||
|
||||
setup_context(*this, settings);
|
||||
const auto application = settings.application.is_absolute() //
|
||||
? settings.application
|
||||
: (working_directory / settings.application);
|
||||
|
||||
context.executable = context.mod_manager.map_module(settings.application, this->log, true);
|
||||
setup_context(*this, settings, application, working_directory);
|
||||
|
||||
context.executable = context.mod_manager.map_module(application, this->log, true);
|
||||
|
||||
context.peb.access([&](PEB64& peb) {
|
||||
peb.ImageBaseAddress = reinterpret_cast<std::uint64_t*>(context.executable->image_base); //
|
||||
@@ -1154,7 +1162,6 @@ void windows_emulator::serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->switch_thread_);
|
||||
buffer.write(this->use_relative_time_);
|
||||
this->file_sys().serialize(buffer);
|
||||
this->emu().serialize(buffer);
|
||||
this->process_.serialize(buffer);
|
||||
this->dispatcher_.serialize(buffer);
|
||||
@@ -1172,7 +1179,6 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer)
|
||||
|
||||
buffer.read(this->switch_thread_);
|
||||
buffer.read(this->use_relative_time_);
|
||||
this->file_sys().deserialize(buffer);
|
||||
|
||||
this->emu().deserialize(buffer);
|
||||
this->process_.deserialize(buffer);
|
||||
@@ -1184,7 +1190,6 @@ void windows_emulator::save_snapshot()
|
||||
this->emu().save_snapshot();
|
||||
|
||||
utils::buffer_serializer serializer{};
|
||||
this->file_sys().serialize(serializer);
|
||||
this->process_.serialize(serializer);
|
||||
|
||||
this->process_snapshot_ = serializer.move_buffer();
|
||||
@@ -1204,7 +1209,6 @@ void windows_emulator::restore_snapshot()
|
||||
this->emu().restore_snapshot();
|
||||
|
||||
utils::buffer_deserializer deserializer{this->process_snapshot_};
|
||||
this->file_sys().deserialize(deserializer);
|
||||
this->process_.deserialize(deserializer);
|
||||
// this->process_ = *this->process_snapshot_;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class windows_emulator
|
||||
windows_emulator& operator=(windows_emulator&&) = delete;
|
||||
windows_emulator& operator=(const windows_emulator&) = delete;
|
||||
|
||||
~windows_emulator() = default;
|
||||
~windows_emulator();
|
||||
|
||||
x64_emulator& emu()
|
||||
{
|
||||
@@ -211,6 +211,6 @@ class windows_emulator
|
||||
// std::optional<process_context> process_snapshot_{};
|
||||
|
||||
void setup_hooks();
|
||||
void setup_process(const emulator_settings& settings);
|
||||
void setup_process(const emulator_settings& settings, const windows_path& working_directory);
|
||||
void on_instruction_execution(uint64_t address);
|
||||
};
|
||||
|
||||
@@ -74,7 +74,8 @@ class windows_path
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(!std::is_same_v<T, windows_path> && !std::is_same_v<T, std::filesystem::path>)
|
||||
requires(!std::is_same_v<std::remove_cvref_t<T>, windows_path> &&
|
||||
!std::is_same_v<std::remove_cvref_t<T>, std::filesystem::path>)
|
||||
windows_path(T&& path_like)
|
||||
: windows_path(std::filesystem::path(std::forward<T>(path_like)))
|
||||
{
|
||||
@@ -155,6 +156,35 @@ class windows_path
|
||||
return path;
|
||||
}
|
||||
|
||||
std::u16string to_device_path() const
|
||||
{
|
||||
if (is_relative())
|
||||
{
|
||||
throw std::runtime_error("Device path can not be computed for relative paths!");
|
||||
}
|
||||
|
||||
const auto drive_index = *this->drive_ - 'a';
|
||||
const auto drive_number = std::to_string(drive_index + 1);
|
||||
const std::u16string number(drive_number.begin(), drive_number.end());
|
||||
|
||||
std::u16string path = u"\\Device\\HarddiskVolume";
|
||||
path.append(number);
|
||||
path.push_back(u'\\');
|
||||
path.append(this->without_drive().u16string());
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
std::optional<char> get_drive() const
|
||||
{
|
||||
return this->drive_;
|
||||
}
|
||||
|
||||
windows_path without_drive() const
|
||||
{
|
||||
return windows_path{std::nullopt, this->folders_};
|
||||
}
|
||||
|
||||
windows_path operator/(const windows_path& path) const
|
||||
{
|
||||
if (path.is_absolute())
|
||||
|
||||
Reference in New Issue
Block a user