Fix path syscalls

This commit is contained in:
momo5502
2025-02-08 12:47:20 +01:00
parent 55557006c7
commit b5a0f73113
6 changed files with 206 additions and 44 deletions

View File

@@ -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;

View 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>();
}

View File

@@ -0,0 +1,4 @@
#pragma once
#include "../io_device.hpp"
std::unique_ptr<io_device> create_mount_point_manager();

View File

@@ -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));
}

View File

@@ -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);
@@ -3034,12 +3051,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;
}

View File

@@ -155,6 +155,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())