diff --git a/src/common/platform/registry.hpp b/src/common/platform/registry.hpp index af2d7286..1543bbf4 100644 --- a/src/common/platform/registry.hpp +++ b/src/common/platform/registry.hpp @@ -110,4 +110,12 @@ struct KEY_VALUE_FULL_INFORMATION char16_t Name[1]; }; +struct KEY_VALUE_ENTRY +{ + EmulatorTraits::PVOID ValueName; + ULONG DataLength; + ULONG DataOffset; + ULONG Type; +}; + // NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) diff --git a/src/common/platform/status.hpp b/src/common/platform/status.hpp index aafc55f2..14c9e6c3 100644 --- a/src/common/platform/status.hpp +++ b/src/common/platform/status.hpp @@ -50,6 +50,7 @@ using NTSTATUS = std::uint32_t; #define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL) #define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) #define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) +#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL) #define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS)0xC000009FL) #define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L) #define STATUS_PIPE_BUSY ((NTSTATUS)0xC00000AAL) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 2818ac75..d8d02f22 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -233,6 +233,9 @@ namespace syscalls emulator_object>> value_name, KEY_VALUE_INFORMATION_CLASS key_value_information_class, uint64_t key_value_information, ULONG length, emulator_object result_length); + NTSTATUS handle_NtQueryMultipleValueKey(const syscall_context& c, handle key_handle, emulator_object value_entries, + ULONG entry_count, uint64_t value_buffer, emulator_object buffer_length, + emulator_object required_buffer_length); NTSTATUS handle_NtCreateKey(const syscall_context& c, emulator_object key_handle, ACCESS_MASK desired_access, emulator_object>> object_attributes, ULONG /*title_index*/, emulator_object>> /*class*/, ULONG /*create_options*/, @@ -1159,6 +1162,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtSetInformationFile); add_handler(NtUserRegisterWindowMessage); add_handler(NtQueryValueKey); + add_handler(NtQueryMultipleValueKey); add_handler(NtQueryKey); add_handler(NtGetNlsSectionPtr); add_handler(NtAccessCheck); diff --git a/src/windows-emulator/syscalls/registry.cpp b/src/windows-emulator/syscalls/registry.cpp index baf880dd..cc8bb7b2 100644 --- a/src/windows-emulator/syscalls/registry.cpp +++ b/src/windows-emulator/syscalls/registry.cpp @@ -261,6 +261,86 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } + NTSTATUS handle_NtQueryMultipleValueKey(const syscall_context& c, const handle key_handle, + const emulator_object value_entries, const ULONG entry_count, + const uint64_t value_buffer, const emulator_object buffer_length, + const emulator_object required_buffer_length) + { + if (entry_count > 0x10000) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + const auto* key = c.proc.registry_keys.get(key_handle); + if (!key) + { + return STATUS_INVALID_HANDLE; + } + + NTSTATUS status = STATUS_SUCCESS; + auto remaining_length = buffer_length.read(); + ULONG required_length = 0; + ULONG written_bytes = 0; + + for (ULONG i = 0; i < entry_count; i++) + { + auto entry = value_entries.read(i); + if (!entry.ValueName) + { + status = STATUS_INVALID_PARAMETER; + break; + } + + const auto query_name = read_unicode_string(c.emu, entry.ValueName); + + if (c.win_emu.callbacks.on_generic_access) + { + // TODO: Find a better way to log this + c.win_emu.callbacks.on_generic_access("Querying multiple value key ", query_name + u" (" + key->to_string() + u")"); + } + + const auto value = c.win_emu.registry.get_value(*key, u16_to_u8(query_name)); + if (!value) + { + status = STATUS_OBJECT_NAME_NOT_FOUND; + break; + } + + const auto data_length = static_cast(value->data.size()); + + if (status == STATUS_SUCCESS) + { + if (remaining_length >= data_length) + { + entry.DataOffset = written_bytes; + entry.DataLength = data_length; + entry.Type = value->type; + + c.emu.write_memory(value_buffer + entry.DataOffset, value->data.data(), entry.DataLength); + value_entries.write(entry, i); + + remaining_length -= data_length; + written_bytes += data_length; + } + else + { + status = STATUS_BUFFER_OVERFLOW; + } + } + + required_length += data_length; + } + + buffer_length.write(written_bytes); + + if (required_buffer_length.value()) + { + required_buffer_length.write(required_length); + } + + return status; + } + NTSTATUS handle_NtCreateKey(const syscall_context& c, const emulator_object key_handle, const ACCESS_MASK desired_access, const emulator_object>> object_attributes, const ULONG /*title_index*/, const emulator_object>> /*class*/,