diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 06bb6e7a..f604eacd 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -198,6 +198,33 @@ void process_context::deserialize(utils::buffer_deserializer& buffer) this->active_thread = this->threads.get(buffer.read()); } +generic_handle_store* process_context::get_handle_store(const handle handle) +{ + switch (handle.value.type) + { + case handle_types::thread: + return &threads; + case handle_types::event: + return &events; + case handle_types::file: + return &files; + case handle_types::device: + return &devices; + case handle_types::semaphore: + return &semaphores; + case handle_types::registry: + return ®istry_keys; + case handle_types::mutant: + return &mutants; + case handle_types::port: + return &ports; + case handle_types::section: + return §ions; + default: + return nullptr; + } +} + handle process_context::create_thread(memory_manager& memory, const uint64_t start_address, const uint64_t argument, const uint64_t stack_size, const bool suspended) { @@ -205,4 +232,4 @@ handle process_context::create_thread(memory_manager& memory, const uint64_t sta auto [h, thr] = this->threads.store_and_get(std::move(t)); this->callbacks_->on_create_thread(h, *thr); return h; -} +} \ No newline at end of file diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index abbecfed..f01647b4 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -54,6 +54,8 @@ struct process_context void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); + generic_handle_store* get_handle_store(handle handle); + callbacks* callbacks_{}; uint64_t current_ip{0}; @@ -90,4 +92,4 @@ struct process_context uint32_t spawned_thread_count{0}; handle_store threads{}; emulator_thread* active_thread{nullptr}; -}; +}; \ No newline at end of file diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 0665b967..414c7514 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -16,8 +15,298 @@ #include -namespace +namespace syscalls { + // syscalls/event.cpp: + NTSTATUS handle_NtSetEvent(const syscall_context& c, uint64_t handle, emulator_object previous_state); + NTSTATUS handle_NtTraceEvent(); + NTSTATUS handle_NtClearEvent(const syscall_context& c, handle event_handle); + NTSTATUS handle_NtCreateEvent(const syscall_context& c, emulator_object event_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes, + EVENT_TYPE event_type, BOOLEAN initial_state); + NTSTATUS handle_NtOpenEvent(const syscall_context& c, emulator_object event_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes); + + // syscalls/exception.cpp + NTSTATUS handle_NtRaiseHardError(const syscall_context& c, NTSTATUS error_status, ULONG /*number_of_parameters*/, + emulator_object>> + /*unicode_string_parameter_mask*/, + emulator_object /*parameters*/, + HARDERROR_RESPONSE_OPTION /*valid_response_option*/, + emulator_object response); + NTSTATUS handle_NtRaiseException(const syscall_context& c, + emulator_object>> + /*exception_record*/, + emulator_object thread_context, BOOLEAN handle_exception); + + // syscalls/file.cpp + NTSTATUS handle_NtSetInformationFile(const syscall_context& c, handle file_handle, + emulator_object>> io_status_block, + uint64_t file_information, ULONG length, FILE_INFORMATION_CLASS info_class); + NTSTATUS handle_NtQueryVolumeInformationFile(const syscall_context& c, handle file_handle, + uint64_t /*io_status_block*/, uint64_t fs_information, + ULONG /*length*/, FS_INFORMATION_CLASS fs_information_class); + NTSTATUS handle_NtQueryDirectoryFileEx(const syscall_context& c, handle file_handle, handle /*event_handle*/, + emulator_pointer /*PIO_APC_ROUTINE*/ /*apc_routine*/, + emulator_pointer /*apc_context*/, + emulator_object>> io_status_block, + uint64_t file_information, uint32_t length, uint32_t info_class, + ULONG query_flags, + emulator_object>> /*file_name*/); + NTSTATUS handle_NtQueryInformationFile(const syscall_context& c, handle file_handle, + emulator_object>> io_status_block, + uint64_t file_information, uint32_t length, uint32_t info_class); + NTSTATUS handle_NtReadFile(const syscall_context& c, handle file_handle, uint64_t /*event*/, + uint64_t /*apc_routine*/, uint64_t /*apc_context*/, + emulator_object>> io_status_block, uint64_t buffer, + ULONG length, emulator_object /*byte_offset*/, + emulator_object /*key*/); + NTSTATUS handle_NtWriteFile(const syscall_context& c, handle file_handle, uint64_t /*event*/, + uint64_t /*apc_routine*/, uint64_t /*apc_context*/, + emulator_object>> io_status_block, + uint64_t buffer, ULONG length, emulator_object /*byte_offset*/, + emulator_object /*key*/); + NTSTATUS handle_NtCreateFile(const syscall_context& c, emulator_object file_handle, + ACCESS_MASK desired_access, + emulator_object>> object_attributes, + emulator_object>> /*io_status_block*/, + emulator_object /*allocation_size*/, ULONG /*file_attributes*/, + ULONG /*share_access*/, ULONG create_disposition, ULONG create_options, + uint64_t ea_buffer, ULONG ea_length); + NTSTATUS handle_NtQueryAttributesFile(const syscall_context& c, + emulator_object>> object_attributes, + emulator_object file_information); + NTSTATUS handle_NtOpenFile(const syscall_context& c, emulator_object file_handle, + ACCESS_MASK desired_access, + emulator_object>> object_attributes, + emulator_object>> io_status_block, + ULONG share_access, ULONG open_options); + NTSTATUS handle_NtOpenDirectoryObject(const syscall_context& c, emulator_object directory_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes); + NTSTATUS handle_NtOpenSymbolicLinkObject( + const syscall_context& c, emulator_object link_handle, ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes); + NTSTATUS handle_NtQuerySymbolicLinkObject(const syscall_context& c, handle link_handle, + emulator_object>> link_target, + emulator_object returned_length); + + // syscalls/locale.cpp: + NTSTATUS handle_NtInitializeNlsFiles(const syscall_context& c, emulator_object base_address, + emulator_object default_locale_id, + emulator_object /*default_casing_table_size*/); + NTSTATUS handle_NtQueryDefaultLocale(const syscall_context&, BOOLEAN /*user_profile*/, + emulator_object default_locale_id); + NTSTATUS handle_NtGetNlsSectionPtr(); + NTSTATUS handle_NtGetMUIRegistryInfo(); + NTSTATUS handle_NtIsUILanguageComitted(); + NTSTATUS handle_NtUserGetKeyboardLayout(); + NTSTATUS handle_NtQueryInstallUILanguage(); + + // syscalls/memory.cpp: + NTSTATUS handle_NtQueryVirtualMemory(const syscall_context& c, handle process_handle, uint64_t base_address, + uint32_t info_class, uint64_t memory_information, + uint32_t memory_information_length, emulator_object return_length); + NTSTATUS handle_NtProtectVirtualMemory(const syscall_context& c, handle process_handle, + emulator_object base_address, + emulator_object bytes_to_protect, uint32_t protection, + emulator_object old_protection); + NTSTATUS handle_NtAllocateVirtualMemoryEx(const syscall_context& c, handle process_handle, + emulator_object base_address, + emulator_object bytes_to_allocate, uint32_t allocation_type, + uint32_t page_protection); + NTSTATUS handle_NtAllocateVirtualMemory(const syscall_context& c, handle process_handle, + emulator_object base_address, uint64_t /*zero_bits*/, + emulator_object bytes_to_allocate, uint32_t allocation_type, + uint32_t page_protection); + NTSTATUS handle_NtFreeVirtualMemory(const syscall_context& c, handle process_handle, + emulator_object base_address, + emulator_object bytes_to_allocate, uint32_t free_type); + NTSTATUS handle_NtReadVirtualMemory(const syscall_context& c, handle process_handle, emulator_pointer base_address, + emulator_pointer buffer, ULONG number_of_bytes_to_read, + emulator_object number_of_bytes_read); + NTSTATUS handle_NtSetInformationVirtualMemory(); + + // syscalls/mutant.cpp: + NTSTATUS handle_NtReleaseMutant(const syscall_context& c, handle mutant_handle, + emulator_object previous_count); + NTSTATUS handle_NtCreateMutant(const syscall_context& c, emulator_object mutant_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes, + BOOLEAN initial_owner); + + // syscalls/object.cpp: + NTSTATUS handle_NtClose(const syscall_context& c, handle h); + NTSTATUS handle_NtDuplicateObject(const syscall_context& c, handle source_process_handle, handle source_handle, + handle target_process_handle, emulator_object target_handle, + ACCESS_MASK /*desired_access*/, ULONG /*handle_attributes*/, ULONG /*options*/); + NTSTATUS handle_NtQueryObject(const syscall_context& c, handle handle, + OBJECT_INFORMATION_CLASS object_information_class, + emulator_pointer object_information, ULONG object_information_length, + emulator_object return_length); + NTSTATUS handle_NtWaitForMultipleObjects(const syscall_context& c, ULONG count, emulator_object handles, + WAIT_TYPE wait_type, BOOLEAN alertable, + emulator_object timeout); + NTSTATUS handle_NtWaitForSingleObject(const syscall_context& c, handle h, BOOLEAN alertable, + emulator_object timeout); + NTSTATUS handle_NtSetInformationObject(); + + // syscalls/port.cpp: + NTSTATUS handle_NtConnectPort(const syscall_context& c, emulator_object client_port_handle, + emulator_object>> server_port_name, + emulator_object /*security_qos*/, + emulator_object client_shared_memory, + emulator_object /*server_shared_memory*/, + emulator_object /*maximum_message_length*/, emulator_pointer connection_info, + emulator_object connection_info_length); + NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& c, handle port_handle, ULONG /*flags*/, + emulator_object /*send_message*/, + emulator_object + /*send_message_attributes*/, + emulator_object receive_message, + emulator_object::SIZE_T> /*buffer_length*/, + emulator_object + /*receive_message_attributes*/, + emulator_object /*timeout*/); + NTSTATUS handle_NtAlpcConnectPort(); + + // syscalls/process.cpp: + NTSTATUS handle_NtQueryInformationProcess(const syscall_context& c, handle process_handle, uint32_t info_class, + uint64_t process_information, uint32_t process_information_length, + emulator_object return_length); + NTSTATUS handle_NtSetInformationProcess(const syscall_context& c, handle process_handle, uint32_t info_class, + uint64_t process_information, uint32_t process_information_length); + NTSTATUS handle_NtOpenProcessToken(const syscall_context&, handle process_handle, ACCESS_MASK /*desired_access*/, + emulator_object token_handle); + NTSTATUS handle_NtOpenProcessTokenEx(const syscall_context& c, handle process_handle, ACCESS_MASK desired_access, + ULONG /*handle_attributes*/, emulator_object token_handle); + NTSTATUS handle_NtTerminateProcess(const syscall_context& c, handle process_handle, NTSTATUS exit_status); + + // syscalls/registry.cpp: + NTSTATUS handle_NtOpenKey(const syscall_context& c, emulator_object key_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes); + NTSTATUS handle_NtOpenKeyEx(const syscall_context& c, emulator_object key_handle, + ACCESS_MASK desired_access, + emulator_object>> object_attributes, + ULONG /*open_options*/); + NTSTATUS handle_NtQueryKey(const syscall_context& c, handle key_handle, KEY_INFORMATION_CLASS key_information_class, + uint64_t key_information, ULONG length, emulator_object result_length); + NTSTATUS handle_NtQueryValueKey(const syscall_context& c, handle key_handle, + 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_NtCreateKey(); + NTSTATUS handle_NtNotifyChangeKey(); + NTSTATUS handle_NtSetInformationKey(); + NTSTATUS handle_NtEnumerateKey(); + + // syscalls/section.cpp: + NTSTATUS handle_NtCreateSection(const syscall_context& c, emulator_object section_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes, + emulator_object maximum_size, ULONG section_page_protection, + ULONG allocation_attributes, handle file_handle); + NTSTATUS handle_NtOpenSection(const syscall_context& c, emulator_object section_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes); + NTSTATUS handle_NtMapViewOfSection(const syscall_context& c, handle section_handle, handle process_handle, + emulator_object base_address, + EMULATOR_CAST(EmulatorTraits::ULONG_PTR, ULONG_PTR) /*zero_bits*/, + EMULATOR_CAST(EmulatorTraits::SIZE_T, SIZE_T) /*commit_size*/, + emulator_object /*section_offset*/, + emulator_object::SIZE_T, SIZE_T)> view_size, + SECTION_INHERIT /*inherit_disposition*/, ULONG /*allocation_type*/, + ULONG /*win32_protect*/); + NTSTATUS handle_NtUnmapViewOfSection(const syscall_context& c, handle process_handle, uint64_t base_address); + NTSTATUS handle_NtUnmapViewOfSectionEx(const syscall_context& c, handle process_handle, uint64_t base_address, + ULONG /*flags*/); + + // syscalls/semaphore.cpp: + NTSTATUS handle_NtOpenSemaphore(const syscall_context& c, emulator_object semaphore_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes); + NTSTATUS handle_NtReleaseSemaphore(const syscall_context& c, handle semaphore_handle, ULONG release_count, + emulator_object previous_count); + NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, emulator_object semaphore_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> object_attributes, + ULONG initial_count, ULONG maximum_count); + + // syscalls/system.cpp: + NTSTATUS handle_NtQuerySystemInformation(const syscall_context& c, uint32_t info_class, uint64_t system_information, + uint32_t system_information_length, + emulator_object return_length); + NTSTATUS handle_NtQuerySystemInformationEx(const syscall_context& c, uint32_t info_class, uint64_t input_buffer, + uint32_t input_buffer_length, uint64_t system_information, + uint32_t system_information_length, + emulator_object return_length); + NTSTATUS handle_NtSetSystemInformation(); + + // syscalls/thread.cpp: + NTSTATUS handle_NtSetInformationThread(const syscall_context& c, handle thread_handle, THREADINFOCLASS info_class, + uint64_t thread_information, uint32_t thread_information_length); + + NTSTATUS handle_NtQueryInformationThread(const syscall_context& c, handle thread_handle, uint32_t info_class, + uint64_t thread_information, uint32_t thread_information_length, + emulator_object return_length); + NTSTATUS handle_NtOpenThreadToken(const syscall_context&, handle thread_handle, ACCESS_MASK /*desired_access*/, + BOOLEAN /*open_as_self*/, emulator_object token_handle); + NTSTATUS handle_NtOpenThreadTokenEx(const syscall_context& c, handle thread_handle, ACCESS_MASK desired_access, + BOOLEAN open_as_self, ULONG /*handle_attributes*/, + emulator_object token_handle); + NTSTATUS handle_NtTerminateThread(const syscall_context& c, handle thread_handle, NTSTATUS exit_status); + NTSTATUS handle_NtDelayExecution(const syscall_context& c, BOOLEAN alertable, + emulator_object delay_interval); + NTSTATUS handle_NtAlertThreadByThreadId(const syscall_context& c, uint64_t thread_id); + NTSTATUS handle_NtAlertThreadByThreadIdEx(const syscall_context& c, uint64_t thread_id, + emulator_object>> lock); + NTSTATUS handle_NtWaitForAlertByThreadId(const syscall_context& c, uint64_t, + emulator_object timeout); + NTSTATUS handle_NtYieldExecution(const syscall_context& c); + NTSTATUS handle_NtResumeThread(const syscall_context& c, handle thread_handle, + emulator_object previous_suspend_count); + NTSTATUS handle_NtContinue(const syscall_context& c, emulator_object thread_context, + BOOLEAN /*raise_alert*/); + NTSTATUS handle_NtGetNextThread(const syscall_context& c, handle process_handle, handle thread_handle, + ACCESS_MASK /*desired_access*/, ULONG /*handle_attributes*/, ULONG flags, + emulator_object new_thread_handle); + NTSTATUS handle_NtGetContextThread(const syscall_context& c, handle thread_handle, + emulator_object thread_context); + NTSTATUS handle_NtSetContextThread(const syscall_context& c, handle thread_handle, + emulator_object thread_context); + NTSTATUS handle_NtCreateThreadEx(const syscall_context& c, emulator_object thread_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> + /*object_attributes*/, + handle process_handle, uint64_t start_routine, uint64_t argument, + ULONG create_flags, EmulatorTraits::SIZE_T /*zero_bits*/, + EmulatorTraits::SIZE_T stack_size, + EmulatorTraits::SIZE_T /*maximum_stack_size*/, + emulator_object>> attribute_list); + NTSTATUS handle_NtGetCurrentProcessorNumberEx(const syscall_context&, + emulator_object processor_number); + + // syscalls/timer.cpp: + NTSTATUS handle_NtQueryTimerResolution(const syscall_context&, emulator_object maximum_time, + emulator_object minimum_time, emulator_object current_time); + NTSTATUS handle_NtSetTimerResolution(const syscall_context&, ULONG /*desired_resolution*/, BOOLEAN set_resolution, + emulator_object current_resolution); + + // syscalls/token.cpp: + NTSTATUS handle_NtDuplicateToken(const syscall_context&, handle existing_token_handle, + ACCESS_MASK /*desired_access*/, + emulator_object>> + /*object_attributes*/, + BOOLEAN /*effective_only*/, TOKEN_TYPE type, + emulator_object new_token_handle); + NTSTATUS handle_NtQueryInformationToken(const syscall_context& c, handle token_handle, + TOKEN_INFORMATION_CLASS token_information_class, uint64_t token_information, + ULONG token_information_length, emulator_object return_length); + NTSTATUS handle_NtQuerySecurityAttributesToken(); + NTSTATUS handle_NtQueryPerformanceCounter(const syscall_context& c, const emulator_object performance_counter, const emulator_object performance_frequency) @@ -56,814 +345,6 @@ namespace return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtOpenKey(const syscall_context& c, const emulator_object key_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - const auto attributes = object_attributes.read(); - auto key = - read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); - - if (attributes.RootDirectory) - { - const auto* parent_handle = c.proc.registry_keys.get(attributes.RootDirectory); - if (!parent_handle) - { - return STATUS_INVALID_HANDLE; - } - - const std::filesystem::path full_path = parent_handle->hive.get() / parent_handle->path.get() / key; - key = full_path.u16string(); - } - - c.win_emu.log.print(color::dark_gray, "--> Registry key: %s\n", u16_to_u8(key).c_str()); - - auto entry = c.win_emu.registry.get_key({key}); - if (!entry.has_value()) - { - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - const auto handle = c.proc.registry_keys.store(std::move(entry.value())); - key_handle.write(handle); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenKeyEx(const syscall_context& c, const emulator_object key_handle, - const ACCESS_MASK desired_access, - const emulator_object>> object_attributes, - ULONG /*open_options*/) - { - return handle_NtOpenKey(c, key_handle, desired_access, object_attributes); - } - - NTSTATUS handle_NtQueryKey(const syscall_context& c, const handle key_handle, - const KEY_INFORMATION_CLASS key_information_class, const uint64_t key_information, - const ULONG length, const emulator_object result_length) - { - const auto* key = c.proc.registry_keys.get(key_handle); - if (!key) - { - return STATUS_INVALID_HANDLE; - } - - if (key_information_class == KeyNameInformation) - { - auto key_name = (key->hive.get() / key->path.get()).u16string(); - while (key_name.ends_with(u'/') || key_name.ends_with(u'\\')) - { - key_name.pop_back(); - } - - std::ranges::transform(key_name, key_name.begin(), std::towupper); - - const auto required_size = sizeof(KEY_NAME_INFORMATION) + (key_name.size() * 2) - 1; - result_length.write(static_cast(required_size)); - - if (required_size > length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - KEY_NAME_INFORMATION info{}; - info.NameLength = static_cast(key_name.size() * 2); - - const emulator_object info_obj{c.emu, key_information}; - info_obj.write(info); - - c.emu.write_memory(key_information + offsetof(KEY_NAME_INFORMATION, Name), key_name.data(), - info.NameLength); - - return STATUS_SUCCESS; - } - - if (key_information_class == KeyFullInformation) - { - return STATUS_NOT_SUPPORTED; - } - - if (key_information_class == KeyHandleTagsInformation) - { - constexpr auto required_size = sizeof(KEY_HANDLE_TAGS_INFORMATION); - result_length.write(required_size); - - if (required_size > length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - KEY_HANDLE_TAGS_INFORMATION info{}; - info.HandleTags = 0; // ? - - const emulator_object info_obj{c.emu, key_information}; - info_obj.write(info); - - return STATUS_SUCCESS; - } - - c.win_emu.log.print(color::gray, "Unsupported registry class: %X\n", key_information_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryValueKey(const syscall_context& c, const handle key_handle, - const emulator_object>> value_name, - const KEY_VALUE_INFORMATION_CLASS key_value_information_class, - const uint64_t key_value_information, const ULONG length, - const emulator_object result_length) - { - const auto* key = c.proc.registry_keys.get(key_handle); - if (!key) - { - return STATUS_INVALID_HANDLE; - } - - const auto query_name = read_unicode_string(c.emu, value_name); - - const auto value = c.win_emu.registry.get_value(*key, u16_to_u8(query_name)); - if (!value) - { - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - const std::u16string original_name(value->name.begin(), value->name.end()); - - if (key_value_information_class == KeyValueBasicInformation) - { - constexpr auto base_size = offsetof(KEY_VALUE_BASIC_INFORMATION, Name); - const auto required_size = base_size + (original_name.size() * 2) - 1; - result_length.write(static_cast(required_size)); - - KEY_VALUE_BASIC_INFORMATION info{}; - info.TitleIndex = 0; - info.Type = value->type; - info.NameLength = static_cast(original_name.size() * 2); - - if (base_size <= length) - { - c.emu.write_memory(key_value_information, &info, base_size); - } - - if (required_size > length) - { - return STATUS_BUFFER_OVERFLOW; - } - - c.emu.write_memory(key_value_information + base_size, original_name.data(), info.NameLength); - - return STATUS_SUCCESS; - } - - if (key_value_information_class == KeyValuePartialInformation) - { - constexpr auto base_size = offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data); - const auto required_size = base_size + value->data.size(); - result_length.write(static_cast(required_size)); - - KEY_VALUE_PARTIAL_INFORMATION info{}; - info.TitleIndex = 0; - info.Type = value->type; - info.DataLength = static_cast(value->data.size()); - - if (base_size <= length) - { - c.emu.write_memory(key_value_information, &info, base_size); - } - - if (required_size > length) - { - return STATUS_BUFFER_OVERFLOW; - } - - c.emu.write_memory(key_value_information + base_size, value->data.data(), value->data.size()); - - return STATUS_SUCCESS; - } - - if (key_value_information_class == KeyValueFullInformation) - { - constexpr auto base_size = offsetof(KEY_VALUE_FULL_INFORMATION, Name); - const auto name_size = original_name.size() * 2; - const auto value_size = value->data.size(); - const auto required_size = base_size + name_size + value_size + -1; - result_length.write(static_cast(required_size)); - - KEY_VALUE_FULL_INFORMATION info{}; - info.TitleIndex = 0; - info.Type = value->type; - info.DataLength = static_cast(value->data.size()); - info.NameLength = static_cast(original_name.size() * 2); - - if (base_size <= length) - { - c.emu.write_memory(key_value_information, &info, base_size); - } - - if (required_size > length) - { - return STATUS_BUFFER_OVERFLOW; - } - - c.emu.write_memory(key_value_information + base_size, original_name.data(), info.NameLength); - - c.emu.write_memory(key_value_information + base_size + info.NameLength, value->data.data(), - value->data.size()); - - return STATUS_SUCCESS; - } - - c.win_emu.log.print(color::gray, "Unsupported registry value class: %X\n", key_value_information_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtCreateKey() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtNotifyChangeKey() - { - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtSetInformationThread(const syscall_context& c, const handle thread_handle, - const THREADINFOCLASS info_class, const uint64_t thread_information, - const uint32_t thread_information_length) - { - auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); - - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - if (info_class == ThreadSchedulerSharedDataSlot || info_class == ThreadBasePriority) - { - return STATUS_SUCCESS; - } - - if (info_class == ThreadHideFromDebugger) - { - c.win_emu.log.print(color::pink, "--> Hiding thread %X from debugger!\n", thread->id); - return STATUS_SUCCESS; - } - - if (info_class == ThreadNameInformation) - { - if (thread_information_length != sizeof(THREAD_NAME_INFORMATION>)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object>> info{c.emu, thread_information}; - const auto i = info.read(); - thread->name = read_unicode_string(c.emu, i.ThreadName); - - c.win_emu.log.print(color::blue, "Setting thread (%d) name: %s\n", thread->id, - u16_to_u8(thread->name).c_str()); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadImpersonationToken) - { - if (thread_information_length != sizeof(handle)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, thread_information}; - info.write(DUMMY_IMPERSONATION_TOKEN); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadZeroTlsCell) - { - if (thread_information_length != sizeof(ULONG)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const auto tls_cell = c.emu.read_memory(thread_information); - - for (const auto& t : c.proc.threads | std::views::values) - { - t.teb->access([&](TEB64& teb) { - if (tls_cell < TLS_MINIMUM_AVAILABLE) - { - teb.TlsSlots.arr[tls_cell] = nullptr; - } - else if (teb.TlsExpansionSlots) - { - const emulator_object expansion_slots(c.emu, teb.TlsExpansionSlots); - expansion_slots.write(0, tls_cell - TLS_MINIMUM_AVAILABLE); - } - }); - } - - return STATUS_SUCCESS; - } - - c.win_emu.log.error("Unsupported thread set info class: %X\n", info_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtSetEvent(const syscall_context& c, const uint64_t handle, - const emulator_object previous_state) - { - if (handle == DBWIN_DATA_READY) - { - if (c.proc.dbwin_buffer) - { - constexpr auto pid_length = 4; - const auto debug_data = read_string(c.win_emu.memory, c.proc.dbwin_buffer + pid_length); - c.win_emu.log.info("--> Debug string: %s\n", debug_data.c_str()); - } - - return STATUS_SUCCESS; - } - - auto* entry = c.proc.events.get(handle); - if (!entry) - { - return STATUS_INVALID_HANDLE; - } - - if (previous_state.value()) - { - previous_state.write(entry->signaled ? 1ULL : 0ULL); - } - - entry->signaled = true; - return STATUS_SUCCESS; - } - - generic_handle_store* get_handle_store(process_context& proc, const handle h) - { - switch (h.value.type) - { - case handle_types::thread: - return &proc.threads; - case handle_types::event: - return &proc.events; - case handle_types::file: - return &proc.files; - case handle_types::device: - return &proc.devices; - case handle_types::semaphore: - return &proc.semaphores; - case handle_types::registry: - return &proc.registry_keys; - case handle_types::mutant: - return &proc.mutants; - case handle_types::port: - return &proc.ports; - case handle_types::section: - return &proc.sections; - default: - return nullptr; - } - } - - NTSTATUS handle_NtClose(const syscall_context& c, const handle h) - { - const auto value = h.value; - if (value.is_pseudo) - { - return STATUS_SUCCESS; - } - - if (h.value.type == handle_types::thread) - { - const auto* t = c.proc.threads.get(h); - if (t == c.proc.active_thread && t->ref_count == 1) - { - // TODO: Better handle ref counting - return STATUS_SUCCESS; - } - } - - auto* handle_store = get_handle_store(c.proc, h); - if (handle_store && handle_store->erase(h)) - { - return STATUS_SUCCESS; - } - - return STATUS_INVALID_HANDLE; - } - - NTSTATUS handle_NtTraceEvent() - { - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtReleaseMutant(const syscall_context& c, const handle mutant_handle, - const emulator_object previous_count) - { - if (mutant_handle.value.type != handle_types::mutant) - { - c.win_emu.log.error("Bad handle type for NtReleaseMutant\n"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - auto* mutant = c.proc.mutants.get(mutant_handle); - if (!mutant) - { - return STATUS_INVALID_HANDLE; - } - - const auto [old_count, succeeded] = mutant->release(c.win_emu.current_thread().id); - - if (previous_count) - { - previous_count.write(static_cast(old_count)); - } - - return succeeded ? STATUS_SUCCESS : STATUS_MUTANT_NOT_OWNED; - } - - NTSTATUS handle_NtCreateMutant(const syscall_context& c, const emulator_object mutant_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes, - const BOOLEAN initial_owner) - { - std::u16string name{}; - if (object_attributes) - { - const auto attributes = object_attributes.read(); - if (attributes.ObjectName) - { - name = read_unicode_string( - c.emu, emulator_object>>{c.emu, attributes.ObjectName}); - c.win_emu.log.print(color::dark_gray, "--> Mutant name: %s\n", u16_to_u8(name).c_str()); - } - } - - if (!name.empty()) - { - for (auto& entry : c.proc.mutants) - { - if (entry.second.name == name) - { - ++entry.second.ref_count; - mutant_handle.write(c.proc.mutants.make_handle(entry.first)); - return STATUS_OBJECT_NAME_EXISTS; - } - } - } - - mutant e{}; - e.name = std::move(name); - - if (initial_owner) - { - e.try_lock(c.win_emu.current_thread().id); - } - - const auto handle = c.proc.mutants.store(std::move(e)); - mutant_handle.write(handle); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtClearEvent(const syscall_context& c, const handle event_handle) - { - auto* e = c.proc.events.get(event_handle); - if (!e) - { - return STATUS_INVALID_HANDLE; - } - - e->signaled = false; - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtCreateEvent(const syscall_context& c, const emulator_object event_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes, - const EVENT_TYPE event_type, const BOOLEAN initial_state) - { - std::u16string name{}; - if (object_attributes) - { - const auto attributes = object_attributes.read(); - if (attributes.ObjectName) - { - name = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - } - } - - if (!name.empty()) - { - for (auto& entry : c.proc.events) - { - if (entry.second.name == name) - { - ++entry.second.ref_count; - event_handle.write(c.proc.events.make_handle(entry.first)); - return STATUS_OBJECT_NAME_EXISTS; - } - } - } - - event e{}; - e.type = event_type; - e.signaled = initial_state != FALSE; - e.name = std::move(name); - - const auto handle = c.proc.events.store(std::move(e)); - event_handle.write(handle); - - static_assert(sizeof(EVENT_TYPE) == sizeof(uint32_t)); - static_assert(sizeof(ACCESS_MASK) == sizeof(uint32_t)); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenEvent(const syscall_context& c, const emulator_object event_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - const auto attributes = object_attributes.read(); - const auto name = - read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); - c.win_emu.log.print(color::dark_gray, "--> Event name: %s\n", u16_to_u8(name).c_str()); - - if (name == u"\\KernelObjects\\SystemErrorPortReady") - { - event_handle.write(WER_PORT_READY.bits); - return STATUS_SUCCESS; - } - - if (name == u"DBWIN_DATA_READY") - { - event_handle.write(DBWIN_DATA_READY.bits); - return STATUS_SUCCESS; - } - - if (name == u"DBWIN_BUFFER_READY") - { - event_handle.write(DBWIN_BUFFER_READY.bits); - return STATUS_SUCCESS; - } - - for (auto& entry : c.proc.events) - { - if (entry.second.name == name) - { - ++entry.second.ref_count; - event_handle.write(c.proc.events.make_handle(entry.first).bits); - return STATUS_SUCCESS; - } - } - - return STATUS_NOT_FOUND; - } - - NTSTATUS handle_NtQueryVolumeInformationFile(const syscall_context& c, const handle file_handle, - const uint64_t /*io_status_block*/, const uint64_t fs_information, - const ULONG /*length*/, - const FS_INFORMATION_CLASS fs_information_class) - { - if (fs_information_class == FileFsDeviceInformation) - { - const emulator_object info_obj{c.emu, fs_information}; - info_obj.access([&](FILE_FS_DEVICE_INFORMATION& info) { - if (file_handle == STDOUT_HANDLE && !c.win_emu.buffer_stdout) - { - info.DeviceType = FILE_DEVICE_CONSOLE; - info.Characteristics = 0x20000; - } - else - { - info.DeviceType = FILE_DEVICE_DISK; - info.Characteristics = 0x20020; - } - }); - - return STATUS_SUCCESS; - } - - if (fs_information_class == FileFsSizeInformation) - { - const emulator_object info_obj{c.emu, fs_information}; - info_obj.access([&](FILE_FS_SIZE_INFORMATION& info) { - info.BytesPerSector = 0x1000; - info.SectorsPerAllocationUnit = 0x1000; - info.TotalAllocationUnits.QuadPart = 0x10000; - info.AvailableAllocationUnits.QuadPart = 0x1000; - }); - - return STATUS_SUCCESS; - } - - if (fs_information_class == FileFsVolumeInformation) - { - constexpr FILE_FS_VOLUME_INFORMATION volume_info{}; - c.emu.write_memory(fs_information, volume_info); - - return STATUS_SUCCESS; - } - - c.win_emu.log.error("Unsupported fs info class: %X\n", fs_information_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtOpenSection(const syscall_context& c, const emulator_object section_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - const auto attributes = object_attributes.read(); - - auto filename = - read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); - c.win_emu.log.print(color::dark_gray, "--> Opening section: %s\n", u16_to_u8(filename).c_str()); - - if (filename == u"\\Windows\\SharedSection") - { - section_handle.write(SHARED_SECTION); - return STATUS_SUCCESS; - } - - if (filename == u"DBWIN_BUFFER") - { - section_handle.write(DBWIN_BUFFER); - return STATUS_SUCCESS; - } - - if (filename == u"windows_shell_global_counters" // - || filename == u"Global\\__ComCatalogCache__" // - || filename == u"{00020000-0000-1005-8005-0000C06B5161}" // - || filename == u"Global\\{00020000-0000-1005-8005-0000C06B5161}") - { - return STATUS_NOT_SUPPORTED; - } - - if (attributes.RootDirectory != KNOWN_DLLS_DIRECTORY) - { - c.win_emu.log.error("Unsupported section\n"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - utils::string::to_lower_inplace(filename); - - for (auto& section_entry : c.proc.sections) - { - if (section_entry.second.is_image() && section_entry.second.name == filename) - { - section_handle.write(c.proc.sections.make_handle(section_entry.first)); - return STATUS_SUCCESS; - } - } - - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - NTSTATUS handle_NtMapViewOfSection( - const syscall_context& c, const handle section_handle, const handle process_handle, - const emulator_object base_address, - const EMULATOR_CAST(EmulatorTraits::ULONG_PTR, ULONG_PTR) /*zero_bits*/, - const EMULATOR_CAST(EmulatorTraits::SIZE_T, SIZE_T) /*commit_size*/, - const emulator_object /*section_offset*/, - const emulator_object::SIZE_T, SIZE_T)> view_size, - const SECTION_INHERIT /*inherit_disposition*/, const ULONG /*allocation_type*/, const ULONG /*win32_protect*/) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_INVALID_HANDLE; - } - - if (section_handle == SHARED_SECTION) - { - constexpr auto shared_section_size = 0x10000; - - const auto address = c.win_emu.memory.find_free_allocation_base(shared_section_size); - c.win_emu.memory.allocate_memory(address, shared_section_size, memory_permission::read_write); - - const std::u16string_view windows_dir = c.proc.kusd.get().NtSystemRoot.arr; - const auto windows_dir_size = windows_dir.size() * 2; - - constexpr auto windows_dir_offset = 0x10; - c.emu.write_memory(address + 8, windows_dir_offset); - - const auto obj_address = address + windows_dir_offset; - - const emulator_object>> windir_obj{c.emu, obj_address}; - windir_obj.access([&](UNICODE_STRING>& ucs) { - const auto dir_address = kusd_mmio::address() + offsetof(KUSER_SHARED_DATA64, NtSystemRoot); - - ucs.Buffer = dir_address - obj_address; - ucs.Length = static_cast(windows_dir_size); - ucs.MaximumLength = ucs.Length; - }); - - const emulator_object>> sysdir_obj{c.emu, windir_obj.value() + - windir_obj.size()}; - sysdir_obj.access([&](UNICODE_STRING>& ucs) { - c.proc.base_allocator.make_unicode_string(ucs, u"C:\\WINDOWS\\System32"); - ucs.Buffer = ucs.Buffer - obj_address; - }); - - const emulator_object>> base_dir_obj{c.emu, sysdir_obj.value() + - sysdir_obj.size()}; - base_dir_obj.access([&](UNICODE_STRING>& ucs) { - c.proc.base_allocator.make_unicode_string(ucs, u"\\Sessions\\1\\BaseNamedObjects"); - ucs.Buffer = ucs.Buffer - obj_address; - }); - - if (view_size) - { - view_size.write(shared_section_size); - } - - base_address.write(address); - - return STATUS_SUCCESS; - } - - if (section_handle == DBWIN_BUFFER) - { - constexpr auto dbwin_buffer_section_size = 0x1000; - - const auto address = c.win_emu.memory.find_free_allocation_base(dbwin_buffer_section_size); - c.win_emu.memory.allocate_memory(address, dbwin_buffer_section_size, memory_permission::read_write); - c.proc.dbwin_buffer = address; - - if (view_size) - { - view_size.write(dbwin_buffer_section_size); - } - - base_address.write(address); - - return STATUS_SUCCESS; - } - - auto* section_entry = c.proc.sections.get(section_handle); - if (!section_entry) - { - return STATUS_INVALID_HANDLE; - } - - if (section_entry->is_image()) - { - const auto* binary = c.win_emu.mod_manager.map_module(section_entry->file_name, c.win_emu.log); - if (!binary) - { - return STATUS_FILE_INVALID; - } - - std::u16string wide_name(binary->name.begin(), binary->name.end()); - section_entry->name = utils::string::to_lower_consume(wide_name); - - if (view_size.value()) - { - view_size.write(binary->size_of_image); - } - - base_address.write(binary->image_base); - - return STATUS_SUCCESS; - } - - uint64_t size = section_entry->maximum_size; - std::vector file_data{}; - - if (!section_entry->file_name.empty()) - { - if (!utils::io::read_file(section_entry->file_name, &file_data)) - { - return STATUS_INVALID_PARAMETER; - } - - size = page_align_up(file_data.size()); - } - - const auto protection = map_nt_to_emulator_protection(section_entry->section_page_protection); - const auto address = c.win_emu.memory.allocate_memory(size, protection); - - if (!file_data.empty()) - { - c.emu.write_memory(address, file_data.data(), file_data.size()); - } - - if (view_size) - { - view_size.write(size); - } - - base_address.write(address); - return STATUS_SUCCESS; - } - NTSTATUS handle_NtCreateIoCompletion( const syscall_context& c, const emulator_object event_handle, const ACCESS_MASK desired_access, const emulator_object>> object_attributes, @@ -879,1620 +360,11 @@ namespace return handle_NtCreateEvent(c, event_handle, desired_access, object_attributes, NotificationEvent, FALSE); } - NTSTATUS handle_NtQueryVirtualMemory(const syscall_context& c, const handle process_handle, - const uint64_t base_address, const uint32_t info_class, - const uint64_t memory_information, const uint32_t memory_information_length, - const emulator_object return_length) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == MemoryWorkingSetExInformation || info_class == MemoryImageExtensionInformation) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == MemoryBasicInformation) - { - if (return_length) - { - return_length.write(sizeof(EMU_MEMORY_BASIC_INFORMATION64)); - } - - if (memory_information_length != sizeof(EMU_MEMORY_BASIC_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, memory_information}; - - info.access([&](EMU_MEMORY_BASIC_INFORMATION64& image_info) { - const auto region_info = c.win_emu.memory.get_region_info(base_address); - - assert(!region_info.is_committed || region_info.is_reserved); - const auto state = region_info.is_reserved ? MEM_RESERVE : MEM_FREE; - image_info.State = region_info.is_committed ? MEM_COMMIT : state; - image_info.BaseAddress = reinterpret_cast(region_info.start); - image_info.AllocationBase = reinterpret_cast(region_info.allocation_base); - image_info.AllocationProtect = 0; - image_info.PartitionId = 0; - image_info.RegionSize = static_cast(region_info.length); - - image_info.Protect = map_emulator_to_nt_protection(region_info.permissions); - image_info.Type = MEM_PRIVATE; - }); - - return STATUS_SUCCESS; - } - - if (info_class == MemoryImageInformation) - { - if (return_length) - { - return_length.write(sizeof(MEMORY_IMAGE_INFORMATION64)); - } - - if (memory_information_length != sizeof(MEMORY_IMAGE_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const auto* mod = c.win_emu.mod_manager.find_by_address(base_address); - if (!mod) - { - c.win_emu.log.error("Bad address for memory image request: 0x%" PRIx64 "\n", base_address); - return STATUS_INVALID_ADDRESS; - } - - const emulator_object info{c.emu, memory_information}; - - info.access([&](MEMORY_IMAGE_INFORMATION64& image_info) { - image_info.ImageBase = reinterpret_cast(mod->image_base); - image_info.SizeOfImage = static_cast(mod->size_of_image); - image_info.ImageFlags = 0; - }); - - return STATUS_SUCCESS; - } - - if (info_class == MemoryRegionInformation) - { - if (return_length) - { - return_length.write(sizeof(MEMORY_REGION_INFORMATION64)); - } - - if (memory_information_length != sizeof(MEMORY_REGION_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const auto region_info = c.win_emu.memory.get_region_info(base_address); - if (!region_info.is_reserved) - { - return STATUS_INVALID_ADDRESS; - } - - const emulator_object info{c.emu, memory_information}; - - info.access([&](MEMORY_REGION_INFORMATION64& image_info) { - memset(&image_info, 0, sizeof(image_info)); - - image_info.AllocationBase = reinterpret_cast(region_info.allocation_base); - image_info.AllocationProtect = 0; - image_info.PartitionId = 0; - image_info.RegionSize = static_cast(region_info.allocation_length); - image_info.Reserved = 0x10; - }); - - return STATUS_SUCCESS; - } - - c.win_emu.log.error("Unsupported memory info class: %X\n", info_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQuerySystemInformation(const syscall_context& c, const uint32_t info_class, - const uint64_t system_information, - const uint32_t system_information_length, - const emulator_object return_length) - { - if (info_class == SystemFlushInformation || info_class == SystemHypervisorSharedPageInformation || - info_class == 250 // Build 27744 - ) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == SystemTimeOfDayInformation) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_TIMEOFDAY_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_TIMEOFDAY_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_TIMEOFDAY_INFORMATION64& info) { - info.BootTime.QuadPart = 0; - // TODO: Fill - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemRangeStartInformation) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_RANGE_START_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_RANGE_START_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_RANGE_START_INFORMATION64& info) { - info.SystemRangeStart = 0xFFFF800000000000; // - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemProcessorInformation) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_PROCESSOR_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_PROCESSOR_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_PROCESSOR_INFORMATION64& info) { - memset(&info, 0, sizeof(info)); - info.MaximumProcessors = 2; - info.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemNumaProcessorMap) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_NUMA_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_NUMA_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_NUMA_INFORMATION64& info) { - memset(&info, 0, sizeof(info)); - info.ActiveProcessorsGroupAffinity->Mask = 0xFFF; - info.AvailableMemory[0] = 0xFFF; - info.Pad[0] = 0xFFF; - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemErrorPortTimeouts) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_ERROR_PORT_TIMEOUTS)); - } - - if (system_information_length != sizeof(SYSTEM_ERROR_PORT_TIMEOUTS)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_ERROR_PORT_TIMEOUTS& info) { - info.StartTimeout = 0; - info.CommTimeout = 0; - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemKernelDebuggerInformation) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION)); - } - - if (system_information_length != sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_KERNEL_DEBUGGER_INFORMATION& info) { - info.KernelDebuggerEnabled = FALSE; - info.KernelDebuggerNotPresent = TRUE; - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemControlFlowTransition) - { - c.win_emu.log.print(color::pink, "Warbird control flow transition!\n"); - return STATUS_NOT_SUPPORTED; - } - - if (info_class == SystemProcessInformation || info_class == SystemModuleInformation || - info_class == SystemMemoryUsageInformation || info_class == SystemCodeIntegrityPolicyInformation) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) - { - c.win_emu.log.error("Unsupported system info class: %X\n", info_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - if (return_length) - { - return_length.write(sizeof(SYSTEM_BASIC_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info{c.emu, system_information}; - - info.access([&](SYSTEM_BASIC_INFORMATION64& basic_info) { - basic_info.Reserved = 0; - basic_info.TimerResolution = 0x0002625a; - basic_info.PageSize = 0x1000; - basic_info.LowestPhysicalPageNumber = 0x00000001; - basic_info.HighestPhysicalPageNumber = 0x00c9c7ff; - basic_info.AllocationGranularity = ALLOCATION_GRANULARITY; - basic_info.MinimumUserModeAddress = MIN_ALLOCATION_ADDRESS; - basic_info.MaximumUserModeAddress = MAX_ALLOCATION_ADDRESS; - basic_info.ActiveProcessorsAffinityMask = 0x0000000000000fff; - basic_info.NumberOfProcessors = 1; - }); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtDuplicateObject(const syscall_context& c, const handle source_process_handle, - const handle source_handle, const handle target_process_handle, - const emulator_object target_handle, const ACCESS_MASK /*desired_access*/, - const ULONG /*handle_attributes*/, const ULONG /*options*/) - { - if (source_process_handle != CURRENT_PROCESS || target_process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - if (source_handle.value.is_pseudo) - { - target_handle.write(source_handle); - return STATUS_SUCCESS; - } - - auto* store = get_handle_store(c.proc, source_handle); - if (!store) - { - return STATUS_NOT_SUPPORTED; - } - - const auto new_handle = store->duplicate(source_handle); - if (!new_handle) - { - return STATUS_INVALID_HANDLE; - } - - target_handle.write(*new_handle); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQuerySystemInformationEx(const syscall_context& c, const uint32_t info_class, - const uint64_t input_buffer, const uint32_t input_buffer_length, - const uint64_t system_information, - const uint32_t system_information_length, - const emulator_object return_length) - { - if (info_class == SystemFlushInformation || info_class == SystemFeatureConfigurationInformation || - info_class == SystemSupportedProcessorArchitectures2 || - info_class == SystemFeatureConfigurationSectionInformation) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == SystemLogicalProcessorInformation) - { - if (input_buffer_length != sizeof(USHORT)) - { - return STATUS_INVALID_PARAMETER; - } - - using INFO_TYPE = EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION>; - - const auto processor_group = c.emu.read_memory(input_buffer); - constexpr auto required_size = sizeof(INFO_TYPE); - - if (return_length) - { - return_length.write(required_size); - } - - if (system_information_length < required_size) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - - INFO_TYPE information{}; - information.Relationship = RelationProcessorCore; - - if (processor_group == 0) - { - const auto active_processor_count = c.proc.kusd.get().ActiveProcessorCount; - information.ProcessorMask = - (static_cast(1) << active_processor_count) - 1; - } - - c.emu.write_memory(system_information, information); - return STATUS_SUCCESS; - } - - if (info_class == SystemLogicalProcessorAndGroupInformation) - { - if (input_buffer_length != sizeof(LOGICAL_PROCESSOR_RELATIONSHIP)) - { - return STATUS_INVALID_PARAMETER; - } - - const auto request = c.emu.read_memory(input_buffer); - - if (request == RelationGroup) - { - constexpr auto root_size = offsetof(EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX64, Group); - constexpr auto required_size = root_size + sizeof(EMU_GROUP_RELATIONSHIP64); - - if (return_length) - { - return_length.write(required_size); - } - - if (system_information_length < required_size) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - - EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX64 proc_info{}; - proc_info.Size = required_size; - proc_info.Relationship = RelationGroup; - - c.emu.write_memory(system_information, &proc_info, root_size); - - EMU_GROUP_RELATIONSHIP64 group{}; - group.ActiveGroupCount = 1; - group.MaximumGroupCount = 1; - - auto& group_info = group.GroupInfo[0]; - group_info.ActiveProcessorCount = static_cast(c.proc.kusd.get().ActiveProcessorCount); - group_info.ActiveProcessorMask = (1 << group_info.ActiveProcessorCount) - 1; - group_info.MaximumProcessorCount = group_info.ActiveProcessorCount; - - c.emu.write_memory(system_information + root_size, group); - return STATUS_SUCCESS; - } - - if (request == RelationNumaNode || request == RelationNumaNodeEx) - { - constexpr auto root_size = offsetof(EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX64, NumaNode); - constexpr auto required_size = root_size + sizeof(EMU_NUMA_NODE_RELATIONSHIP64); - - if (return_length) - { - return_length.write(required_size); - } - - if (system_information_length < required_size) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - - EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX64 proc_info{}; - proc_info.Size = required_size; - proc_info.Relationship = RelationNumaNode; - - c.emu.write_memory(system_information, &proc_info, root_size); - - EMU_NUMA_NODE_RELATIONSHIP64 numa_node{}; - memset(&numa_node, 0, sizeof(numa_node)); - - c.emu.write_memory(system_information + root_size, numa_node); - return STATUS_SUCCESS; - } - - c.win_emu.log.error("Unsupported processor relationship: %X\n", request); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) - { - c.win_emu.log.error("Unsupported system info ex class: %X\n", info_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - if (return_length) - { - return_length.write(sizeof(SYSTEM_BASIC_INFORMATION64)); - } - - if (system_information_length < sizeof(SYSTEM_BASIC_INFORMATION64)) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - - const emulator_object info{c.emu, system_information}; - - info.access([&](SYSTEM_BASIC_INFORMATION64& basic_info) { - basic_info.Reserved = 0; - basic_info.TimerResolution = 0x0002625a; - basic_info.PageSize = 0x1000; - basic_info.LowestPhysicalPageNumber = 0x00000001; - basic_info.HighestPhysicalPageNumber = 0x00c9c7ff; - basic_info.AllocationGranularity = ALLOCATION_GRANULARITY; - basic_info.MinimumUserModeAddress = MIN_ALLOCATION_ADDRESS; - basic_info.MaximumUserModeAddress = MAX_ALLOCATION_ADDRESS; - basic_info.ActiveProcessorsAffinityMask = 0x0000000000000fff; - basic_info.NumberOfProcessors = 1; - }); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryInformationProcess(const syscall_context& c, const handle process_handle, - const uint32_t info_class, const uint64_t process_information, - const uint32_t process_information_length, - const emulator_object return_length) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == ProcessImageInformation) - { - if (return_length) - { - return_length.write(sizeof(SECTION_IMAGE_INFORMATION>)); - } - - if (process_information_length != sizeof(SECTION_IMAGE_INFORMATION>)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object>> info{c.emu, process_information}; - info.access([&](SECTION_IMAGE_INFORMATION>& i) { - const auto& mod = *c.win_emu.mod_manager.executable; - - const emulator_object dos_header_obj{c.emu, mod.image_base}; - const auto dos_header = dos_header_obj.read(); - - const emulator_object> nt_headers_obj{c.emu, - mod.image_base + dos_header.e_lfanew}; - const auto nt_headers = nt_headers_obj.read(); - - const auto& file_header = nt_headers.FileHeader; - const auto& optional_header = nt_headers.OptionalHeader; - - i.TransferAddress = 0; - i.MaximumStackSize = optional_header.SizeOfStackReserve; - i.CommittedStackSize = optional_header.SizeOfStackCommit; - i.SubSystemType = optional_header.Subsystem; - i.SubSystemMajorVersion = optional_header.MajorSubsystemVersion; - i.SubSystemMinorVersion = optional_header.MinorSubsystemVersion; - i.MajorOperatingSystemVersion = optional_header.MajorOperatingSystemVersion; - i.MinorOperatingSystemVersion = optional_header.MinorOperatingSystemVersion; - i.ImageCharacteristics = file_header.Characteristics; - i.DllCharacteristics = optional_header.DllCharacteristics; - i.Machine = file_header.Machine; - i.ImageContainsCode = TRUE; - i.ImageFlags = 0; // TODO - i.ImageFileSize = optional_header.SizeOfImage; - i.LoaderFlags = optional_header.LoaderFlags; - i.CheckSum = optional_header.CheckSum; - }); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessCookie) - { - if (return_length) - { - return_length.write(sizeof(uint32_t)); - } - - if (process_information_length != sizeof(uint32_t)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.write(0x01234567); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessDebugPort) - { - if (return_length) - { - return_length.write(sizeof(EmulatorTraits::PVOID)); - } - - if (process_information_length != sizeof(EmulatorTraits::PVOID)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object::PVOID> info{c.emu, process_information}; - info.write(0); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessDefaultHardErrorMode || info_class == ProcessWx86Information || - info_class == ProcessDebugFlags) - { - if (return_length) - { - return_length.write(sizeof(ULONG)); - } - - if (process_information_length != sizeof(ULONG)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.write(info_class == ProcessDebugFlags ? 1 : 0); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessDeviceMap) - { - c.win_emu.log.info("Handling ProcessDeviceMap request.\n"); - - if (return_length) - { - return_length.write(sizeof(EmulatorTraits::PVOID)); - } - - if (process_information_length != sizeof(EmulatorTraits::PVOID)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object::PVOID> info{c.emu, process_information}; - info.write(0); // NULL pointer - - return STATUS_SUCCESS; - } - - if (info_class == ProcessEnableAlignmentFaultFixup) - { - if (return_length) - { - return_length.write(sizeof(BOOLEAN)); - } - - if (process_information_length != sizeof(BOOLEAN)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.write(FALSE); // Alignment fault fixup is disabled - - return STATUS_SUCCESS; - } - - if (info_class == ProcessDebugObjectHandle) - { - if (return_length) - { - return_length.write(sizeof(handle)); - } - - if (process_information_length != sizeof(handle)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.write(NULL_HANDLE); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessEnclaveInformation || info_class == ProcessMitigationPolicy || - info_class == ProcessGroupInformation) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == ProcessTimes) - { - if (return_length) - { - return_length.write(sizeof(KERNEL_USER_TIMES)); - } - - if (process_information_length != sizeof(KERNEL_USER_TIMES)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.write(KERNEL_USER_TIMES{}); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessBasicInformation) - { - if (return_length) - { - return_length.write(sizeof(PROCESS_BASIC_INFORMATION64)); - } - - if (process_information_length != sizeof(PROCESS_BASIC_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.access([&](PROCESS_BASIC_INFORMATION64& basic_info) { - basic_info.PebBaseAddress = c.proc.peb.ptr(); - basic_info.UniqueProcessId = 1; - }); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessImageFileNameWin32) - { - const auto peb = c.proc.peb.read(); - emulator_object proc_params{c.emu, peb.ProcessParameters}; - const auto params = proc_params.read(); - const auto length = params.ImagePathName.Length + sizeof(UNICODE_STRING>) + 2; - - if (return_length) - { - return_length.write(static_cast(length)); - } - - if (process_information_length < length) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object>> info{c.emu, process_information}; - info.access([&](UNICODE_STRING>& str) { - const auto buffer_start = - static_cast(process_information) + sizeof(UNICODE_STRING>); - const auto string = read_unicode_string(c.emu, params.ImagePathName); - c.emu.write_memory(buffer_start, string.c_str(), (string.size() + 1) * 2); - str.Length = params.ImagePathName.Length; - str.MaximumLength = str.Length; - str.Buffer = buffer_start; - }); - - return STATUS_SUCCESS; - } - - c.win_emu.log.error("Unsupported process info class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryInformationThread(const syscall_context& c, const handle thread_handle, - const uint32_t info_class, const uint64_t thread_information, - const uint32_t thread_information_length, - const emulator_object return_length) - { - const auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); - - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - if (info_class == ThreadTebInformation) - { - if (return_length) - { - return_length.write(sizeof(THREAD_TEB_INFORMATION)); - } - - if (thread_information_length < sizeof(THREAD_TEB_INFORMATION)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const auto teb_info = c.emu.read_memory(thread_information); - const auto data = c.emu.read_memory(thread->teb->value() + teb_info.TebOffset, teb_info.BytesToRead); - c.emu.write_memory(teb_info.TebInformation, data.data(), data.size()); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadBasicInformation) - { - if (return_length) - { - return_length.write(sizeof(THREAD_BASIC_INFORMATION64)); - } - - if (thread_information_length < sizeof(THREAD_BASIC_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, thread_information}; - info.access([&](THREAD_BASIC_INFORMATION64& i) { - i.TebBaseAddress = thread->teb->ptr(); - i.ClientId = thread->teb->read().ClientId; - }); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadAmILastThread) - { - if (return_length) - { - return_length.write(sizeof(ULONG)); - } - - if (thread_information_length < sizeof(ULONG)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, thread_information}; - info.write(c.proc.threads.size() <= 1); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadQuerySetWin32StartAddress) - { - if (return_length) - { - return_length.write(sizeof(EmulatorTraits::PVOID)); - } - - if (thread_information_length < sizeof(EmulatorTraits::PVOID)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object::PVOID> info{c.emu, thread_information}; - info.write(thread->start_address); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadPerformanceCount) - { - if (return_length) - { - return_length.write(sizeof(LARGE_INTEGER)); - } - - if (thread_information_length < sizeof(LARGE_INTEGER)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, thread_information}; - info.write({}); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadHideFromDebugger) - { - if (return_length) - { - return_length.write(sizeof(BOOLEAN)); - } - - if (thread_information_length < sizeof(BOOLEAN)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, thread_information}; - info.write(0); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadTimes) - { - if (return_length) - { - return_length.write(sizeof(KERNEL_USER_TIMES)); - } - - if (thread_information_length != sizeof(KERNEL_USER_TIMES)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, thread_information}; - info.write(KERNEL_USER_TIMES{}); - - return STATUS_SUCCESS; - } - - c.win_emu.log.error("Unsupported thread query info class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtSetInformationFile(const syscall_context& c, const handle file_handle, - const emulator_object>> io_status_block, - const uint64_t file_information, const ULONG length, - const FILE_INFORMATION_CLASS info_class) - { - const auto* f = c.proc.files.get(file_handle); - if (!f) - { - return STATUS_INVALID_HANDLE; - } - - if (info_class == FilePositionInformation) - { - if (!f->handle) - { - return STATUS_NOT_SUPPORTED; - } - - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_POSITION_INFORMATION); - io_status_block.write(block); - } - - if (length != sizeof(FILE_POSITION_INFORMATION)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, file_information}; - const auto i = info.read(); - - if (!f->handle.seek_to(i.CurrentByteOffset.QuadPart)) - { - return STATUS_INVALID_PARAMETER; - } - - return STATUS_SUCCESS; - } - - c.win_emu.log.error("Unsupported set file info class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - std::vector scan_directory(const std::filesystem::path& dir) - { - std::vector files{ - {"."}, - {".."}, - }; - - for (const auto& file : std::filesystem::directory_iterator(dir)) - { - files.emplace_back(file_entry{ - .file_path = file.path().filename(), - }); - } - - return files; - } - - template - NTSTATUS handle_file_enumeration(const syscall_context& c, - const emulator_object>> io_status_block, - const uint64_t file_information, const uint32_t length, const ULONG query_flags, - file* f) - { - 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)); - } - - auto& enum_state = *f->enumeration_state; - - size_t current_offset{0}; - emulator_object object{c.emu}; - - size_t current_index = enum_state.current_index; - - do - { - if (current_index >= enum_state.files.size()) - { - break; - } - - const auto new_offset = align_up(current_offset, 8); - const auto& current_file = enum_state.files[current_index]; - const auto file_name = current_file.file_path.u16string(); - const auto required_size = sizeof(T) + (file_name.size() * 2) - 2; - const auto end_offset = new_offset + required_size; - - if (end_offset > length) - { - if (current_offset == 0) - { - IO_STATUS_BLOCK> block{}; - block.Information = end_offset; - io_status_block.write(block); - - return STATUS_BUFFER_OVERFLOW; - } - - break; - } - - if (object) - { - const auto object_offset = object.value() - file_information; - - object.access( - [&](T& dir_info) { dir_info.NextEntryOffset = static_cast(new_offset - object_offset); }); - } - - T info{}; - info.NextEntryOffset = 0; - info.FileIndex = static_cast(current_index); - info.FileAttributes = FILE_ATTRIBUTE_NORMAL; - info.FileNameLength = static_cast(file_name.size() * 2); - - object.set_address(file_information + new_offset); - object.write(info); - - c.emu.write_memory(object.value() + offsetof(T, FileName), file_name.data(), info.FileNameLength); - - ++current_index; - current_offset = end_offset; - } while ((query_flags & SL_RETURN_SINGLE_ENTRY) == 0); - - if ((query_flags & SL_NO_CURSOR_UPDATE) == 0) - { - enum_state.current_index = current_index; - } - - IO_STATUS_BLOCK> block{}; - block.Information = current_offset; - io_status_block.write(block); - - return current_index < enum_state.files.size() ? STATUS_SUCCESS : STATUS_NO_MORE_FILES; - } - - NTSTATUS handle_NtQueryDirectoryFileEx( - const syscall_context& c, const handle file_handle, const handle /*event_handle*/, - const emulator_pointer /*PIO_APC_ROUTINE*/ /*apc_routine*/, const emulator_pointer /*apc_context*/, - const emulator_object>> io_status_block, const uint64_t file_information, - const uint32_t length, const uint32_t info_class, const ULONG query_flags, - const emulator_object>> /*file_name*/) - { - auto* f = c.proc.files.get(file_handle); - if (!f || !f->is_directory()) - { - return STATUS_INVALID_HANDLE; - } - - if (info_class == FileDirectoryInformation) - { - return handle_file_enumeration(c, io_status_block, file_information, length, - query_flags, f); - } - - if (info_class == FileFullDirectoryInformation) - { - return handle_file_enumeration(c, io_status_block, file_information, length, - query_flags, f); - } - - if (info_class == FileBothDirectoryInformation) - { - return handle_file_enumeration(c, io_status_block, file_information, length, - query_flags, f); - } - - c.win_emu.log.error("Unsupported query directory file info class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryInformationFile( - const syscall_context& c, const handle file_handle, - const emulator_object>> io_status_block, const uint64_t file_information, - const uint32_t length, const uint32_t info_class) - { - IO_STATUS_BLOCK> 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 ret(STATUS_INVALID_HANDLE); - } - - if (info_class == FileNameInformation || info_class == FileNormalizedNameInformation) - { - const auto relative_path = u"\\" + windows_path(f->name).without_drive().u16string(); - const auto required_length = sizeof(FILE_NAME_INFORMATION) + (relative_path.size() * 2); - - block.Information = required_length; - - if (length < block.Information) - { - return ret(STATUS_BUFFER_OVERFLOW); - } - - c.emu.write_memory(file_information, FILE_NAME_INFORMATION{ - .FileNameLength = static_cast(relative_path.size() * 2), - .FileName = {}, - }); - - c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), relative_path.c_str(), - (relative_path.size() + 1) * 2); - - return ret(STATUS_SUCCESS); - } - - if (info_class == FileStandardInformation) - { - block.Information = sizeof(FILE_STANDARD_INFORMATION); - - if (length < block.Information) - { - return ret(STATUS_BUFFER_OVERFLOW); - } - - const emulator_object info{c.emu, file_information}; - FILE_STANDARD_INFORMATION i{}; - i.Directory = f->is_directory() ? TRUE : FALSE; - - if (f->handle) - { - i.EndOfFile.QuadPart = f->handle.size(); - } - - info.write(i); - - return ret(STATUS_SUCCESS); - } - - if (info_class == FilePositionInformation) - { - if (!f->handle) - { - return ret(STATUS_NOT_SUPPORTED); - } - - block.Information = sizeof(FILE_POSITION_INFORMATION); - - if (length < block.Information) - { - return ret(STATUS_BUFFER_OVERFLOW); - } - - const emulator_object info{c.emu, file_information}; - FILE_POSITION_INFORMATION i{}; - - i.CurrentByteOffset.QuadPart = f->handle.tell(); - - info.write(i); - - return ret(STATUS_SUCCESS); - } - - if (info_class == FileAttributeTagInformation) - { - if (!f->handle) - { - return ret(STATUS_NOT_SUPPORTED); - } - - block.Information = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION); - - if (length < block.Information) - { - return ret(STATUS_BUFFER_OVERFLOW); - } - - const emulator_object info{c.emu, file_information}; - FILE_ATTRIBUTE_TAG_INFORMATION i{}; - - i.FileAttributes = f->is_directory() ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; - - info.write(i); - - return ret(STATUS_SUCCESS); - } - - c.win_emu.log.error("Unsupported query file info class: %X\n", info_class); - c.emu.stop(); - - return ret(STATUS_NOT_SUPPORTED); - } - - NTSTATUS handle_NtSetInformationProcess(const syscall_context& c, const handle process_handle, - const uint32_t info_class, const uint64_t process_information, - const uint32_t process_information_length) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == ProcessSchedulerSharedData || info_class == ProcessConsoleHostProcess || - info_class == ProcessFaultInformation || info_class == ProcessDefaultHardErrorMode || - info_class == ProcessRaiseUMExceptionOnInvalidHandleClose || - info_class == ProcessDynamicFunctionTableInformation) - { - return STATUS_SUCCESS; - } - - if (info_class == ProcessTlsInformation) - { - constexpr auto thread_data_offset = offsetof(PROCESS_TLS_INFO, ThreadData); - if (process_information_length < thread_data_offset) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object data{c.emu, process_information + thread_data_offset}; - - PROCESS_TLS_INFO tls_info{}; - c.emu.read_memory(process_information, &tls_info, thread_data_offset); - - for (uint32_t i = 0; i < tls_info.ThreadDataCount; ++i) - { - auto entry = data.read(i); - - const auto _ = utils::finally([&] { data.write(entry, i); }); - - if (i >= c.proc.threads.size()) - { - entry.Flags = 0; - continue; - } - - auto thread_iterator = c.proc.threads.begin(); - std::advance(thread_iterator, i); - - entry.Flags = 2; - - thread_iterator->second.teb->access([&](TEB64& teb) { - entry.ThreadId = teb.ClientId.UniqueThread; - - auto* tls_vector = teb.ThreadLocalStoragePointer; - - if (tls_info.TlsRequest == ProcessTlsReplaceIndex) - { - auto* tls_entry_ptr = tls_vector + tls_info.TlsIndex; - - const auto old_entry = c.emu.read_memory::PVOID>(tls_entry_ptr); - c.emu.write_memory::PVOID>(tls_entry_ptr, entry.TlsModulePointer); - - entry.TlsModulePointer = old_entry; - } - else if (tls_info.TlsRequest == ProcessTlsReplaceVector) - { - auto* new_tls_vector = entry.TlsVector; - - for (uint32_t index = 0; index < tls_info.TlsVectorLength; ++index) - { - auto* old_entry = c.emu.read_memory(tls_vector + index); - c.emu.write_memory(new_tls_vector + index, old_entry); - } - - teb.ThreadLocalStoragePointer = new_tls_vector; - entry.TlsVector = tls_vector; - } - }); - } - - return STATUS_SUCCESS; - } - - c.win_emu.log.error("Unsupported info process class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtSetInformationKey() - { - return STATUS_NOT_SUPPORTED; - } - NTSTATUS handle_NtApphelpCacheControl() { return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtProtectVirtualMemory(const syscall_context& c, const handle process_handle, - const emulator_object base_address, - const emulator_object bytes_to_protect, const uint32_t protection, - const emulator_object old_protection) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - const auto orig_start = base_address.read(); - const auto orig_length = bytes_to_protect.read(); - - const auto aligned_start = page_align_down(orig_start); - const auto aligned_length = page_align_up(orig_start + orig_length) - aligned_start; - - base_address.write(aligned_start); - bytes_to_protect.write(static_cast(aligned_length)); - - const auto requested_protection = map_nt_to_emulator_protection(protection); - - c.win_emu.log.print(color::dark_gray, "--> Changing protection at 0x%" PRIx64 "-0x%" PRIx64 " to %s\n", - aligned_start, aligned_start + aligned_length, - get_permission_string(requested_protection).c_str()); - - memory_permission old_protection_value{}; - - try - { - c.win_emu.memory.protect_memory(aligned_start, aligned_length, requested_protection, &old_protection_value); - } - catch (...) - { - return STATUS_INVALID_ADDRESS; - } - - const auto current_protection = map_emulator_to_nt_protection(old_protection_value); - old_protection.write(current_protection); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenDirectoryObject( - const syscall_context& c, const emulator_object directory_handle, const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - const auto attributes = object_attributes.read(); - const auto object_name = - read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); - - if (object_name == u"\\KnownDlls") - { - directory_handle.write(KNOWN_DLLS_DIRECTORY); - return STATUS_SUCCESS; - } - - if (object_name == u"\\Sessions\\1\\BaseNamedObjects") - { - directory_handle.write(BASE_NAMED_OBJECTS_DIRECTORY); - return STATUS_SUCCESS; - } - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtOpenSymbolicLinkObject( - const syscall_context& c, const emulator_object link_handle, ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - const auto attributes = object_attributes.read(); - const auto object_name = - read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); - - if (object_name == u"KnownDllPath") - { - link_handle.write(KNOWN_DLLS_SYMLINK); - return STATUS_SUCCESS; - } - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQuerySymbolicLinkObject(const syscall_context& c, const handle link_handle, - const emulator_object>> link_target, - const emulator_object returned_length) - { - if (link_handle == KNOWN_DLLS_SYMLINK) - { - constexpr std::u16string_view system32 = u"C:\\WINDOWS\\System32"; - constexpr auto str_length = system32.size() * 2; - constexpr auto max_length = str_length + 2; - - returned_length.write(max_length); - - bool too_small = false; - link_target.access([&](UNICODE_STRING>& str) { - if (str.MaximumLength < max_length) - { - too_small = true; - return; - } - - str.Length = str_length; - c.emu.write_memory(str.Buffer, system32.data(), max_length); - }); - - return too_small ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; - } - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtAllocateVirtualMemoryEx(const syscall_context& c, const handle process_handle, - const emulator_object base_address, - const emulator_object bytes_to_allocate, - const uint32_t allocation_type, const uint32_t page_protection) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - auto allocation_bytes = bytes_to_allocate.read(); - allocation_bytes = page_align_up(allocation_bytes); - bytes_to_allocate.write(allocation_bytes); - - const auto protection = map_nt_to_emulator_protection(page_protection); - - auto potential_base = base_address.read(); - if (!potential_base) - { - potential_base = c.win_emu.memory.find_free_allocation_base(allocation_bytes); - } - - if (!potential_base) - { - c.win_emu.log.print(color::dark_gray, "--> Not allocated\n"); - - return STATUS_MEMORY_NOT_ALLOCATED; - } - - base_address.write(potential_base); - - const bool reserve = allocation_type & MEM_RESERVE; - const bool commit = allocation_type & MEM_COMMIT; - - if ((allocation_type & ~(MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN)) || (!commit && !reserve)) - { - throw std::runtime_error("Unsupported allocation type!"); - } - - if (commit && !reserve && c.win_emu.memory.commit_memory(potential_base, allocation_bytes, protection)) - { - c.win_emu.log.print(color::dark_gray, "--> Committed 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base, - potential_base + allocation_bytes); - - return STATUS_SUCCESS; - } - - c.win_emu.log.print(color::dark_gray, "--> Allocated 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base, - potential_base + allocation_bytes); - - return c.win_emu.memory.allocate_memory(potential_base, allocation_bytes, protection, !commit) - ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; - } - - NTSTATUS handle_NtAllocateVirtualMemory(const syscall_context& c, const handle process_handle, - const emulator_object base_address, const uint64_t /*zero_bits*/, - const emulator_object bytes_to_allocate, - const uint32_t allocation_type, const uint32_t page_protection) - { - return handle_NtAllocateVirtualMemoryEx(c, process_handle, base_address, bytes_to_allocate, allocation_type, - page_protection); - } - - NTSTATUS handle_NtFreeVirtualMemory(const syscall_context& c, const handle process_handle, - const emulator_object base_address, - const emulator_object bytes_to_allocate, const uint32_t free_type) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - const auto allocation_base = base_address.read(); - const auto allocation_size = bytes_to_allocate.read(); - - if (free_type & MEM_RELEASE) - { - return c.win_emu.memory.release_memory(allocation_base, allocation_size) ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; - } - - if (free_type & MEM_DECOMMIT) - { - return c.win_emu.memory.decommit_memory(allocation_base, allocation_size) ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; - } - - throw std::runtime_error("Bad free type"); - } - - NTSTATUS handle_NtCreateSection(const syscall_context& c, const emulator_object section_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes, - const emulator_object maximum_size, - const ULONG section_page_protection, const ULONG allocation_attributes, - const handle file_handle) - { - section s{}; - s.section_page_protection = section_page_protection; - s.allocation_attributes = allocation_attributes; - - const auto* file = c.proc.files.get(file_handle); - if (file) - { - c.win_emu.log.print(color::dark_gray, "--> Section for file %s\n", u16_to_u8(file->name).c_str()); - s.file_name = file->name; - } - - if (object_attributes) - { - const auto attributes = object_attributes.read(); - if (attributes.ObjectName) - { - auto name = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - c.win_emu.log.print(color::dark_gray, "--> Section with name %s\n", u16_to_u8(name).c_str()); - s.name = std::move(name); - } - } - - if (maximum_size) - { - maximum_size.access([&](ULARGE_INTEGER& large_int) { - large_int.QuadPart = page_align_up(large_int.QuadPart); - s.maximum_size = large_int.QuadPart; - }); - } - else if (!file) - { - return STATUS_INVALID_PARAMETER; - } - - const auto h = c.proc.sections.store(std::move(s)); - section_handle.write(h); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtConnectPort(const syscall_context& c, const emulator_object client_port_handle, - const emulator_object>> server_port_name, - const emulator_object /*security_qos*/, - const emulator_object client_shared_memory, - const emulator_object /*server_shared_memory*/, - const emulator_object /*maximum_message_length*/, - const emulator_pointer connection_info, - const emulator_object connection_info_length) - { - auto port_name = read_unicode_string(c.emu, server_port_name); - c.win_emu.log.print(color::dark_gray, "NtConnectPort: %s\n", u16_to_u8(port_name).c_str()); - - port p{}; - p.name = std::move(port_name); - - if (connection_info) - { - std::vector zero_mem{}; - zero_mem.resize(connection_info_length.read(), 0); - c.emu.write_memory(connection_info, zero_mem.data(), zero_mem.size()); - } - - client_shared_memory.access([&](PORT_VIEW64& view) { - p.view_base = c.win_emu.memory.allocate_memory(view.ViewSize, memory_permission::read_write); - view.ViewBase = p.view_base; - view.ViewRemoteBase = view.ViewBase; - }); - - const auto handle = c.proc.ports.store(std::move(p)); - client_port_handle.write(handle); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtReadVirtualMemory(const syscall_context& c, const handle process_handle, - const emulator_pointer base_address, const emulator_pointer buffer, - const ULONG number_of_bytes_to_read, - const emulator_object number_of_bytes_read) - { - number_of_bytes_read.write(0); - - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - std::vector memory{}; - memory.resize(number_of_bytes_to_read); - - if (!c.emu.try_read_memory(base_address, memory.data(), memory.size())) - { - return STATUS_INVALID_ADDRESS; - } - - c.emu.write_memory(buffer, memory.data(), memory.size()); - number_of_bytes_read.write(number_of_bytes_to_read); - return STATUS_SUCCESS; - } - NTSTATUS handle_NtDeviceIoControlFile(const syscall_context& c, const handle file_handle, const handle event, const emulator_pointer /*PIO_APC_ROUTINE*/ apc_routine, const emulator_pointer apc_context, @@ -2534,53 +406,6 @@ namespace return STATUS_SUCCESS; } - NTSTATUS handle_NtOpenThreadToken(const syscall_context&, const handle thread_handle, - const ACCESS_MASK /*desired_access*/, const BOOLEAN /*open_as_self*/, - const emulator_object token_handle) - { - if (thread_handle != CURRENT_THREAD) - { - return STATUS_NOT_SUPPORTED; - } - - token_handle.write(CURRENT_THREAD_TOKEN); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenThreadTokenEx(const syscall_context& c, const handle thread_handle, - const ACCESS_MASK desired_access, const BOOLEAN open_as_self, - const ULONG /*handle_attributes*/, const emulator_object token_handle) - { - return handle_NtOpenThreadToken(c, thread_handle, desired_access, open_as_self, token_handle); - } - - NTSTATUS handle_NtOpenProcessToken(const syscall_context&, const handle process_handle, - const ACCESS_MASK /*desired_access*/, const emulator_object token_handle) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - token_handle.write(CURRENT_PROCESS_TOKEN); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenProcessTokenEx(const syscall_context& c, const handle process_handle, - const ACCESS_MASK desired_access, const ULONG /*handle_attributes*/, - const emulator_object token_handle) - { - return handle_NtOpenProcessToken(c, process_handle, desired_access, token_handle); - } - - NTSTATUS handle_NtQuerySecurityAttributesToken() - { - // puts("NtQuerySecurityAttributesToken not supported"); - return STATUS_NOT_SUPPORTED; - } - NTSTATUS handle_NtQueryLicenseValue() { // puts("NtQueryLicenseValue not supported"); @@ -2598,261 +423,12 @@ namespace return STATUS_NOT_SUPPORTED; } - TOKEN_TYPE get_token_type(const handle token_handle) - { - return token_handle == DUMMY_IMPERSONATION_TOKEN // - ? TokenImpersonation - : TokenPrimary; - } - - NTSTATUS handle_NtDuplicateToken(const syscall_context&, const handle existing_token_handle, - ACCESS_MASK /*desired_access*/, - const emulator_object>> - /*object_attributes*/, - const BOOLEAN /*effective_only*/, const TOKEN_TYPE type, - const emulator_object new_token_handle) - { - if (get_token_type(existing_token_handle) == type) - { - new_token_handle.write(existing_token_handle); - } - else if (type == TokenPrimary) - { - new_token_handle.write(CURRENT_PROCESS_TOKEN); - } - else - { - new_token_handle.write(DUMMY_IMPERSONATION_TOKEN); - } - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryTimerResolution(const syscall_context&, const emulator_object maximum_time, - const emulator_object minimum_time, - const emulator_object current_time) - { - maximum_time.write_if_valid(0x0002625a); - minimum_time.write_if_valid(0x00001388); - current_time.write_if_valid(0x00002710); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryInformationToken(const syscall_context& c, const handle token_handle, - const TOKEN_INFORMATION_CLASS token_information_class, - const uint64_t token_information, const ULONG token_information_length, - const emulator_object return_length) - { - if (token_handle != CURRENT_PROCESS_TOKEN && token_handle != CURRENT_THREAD_TOKEN && - token_handle != CURRENT_THREAD_EFFECTIVE_TOKEN && token_handle != DUMMY_IMPERSONATION_TOKEN) - { - return STATUS_NOT_SUPPORTED; - } - - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - const uint8_t sid[] = { - 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x84, 0x94, - 0xD4, 0x04, 0x4B, 0x68, 0x42, 0x34, 0x23, 0xBE, 0x69, 0x4E, 0xE9, 0x03, 0x00, 0x00, - }; - - if (token_information_class == TokenAppContainerSid) - { - return STATUS_NOT_SUPPORTED; - } - - if (token_information_class == TokenUser) - { - constexpr auto required_size = sizeof(sid) + 0x10; - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - TOKEN_USER64 user{}; - user.User.Attributes = 0; - user.User.Sid = token_information + 0x10; - - emulator_object{c.emu, token_information}.write(user); - c.emu.write_memory(token_information + 0x10, sid, sizeof(sid)); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenType) - { - constexpr auto required_size = sizeof(TOKEN_TYPE); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(get_token_type(token_handle)); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenSessionId) - { - constexpr auto required_size = sizeof(ULONG); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(1); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenPrivateNameSpace) - { - constexpr auto required_size = sizeof(ULONG); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(0); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenUIAccess) - { - constexpr auto required_size = sizeof(ULONG); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(1); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenElevation) - { - constexpr auto required_size = sizeof(TOKEN_ELEVATION); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - c.emu.write_memory(token_information, TOKEN_ELEVATION{ - .TokenIsElevated = 0, - }); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenIsAppContainer) - { - constexpr auto required_size = sizeof(ULONG); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(0); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenStatistics) - { - constexpr auto required_size = sizeof(TOKEN_STATISTICS); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - c.emu.write_memory(token_information, TOKEN_STATISTICS{}); - - return STATUS_SUCCESS; - } - - if (token_information_class == TokenSecurityAttributes) - { - constexpr auto required_size = sizeof(TOKEN_SECURITY_ATTRIBUTES_INFORMATION); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - c.emu.write_memory(token_information, TOKEN_SECURITY_ATTRIBUTES_INFORMATION{ - .Version = 0, - .Reserved = {}, - .AttributeCount = 0, - .Attribute = {}, - }); - - return STATUS_SUCCESS; - } - - if (token_information_class == TokenIntegrityLevel) - { - constexpr auto required_size = sizeof(sid) + sizeof(TOKEN_MANDATORY_LABEL64); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - TOKEN_MANDATORY_LABEL64 label{}; - label.Label.Attributes = 0; - label.Label.Sid = token_information + sizeof(TOKEN_MANDATORY_LABEL64); - - emulator_object{c.emu, token_information}.write(label); - c.emu.write_memory(token_information + sizeof(TOKEN_MANDATORY_LABEL64), sid, sizeof(sid)); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenBnoIsolation) - { - constexpr auto required_size = sizeof(TOKEN_BNO_ISOLATION_INFORMATION64); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - c.emu.write_memory(token_information, TOKEN_BNO_ISOLATION_INFORMATION64{ - .IsolationPrefix = 0, - .IsolationEnabled = FALSE, - }); - - return STATUS_SUCCESS; - } - - c.win_emu.log.error("Unsupported token info class: %X\n", token_information_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - NTSTATUS handle_NtDxgkIsFeatureEnabled() { // puts("NtDxgkIsFeatureEnabled not supported"); return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtQueryInstallUILanguage() - { - return STATUS_NOT_SUPPORTED; - } - NTSTATUS handle_NtUserDisplayConfigGetDeviceInfo() { // puts("NtUserDisplayConfigGetDeviceInfo not supported"); @@ -2884,11 +460,6 @@ namespace return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtGetMUIRegistryInfo() - { - return STATUS_NOT_SUPPORTED; - } - NTSTATUS handle_NtUserRegisterWindowMessage() { return STATUS_NOT_SUPPORTED; @@ -2899,664 +470,21 @@ namespace return 0; } - NTSTATUS handle_NtIsUILanguageComitted() - { - return STATUS_NOT_SUPPORTED; - } - NTSTATUS handle_NtUpdateWnfStateData() { return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtGetNlsSectionPtr() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& c, const handle port_handle, const ULONG /*flags*/, - const emulator_object /*send_message*/, - const emulator_object - /*send_message_attributes*/ - , - const emulator_object receive_message, - const emulator_object::SIZE_T> /*buffer_length*/, - const emulator_object - /*receive_message_attributes*/, - const emulator_object /*timeout*/) - { - const auto* port = c.proc.ports.get(port_handle); - if (!port) - { - return STATUS_INVALID_HANDLE; - } - - if (port->name != u"\\Windows\\ApiPort") - { - c.win_emu.log.error("!!! BAD PORT\n"); - return STATUS_NOT_SUPPORTED; - } - - // TODO: Fix this. This is broken and wrong. - - const emulator_object>> data{c.emu, receive_message.value() + 0x48}; - const auto dest = data.read(); - const auto base = dest.Base; - - const auto value = base + 0x10; - c.emu.write_memory(base + 8, &value, sizeof(value)); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtInitializeNlsFiles(const syscall_context& c, const emulator_object base_address, - const emulator_object default_locale_id, - const emulator_object /*default_casing_table_size*/) - { - const auto locale_file = - utils::io::read_file(c.win_emu.file_sys.translate(R"(C:\Windows\System32\locale.nls)")); - if (locale_file.empty()) - { - return STATUS_FILE_INVALID; - } - - const auto size = page_align_up(locale_file.size()); - const auto base = c.win_emu.memory.allocate_memory(size, memory_permission::read); - c.emu.write_memory(base, locale_file.data(), locale_file.size()); - - base_address.write(base); - default_locale_id.write(0x407); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryDefaultLocale(const syscall_context&, BOOLEAN /*user_profile*/, - const emulator_object default_locale_id) - { - default_locale_id.write(0x407); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtContinue(const syscall_context& c, const emulator_object thread_context, - const BOOLEAN /*raise_alert*/) - { - c.write_status = false; - - const auto context = thread_context.read(); - cpu_context::restore(c.emu, context); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtTerminateProcess(const syscall_context& c, const handle process_handle, NTSTATUS exit_status) - { - if (process_handle == 0) - { - for (auto& thread : c.proc.threads | std::views::values) - { - if (&thread != c.proc.active_thread) - { - thread.exit_status = exit_status; - } - } - - return STATUS_SUCCESS; - } - - if (process_handle == CURRENT_PROCESS) - { - c.proc.exit_status = exit_status; - c.emu.stop(); - return STATUS_SUCCESS; - } - - return STATUS_NOT_SUPPORTED; - } - - void commit_file_data(const std::string_view data, emulator& emu, - const emulator_object>> io_status_block, - const uint64_t buffer) - { - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = data.size(); - io_status_block.write(block); - } - - emu.write_memory(buffer, data.data(), data.size()); - } - - NTSTATUS handle_NtReadFile(const syscall_context& c, const handle file_handle, const uint64_t /*event*/, - const uint64_t /*apc_routine*/, const uint64_t /*apc_context*/, - const emulator_object>> io_status_block, - const uint64_t buffer, const ULONG length, - const emulator_object /*byte_offset*/, - const emulator_object /*key*/) - { - std::string temp_buffer{}; - temp_buffer.resize(length); - - if (file_handle == STDIN_HANDLE) - { - char chr{}; - if (std::cin.readsome(&chr, 1) <= 0) - { - std::cin.read(&chr, 1); - } - - std::cin.putback(chr); - - const auto read_count = - std::cin.readsome(temp_buffer.data(), static_cast(temp_buffer.size())); - const auto count = std::max(read_count, static_cast(0)); - - commit_file_data(std::string_view(temp_buffer.data(), count), c.emu, io_status_block, buffer); - return STATUS_SUCCESS; - } - - const auto* f = c.proc.files.get(file_handle); - if (!f) - { - return STATUS_INVALID_HANDLE; - } - - const auto bytes_read = fread(temp_buffer.data(), 1, temp_buffer.size(), f->handle); - commit_file_data(std::string_view(temp_buffer.data(), bytes_read), c.emu, io_status_block, buffer); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtWriteFile(const syscall_context& c, const handle file_handle, const uint64_t /*event*/, - const uint64_t /*apc_routine*/, const uint64_t /*apc_context*/, - const emulator_object>> io_status_block, - const uint64_t buffer, const ULONG length, - const emulator_object /*byte_offset*/, - const emulator_object /*key*/) - { - std::string temp_buffer{}; - temp_buffer.resize(length); - c.emu.read_memory(buffer, temp_buffer.data(), temp_buffer.size()); - - if (file_handle == STDOUT_HANDLE) - { - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = length; - io_status_block.write(block); - } - - c.win_emu.callbacks.on_stdout(temp_buffer); - - if (!temp_buffer.ends_with("\n")) - { - temp_buffer.push_back('\n'); - } - - c.win_emu.log.info("%.*s", static_cast(temp_buffer.size()), temp_buffer.data()); - - return STATUS_SUCCESS; - } - - const auto* f = c.proc.files.get(file_handle); - if (!f) - { - return STATUS_INVALID_HANDLE; - } - - const auto bytes_written = fwrite(temp_buffer.data(), 1, temp_buffer.size(), f->handle); - - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = bytes_written; - io_status_block.write(block); - } - - return STATUS_SUCCESS; - } - - constexpr std::u16string map_mode(const ACCESS_MASK desired_access, const ULONG create_disposition) - { - std::u16string mode{}; - - switch (create_disposition) - { - case FILE_CREATE: - case FILE_SUPERSEDE: - if (desired_access & GENERIC_WRITE) - { - mode = u"wb"; - } - break; - - case FILE_OPEN: - case FILE_OPEN_IF: - if (desired_access & GENERIC_WRITE) - { - mode = u"r+b"; - } - else if (desired_access & GENERIC_READ || desired_access & SYNCHRONIZE) - { - mode = u"rb"; - } - break; - - case FILE_OVERWRITE: - case FILE_OVERWRITE_IF: - if (desired_access & GENERIC_WRITE) - { - mode = u"w+b"; - } - break; - - default: - mode = u""; - break; - } - - if (desired_access & FILE_APPEND_DATA) - { - mode = u"a+b"; - } - - return mode; - } - std::optional 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()); - } - - constexpr std::u16string_view unc_prefix = u"\\??\\"; - if (!filename.starts_with(unc_prefix)) - { - return std::nullopt; - } - - const auto path = filename.substr(unc_prefix.size()); - - const std::set> devices{ - u"Nsi", - u"MountPointManager", - }; - - if (devices.contains(path)) - { - return path; - } - - return std::nullopt; - } - - NTSTATUS handle_NtCreateFile(const syscall_context& c, const emulator_object file_handle, - ACCESS_MASK desired_access, - const emulator_object>> object_attributes, - const emulator_object>> /*io_status_block*/, - const emulator_object /*allocation_size*/, ULONG /*file_attributes*/, - ULONG /*share_access*/, ULONG create_disposition, ULONG create_options, - uint64_t ea_buffer, ULONG ea_length) - { - const auto attributes = object_attributes.read(); - auto filename = - read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); - - auto printer = utils::finally([&] { - c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(filename).c_str()); // - }); - - 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, - }; - - 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); - - return STATUS_SUCCESS; - } - - handle root_handle{}; - root_handle.bits = attributes.RootDirectory; - if (root_handle.value.is_pseudo && (filename == u"\\Reference" || filename == u"\\Connect")) - { - file_handle.write(root_handle); - return STATUS_SUCCESS; - } - - file f{}; - f.name = std::move(filename); - - if (attributes.RootDirectory) - { - const auto* root = c.proc.files.get(attributes.RootDirectory); - if (!root) - { - return STATUS_INVALID_HANDLE; - } - - 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(); - - if (f.name.ends_with(u"\\") || create_options & FILE_DIRECTORY_FILE) - { - c.win_emu.log.print(color::dark_gray, "--> Opening folder: %s\n", u16_to_u8(f.name).c_str()); - - if (create_disposition & FILE_CREATE) - { - std::error_code 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))) - { - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - const auto handle = c.proc.files.store(std::move(f)); - file_handle.write(handle); - - return STATUS_SUCCESS; - } - - c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(f.name).c_str()); - - const windows_path path = f.name; - std::u16string mode = map_mode(desired_access, create_disposition); - - if (mode.empty() || path.is_relative()) - { - return STATUS_NOT_SUPPORTED; - } - - FILE* file{}; - - const auto error = open_unicode(&file, c.win_emu.file_sys.translate(path), mode); - - if (!file) - { - switch (error) - { - case ENOENT: - return STATUS_OBJECT_NAME_NOT_FOUND; - case EACCES: - return STATUS_ACCESS_DENIED; - case EISDIR: - return STATUS_FILE_IS_A_DIRECTORY; - default: - return STATUS_NOT_SUPPORTED; - } - } - - f.handle = file; - - const auto handle = c.proc.files.store(std::move(f)); - file_handle.write(handle); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryAttributesFile( - const syscall_context& c, const emulator_object>> object_attributes, - const emulator_object file_information) - { - if (!object_attributes) - { - return STATUS_INVALID_PARAMETER; - } - - const auto attributes = object_attributes.read(); - if (!attributes.ObjectName) - { - return STATUS_INVALID_PARAMETER; - } - - const auto filename = read_unicode_string( - c.emu, emulator_object>>{c.emu, attributes.ObjectName}); - - 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(); - - struct _stat64 file_stat{}; - if (_stat64(local_filename.c_str(), &file_stat) != 0) - { - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - file_information.access([&](FILE_BASIC_INFORMATION& info) { - info.CreationTime = utils::convert_unix_to_windows_time(file_stat.st_atime); - info.LastAccessTime = utils::convert_unix_to_windows_time(file_stat.st_atime); - info.LastWriteTime = utils::convert_unix_to_windows_time(file_stat.st_mtime); - info.ChangeTime = info.LastWriteTime; - info.FileAttributes = FILE_ATTRIBUTE_NORMAL; - }); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenFile(const syscall_context& c, const emulator_object file_handle, - const ACCESS_MASK desired_access, - const emulator_object>> object_attributes, - const emulator_object>> io_status_block, - const ULONG share_access, const ULONG open_options) - { - return handle_NtCreateFile(c, file_handle, desired_access, object_attributes, io_status_block, {c.emu}, 0, - share_access, FILE_OPEN, open_options, 0, 0); - } - - 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 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>) + (device_path.size() + 1) * 2; - return_length.write(static_cast(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; - } - NTSTATUS handle_NtQueryInformationJobObject() { return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtSetSystemInformation() - { - return STATUS_NOT_SUPPORTED; - } - NTSTATUS handle_NtAccessCheck() { return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtUserGetKeyboardLayout() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtRaiseHardError(const syscall_context& c, const NTSTATUS error_status, - const ULONG /*number_of_parameters*/, - const emulator_object>> - /*unicode_string_parameter_mask*/, - const emulator_object /*parameters*/, - const HARDERROR_RESPONSE_OPTION /*valid_response_option*/, - const emulator_object response) - { - if (response) - { - response.write(ResponseAbort); - } - - c.proc.exit_status = error_status; - c.proc.exception_rip = c.emu.read_instruction_pointer(); - c.emu.stop(); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtRaiseException(const syscall_context& c, - const emulator_object>> - /*exception_record*/, - const emulator_object thread_context, const BOOLEAN handle_exception) - { - if (handle_exception) - { - c.win_emu.log.error("Unhandled exceptions not supported yet!\n"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - c.proc.exception_rip = thread_context.read().Rip; - c.emu.stop(); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenSemaphore(const syscall_context& c, const emulator_object semaphore_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - if (!object_attributes) - { - return STATUS_INVALID_PARAMETER; - } - - const auto attributes = object_attributes.read(); - if (!attributes.ObjectName) - { - return STATUS_INVALID_PARAMETER; - } - - const auto name = read_unicode_string( - c.emu, emulator_object>>{c.emu, attributes.ObjectName}); - if (name.empty()) - { - return STATUS_INVALID_PARAMETER; - } - - for (const auto& semaphore : c.proc.semaphores) - { - if (semaphore.second.name == name) - { - semaphore_handle.write(c.proc.semaphores.make_handle(semaphore.first)); - return STATUS_SUCCESS; - } - } - - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - NTSTATUS handle_NtReleaseSemaphore(const syscall_context& c, const handle semaphore_handle, - const ULONG release_count, const emulator_object previous_count) - { - if (semaphore_handle.value.type != handle_types::semaphore) - { - c.win_emu.log.error("Bad handle type for NtReleaseSemaphore\n"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - auto* mutant = c.proc.semaphores.get(semaphore_handle); - if (!mutant) - { - return STATUS_INVALID_HANDLE; - } - - const auto [old_count, succeeded] = mutant->release(release_count); - - if (previous_count) - { - previous_count.write(static_cast(old_count)); - } - - return succeeded ? STATUS_SUCCESS : STATUS_SEMAPHORE_LIMIT_EXCEEDED; - } - - NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, const emulator_object semaphore_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes, - const ULONG initial_count, const ULONG maximum_count) - { - semaphore s{}; - s.current_count = initial_count; - s.max_count = maximum_count; - - if (object_attributes) - { - const auto attributes = object_attributes.read(); - if (attributes.ObjectName) - { - s.name = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - } - } - - if (!s.name.empty()) - { - for (auto& entry : c.proc.semaphores) - { - if (entry.second.name == s.name) - { - ++entry.second.ref_count; - semaphore_handle.write(c.proc.semaphores.make_handle(entry.first)); - return STATUS_OBJECT_NAME_EXISTS; - } - } - } - - const auto handle = c.proc.semaphores.store(std::move(s)); - semaphore_handle.write(handle); - - return STATUS_SUCCESS; - } - NTSTATUS handle_NtAddAtomEx(const syscall_context& c, const uint64_t atom_name, const ULONG length, const emulator_object atom, const ULONG /*flags*/) { @@ -3609,109 +537,6 @@ namespace return STATUS_SUCCESS; } - NTSTATUS handle_NtUnmapViewOfSection(const syscall_context& c, const handle process_handle, - const uint64_t base_address) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - if (!base_address) - { - return STATUS_INVALID_PARAMETER; - } - - if (base_address == c.proc.dbwin_buffer) - { - c.proc.dbwin_buffer = 0; - c.win_emu.memory.release_memory(base_address, 0x1000); - return STATUS_SUCCESS; - } - - const auto* mod = c.win_emu.mod_manager.find_by_address(base_address); - if (!mod) - { - c.win_emu.log.error("Unmapping non-module section not supported!\n"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - if (c.win_emu.mod_manager.unmap(base_address, c.win_emu.log)) - { - return STATUS_SUCCESS; - } - - return STATUS_INVALID_PARAMETER; - } - - NTSTATUS handle_NtUnmapViewOfSectionEx(const syscall_context& c, const handle process_handle, - const uint64_t base_address, const ULONG /*flags*/) - { - return handle_NtUnmapViewOfSection(c, process_handle, base_address); - } - - NTSTATUS handle_NtCreateThreadEx(const syscall_context& c, const emulator_object thread_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> - /*object_attributes*/, - const handle process_handle, const uint64_t start_routine, const uint64_t argument, - const ULONG create_flags, const EmulatorTraits::SIZE_T /*zero_bits*/, - const EmulatorTraits::SIZE_T stack_size, - const EmulatorTraits::SIZE_T /*maximum_stack_size*/, - const emulator_object>> attribute_list) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - const auto h = c.proc.create_thread(c.win_emu.memory, start_routine, argument, stack_size, - create_flags & CREATE_SUSPENDED); - thread_handle.write(h); - - if (!attribute_list) - { - return STATUS_SUCCESS; - } - - const auto* thread = c.proc.threads.get(h); - - const emulator_object>> attributes{ - c.emu, attribute_list.value() + offsetof(PS_ATTRIBUTE_LIST>, Attributes)}; - - const auto total_length = attribute_list.read().TotalLength; - - constexpr auto entry_size = sizeof(PS_ATTRIBUTE>); - constexpr auto header_size = sizeof(PS_ATTRIBUTE_LIST>) - entry_size; - const auto attribute_count = (total_length - header_size) / entry_size; - - for (size_t i = 0; i < attribute_count; ++i) - { - attributes.access( - [&](const PS_ATTRIBUTE>& attribute) { - const auto type = attribute.Attribute & ~PS_ATTRIBUTE_THREAD; - - if (type == PsAttributeClientId) - { - const auto client_id = thread->teb->read().ClientId; - write_attribute(c.emu, attribute, client_id); - } - else if (type == PsAttributeTebAddress) - { - write_attribute(c.emu, attribute, thread->teb->ptr()); - } - else - { - c.win_emu.log.error("Unsupported thread attribute type: %" PRIx64 "\n", type); - } - }, - i); - } - - return STATUS_SUCCESS; - } - NTSTATUS handle_NtQueryDebugFilterState() { return FALSE; @@ -3747,192 +572,6 @@ namespace return STATUS_SUCCESS; } - bool is_awaitable_object_type(const handle h) - { - return h.value.type == handle_types::thread // - || h.value.type == handle_types::mutant // - || h.value.type == handle_types::semaphore // - || h.value.type == handle_types::event; - } - - NTSTATUS handle_NtWaitForMultipleObjects(const syscall_context& c, const ULONG count, - const emulator_object handles, const WAIT_TYPE wait_type, - const BOOLEAN alertable, const emulator_object timeout) - { - if (alertable) - { - c.win_emu.log.print(color::gray, "Alertable NtWaitForMultipleObjects not supported yet!\n"); - } - - if (wait_type != WaitAny && wait_type != WaitAll) - { - c.win_emu.log.error("Wait type not supported!\n"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - auto& t = c.win_emu.current_thread(); - t.await_objects.clear(); - t.await_any = wait_type == WaitAny; - - for (ULONG i = 0; i < count; ++i) - { - const auto h = handles.read(i); - - if (!is_awaitable_object_type(h)) - { - c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForMultipleObjects: %d!\n", - h.value.type); - return STATUS_NOT_SUPPORTED; - } - - t.await_objects.push_back(h); - } - - if (timeout.value() && !t.await_time.has_value()) - { - t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read()); - } - - c.win_emu.yield_thread(); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtWaitForSingleObject(const syscall_context& c, const handle h, const BOOLEAN alertable, - const emulator_object timeout) - { - if (alertable) - { - c.win_emu.log.print(color::gray, "Alertable NtWaitForSingleObject not supported yet!\n"); - } - - if (!is_awaitable_object_type(h)) - { - c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForSingleObject: %d!\n", h.value.type); - return STATUS_NOT_SUPPORTED; - } - - auto& t = c.win_emu.current_thread(); - t.await_objects = {h}; - t.await_any = false; - - if (timeout.value() && !t.await_time.has_value()) - { - t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read()); - } - - c.win_emu.yield_thread(); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtTerminateThread(const syscall_context& c, const handle thread_handle, const NTSTATUS exit_status) - { - auto* thread = !thread_handle.bits ? c.proc.active_thread : c.proc.threads.get(thread_handle); - - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - thread->exit_status = exit_status; - c.win_emu.callbacks.on_thread_terminated(thread_handle, *thread); - if (thread == c.proc.active_thread) - { - c.win_emu.yield_thread(); - } - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtDelayExecution(const syscall_context& c, const BOOLEAN alertable, - const emulator_object delay_interval) - { - if (alertable) - { - c.win_emu.log.error("Alertable NtDelayExecution not supported yet!\n"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - auto& t = c.win_emu.current_thread(); - t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), delay_interval.read()); - - c.win_emu.yield_thread(); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtAlertThreadByThreadId(const syscall_context& c, const uint64_t thread_id) - { - for (auto& t : c.proc.threads | std::views::values) - { - if (t.id == thread_id) - { - t.alerted = true; - return STATUS_SUCCESS; - } - } - - return STATUS_INVALID_HANDLE; - } - - NTSTATUS handle_NtAlertThreadByThreadIdEx(const syscall_context& c, const uint64_t thread_id, - const emulator_object>> lock) - { - if (lock.value()) - { - c.win_emu.log.print(color::gray, "NtAlertThreadByThreadIdEx with lock not supported yet!"); - // c.emu.stop(); - // return STATUS_NOT_SUPPORTED; - } - - return handle_NtAlertThreadByThreadId(c, thread_id); - } - - NTSTATUS handle_NtWaitForAlertByThreadId(const syscall_context& c, const uint64_t, - const emulator_object timeout) - { - auto& t = c.win_emu.current_thread(); - t.waiting_for_alert = true; - - if (timeout.value() && !t.await_time.has_value()) - { - t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read()); - } - - c.win_emu.yield_thread(); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtGetCurrentProcessorNumberEx(const syscall_context&, - const emulator_object processor_number) - { - constexpr PROCESSOR_NUMBER number{}; - processor_number.write(number); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtSetInformationVirtualMemory() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtEnumerateKey() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtAlpcConnectPort() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtSetInformationObject() - { - return STATUS_NOT_SUPPORTED; - } - NTSTATUS handle_NtUserGetCursorPos() { return STATUS_NOT_SUPPORTED; @@ -3972,160 +611,14 @@ namespace { return 0; } - - NTSTATUS handle_NtGetNextThread(const syscall_context& c, const handle process_handle, const handle thread_handle, - const ACCESS_MASK /*desired_access*/, const ULONG /*handle_attributes*/, - const ULONG flags, const emulator_object new_thread_handle) - { - if (process_handle != CURRENT_PROCESS || thread_handle.value.type != handle_types::thread) - { - return STATUS_INVALID_HANDLE; - } - - if (flags != 0) - { - c.win_emu.log.error("NtGetNextThread flags %X not supported\n", flags); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - bool return_next_thread = thread_handle == NULL_HANDLE; - for (auto& t : c.proc.threads) - { - if (return_next_thread && !t.second.is_terminated()) - { - ++t.second.ref_count; - new_thread_handle.write(c.proc.threads.make_handle(t.first)); - return STATUS_SUCCESS; - } - - if (t.first == thread_handle.value.id) - { - return_next_thread = true; - } - } - - new_thread_handle.write(NULL_HANDLE); - return STATUS_NO_MORE_ENTRIES; - } - - NTSTATUS handle_NtGetContextThread(const syscall_context& c, const handle thread_handle, - const emulator_object thread_context) - { - const auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); - - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - c.proc.active_thread->save(c.emu); - const auto _ = utils::finally([&] { - c.proc.active_thread->restore(c.emu); // - }); - - thread->restore(c.emu); - - thread_context.access([&](CONTEXT64& context) { - if ((context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) == CONTEXT_DEBUG_REGISTERS_64) - { - c.win_emu.log.print(color::pink, "--> Reading debug registers!\n"); - } - - cpu_context::save(c.emu, context); - }); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtSetTimerResolution(const syscall_context&, const ULONG /*desired_resolution*/, - const BOOLEAN set_resolution, const emulator_object current_resolution) - { - if (current_resolution) - { - current_resolution.write(0x0002625a); - } - - if (set_resolution) - { - return STATUS_TIMER_RESOLUTION_NOT_SET; - } - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtSetContextThread(const syscall_context& c, const handle thread_handle, - const emulator_object thread_context) - { - const auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); - - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - const auto needs_swich = thread != c.proc.active_thread; - - if (needs_swich) - { - c.proc.active_thread->save(c.emu); - thread->restore(c.emu); - } - - const auto _ = utils::finally([&] { - if (needs_swich) - { - c.proc.active_thread->restore(c.emu); // - } - }); - - const auto context = thread_context.read(); - cpu_context::restore(c.emu, context); - - if ((context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) == CONTEXT_DEBUG_REGISTERS_64) - { - c.win_emu.log.print(color::pink, "--> Setting debug registers!\n"); - } - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtYieldExecution(const syscall_context& c) - { - c.win_emu.yield_thread(); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtResumeThread(const syscall_context& c, const handle thread_handle, - const emulator_object previous_suspend_count) - { - auto* thread = c.proc.threads.get(thread_handle); - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - const auto old_count = thread->suspended; - if (previous_suspend_count) - { - previous_suspend_count.write(old_count); - } - - if (old_count > 0) - { - thread->suspended -= 1; - } - - return STATUS_SUCCESS; - } } void syscall_dispatcher::add_handlers(std::map& handler_mapping) { -#define add_handler(syscall) \ - do \ - { \ - handler_mapping[#syscall] = make_syscall_handler(); \ +#define add_handler(syscall) \ + do \ + { \ + handler_mapping[#syscall] = make_syscall_handler(); \ } while (0) add_handler(NtSetInformationThread); @@ -4257,4 +750,4 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtUserGetProcessUIContextInformation); #undef add_handler -} +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/event.cpp b/src/windows-emulator/syscalls/event.cpp new file mode 100644 index 00000000..64aa329a --- /dev/null +++ b/src/windows-emulator/syscalls/event.cpp @@ -0,0 +1,136 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtSetEvent(const syscall_context& c, const uint64_t handle, + const emulator_object previous_state) + { + if (handle == DBWIN_DATA_READY) + { + if (c.proc.dbwin_buffer) + { + constexpr auto pid_length = 4; + const auto debug_data = read_string(c.win_emu.memory, c.proc.dbwin_buffer + pid_length); + c.win_emu.log.info("--> Debug string: %s\n", debug_data.c_str()); + } + + return STATUS_SUCCESS; + } + + auto* entry = c.proc.events.get(handle); + if (!entry) + { + return STATUS_INVALID_HANDLE; + } + + if (previous_state.value()) + { + previous_state.write(entry->signaled ? 1ULL : 0ULL); + } + + entry->signaled = true; + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtTraceEvent() + { + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtClearEvent(const syscall_context& c, const handle event_handle) + { + auto* e = c.proc.events.get(event_handle); + if (!e) + { + return STATUS_INVALID_HANDLE; + } + + e->signaled = false; + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtCreateEvent(const syscall_context& c, const emulator_object event_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes, + const EVENT_TYPE event_type, const BOOLEAN initial_state) + { + std::u16string name{}; + if (object_attributes) + { + const auto attributes = object_attributes.read(); + if (attributes.ObjectName) + { + name = read_unicode_string( + c.emu, reinterpret_cast>*>(attributes.ObjectName)); + } + } + + if (!name.empty()) + { + for (auto& entry : c.proc.events) + { + if (entry.second.name == name) + { + ++entry.second.ref_count; + event_handle.write(c.proc.events.make_handle(entry.first)); + return STATUS_OBJECT_NAME_EXISTS; + } + } + } + + event e{}; + e.type = event_type; + e.signaled = initial_state != FALSE; + e.name = std::move(name); + + const auto handle = c.proc.events.store(std::move(e)); + event_handle.write(handle); + + static_assert(sizeof(EVENT_TYPE) == sizeof(uint32_t)); + static_assert(sizeof(ACCESS_MASK) == sizeof(uint32_t)); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenEvent(const syscall_context& c, const emulator_object event_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + const auto name = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + c.win_emu.log.print(color::dark_gray, "--> Event name: %s\n", u16_to_u8(name).c_str()); + + if (name == u"\\KernelObjects\\SystemErrorPortReady") + { + event_handle.write(WER_PORT_READY.bits); + return STATUS_SUCCESS; + } + + if (name == u"DBWIN_DATA_READY") + { + event_handle.write(DBWIN_DATA_READY.bits); + return STATUS_SUCCESS; + } + + if (name == u"DBWIN_BUFFER_READY") + { + event_handle.write(DBWIN_BUFFER_READY.bits); + return STATUS_SUCCESS; + } + + for (auto& entry : c.proc.events) + { + if (entry.second.name == name) + { + ++entry.second.ref_count; + event_handle.write(c.proc.events.make_handle(entry.first).bits); + return STATUS_SUCCESS; + } + } + + return STATUS_NOT_FOUND; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/exception.cpp b/src/windows-emulator/syscalls/exception.cpp new file mode 100644 index 00000000..dcaebb91 --- /dev/null +++ b/src/windows-emulator/syscalls/exception.cpp @@ -0,0 +1,44 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtRaiseHardError(const syscall_context& c, const NTSTATUS error_status, + const ULONG /*number_of_parameters*/, + const emulator_object>> + /*unicode_string_parameter_mask*/, + const emulator_object /*parameters*/, + const HARDERROR_RESPONSE_OPTION /*valid_response_option*/, + const emulator_object response) + { + if (response) + { + response.write(ResponseAbort); + } + + c.proc.exit_status = error_status; + c.proc.exception_rip = c.emu.read_instruction_pointer(); + c.emu.stop(); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtRaiseException(const syscall_context& c, + const emulator_object>> + /*exception_record*/, + const emulator_object thread_context, const BOOLEAN handle_exception) + { + if (handle_exception) + { + c.win_emu.log.error("Unhandled exceptions not supported yet!\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + c.proc.exception_rip = thread_context.read().Rip; + c.emu.stop(); + + return STATUS_SUCCESS; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/file.cpp b/src/windows-emulator/syscalls/file.cpp new file mode 100644 index 00000000..471329b7 --- /dev/null +++ b/src/windows-emulator/syscalls/file.cpp @@ -0,0 +1,788 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +#include +#include + +#include + +namespace syscalls +{ + NTSTATUS handle_NtSetInformationFile(const syscall_context& c, const handle file_handle, + const emulator_object>> io_status_block, + const uint64_t file_information, const ULONG length, + const FILE_INFORMATION_CLASS info_class) + { + const auto* f = c.proc.files.get(file_handle); + if (!f) + { + return STATUS_INVALID_HANDLE; + } + + if (info_class == FilePositionInformation) + { + if (!f->handle) + { + return STATUS_NOT_SUPPORTED; + } + + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = sizeof(FILE_POSITION_INFORMATION); + io_status_block.write(block); + } + + if (length != sizeof(FILE_POSITION_INFORMATION)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, file_information}; + const auto i = info.read(); + + if (!f->handle.seek_to(i.CurrentByteOffset.QuadPart)) + { + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported set file info class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryVolumeInformationFile(const syscall_context& c, const handle file_handle, + const uint64_t /*io_status_block*/, const uint64_t fs_information, + const ULONG /*length*/, + const FS_INFORMATION_CLASS fs_information_class) + { + if (fs_information_class == FileFsDeviceInformation) + { + const emulator_object info_obj{c.emu, fs_information}; + info_obj.access([&](FILE_FS_DEVICE_INFORMATION& info) { + if (file_handle == STDOUT_HANDLE && !c.win_emu.buffer_stdout) + { + info.DeviceType = FILE_DEVICE_CONSOLE; + info.Characteristics = 0x20000; + } + else + { + info.DeviceType = FILE_DEVICE_DISK; + info.Characteristics = 0x20020; + } + }); + + return STATUS_SUCCESS; + } + + if (fs_information_class == FileFsSizeInformation) + { + const emulator_object info_obj{c.emu, fs_information}; + info_obj.access([&](FILE_FS_SIZE_INFORMATION& info) { + info.BytesPerSector = 0x1000; + info.SectorsPerAllocationUnit = 0x1000; + info.TotalAllocationUnits.QuadPart = 0x10000; + info.AvailableAllocationUnits.QuadPart = 0x1000; + }); + + return STATUS_SUCCESS; + } + + if (fs_information_class == FileFsVolumeInformation) + { + constexpr FILE_FS_VOLUME_INFORMATION volume_info{}; + c.emu.write_memory(fs_information, volume_info); + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported fs info class: %X\n", fs_information_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + std::vector scan_directory(const std::filesystem::path& dir) + { + std::vector files{ + {"."}, + {".."}, + }; + + for (const auto& file : std::filesystem::directory_iterator(dir)) + { + files.emplace_back(file_entry{ + .file_path = file.path().filename(), + }); + } + + return files; + } + + template + NTSTATUS handle_file_enumeration(const syscall_context& c, + const emulator_object>> io_status_block, + const uint64_t file_information, const uint32_t length, const ULONG query_flags, + file* f) + { + 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)); + } + + auto& enum_state = *f->enumeration_state; + + size_t current_offset{0}; + emulator_object object{c.emu}; + + size_t current_index = enum_state.current_index; + + do + { + if (current_index >= enum_state.files.size()) + { + break; + } + + const auto new_offset = align_up(current_offset, 8); + const auto& current_file = enum_state.files[current_index]; + const auto file_name = current_file.file_path.u16string(); + const auto required_size = sizeof(T) + (file_name.size() * 2) - 2; + const auto end_offset = new_offset + required_size; + + if (end_offset > length) + { + if (current_offset == 0) + { + IO_STATUS_BLOCK> block{}; + block.Information = end_offset; + io_status_block.write(block); + + return STATUS_BUFFER_OVERFLOW; + } + + break; + } + + if (object) + { + const auto object_offset = object.value() - file_information; + + object.access( + [&](T& dir_info) { dir_info.NextEntryOffset = static_cast(new_offset - object_offset); }); + } + + T info{}; + info.NextEntryOffset = 0; + info.FileIndex = static_cast(current_index); + info.FileAttributes = FILE_ATTRIBUTE_NORMAL; + info.FileNameLength = static_cast(file_name.size() * 2); + + object.set_address(file_information + new_offset); + object.write(info); + + c.emu.write_memory(object.value() + offsetof(T, FileName), file_name.data(), info.FileNameLength); + + ++current_index; + current_offset = end_offset; + } while ((query_flags & SL_RETURN_SINGLE_ENTRY) == 0); + + if ((query_flags & SL_NO_CURSOR_UPDATE) == 0) + { + enum_state.current_index = current_index; + } + + IO_STATUS_BLOCK> block{}; + block.Information = current_offset; + io_status_block.write(block); + + return current_index < enum_state.files.size() ? STATUS_SUCCESS : STATUS_NO_MORE_FILES; + } + + NTSTATUS handle_NtQueryDirectoryFileEx( + const syscall_context& c, const handle file_handle, const handle /*event_handle*/, + const emulator_pointer /*PIO_APC_ROUTINE*/ /*apc_routine*/, const emulator_pointer /*apc_context*/, + const emulator_object>> io_status_block, const uint64_t file_information, + const uint32_t length, const uint32_t info_class, const ULONG query_flags, + const emulator_object>> /*file_name*/) + { + auto* f = c.proc.files.get(file_handle); + if (!f || !f->is_directory()) + { + return STATUS_INVALID_HANDLE; + } + + if (info_class == FileDirectoryInformation) + { + return handle_file_enumeration(c, io_status_block, file_information, length, + query_flags, f); + } + + if (info_class == FileFullDirectoryInformation) + { + return handle_file_enumeration(c, io_status_block, file_information, length, + query_flags, f); + } + + if (info_class == FileBothDirectoryInformation) + { + return handle_file_enumeration(c, io_status_block, file_information, length, + query_flags, f); + } + + c.win_emu.log.error("Unsupported query directory file info class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryInformationFile( + const syscall_context& c, const handle file_handle, + const emulator_object>> io_status_block, const uint64_t file_information, + const uint32_t length, const uint32_t info_class) + { + IO_STATUS_BLOCK> 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 ret(STATUS_INVALID_HANDLE); + } + + if (info_class == FileNameInformation || info_class == FileNormalizedNameInformation) + { + const auto relative_path = u"\\" + windows_path(f->name).without_drive().u16string(); + const auto required_length = sizeof(FILE_NAME_INFORMATION) + (relative_path.size() * 2); + + block.Information = required_length; + + if (length < block.Information) + { + return ret(STATUS_BUFFER_OVERFLOW); + } + + c.emu.write_memory(file_information, FILE_NAME_INFORMATION{ + .FileNameLength = static_cast(relative_path.size() * 2), + .FileName = {}, + }); + + c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), relative_path.c_str(), + (relative_path.size() + 1) * 2); + + return ret(STATUS_SUCCESS); + } + + if (info_class == FileStandardInformation) + { + block.Information = sizeof(FILE_STANDARD_INFORMATION); + + if (length < block.Information) + { + return ret(STATUS_BUFFER_OVERFLOW); + } + + const emulator_object info{c.emu, file_information}; + FILE_STANDARD_INFORMATION i{}; + i.Directory = f->is_directory() ? TRUE : FALSE; + + if (f->handle) + { + i.EndOfFile.QuadPart = f->handle.size(); + } + + info.write(i); + + return ret(STATUS_SUCCESS); + } + + if (info_class == FilePositionInformation) + { + if (!f->handle) + { + return ret(STATUS_NOT_SUPPORTED); + } + + block.Information = sizeof(FILE_POSITION_INFORMATION); + + if (length < block.Information) + { + return ret(STATUS_BUFFER_OVERFLOW); + } + + const emulator_object info{c.emu, file_information}; + FILE_POSITION_INFORMATION i{}; + + i.CurrentByteOffset.QuadPart = f->handle.tell(); + + info.write(i); + + return ret(STATUS_SUCCESS); + } + + if (info_class == FileAttributeTagInformation) + { + if (!f->handle) + { + return ret(STATUS_NOT_SUPPORTED); + } + + block.Information = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION); + + if (length < block.Information) + { + return ret(STATUS_BUFFER_OVERFLOW); + } + + const emulator_object info{c.emu, file_information}; + FILE_ATTRIBUTE_TAG_INFORMATION i{}; + + i.FileAttributes = f->is_directory() ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; + + info.write(i); + + return ret(STATUS_SUCCESS); + } + + c.win_emu.log.error("Unsupported query file info class: %X\n", info_class); + c.emu.stop(); + + return ret(STATUS_NOT_SUPPORTED); + } + + void commit_file_data(const std::string_view data, emulator& emu, + const emulator_object>> io_status_block, + const uint64_t buffer) + { + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = data.size(); + io_status_block.write(block); + } + + emu.write_memory(buffer, data.data(), data.size()); + } + + NTSTATUS handle_NtReadFile(const syscall_context& c, const handle file_handle, const uint64_t /*event*/, + const uint64_t /*apc_routine*/, const uint64_t /*apc_context*/, + const emulator_object>> io_status_block, + const uint64_t buffer, const ULONG length, + const emulator_object /*byte_offset*/, + const emulator_object /*key*/) + { + std::string temp_buffer{}; + temp_buffer.resize(length); + + if (file_handle == STDIN_HANDLE) + { + char chr{}; + if (std::cin.readsome(&chr, 1) <= 0) + { + std::cin.read(&chr, 1); + } + + std::cin.putback(chr); + + const auto read_count = + std::cin.readsome(temp_buffer.data(), static_cast(temp_buffer.size())); + const auto count = std::max(read_count, static_cast(0)); + + commit_file_data(std::string_view(temp_buffer.data(), count), c.emu, io_status_block, buffer); + return STATUS_SUCCESS; + } + + const auto* f = c.proc.files.get(file_handle); + if (!f) + { + return STATUS_INVALID_HANDLE; + } + + const auto bytes_read = fread(temp_buffer.data(), 1, temp_buffer.size(), f->handle); + commit_file_data(std::string_view(temp_buffer.data(), bytes_read), c.emu, io_status_block, buffer); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtWriteFile(const syscall_context& c, const handle file_handle, const uint64_t /*event*/, + const uint64_t /*apc_routine*/, const uint64_t /*apc_context*/, + const emulator_object>> io_status_block, + const uint64_t buffer, const ULONG length, + const emulator_object /*byte_offset*/, + const emulator_object /*key*/) + { + std::string temp_buffer{}; + temp_buffer.resize(length); + c.emu.read_memory(buffer, temp_buffer.data(), temp_buffer.size()); + + if (file_handle == STDOUT_HANDLE) + { + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = length; + io_status_block.write(block); + } + + c.win_emu.callbacks.on_stdout(temp_buffer); + + if (!temp_buffer.ends_with("\n")) + { + temp_buffer.push_back('\n'); + } + + c.win_emu.log.info("%.*s", static_cast(temp_buffer.size()), temp_buffer.data()); + + return STATUS_SUCCESS; + } + + const auto* f = c.proc.files.get(file_handle); + if (!f) + { + return STATUS_INVALID_HANDLE; + } + + const auto bytes_written = fwrite(temp_buffer.data(), 1, temp_buffer.size(), f->handle); + + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = bytes_written; + io_status_block.write(block); + } + + return STATUS_SUCCESS; + } + + constexpr std::u16string map_mode(const ACCESS_MASK desired_access, const ULONG create_disposition) + { + std::u16string mode{}; + + switch (create_disposition) + { + case FILE_CREATE: + case FILE_SUPERSEDE: + if (desired_access & GENERIC_WRITE) + { + mode = u"wb"; + } + break; + + case FILE_OPEN: + case FILE_OPEN_IF: + if (desired_access & GENERIC_WRITE) + { + mode = u"r+b"; + } + else if (desired_access & GENERIC_READ || desired_access & SYNCHRONIZE) + { + mode = u"rb"; + } + break; + + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + if (desired_access & GENERIC_WRITE) + { + mode = u"w+b"; + } + break; + + default: + mode = u""; + break; + } + + if (desired_access & FILE_APPEND_DATA) + { + mode = u"a+b"; + } + + return mode; + } + + std::optional 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()); + } + + constexpr std::u16string_view unc_prefix = u"\\??\\"; + if (!filename.starts_with(unc_prefix)) + { + return std::nullopt; + } + + const auto path = filename.substr(unc_prefix.size()); + + const std::set> devices{ + u"Nsi", + u"MountPointManager", + }; + + if (devices.contains(path)) + { + return path; + } + + return std::nullopt; + } + + NTSTATUS handle_NtCreateFile(const syscall_context& c, const emulator_object file_handle, + ACCESS_MASK desired_access, + const emulator_object>> object_attributes, + const emulator_object>> /*io_status_block*/, + const emulator_object /*allocation_size*/, ULONG /*file_attributes*/, + ULONG /*share_access*/, ULONG create_disposition, ULONG create_options, + uint64_t ea_buffer, ULONG ea_length) + { + const auto attributes = object_attributes.read(); + auto filename = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + + auto printer = utils::finally([&] { + c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(filename).c_str()); // + }); + + 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, + }; + + 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); + + return STATUS_SUCCESS; + } + + handle root_handle{}; + root_handle.bits = attributes.RootDirectory; + if (root_handle.value.is_pseudo && (filename == u"\\Reference" || filename == u"\\Connect")) + { + file_handle.write(root_handle); + return STATUS_SUCCESS; + } + + file f{}; + f.name = std::move(filename); + + if (attributes.RootDirectory) + { + const auto* root = c.proc.files.get(attributes.RootDirectory); + if (!root) + { + return STATUS_INVALID_HANDLE; + } + + 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(); + + if (f.name.ends_with(u"\\") || create_options & FILE_DIRECTORY_FILE) + { + c.win_emu.log.print(color::dark_gray, "--> Opening folder: %s\n", u16_to_u8(f.name).c_str()); + + if (create_disposition & FILE_CREATE) + { + std::error_code 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))) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + const auto handle = c.proc.files.store(std::move(f)); + file_handle.write(handle); + + return STATUS_SUCCESS; + } + + c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(f.name).c_str()); + + const windows_path path = f.name; + std::u16string mode = map_mode(desired_access, create_disposition); + + if (mode.empty() || path.is_relative()) + { + return STATUS_NOT_SUPPORTED; + } + + FILE* file{}; + + const auto error = open_unicode(&file, c.win_emu.file_sys.translate(path), mode); + + if (!file) + { + switch (error) + { + case ENOENT: + return STATUS_OBJECT_NAME_NOT_FOUND; + case EACCES: + return STATUS_ACCESS_DENIED; + case EISDIR: + return STATUS_FILE_IS_A_DIRECTORY; + default: + return STATUS_NOT_SUPPORTED; + } + } + + f.handle = file; + + const auto handle = c.proc.files.store(std::move(f)); + file_handle.write(handle); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtQueryAttributesFile( + const syscall_context& c, const emulator_object>> object_attributes, + const emulator_object file_information) + { + if (!object_attributes) + { + return STATUS_INVALID_PARAMETER; + } + + const auto attributes = object_attributes.read(); + if (!attributes.ObjectName) + { + return STATUS_INVALID_PARAMETER; + } + + const auto filename = read_unicode_string( + c.emu, emulator_object>>{c.emu, attributes.ObjectName}); + + 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(); + + struct _stat64 file_stat{}; + if (_stat64(local_filename.c_str(), &file_stat) != 0) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + file_information.access([&](FILE_BASIC_INFORMATION& info) { + info.CreationTime = utils::convert_unix_to_windows_time(file_stat.st_atime); + info.LastAccessTime = utils::convert_unix_to_windows_time(file_stat.st_atime); + info.LastWriteTime = utils::convert_unix_to_windows_time(file_stat.st_mtime); + info.ChangeTime = info.LastWriteTime; + info.FileAttributes = FILE_ATTRIBUTE_NORMAL; + }); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenFile(const syscall_context& c, const emulator_object file_handle, + const ACCESS_MASK desired_access, + const emulator_object>> object_attributes, + const emulator_object>> io_status_block, + const ULONG share_access, const ULONG open_options) + { + return handle_NtCreateFile(c, file_handle, desired_access, object_attributes, io_status_block, {c.emu}, 0, + share_access, FILE_OPEN, open_options, 0, 0); + } + + NTSTATUS handle_NtOpenDirectoryObject( + const syscall_context& c, const emulator_object directory_handle, const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + const auto object_name = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + + if (object_name == u"\\KnownDlls") + { + directory_handle.write(KNOWN_DLLS_DIRECTORY); + return STATUS_SUCCESS; + } + + if (object_name == u"\\Sessions\\1\\BaseNamedObjects") + { + directory_handle.write(BASE_NAMED_OBJECTS_DIRECTORY); + return STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtOpenSymbolicLinkObject( + const syscall_context& c, const emulator_object link_handle, ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + const auto object_name = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + + if (object_name == u"KnownDllPath") + { + link_handle.write(KNOWN_DLLS_SYMLINK); + return STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQuerySymbolicLinkObject(const syscall_context& c, const handle link_handle, + const emulator_object>> link_target, + const emulator_object returned_length) + { + if (link_handle == KNOWN_DLLS_SYMLINK) + { + constexpr std::u16string_view system32 = u"C:\\WINDOWS\\System32"; + constexpr auto str_length = system32.size() * 2; + constexpr auto max_length = str_length + 2; + + returned_length.write(max_length); + + bool too_small = false; + link_target.access([&](UNICODE_STRING>& str) { + if (str.MaximumLength < max_length) + { + too_small = true; + return; + } + + str.Length = str_length; + c.emu.write_memory(str.Buffer, system32.data(), max_length); + }); + + return too_small ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/locale.cpp b/src/windows-emulator/syscalls/locale.cpp new file mode 100644 index 00000000..418993bb --- /dev/null +++ b/src/windows-emulator/syscalls/locale.cpp @@ -0,0 +1,61 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +#include + +namespace syscalls +{ + NTSTATUS handle_NtInitializeNlsFiles(const syscall_context& c, const emulator_object base_address, + const emulator_object default_locale_id, + const emulator_object /*default_casing_table_size*/) + { + const auto locale_file = + utils::io::read_file(c.win_emu.file_sys.translate(R"(C:\Windows\System32\locale.nls)")); + if (locale_file.empty()) + { + return STATUS_FILE_INVALID; + } + + const auto size = page_align_up(locale_file.size()); + const auto base = c.win_emu.memory.allocate_memory(size, memory_permission::read); + c.emu.write_memory(base, locale_file.data(), locale_file.size()); + + base_address.write(base); + default_locale_id.write(0x407); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtQueryDefaultLocale(const syscall_context&, BOOLEAN /*user_profile*/, + const emulator_object default_locale_id) + { + default_locale_id.write(0x407); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtGetNlsSectionPtr() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtGetMUIRegistryInfo() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtIsUILanguageComitted() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtUserGetKeyboardLayout() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryInstallUILanguage() + { + return STATUS_NOT_SUPPORTED; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/memory.cpp b/src/windows-emulator/syscalls/memory.cpp new file mode 100644 index 00000000..af531ab1 --- /dev/null +++ b/src/windows-emulator/syscalls/memory.cpp @@ -0,0 +1,287 @@ +#include "../std_include.hpp" +#include "../syscall_dispatcher.hpp" +#include "../cpu_context.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtQueryVirtualMemory(const syscall_context& c, const handle process_handle, + const uint64_t base_address, const uint32_t info_class, + const uint64_t memory_information, const uint32_t memory_information_length, + const emulator_object return_length) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == MemoryWorkingSetExInformation || info_class == MemoryImageExtensionInformation) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == MemoryBasicInformation) + { + if (return_length) + { + return_length.write(sizeof(EMU_MEMORY_BASIC_INFORMATION64)); + } + + if (memory_information_length != sizeof(EMU_MEMORY_BASIC_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, memory_information}; + + info.access([&](EMU_MEMORY_BASIC_INFORMATION64& image_info) { + const auto region_info = c.win_emu.memory.get_region_info(base_address); + + assert(!region_info.is_committed || region_info.is_reserved); + const auto state = region_info.is_reserved ? MEM_RESERVE : MEM_FREE; + image_info.State = region_info.is_committed ? MEM_COMMIT : state; + image_info.BaseAddress = reinterpret_cast(region_info.start); + image_info.AllocationBase = reinterpret_cast(region_info.allocation_base); + image_info.AllocationProtect = 0; + image_info.PartitionId = 0; + image_info.RegionSize = static_cast(region_info.length); + + image_info.Protect = map_emulator_to_nt_protection(region_info.permissions); + image_info.Type = MEM_PRIVATE; + }); + + return STATUS_SUCCESS; + } + + if (info_class == MemoryImageInformation) + { + if (return_length) + { + return_length.write(sizeof(MEMORY_IMAGE_INFORMATION64)); + } + + if (memory_information_length != sizeof(MEMORY_IMAGE_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const auto* mod = c.win_emu.mod_manager.find_by_address(base_address); + if (!mod) + { + c.win_emu.log.error("Bad address for memory image request: 0x%" PRIx64 "\n", base_address); + return STATUS_INVALID_ADDRESS; + } + + const emulator_object info{c.emu, memory_information}; + + info.access([&](MEMORY_IMAGE_INFORMATION64& image_info) { + image_info.ImageBase = reinterpret_cast(mod->image_base); + image_info.SizeOfImage = static_cast(mod->size_of_image); + image_info.ImageFlags = 0; + }); + + return STATUS_SUCCESS; + } + + if (info_class == MemoryRegionInformation) + { + if (return_length) + { + return_length.write(sizeof(MEMORY_REGION_INFORMATION64)); + } + + if (memory_information_length != sizeof(MEMORY_REGION_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const auto region_info = c.win_emu.memory.get_region_info(base_address); + if (!region_info.is_reserved) + { + return STATUS_INVALID_ADDRESS; + } + + const emulator_object info{c.emu, memory_information}; + + info.access([&](MEMORY_REGION_INFORMATION64& image_info) { + memset(&image_info, 0, sizeof(image_info)); + + image_info.AllocationBase = reinterpret_cast(region_info.allocation_base); + image_info.AllocationProtect = 0; + image_info.PartitionId = 0; + image_info.RegionSize = static_cast(region_info.allocation_length); + image_info.Reserved = 0x10; + }); + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported memory info class: %X\n", info_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtProtectVirtualMemory(const syscall_context& c, const handle process_handle, + const emulator_object base_address, + const emulator_object bytes_to_protect, const uint32_t protection, + const emulator_object old_protection) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + const auto orig_start = base_address.read(); + const auto orig_length = bytes_to_protect.read(); + + const auto aligned_start = page_align_down(orig_start); + const auto aligned_length = page_align_up(orig_start + orig_length) - aligned_start; + + base_address.write(aligned_start); + bytes_to_protect.write(static_cast(aligned_length)); + + const auto requested_protection = map_nt_to_emulator_protection(protection); + + c.win_emu.log.print(color::dark_gray, "--> Changing protection at 0x%" PRIx64 "-0x%" PRIx64 " to %s\n", + aligned_start, aligned_start + aligned_length, + get_permission_string(requested_protection).c_str()); + + memory_permission old_protection_value{}; + + try + { + c.win_emu.memory.protect_memory(aligned_start, aligned_length, requested_protection, &old_protection_value); + } + catch (...) + { + return STATUS_INVALID_ADDRESS; + } + + const auto current_protection = map_emulator_to_nt_protection(old_protection_value); + old_protection.write(current_protection); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtAllocateVirtualMemoryEx(const syscall_context& c, const handle process_handle, + const emulator_object base_address, + const emulator_object bytes_to_allocate, + const uint32_t allocation_type, const uint32_t page_protection) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + auto allocation_bytes = bytes_to_allocate.read(); + allocation_bytes = page_align_up(allocation_bytes); + bytes_to_allocate.write(allocation_bytes); + + const auto protection = map_nt_to_emulator_protection(page_protection); + + auto potential_base = base_address.read(); + if (!potential_base) + { + potential_base = c.win_emu.memory.find_free_allocation_base(allocation_bytes); + } + + if (!potential_base) + { + c.win_emu.log.print(color::dark_gray, "--> Not allocated\n"); + + return STATUS_MEMORY_NOT_ALLOCATED; + } + + base_address.write(potential_base); + + const bool reserve = allocation_type & MEM_RESERVE; + const bool commit = allocation_type & MEM_COMMIT; + + if ((allocation_type & ~(MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN)) || (!commit && !reserve)) + { + throw std::runtime_error("Unsupported allocation type!"); + } + + if (commit && !reserve && c.win_emu.memory.commit_memory(potential_base, allocation_bytes, protection)) + { + c.win_emu.log.print(color::dark_gray, "--> Committed 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base, + potential_base + allocation_bytes); + + return STATUS_SUCCESS; + } + + c.win_emu.log.print(color::dark_gray, "--> Allocated 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base, + potential_base + allocation_bytes); + + return c.win_emu.memory.allocate_memory(potential_base, allocation_bytes, protection, !commit) + ? STATUS_SUCCESS + : STATUS_MEMORY_NOT_ALLOCATED; + } + + NTSTATUS handle_NtAllocateVirtualMemory(const syscall_context& c, const handle process_handle, + const emulator_object base_address, const uint64_t /*zero_bits*/, + const emulator_object bytes_to_allocate, + const uint32_t allocation_type, const uint32_t page_protection) + { + return handle_NtAllocateVirtualMemoryEx(c, process_handle, base_address, bytes_to_allocate, allocation_type, + page_protection); + } + + NTSTATUS handle_NtFreeVirtualMemory(const syscall_context& c, const handle process_handle, + const emulator_object base_address, + const emulator_object bytes_to_allocate, const uint32_t free_type) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + const auto allocation_base = base_address.read(); + const auto allocation_size = bytes_to_allocate.read(); + + if (free_type & MEM_RELEASE) + { + return c.win_emu.memory.release_memory(allocation_base, allocation_size) ? STATUS_SUCCESS + : STATUS_MEMORY_NOT_ALLOCATED; + } + + if (free_type & MEM_DECOMMIT) + { + return c.win_emu.memory.decommit_memory(allocation_base, allocation_size) ? STATUS_SUCCESS + : STATUS_MEMORY_NOT_ALLOCATED; + } + + throw std::runtime_error("Bad free type"); + } + + NTSTATUS handle_NtReadVirtualMemory(const syscall_context& c, const handle process_handle, + const emulator_pointer base_address, const emulator_pointer buffer, + const ULONG number_of_bytes_to_read, + const emulator_object number_of_bytes_read) + { + number_of_bytes_read.write(0); + + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + std::vector memory{}; + memory.resize(number_of_bytes_to_read); + + if (!c.emu.try_read_memory(base_address, memory.data(), memory.size())) + { + return STATUS_INVALID_ADDRESS; + } + + c.emu.write_memory(buffer, memory.data(), memory.size()); + number_of_bytes_read.write(number_of_bytes_to_read); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtSetInformationVirtualMemory() + { + return STATUS_NOT_SUPPORTED; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/mutant.cpp b/src/windows-emulator/syscalls/mutant.cpp new file mode 100644 index 00000000..b3bba6ca --- /dev/null +++ b/src/windows-emulator/syscalls/mutant.cpp @@ -0,0 +1,78 @@ +#include "../std_include.hpp" +#include "../syscall_dispatcher.hpp" +#include "../cpu_context.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtReleaseMutant(const syscall_context& c, const handle mutant_handle, + const emulator_object previous_count) + { + if (mutant_handle.value.type != handle_types::mutant) + { + c.win_emu.log.error("Bad handle type for NtReleaseMutant\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto* mutant = c.proc.mutants.get(mutant_handle); + if (!mutant) + { + return STATUS_INVALID_HANDLE; + } + + const auto [old_count, succeeded] = mutant->release(c.win_emu.current_thread().id); + + if (previous_count) + { + previous_count.write(static_cast(old_count)); + } + + return succeeded ? STATUS_SUCCESS : STATUS_MUTANT_NOT_OWNED; + } + + NTSTATUS handle_NtCreateMutant(const syscall_context& c, const emulator_object mutant_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes, + const BOOLEAN initial_owner) + { + std::u16string name{}; + if (object_attributes) + { + const auto attributes = object_attributes.read(); + if (attributes.ObjectName) + { + name = read_unicode_string( + c.emu, emulator_object>>{c.emu, attributes.ObjectName}); + c.win_emu.log.print(color::dark_gray, "--> Mutant name: %s\n", u16_to_u8(name).c_str()); + } + } + + if (!name.empty()) + { + for (auto& entry : c.proc.mutants) + { + if (entry.second.name == name) + { + ++entry.second.ref_count; + mutant_handle.write(c.proc.mutants.make_handle(entry.first)); + return STATUS_OBJECT_NAME_EXISTS; + } + } + } + + mutant e{}; + e.name = std::move(name); + + if (initial_owner) + { + e.try_lock(c.win_emu.current_thread().id); + } + + const auto handle = c.proc.mutants.store(std::move(e)); + mutant_handle.write(handle); + + return STATUS_SUCCESS; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/object.cpp b/src/windows-emulator/syscalls/object.cpp new file mode 100644 index 00000000..76ca46e4 --- /dev/null +++ b/src/windows-emulator/syscalls/object.cpp @@ -0,0 +1,189 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtClose(const syscall_context& c, const handle h) + { + const auto value = h.value; + if (value.is_pseudo) + { + return STATUS_SUCCESS; + } + + if (h.value.type == handle_types::thread) + { + const auto* t = c.proc.threads.get(h); + if (t == c.proc.active_thread && t->ref_count == 1) + { + // TODO: Better handle ref counting + return STATUS_SUCCESS; + } + } + + auto* handle_store = c.proc.get_handle_store(h); + if (handle_store && handle_store->erase(h)) + { + return STATUS_SUCCESS; + } + + return STATUS_INVALID_HANDLE; + } + + NTSTATUS handle_NtDuplicateObject(const syscall_context& c, const handle source_process_handle, + const handle source_handle, const handle target_process_handle, + const emulator_object target_handle, const ACCESS_MASK /*desired_access*/, + const ULONG /*handle_attributes*/, const ULONG /*options*/) + { + if (source_process_handle != CURRENT_PROCESS || target_process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + if (source_handle.value.is_pseudo) + { + target_handle.write(source_handle); + return STATUS_SUCCESS; + } + + auto* store = c.proc.get_handle_store(source_handle); + if (!store) + { + return STATUS_NOT_SUPPORTED; + } + + const auto new_handle = store->duplicate(source_handle); + if (!new_handle) + { + return STATUS_INVALID_HANDLE; + } + + target_handle.write(*new_handle); + return STATUS_SUCCESS; + } + + 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 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>) + (device_path.size() + 1) * 2; + return_length.write(static_cast(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; + } + + bool is_awaitable_object_type(const handle h) + { + return h.value.type == handle_types::thread // + || h.value.type == handle_types::mutant // + || h.value.type == handle_types::semaphore // + || h.value.type == handle_types::event; + } + + NTSTATUS handle_NtWaitForMultipleObjects(const syscall_context& c, const ULONG count, + const emulator_object handles, const WAIT_TYPE wait_type, + const BOOLEAN alertable, const emulator_object timeout) + { + if (alertable) + { + c.win_emu.log.print(color::gray, "Alertable NtWaitForMultipleObjects not supported yet!\n"); + } + + if (wait_type != WaitAny && wait_type != WaitAll) + { + c.win_emu.log.error("Wait type not supported!\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto& t = c.win_emu.current_thread(); + t.await_objects.clear(); + t.await_any = wait_type == WaitAny; + + for (ULONG i = 0; i < count; ++i) + { + const auto h = handles.read(i); + + if (!is_awaitable_object_type(h)) + { + c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForMultipleObjects: %d!\n", + h.value.type); + return STATUS_NOT_SUPPORTED; + } + + t.await_objects.push_back(h); + } + + if (timeout.value() && !t.await_time.has_value()) + { + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read()); + } + + c.win_emu.yield_thread(); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtWaitForSingleObject(const syscall_context& c, const handle h, const BOOLEAN alertable, + const emulator_object timeout) + { + if (alertable) + { + c.win_emu.log.print(color::gray, "Alertable NtWaitForSingleObject not supported yet!\n"); + } + + if (!is_awaitable_object_type(h)) + { + c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForSingleObject: %d!\n", h.value.type); + return STATUS_NOT_SUPPORTED; + } + + auto& t = c.win_emu.current_thread(); + t.await_objects = {h}; + t.await_any = false; + + if (timeout.value() && !t.await_time.has_value()) + { + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read()); + } + + c.win_emu.yield_thread(); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtSetInformationObject() + { + return STATUS_NOT_SUPPORTED; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/port.cpp b/src/windows-emulator/syscalls/port.cpp new file mode 100644 index 00000000..28e91e8b --- /dev/null +++ b/src/windows-emulator/syscalls/port.cpp @@ -0,0 +1,79 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtConnectPort(const syscall_context& c, const emulator_object client_port_handle, + const emulator_object>> server_port_name, + const emulator_object /*security_qos*/, + const emulator_object client_shared_memory, + const emulator_object /*server_shared_memory*/, + const emulator_object /*maximum_message_length*/, + const emulator_pointer connection_info, + const emulator_object connection_info_length) + { + auto port_name = read_unicode_string(c.emu, server_port_name); + c.win_emu.log.print(color::dark_gray, "NtConnectPort: %s\n", u16_to_u8(port_name).c_str()); + + port p{}; + p.name = std::move(port_name); + + if (connection_info) + { + std::vector zero_mem{}; + zero_mem.resize(connection_info_length.read(), 0); + c.emu.write_memory(connection_info, zero_mem.data(), zero_mem.size()); + } + + client_shared_memory.access([&](PORT_VIEW64& view) { + p.view_base = c.win_emu.memory.allocate_memory(view.ViewSize, memory_permission::read_write); + view.ViewBase = p.view_base; + view.ViewRemoteBase = view.ViewBase; + }); + + const auto handle = c.proc.ports.store(std::move(p)); + client_port_handle.write(handle); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& c, const handle port_handle, const ULONG /*flags*/, + const emulator_object /*send_message*/, + const emulator_object + /*send_message_attributes*/, + const emulator_object receive_message, + const emulator_object::SIZE_T> /*buffer_length*/, + const emulator_object + /*receive_message_attributes*/, + const emulator_object /*timeout*/) + { + const auto* port = c.proc.ports.get(port_handle); + if (!port) + { + return STATUS_INVALID_HANDLE; + } + + if (port->name != u"\\Windows\\ApiPort") + { + c.win_emu.log.error("!!! BAD PORT\n"); + return STATUS_NOT_SUPPORTED; + } + + // TODO: Fix this. This is broken and wrong. + + const emulator_object>> data{c.emu, receive_message.value() + 0x48}; + const auto dest = data.read(); + const auto base = dest.Base; + + const auto value = base + 0x10; + c.emu.write_memory(base + 8, &value, sizeof(value)); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtAlpcConnectPort() + { + return STATUS_NOT_SUPPORTED; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/process.cpp b/src/windows-emulator/syscalls/process.cpp new file mode 100644 index 00000000..7075fa34 --- /dev/null +++ b/src/windows-emulator/syscalls/process.cpp @@ -0,0 +1,389 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +#include + +namespace syscalls +{ + NTSTATUS handle_NtQueryInformationProcess(const syscall_context& c, const handle process_handle, + const uint32_t info_class, const uint64_t process_information, + const uint32_t process_information_length, + const emulator_object return_length) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == ProcessImageInformation) + { + if (return_length) + { + return_length.write(sizeof(SECTION_IMAGE_INFORMATION>)); + } + + if (process_information_length != sizeof(SECTION_IMAGE_INFORMATION>)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object>> info{c.emu, process_information}; + info.access([&](SECTION_IMAGE_INFORMATION>& i) { + const auto& mod = *c.win_emu.mod_manager.executable; + + const emulator_object dos_header_obj{c.emu, mod.image_base}; + const auto dos_header = dos_header_obj.read(); + + const emulator_object> nt_headers_obj{c.emu, + mod.image_base + dos_header.e_lfanew}; + const auto nt_headers = nt_headers_obj.read(); + + const auto& file_header = nt_headers.FileHeader; + const auto& optional_header = nt_headers.OptionalHeader; + + i.TransferAddress = 0; + i.MaximumStackSize = optional_header.SizeOfStackReserve; + i.CommittedStackSize = optional_header.SizeOfStackCommit; + i.SubSystemType = optional_header.Subsystem; + i.SubSystemMajorVersion = optional_header.MajorSubsystemVersion; + i.SubSystemMinorVersion = optional_header.MinorSubsystemVersion; + i.MajorOperatingSystemVersion = optional_header.MajorOperatingSystemVersion; + i.MinorOperatingSystemVersion = optional_header.MinorOperatingSystemVersion; + i.ImageCharacteristics = file_header.Characteristics; + i.DllCharacteristics = optional_header.DllCharacteristics; + i.Machine = file_header.Machine; + i.ImageContainsCode = TRUE; + i.ImageFlags = 0; // TODO + i.ImageFileSize = optional_header.SizeOfImage; + i.LoaderFlags = optional_header.LoaderFlags; + i.CheckSum = optional_header.CheckSum; + }); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessCookie) + { + if (return_length) + { + return_length.write(sizeof(uint32_t)); + } + + if (process_information_length != sizeof(uint32_t)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.write(0x01234567); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessDebugPort) + { + if (return_length) + { + return_length.write(sizeof(EmulatorTraits::PVOID)); + } + + if (process_information_length != sizeof(EmulatorTraits::PVOID)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object::PVOID> info{c.emu, process_information}; + info.write(0); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessDefaultHardErrorMode || info_class == ProcessWx86Information || + info_class == ProcessDebugFlags) + { + if (return_length) + { + return_length.write(sizeof(ULONG)); + } + + if (process_information_length != sizeof(ULONG)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.write(info_class == ProcessDebugFlags ? 1 : 0); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessDeviceMap) + { + c.win_emu.log.info("Handling ProcessDeviceMap request.\n"); + + if (return_length) + { + return_length.write(sizeof(EmulatorTraits::PVOID)); + } + + if (process_information_length != sizeof(EmulatorTraits::PVOID)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object::PVOID> info{c.emu, process_information}; + info.write(0); // NULL pointer + + return STATUS_SUCCESS; + } + + if (info_class == ProcessEnableAlignmentFaultFixup) + { + if (return_length) + { + return_length.write(sizeof(BOOLEAN)); + } + + if (process_information_length != sizeof(BOOLEAN)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.write(FALSE); // Alignment fault fixup is disabled + + return STATUS_SUCCESS; + } + + if (info_class == ProcessDebugObjectHandle) + { + if (return_length) + { + return_length.write(sizeof(handle)); + } + + if (process_information_length != sizeof(handle)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.write(NULL_HANDLE); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessEnclaveInformation || info_class == ProcessMitigationPolicy || + info_class == ProcessGroupInformation) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == ProcessTimes) + { + if (return_length) + { + return_length.write(sizeof(KERNEL_USER_TIMES)); + } + + if (process_information_length != sizeof(KERNEL_USER_TIMES)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.write(KERNEL_USER_TIMES{}); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessBasicInformation) + { + if (return_length) + { + return_length.write(sizeof(PROCESS_BASIC_INFORMATION64)); + } + + if (process_information_length != sizeof(PROCESS_BASIC_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.access([&](PROCESS_BASIC_INFORMATION64& basic_info) { + basic_info.PebBaseAddress = c.proc.peb.ptr(); + basic_info.UniqueProcessId = 1; + }); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessImageFileNameWin32) + { + const auto peb = c.proc.peb.read(); + emulator_object proc_params{c.emu, peb.ProcessParameters}; + const auto params = proc_params.read(); + const auto length = params.ImagePathName.Length + sizeof(UNICODE_STRING>) + 2; + + if (return_length) + { + return_length.write(static_cast(length)); + } + + if (process_information_length < length) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object>> info{c.emu, process_information}; + info.access([&](UNICODE_STRING>& str) { + const auto buffer_start = + static_cast(process_information) + sizeof(UNICODE_STRING>); + const auto string = read_unicode_string(c.emu, params.ImagePathName); + c.emu.write_memory(buffer_start, string.c_str(), (string.size() + 1) * 2); + str.Length = params.ImagePathName.Length; + str.MaximumLength = str.Length; + str.Buffer = buffer_start; + }); + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported process info class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtSetInformationProcess(const syscall_context& c, const handle process_handle, + const uint32_t info_class, const uint64_t process_information, + const uint32_t process_information_length) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == ProcessSchedulerSharedData || info_class == ProcessConsoleHostProcess || + info_class == ProcessFaultInformation || info_class == ProcessDefaultHardErrorMode || + info_class == ProcessRaiseUMExceptionOnInvalidHandleClose || + info_class == ProcessDynamicFunctionTableInformation) + { + return STATUS_SUCCESS; + } + + if (info_class == ProcessTlsInformation) + { + constexpr auto thread_data_offset = offsetof(PROCESS_TLS_INFO, ThreadData); + if (process_information_length < thread_data_offset) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object data{c.emu, process_information + thread_data_offset}; + + PROCESS_TLS_INFO tls_info{}; + c.emu.read_memory(process_information, &tls_info, thread_data_offset); + + for (uint32_t i = 0; i < tls_info.ThreadDataCount; ++i) + { + auto entry = data.read(i); + + const auto _ = utils::finally([&] { data.write(entry, i); }); + + if (i >= c.proc.threads.size()) + { + entry.Flags = 0; + continue; + } + + auto thread_iterator = c.proc.threads.begin(); + std::advance(thread_iterator, i); + + entry.Flags = 2; + + thread_iterator->second.teb->access([&](TEB64& teb) { + entry.ThreadId = teb.ClientId.UniqueThread; + + auto* tls_vector = teb.ThreadLocalStoragePointer; + + if (tls_info.TlsRequest == ProcessTlsReplaceIndex) + { + auto* tls_entry_ptr = tls_vector + tls_info.TlsIndex; + + const auto old_entry = c.emu.read_memory::PVOID>(tls_entry_ptr); + c.emu.write_memory::PVOID>(tls_entry_ptr, entry.TlsModulePointer); + + entry.TlsModulePointer = old_entry; + } + else if (tls_info.TlsRequest == ProcessTlsReplaceVector) + { + auto* new_tls_vector = entry.TlsVector; + + for (uint32_t index = 0; index < tls_info.TlsVectorLength; ++index) + { + auto* old_entry = c.emu.read_memory(tls_vector + index); + c.emu.write_memory(new_tls_vector + index, old_entry); + } + + teb.ThreadLocalStoragePointer = new_tls_vector; + entry.TlsVector = tls_vector; + } + }); + } + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported info process class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtOpenProcessToken(const syscall_context&, const handle process_handle, + const ACCESS_MASK /*desired_access*/, const emulator_object token_handle) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + token_handle.write(CURRENT_PROCESS_TOKEN); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenProcessTokenEx(const syscall_context& c, const handle process_handle, + const ACCESS_MASK desired_access, const ULONG /*handle_attributes*/, + const emulator_object token_handle) + { + return handle_NtOpenProcessToken(c, process_handle, desired_access, token_handle); + } + + NTSTATUS handle_NtTerminateProcess(const syscall_context& c, const handle process_handle, NTSTATUS exit_status) + { + if (process_handle == 0) + { + for (auto& thread : c.proc.threads | std::views::values) + { + if (&thread != c.proc.active_thread) + { + thread.exit_status = exit_status; + } + } + + return STATUS_SUCCESS; + } + + if (process_handle == CURRENT_PROCESS) + { + c.proc.exit_status = exit_status; + c.emu.stop(); + return STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/registry.cpp b/src/windows-emulator/syscalls/registry.cpp new file mode 100644 index 00000000..2dcaf779 --- /dev/null +++ b/src/windows-emulator/syscalls/registry.cpp @@ -0,0 +1,250 @@ +#include "../std_include.hpp" +#include "../syscall_dispatcher.hpp" +#include "../cpu_context.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtOpenKey(const syscall_context& c, const emulator_object key_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + auto key = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + + if (attributes.RootDirectory) + { + const auto* parent_handle = c.proc.registry_keys.get(attributes.RootDirectory); + if (!parent_handle) + { + return STATUS_INVALID_HANDLE; + } + + const std::filesystem::path full_path = parent_handle->hive.get() / parent_handle->path.get() / key; + key = full_path.u16string(); + } + + c.win_emu.log.print(color::dark_gray, "--> Registry key: %s\n", u16_to_u8(key).c_str()); + + auto entry = c.win_emu.registry.get_key({key}); + if (!entry.has_value()) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + const auto handle = c.proc.registry_keys.store(std::move(entry.value())); + key_handle.write(handle); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenKeyEx(const syscall_context& c, const emulator_object key_handle, + const ACCESS_MASK desired_access, + const emulator_object>> object_attributes, + ULONG /*open_options*/) + { + return handle_NtOpenKey(c, key_handle, desired_access, object_attributes); + } + + NTSTATUS handle_NtQueryKey(const syscall_context& c, const handle key_handle, + const KEY_INFORMATION_CLASS key_information_class, const uint64_t key_information, + const ULONG length, const emulator_object result_length) + { + const auto* key = c.proc.registry_keys.get(key_handle); + if (!key) + { + return STATUS_INVALID_HANDLE; + } + + if (key_information_class == KeyNameInformation) + { + auto key_name = (key->hive.get() / key->path.get()).u16string(); + while (key_name.ends_with(u'/') || key_name.ends_with(u'\\')) + { + key_name.pop_back(); + } + + std::ranges::transform(key_name, key_name.begin(), std::towupper); + + const auto required_size = sizeof(KEY_NAME_INFORMATION) + (key_name.size() * 2) - 1; + result_length.write(static_cast(required_size)); + + if (required_size > length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + KEY_NAME_INFORMATION info{}; + info.NameLength = static_cast(key_name.size() * 2); + + const emulator_object info_obj{c.emu, key_information}; + info_obj.write(info); + + c.emu.write_memory(key_information + offsetof(KEY_NAME_INFORMATION, Name), key_name.data(), + info.NameLength); + + return STATUS_SUCCESS; + } + + if (key_information_class == KeyFullInformation) + { + return STATUS_NOT_SUPPORTED; + } + + if (key_information_class == KeyHandleTagsInformation) + { + constexpr auto required_size = sizeof(KEY_HANDLE_TAGS_INFORMATION); + result_length.write(required_size); + + if (required_size > length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + KEY_HANDLE_TAGS_INFORMATION info{}; + info.HandleTags = 0; // ? + + const emulator_object info_obj{c.emu, key_information}; + info_obj.write(info); + + return STATUS_SUCCESS; + } + + c.win_emu.log.print(color::gray, "Unsupported registry class: %X\n", key_information_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryValueKey(const syscall_context& c, const handle key_handle, + const emulator_object>> value_name, + const KEY_VALUE_INFORMATION_CLASS key_value_information_class, + const uint64_t key_value_information, const ULONG length, + const emulator_object result_length) + { + const auto* key = c.proc.registry_keys.get(key_handle); + if (!key) + { + return STATUS_INVALID_HANDLE; + } + + const auto query_name = read_unicode_string(c.emu, value_name); + + const auto value = c.win_emu.registry.get_value(*key, u16_to_u8(query_name)); + if (!value) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + const std::u16string original_name(value->name.begin(), value->name.end()); + + if (key_value_information_class == KeyValueBasicInformation) + { + constexpr auto base_size = offsetof(KEY_VALUE_BASIC_INFORMATION, Name); + const auto required_size = base_size + (original_name.size() * 2) - 1; + result_length.write(static_cast(required_size)); + + KEY_VALUE_BASIC_INFORMATION info{}; + info.TitleIndex = 0; + info.Type = value->type; + info.NameLength = static_cast(original_name.size() * 2); + + if (base_size <= length) + { + c.emu.write_memory(key_value_information, &info, base_size); + } + + if (required_size > length) + { + return STATUS_BUFFER_OVERFLOW; + } + + c.emu.write_memory(key_value_information + base_size, original_name.data(), info.NameLength); + + return STATUS_SUCCESS; + } + + if (key_value_information_class == KeyValuePartialInformation) + { + constexpr auto base_size = offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data); + const auto required_size = base_size + value->data.size(); + result_length.write(static_cast(required_size)); + + KEY_VALUE_PARTIAL_INFORMATION info{}; + info.TitleIndex = 0; + info.Type = value->type; + info.DataLength = static_cast(value->data.size()); + + if (base_size <= length) + { + c.emu.write_memory(key_value_information, &info, base_size); + } + + if (required_size > length) + { + return STATUS_BUFFER_OVERFLOW; + } + + c.emu.write_memory(key_value_information + base_size, value->data.data(), value->data.size()); + + return STATUS_SUCCESS; + } + + if (key_value_information_class == KeyValueFullInformation) + { + constexpr auto base_size = offsetof(KEY_VALUE_FULL_INFORMATION, Name); + const auto name_size = original_name.size() * 2; + const auto value_size = value->data.size(); + const auto required_size = base_size + name_size + value_size + -1; + result_length.write(static_cast(required_size)); + + KEY_VALUE_FULL_INFORMATION info{}; + info.TitleIndex = 0; + info.Type = value->type; + info.DataLength = static_cast(value->data.size()); + info.NameLength = static_cast(original_name.size() * 2); + + if (base_size <= length) + { + c.emu.write_memory(key_value_information, &info, base_size); + } + + if (required_size > length) + { + return STATUS_BUFFER_OVERFLOW; + } + + c.emu.write_memory(key_value_information + base_size, original_name.data(), info.NameLength); + + c.emu.write_memory(key_value_information + base_size + info.NameLength, value->data.data(), + value->data.size()); + + return STATUS_SUCCESS; + } + + c.win_emu.log.print(color::gray, "Unsupported registry value class: %X\n", key_value_information_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtCreateKey() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtNotifyChangeKey() + { + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtSetInformationKey() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtEnumerateKey() + { + return STATUS_NOT_SUPPORTED; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/section.cpp b/src/windows-emulator/syscalls/section.cpp new file mode 100644 index 00000000..5cf2cc3b --- /dev/null +++ b/src/windows-emulator/syscalls/section.cpp @@ -0,0 +1,286 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +#include + +namespace syscalls +{ + NTSTATUS handle_NtCreateSection(const syscall_context& c, const emulator_object section_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes, + const emulator_object maximum_size, + const ULONG section_page_protection, const ULONG allocation_attributes, + const handle file_handle) + { + section s{}; + s.section_page_protection = section_page_protection; + s.allocation_attributes = allocation_attributes; + + const auto* file = c.proc.files.get(file_handle); + if (file) + { + c.win_emu.log.print(color::dark_gray, "--> Section for file %s\n", u16_to_u8(file->name).c_str()); + s.file_name = file->name; + } + + if (object_attributes) + { + const auto attributes = object_attributes.read(); + if (attributes.ObjectName) + { + auto name = read_unicode_string( + c.emu, reinterpret_cast>*>(attributes.ObjectName)); + c.win_emu.log.print(color::dark_gray, "--> Section with name %s\n", u16_to_u8(name).c_str()); + s.name = std::move(name); + } + } + + if (maximum_size) + { + maximum_size.access([&](ULARGE_INTEGER& large_int) { + large_int.QuadPart = page_align_up(large_int.QuadPart); + s.maximum_size = large_int.QuadPart; + }); + } + else if (!file) + { + return STATUS_INVALID_PARAMETER; + } + + const auto h = c.proc.sections.store(std::move(s)); + section_handle.write(h); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenSection(const syscall_context& c, const emulator_object section_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + + auto filename = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + c.win_emu.log.print(color::dark_gray, "--> Opening section: %s\n", u16_to_u8(filename).c_str()); + + if (filename == u"\\Windows\\SharedSection") + { + section_handle.write(SHARED_SECTION); + return STATUS_SUCCESS; + } + + if (filename == u"DBWIN_BUFFER") + { + section_handle.write(DBWIN_BUFFER); + return STATUS_SUCCESS; + } + + if (filename == u"windows_shell_global_counters" // + || filename == u"Global\\__ComCatalogCache__" // + || filename == u"{00020000-0000-1005-8005-0000C06B5161}" // + || filename == u"Global\\{00020000-0000-1005-8005-0000C06B5161}") + { + return STATUS_NOT_SUPPORTED; + } + + if (attributes.RootDirectory != KNOWN_DLLS_DIRECTORY) + { + c.win_emu.log.error("Unsupported section\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + utils::string::to_lower_inplace(filename); + + for (auto& section_entry : c.proc.sections) + { + if (section_entry.second.is_image() && section_entry.second.name == filename) + { + section_handle.write(c.proc.sections.make_handle(section_entry.first)); + return STATUS_SUCCESS; + } + } + + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + NTSTATUS handle_NtMapViewOfSection( + const syscall_context& c, const handle section_handle, const handle process_handle, + const emulator_object base_address, + const EMULATOR_CAST(EmulatorTraits::ULONG_PTR, ULONG_PTR) /*zero_bits*/, + const EMULATOR_CAST(EmulatorTraits::SIZE_T, SIZE_T) /*commit_size*/, + const emulator_object /*section_offset*/, + const emulator_object::SIZE_T, SIZE_T)> view_size, + const SECTION_INHERIT /*inherit_disposition*/, const ULONG /*allocation_type*/, const ULONG /*win32_protect*/) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_INVALID_HANDLE; + } + + if (section_handle == SHARED_SECTION) + { + constexpr auto shared_section_size = 0x10000; + + const auto address = c.win_emu.memory.find_free_allocation_base(shared_section_size); + c.win_emu.memory.allocate_memory(address, shared_section_size, memory_permission::read_write); + + const std::u16string_view windows_dir = c.proc.kusd.get().NtSystemRoot.arr; + const auto windows_dir_size = windows_dir.size() * 2; + + constexpr auto windows_dir_offset = 0x10; + c.emu.write_memory(address + 8, windows_dir_offset); + + const auto obj_address = address + windows_dir_offset; + + const emulator_object>> windir_obj{c.emu, obj_address}; + windir_obj.access([&](UNICODE_STRING>& ucs) { + const auto dir_address = kusd_mmio::address() + offsetof(KUSER_SHARED_DATA64, NtSystemRoot); + + ucs.Buffer = dir_address - obj_address; + ucs.Length = static_cast(windows_dir_size); + ucs.MaximumLength = ucs.Length; + }); + + const emulator_object>> sysdir_obj{c.emu, windir_obj.value() + + windir_obj.size()}; + sysdir_obj.access([&](UNICODE_STRING>& ucs) { + c.proc.base_allocator.make_unicode_string(ucs, u"C:\\WINDOWS\\System32"); + ucs.Buffer = ucs.Buffer - obj_address; + }); + + const emulator_object>> base_dir_obj{c.emu, sysdir_obj.value() + + sysdir_obj.size()}; + base_dir_obj.access([&](UNICODE_STRING>& ucs) { + c.proc.base_allocator.make_unicode_string(ucs, u"\\Sessions\\1\\BaseNamedObjects"); + ucs.Buffer = ucs.Buffer - obj_address; + }); + + if (view_size) + { + view_size.write(shared_section_size); + } + + base_address.write(address); + + return STATUS_SUCCESS; + } + + if (section_handle == DBWIN_BUFFER) + { + constexpr auto dbwin_buffer_section_size = 0x1000; + + const auto address = c.win_emu.memory.find_free_allocation_base(dbwin_buffer_section_size); + c.win_emu.memory.allocate_memory(address, dbwin_buffer_section_size, memory_permission::read_write); + c.proc.dbwin_buffer = address; + + if (view_size) + { + view_size.write(dbwin_buffer_section_size); + } + + base_address.write(address); + + return STATUS_SUCCESS; + } + + auto* section_entry = c.proc.sections.get(section_handle); + if (!section_entry) + { + return STATUS_INVALID_HANDLE; + } + + if (section_entry->is_image()) + { + const auto* binary = c.win_emu.mod_manager.map_module(section_entry->file_name, c.win_emu.log); + if (!binary) + { + return STATUS_FILE_INVALID; + } + + std::u16string wide_name(binary->name.begin(), binary->name.end()); + section_entry->name = utils::string::to_lower_consume(wide_name); + + if (view_size.value()) + { + view_size.write(binary->size_of_image); + } + + base_address.write(binary->image_base); + + return STATUS_SUCCESS; + } + + uint64_t size = section_entry->maximum_size; + std::vector file_data{}; + + if (!section_entry->file_name.empty()) + { + if (!utils::io::read_file(section_entry->file_name, &file_data)) + { + return STATUS_INVALID_PARAMETER; + } + + size = page_align_up(file_data.size()); + } + + const auto protection = map_nt_to_emulator_protection(section_entry->section_page_protection); + const auto address = c.win_emu.memory.allocate_memory(size, protection); + + if (!file_data.empty()) + { + c.emu.write_memory(address, file_data.data(), file_data.size()); + } + + if (view_size) + { + view_size.write(size); + } + + base_address.write(address); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtUnmapViewOfSection(const syscall_context& c, const handle process_handle, + const uint64_t base_address) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + if (!base_address) + { + return STATUS_INVALID_PARAMETER; + } + + if (base_address == c.proc.dbwin_buffer) + { + c.proc.dbwin_buffer = 0; + c.win_emu.memory.release_memory(base_address, 0x1000); + return STATUS_SUCCESS; + } + + const auto* mod = c.win_emu.mod_manager.find_by_address(base_address); + if (!mod) + { + c.win_emu.log.error("Unmapping non-module section not supported!\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + if (c.win_emu.mod_manager.unmap(base_address, c.win_emu.log)) + { + return STATUS_SUCCESS; + } + + return STATUS_INVALID_PARAMETER; + } + + NTSTATUS handle_NtUnmapViewOfSectionEx(const syscall_context& c, const handle process_handle, + const uint64_t base_address, const ULONG /*flags*/) + { + return handle_NtUnmapViewOfSection(c, process_handle, base_address); + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/semaphore.cpp b/src/windows-emulator/syscalls/semaphore.cpp new file mode 100644 index 00000000..6b482a17 --- /dev/null +++ b/src/windows-emulator/syscalls/semaphore.cpp @@ -0,0 +1,104 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtOpenSemaphore(const syscall_context& c, const emulator_object semaphore_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + if (!object_attributes) + { + return STATUS_INVALID_PARAMETER; + } + + const auto attributes = object_attributes.read(); + if (!attributes.ObjectName) + { + return STATUS_INVALID_PARAMETER; + } + + const auto name = read_unicode_string( + c.emu, emulator_object>>{c.emu, attributes.ObjectName}); + if (name.empty()) + { + return STATUS_INVALID_PARAMETER; + } + + for (const auto& semaphore : c.proc.semaphores) + { + if (semaphore.second.name == name) + { + semaphore_handle.write(c.proc.semaphores.make_handle(semaphore.first)); + return STATUS_SUCCESS; + } + } + + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + NTSTATUS handle_NtReleaseSemaphore(const syscall_context& c, const handle semaphore_handle, + const ULONG release_count, const emulator_object previous_count) + { + if (semaphore_handle.value.type != handle_types::semaphore) + { + c.win_emu.log.error("Bad handle type for NtReleaseSemaphore\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto* mutant = c.proc.semaphores.get(semaphore_handle); + if (!mutant) + { + return STATUS_INVALID_HANDLE; + } + + const auto [old_count, succeeded] = mutant->release(release_count); + + if (previous_count) + { + previous_count.write(static_cast(old_count)); + } + + return succeeded ? STATUS_SUCCESS : STATUS_SEMAPHORE_LIMIT_EXCEEDED; + } + + NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, const emulator_object semaphore_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes, + const ULONG initial_count, const ULONG maximum_count) + { + semaphore s{}; + s.current_count = initial_count; + s.max_count = maximum_count; + + if (object_attributes) + { + const auto attributes = object_attributes.read(); + if (attributes.ObjectName) + { + s.name = read_unicode_string( + c.emu, reinterpret_cast>*>(attributes.ObjectName)); + } + } + + if (!s.name.empty()) + { + for (auto& entry : c.proc.semaphores) + { + if (entry.second.name == s.name) + { + ++entry.second.ref_count; + semaphore_handle.write(c.proc.semaphores.make_handle(entry.first)); + return STATUS_OBJECT_NAME_EXISTS; + } + } + } + + const auto handle = c.proc.semaphores.store(std::move(s)); + semaphore_handle.write(handle); + + return STATUS_SUCCESS; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/system.cpp b/src/windows-emulator/syscalls/system.cpp new file mode 100644 index 00000000..426bc207 --- /dev/null +++ b/src/windows-emulator/syscalls/system.cpp @@ -0,0 +1,364 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtQuerySystemInformation(const syscall_context& c, const uint32_t info_class, + const uint64_t system_information, + const uint32_t system_information_length, + const emulator_object return_length) + { + if (info_class == SystemFlushInformation || info_class == SystemHypervisorSharedPageInformation || + info_class == 250 // Build 27744 + ) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == SystemTimeOfDayInformation) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_TIMEOFDAY_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_TIMEOFDAY_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_TIMEOFDAY_INFORMATION64& info) { + info.BootTime.QuadPart = 0; + // TODO: Fill + }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemRangeStartInformation) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_RANGE_START_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_RANGE_START_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_RANGE_START_INFORMATION64& info) { + info.SystemRangeStart = 0xFFFF800000000000; // + }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemProcessorInformation) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_PROCESSOR_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_PROCESSOR_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_PROCESSOR_INFORMATION64& info) { + memset(&info, 0, sizeof(info)); + info.MaximumProcessors = 2; + info.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; + }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemNumaProcessorMap) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_NUMA_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_NUMA_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_NUMA_INFORMATION64& info) { + memset(&info, 0, sizeof(info)); + info.ActiveProcessorsGroupAffinity->Mask = 0xFFF; + info.AvailableMemory[0] = 0xFFF; + info.Pad[0] = 0xFFF; + }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemErrorPortTimeouts) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_ERROR_PORT_TIMEOUTS)); + } + + if (system_information_length != sizeof(SYSTEM_ERROR_PORT_TIMEOUTS)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_ERROR_PORT_TIMEOUTS& info) { + info.StartTimeout = 0; + info.CommTimeout = 0; + }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemKernelDebuggerInformation) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION)); + } + + if (system_information_length != sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_KERNEL_DEBUGGER_INFORMATION& info) { + info.KernelDebuggerEnabled = FALSE; + info.KernelDebuggerNotPresent = TRUE; + }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemControlFlowTransition) + { + c.win_emu.log.print(color::pink, "Warbird control flow transition!\n"); + return STATUS_NOT_SUPPORTED; + } + + if (info_class == SystemProcessInformation || info_class == SystemModuleInformation || + info_class == SystemMemoryUsageInformation || info_class == SystemCodeIntegrityPolicyInformation) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) + { + c.win_emu.log.error("Unsupported system info class: %X\n", info_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + if (return_length) + { + return_length.write(sizeof(SYSTEM_BASIC_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info{c.emu, system_information}; + + info.access([&](SYSTEM_BASIC_INFORMATION64& basic_info) { + basic_info.Reserved = 0; + basic_info.TimerResolution = 0x0002625a; + basic_info.PageSize = 0x1000; + basic_info.LowestPhysicalPageNumber = 0x00000001; + basic_info.HighestPhysicalPageNumber = 0x00c9c7ff; + basic_info.AllocationGranularity = ALLOCATION_GRANULARITY; + basic_info.MinimumUserModeAddress = MIN_ALLOCATION_ADDRESS; + basic_info.MaximumUserModeAddress = MAX_ALLOCATION_ADDRESS; + basic_info.ActiveProcessorsAffinityMask = 0x0000000000000fff; + basic_info.NumberOfProcessors = 1; + }); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtQuerySystemInformationEx(const syscall_context& c, const uint32_t info_class, + const uint64_t input_buffer, const uint32_t input_buffer_length, + const uint64_t system_information, + const uint32_t system_information_length, + const emulator_object return_length) + { + if (info_class == SystemFlushInformation || info_class == SystemFeatureConfigurationInformation || + info_class == SystemSupportedProcessorArchitectures2 || + info_class == SystemFeatureConfigurationSectionInformation) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == SystemLogicalProcessorInformation) + { + if (input_buffer_length != sizeof(USHORT)) + { + return STATUS_INVALID_PARAMETER; + } + + using INFO_TYPE = EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION>; + + const auto processor_group = c.emu.read_memory(input_buffer); + constexpr auto required_size = sizeof(INFO_TYPE); + + if (return_length) + { + return_length.write(required_size); + } + + if (system_information_length < required_size) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + + INFO_TYPE information{}; + information.Relationship = RelationProcessorCore; + + if (processor_group == 0) + { + const auto active_processor_count = c.proc.kusd.get().ActiveProcessorCount; + information.ProcessorMask = + (static_cast(1) << active_processor_count) - 1; + } + + c.emu.write_memory(system_information, information); + return STATUS_SUCCESS; + } + + if (info_class == SystemLogicalProcessorAndGroupInformation) + { + if (input_buffer_length != sizeof(LOGICAL_PROCESSOR_RELATIONSHIP)) + { + return STATUS_INVALID_PARAMETER; + } + + const auto request = c.emu.read_memory(input_buffer); + + if (request == RelationGroup) + { + constexpr auto root_size = offsetof(EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX64, Group); + constexpr auto required_size = root_size + sizeof(EMU_GROUP_RELATIONSHIP64); + + if (return_length) + { + return_length.write(required_size); + } + + if (system_information_length < required_size) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + + EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX64 proc_info{}; + proc_info.Size = required_size; + proc_info.Relationship = RelationGroup; + + c.emu.write_memory(system_information, &proc_info, root_size); + + EMU_GROUP_RELATIONSHIP64 group{}; + group.ActiveGroupCount = 1; + group.MaximumGroupCount = 1; + + auto& group_info = group.GroupInfo[0]; + group_info.ActiveProcessorCount = static_cast(c.proc.kusd.get().ActiveProcessorCount); + group_info.ActiveProcessorMask = (1 << group_info.ActiveProcessorCount) - 1; + group_info.MaximumProcessorCount = group_info.ActiveProcessorCount; + + c.emu.write_memory(system_information + root_size, group); + return STATUS_SUCCESS; + } + + if (request == RelationNumaNode || request == RelationNumaNodeEx) + { + constexpr auto root_size = offsetof(EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX64, NumaNode); + constexpr auto required_size = root_size + sizeof(EMU_NUMA_NODE_RELATIONSHIP64); + + if (return_length) + { + return_length.write(required_size); + } + + if (system_information_length < required_size) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + + EMU_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX64 proc_info{}; + proc_info.Size = required_size; + proc_info.Relationship = RelationNumaNode; + + c.emu.write_memory(system_information, &proc_info, root_size); + + EMU_NUMA_NODE_RELATIONSHIP64 numa_node{}; + memset(&numa_node, 0, sizeof(numa_node)); + + c.emu.write_memory(system_information + root_size, numa_node); + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported processor relationship: %X\n", request); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) + { + c.win_emu.log.error("Unsupported system info ex class: %X\n", info_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + if (return_length) + { + return_length.write(sizeof(SYSTEM_BASIC_INFORMATION64)); + } + + if (system_information_length < sizeof(SYSTEM_BASIC_INFORMATION64)) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + + const emulator_object info{c.emu, system_information}; + + info.access([&](SYSTEM_BASIC_INFORMATION64& basic_info) { + basic_info.Reserved = 0; + basic_info.TimerResolution = 0x0002625a; + basic_info.PageSize = 0x1000; + basic_info.LowestPhysicalPageNumber = 0x00000001; + basic_info.HighestPhysicalPageNumber = 0x00c9c7ff; + basic_info.AllocationGranularity = ALLOCATION_GRANULARITY; + basic_info.MinimumUserModeAddress = MIN_ALLOCATION_ADDRESS; + basic_info.MaximumUserModeAddress = MAX_ALLOCATION_ADDRESS; + basic_info.ActiveProcessorsAffinityMask = 0x0000000000000fff; + basic_info.NumberOfProcessors = 1; + }); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtSetSystemInformation() + { + return STATUS_NOT_SUPPORTED; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/thread.cpp b/src/windows-emulator/syscalls/thread.cpp new file mode 100644 index 00000000..8c65a5a1 --- /dev/null +++ b/src/windows-emulator/syscalls/thread.cpp @@ -0,0 +1,552 @@ +#include "../std_include.hpp" +#include "../cpu_context.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +#include + +namespace syscalls +{ + NTSTATUS handle_NtSetInformationThread(const syscall_context& c, const handle thread_handle, + const THREADINFOCLASS info_class, const uint64_t thread_information, + const uint32_t thread_information_length) + { + auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); + + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + if (info_class == ThreadSchedulerSharedDataSlot || info_class == ThreadBasePriority) + { + return STATUS_SUCCESS; + } + + if (info_class == ThreadHideFromDebugger) + { + c.win_emu.log.print(color::pink, "--> Hiding thread %X from debugger!\n", thread->id); + return STATUS_SUCCESS; + } + + if (info_class == ThreadNameInformation) + { + if (thread_information_length != sizeof(THREAD_NAME_INFORMATION>)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object>> info{c.emu, thread_information}; + const auto i = info.read(); + thread->name = read_unicode_string(c.emu, i.ThreadName); + + c.win_emu.log.print(color::blue, "Setting thread (%d) name: %s\n", thread->id, + u16_to_u8(thread->name).c_str()); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadImpersonationToken) + { + if (thread_information_length != sizeof(handle)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, thread_information}; + info.write(DUMMY_IMPERSONATION_TOKEN); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadZeroTlsCell) + { + if (thread_information_length != sizeof(ULONG)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const auto tls_cell = c.emu.read_memory(thread_information); + + for (const auto& t : c.proc.threads | std::views::values) + { + t.teb->access([&](TEB64& teb) { + if (tls_cell < TLS_MINIMUM_AVAILABLE) + { + teb.TlsSlots.arr[tls_cell] = nullptr; + } + else if (teb.TlsExpansionSlots) + { + const emulator_object expansion_slots(c.emu, teb.TlsExpansionSlots); + expansion_slots.write(0, tls_cell - TLS_MINIMUM_AVAILABLE); + } + }); + } + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported thread set info class: %X\n", info_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryInformationThread(const syscall_context& c, const handle thread_handle, + const uint32_t info_class, const uint64_t thread_information, + const uint32_t thread_information_length, + const emulator_object return_length) + { + const auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); + + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + if (info_class == ThreadTebInformation) + { + if (return_length) + { + return_length.write(sizeof(THREAD_TEB_INFORMATION)); + } + + if (thread_information_length < sizeof(THREAD_TEB_INFORMATION)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const auto teb_info = c.emu.read_memory(thread_information); + const auto data = c.emu.read_memory(thread->teb->value() + teb_info.TebOffset, teb_info.BytesToRead); + c.emu.write_memory(teb_info.TebInformation, data.data(), data.size()); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadBasicInformation) + { + if (return_length) + { + return_length.write(sizeof(THREAD_BASIC_INFORMATION64)); + } + + if (thread_information_length < sizeof(THREAD_BASIC_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, thread_information}; + info.access([&](THREAD_BASIC_INFORMATION64& i) { + i.TebBaseAddress = thread->teb->ptr(); + i.ClientId = thread->teb->read().ClientId; + }); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadAmILastThread) + { + if (return_length) + { + return_length.write(sizeof(ULONG)); + } + + if (thread_information_length < sizeof(ULONG)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, thread_information}; + info.write(c.proc.threads.size() <= 1); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadQuerySetWin32StartAddress) + { + if (return_length) + { + return_length.write(sizeof(EmulatorTraits::PVOID)); + } + + if (thread_information_length < sizeof(EmulatorTraits::PVOID)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object::PVOID> info{c.emu, thread_information}; + info.write(thread->start_address); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadPerformanceCount) + { + if (return_length) + { + return_length.write(sizeof(LARGE_INTEGER)); + } + + if (thread_information_length < sizeof(LARGE_INTEGER)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, thread_information}; + info.write({}); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadHideFromDebugger) + { + if (return_length) + { + return_length.write(sizeof(BOOLEAN)); + } + + if (thread_information_length < sizeof(BOOLEAN)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, thread_information}; + info.write(0); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadTimes) + { + if (return_length) + { + return_length.write(sizeof(KERNEL_USER_TIMES)); + } + + if (thread_information_length != sizeof(KERNEL_USER_TIMES)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, thread_information}; + info.write(KERNEL_USER_TIMES{}); + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported thread query info class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtOpenThreadToken(const syscall_context&, const handle thread_handle, + const ACCESS_MASK /*desired_access*/, const BOOLEAN /*open_as_self*/, + const emulator_object token_handle) + { + if (thread_handle != CURRENT_THREAD) + { + return STATUS_NOT_SUPPORTED; + } + + token_handle.write(CURRENT_THREAD_TOKEN); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenThreadTokenEx(const syscall_context& c, const handle thread_handle, + const ACCESS_MASK desired_access, const BOOLEAN open_as_self, + const ULONG /*handle_attributes*/, const emulator_object token_handle) + { + return handle_NtOpenThreadToken(c, thread_handle, desired_access, open_as_self, token_handle); + } + + NTSTATUS handle_NtTerminateThread(const syscall_context& c, const handle thread_handle, const NTSTATUS exit_status) + { + auto* thread = !thread_handle.bits ? c.proc.active_thread : c.proc.threads.get(thread_handle); + + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + thread->exit_status = exit_status; + c.win_emu.callbacks.on_thread_terminated(thread_handle, *thread); + if (thread == c.proc.active_thread) + { + c.win_emu.yield_thread(); + } + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtDelayExecution(const syscall_context& c, const BOOLEAN alertable, + const emulator_object delay_interval) + { + if (alertable) + { + c.win_emu.log.error("Alertable NtDelayExecution not supported yet!\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto& t = c.win_emu.current_thread(); + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), delay_interval.read()); + + c.win_emu.yield_thread(); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtAlertThreadByThreadId(const syscall_context& c, const uint64_t thread_id) + { + for (auto& t : c.proc.threads | std::views::values) + { + if (t.id == thread_id) + { + t.alerted = true; + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_HANDLE; + } + + NTSTATUS handle_NtAlertThreadByThreadIdEx(const syscall_context& c, const uint64_t thread_id, + const emulator_object>> lock) + { + if (lock.value()) + { + c.win_emu.log.print(color::gray, "NtAlertThreadByThreadIdEx with lock not supported yet!"); + // c.emu.stop(); + // return STATUS_NOT_SUPPORTED; + } + + return handle_NtAlertThreadByThreadId(c, thread_id); + } + + NTSTATUS handle_NtWaitForAlertByThreadId(const syscall_context& c, const uint64_t, + const emulator_object timeout) + { + auto& t = c.win_emu.current_thread(); + t.waiting_for_alert = true; + + if (timeout.value() && !t.await_time.has_value()) + { + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read()); + } + + c.win_emu.yield_thread(); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtYieldExecution(const syscall_context& c) + { + c.win_emu.yield_thread(); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtResumeThread(const syscall_context& c, const handle thread_handle, + const emulator_object previous_suspend_count) + { + auto* thread = c.proc.threads.get(thread_handle); + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + const auto old_count = thread->suspended; + if (previous_suspend_count) + { + previous_suspend_count.write(old_count); + } + + if (old_count > 0) + { + thread->suspended -= 1; + } + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtContinue(const syscall_context& c, const emulator_object thread_context, + const BOOLEAN /*raise_alert*/) + { + c.write_status = false; + + const auto context = thread_context.read(); + cpu_context::restore(c.emu, context); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtGetNextThread(const syscall_context& c, const handle process_handle, const handle thread_handle, + const ACCESS_MASK /*desired_access*/, const ULONG /*handle_attributes*/, + const ULONG flags, const emulator_object new_thread_handle) + { + if (process_handle != CURRENT_PROCESS || thread_handle.value.type != handle_types::thread) + { + return STATUS_INVALID_HANDLE; + } + + if (flags != 0) + { + c.win_emu.log.error("NtGetNextThread flags %X not supported\n", flags); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + bool return_next_thread = thread_handle == NULL_HANDLE; + for (auto& t : c.proc.threads) + { + if (return_next_thread && !t.second.is_terminated()) + { + ++t.second.ref_count; + new_thread_handle.write(c.proc.threads.make_handle(t.first)); + return STATUS_SUCCESS; + } + + if (t.first == thread_handle.value.id) + { + return_next_thread = true; + } + } + + new_thread_handle.write(NULL_HANDLE); + return STATUS_NO_MORE_ENTRIES; + } + + NTSTATUS handle_NtGetContextThread(const syscall_context& c, const handle thread_handle, + const emulator_object thread_context) + { + const auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); + + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + c.proc.active_thread->save(c.emu); + const auto _ = utils::finally([&] { + c.proc.active_thread->restore(c.emu); // + }); + + thread->restore(c.emu); + + thread_context.access([&](CONTEXT64& context) { + if ((context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) == CONTEXT_DEBUG_REGISTERS_64) + { + c.win_emu.log.print(color::pink, "--> Reading debug registers!\n"); + } + + cpu_context::save(c.emu, context); + }); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtSetContextThread(const syscall_context& c, const handle thread_handle, + const emulator_object thread_context) + { + const auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); + + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + const auto needs_swich = thread != c.proc.active_thread; + + if (needs_swich) + { + c.proc.active_thread->save(c.emu); + thread->restore(c.emu); + } + + const auto _ = utils::finally([&] { + if (needs_swich) + { + c.proc.active_thread->restore(c.emu); // + } + }); + + const auto context = thread_context.read(); + cpu_context::restore(c.emu, context); + + if ((context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) == CONTEXT_DEBUG_REGISTERS_64) + { + c.win_emu.log.print(color::pink, "--> Setting debug registers!\n"); + } + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtCreateThreadEx(const syscall_context& c, const emulator_object thread_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> + /*object_attributes*/, + const handle process_handle, const uint64_t start_routine, const uint64_t argument, + const ULONG create_flags, const EmulatorTraits::SIZE_T /*zero_bits*/, + const EmulatorTraits::SIZE_T stack_size, + const EmulatorTraits::SIZE_T /*maximum_stack_size*/, + const emulator_object>> attribute_list) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + const auto h = c.proc.create_thread(c.win_emu.memory, start_routine, argument, stack_size, + create_flags & CREATE_SUSPENDED); + thread_handle.write(h); + + if (!attribute_list) + { + return STATUS_SUCCESS; + } + + const auto* thread = c.proc.threads.get(h); + + const emulator_object>> attributes{ + c.emu, attribute_list.value() + offsetof(PS_ATTRIBUTE_LIST>, Attributes)}; + + const auto total_length = attribute_list.read().TotalLength; + + constexpr auto entry_size = sizeof(PS_ATTRIBUTE>); + constexpr auto header_size = sizeof(PS_ATTRIBUTE_LIST>) - entry_size; + const auto attribute_count = (total_length - header_size) / entry_size; + + for (size_t i = 0; i < attribute_count; ++i) + { + attributes.access( + [&](const PS_ATTRIBUTE>& attribute) { + const auto type = attribute.Attribute & ~PS_ATTRIBUTE_THREAD; + + if (type == PsAttributeClientId) + { + const auto client_id = thread->teb->read().ClientId; + write_attribute(c.emu, attribute, client_id); + } + else if (type == PsAttributeTebAddress) + { + write_attribute(c.emu, attribute, thread->teb->ptr()); + } + else + { + c.win_emu.log.error("Unsupported thread attribute type: %" PRIx64 "\n", type); + } + }, + i); + } + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtGetCurrentProcessorNumberEx(const syscall_context&, + const emulator_object processor_number) + { + constexpr PROCESSOR_NUMBER number{}; + processor_number.write(number); + return STATUS_SUCCESS; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/timer.cpp b/src/windows-emulator/syscalls/timer.cpp new file mode 100644 index 00000000..1cd5b7c7 --- /dev/null +++ b/src/windows-emulator/syscalls/timer.cpp @@ -0,0 +1,33 @@ +#include "../std_include.hpp" +#include "../syscall_dispatcher.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + NTSTATUS handle_NtQueryTimerResolution(const syscall_context&, const emulator_object maximum_time, + const emulator_object minimum_time, + const emulator_object current_time) + { + maximum_time.write_if_valid(0x0002625a); + minimum_time.write_if_valid(0x00001388); + current_time.write_if_valid(0x00002710); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtSetTimerResolution(const syscall_context&, const ULONG /*desired_resolution*/, + const BOOLEAN set_resolution, const emulator_object current_resolution) + { + if (current_resolution) + { + current_resolution.write(0x0002625a); + } + + if (set_resolution) + { + return STATUS_TIMER_RESOLUTION_NOT_SET; + } + + return STATUS_SUCCESS; + } +} \ No newline at end of file diff --git a/src/windows-emulator/syscalls/token.cpp b/src/windows-emulator/syscalls/token.cpp new file mode 100644 index 00000000..70dbe135 --- /dev/null +++ b/src/windows-emulator/syscalls/token.cpp @@ -0,0 +1,246 @@ +#include "../std_include.hpp" +#include "../emulator_utils.hpp" +#include "../syscall_utils.hpp" + +namespace syscalls +{ + TOKEN_TYPE get_token_type(const handle token_handle) + { + return token_handle == DUMMY_IMPERSONATION_TOKEN // + ? TokenImpersonation + : TokenPrimary; + } + + NTSTATUS handle_NtDuplicateToken(const syscall_context&, const handle existing_token_handle, + ACCESS_MASK /*desired_access*/, + const emulator_object>> + /*object_attributes*/, + const BOOLEAN /*effective_only*/, const TOKEN_TYPE type, + const emulator_object new_token_handle) + { + if (get_token_type(existing_token_handle) == type) + { + new_token_handle.write(existing_token_handle); + } + else if (type == TokenPrimary) + { + new_token_handle.write(CURRENT_PROCESS_TOKEN); + } + else + { + new_token_handle.write(DUMMY_IMPERSONATION_TOKEN); + } + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtQueryInformationToken(const syscall_context& c, const handle token_handle, + const TOKEN_INFORMATION_CLASS token_information_class, + const uint64_t token_information, const ULONG token_information_length, + const emulator_object return_length) + { + if (token_handle != CURRENT_PROCESS_TOKEN && token_handle != CURRENT_THREAD_TOKEN && + token_handle != CURRENT_THREAD_EFFECTIVE_TOKEN && token_handle != DUMMY_IMPERSONATION_TOKEN) + { + return STATUS_NOT_SUPPORTED; + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + const uint8_t sid[] = { + 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x84, 0x94, + 0xD4, 0x04, 0x4B, 0x68, 0x42, 0x34, 0x23, 0xBE, 0x69, 0x4E, 0xE9, 0x03, 0x00, 0x00, + }; + + if (token_information_class == TokenAppContainerSid) + { + return STATUS_NOT_SUPPORTED; + } + + if (token_information_class == TokenUser) + { + constexpr auto required_size = sizeof(sid) + 0x10; + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + TOKEN_USER64 user{}; + user.User.Attributes = 0; + user.User.Sid = token_information + 0x10; + + emulator_object{c.emu, token_information}.write(user); + c.emu.write_memory(token_information + 0x10, sid, sizeof(sid)); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenType) + { + constexpr auto required_size = sizeof(TOKEN_TYPE); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(get_token_type(token_handle)); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenSessionId) + { + constexpr auto required_size = sizeof(ULONG); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(1); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenPrivateNameSpace) + { + constexpr auto required_size = sizeof(ULONG); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(0); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenUIAccess) + { + constexpr auto required_size = sizeof(ULONG); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(1); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenElevation) + { + constexpr auto required_size = sizeof(TOKEN_ELEVATION); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + c.emu.write_memory(token_information, TOKEN_ELEVATION{ + .TokenIsElevated = 0, + }); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenIsAppContainer) + { + constexpr auto required_size = sizeof(ULONG); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(0); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenStatistics) + { + constexpr auto required_size = sizeof(TOKEN_STATISTICS); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + c.emu.write_memory(token_information, TOKEN_STATISTICS{}); + + return STATUS_SUCCESS; + } + + if (token_information_class == TokenSecurityAttributes) + { + constexpr auto required_size = sizeof(TOKEN_SECURITY_ATTRIBUTES_INFORMATION); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + c.emu.write_memory(token_information, TOKEN_SECURITY_ATTRIBUTES_INFORMATION{ + .Version = 0, + .Reserved = {}, + .AttributeCount = 0, + .Attribute = {}, + }); + + return STATUS_SUCCESS; + } + + if (token_information_class == TokenIntegrityLevel) + { + constexpr auto required_size = sizeof(sid) + sizeof(TOKEN_MANDATORY_LABEL64); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + TOKEN_MANDATORY_LABEL64 label{}; + label.Label.Attributes = 0; + label.Label.Sid = token_information + sizeof(TOKEN_MANDATORY_LABEL64); + + emulator_object{c.emu, token_information}.write(label); + c.emu.write_memory(token_information + sizeof(TOKEN_MANDATORY_LABEL64), sid, sizeof(sid)); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenBnoIsolation) + { + constexpr auto required_size = sizeof(TOKEN_BNO_ISOLATION_INFORMATION64); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + c.emu.write_memory(token_information, TOKEN_BNO_ISOLATION_INFORMATION64{ + .IsolationPrefix = 0, + .IsolationEnabled = FALSE, + }); + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported token info class: %X\n", token_information_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQuerySecurityAttributesToken() + { + // puts("NtQuerySecurityAttributesToken not supported"); + return STATUS_NOT_SUPPORTED; + } +} \ No newline at end of file