From af529a62d76767e6d41d21cd79656e1ead04f024 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 22 Oct 2024 20:09:33 +0200 Subject: [PATCH] Basic working file writing --- src/analyzer/main.cpp | 2 +- src/common/utils/file_handle.hpp | 74 ++++++++++ src/windows-emulator/process_context.hpp | 6 +- src/windows-emulator/syscall_utils.hpp | 9 ++ src/windows-emulator/syscalls.cpp | 173 ++++++++++++++--------- 5 files changed, 194 insertions(+), 70 deletions(-) create mode 100644 src/common/utils/file_handle.hpp diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 554838c..2d5f842 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -78,7 +78,7 @@ namespace (void)&watch_system_objects; //watch_system_objects(win_emu); - win_emu.buffer_stdout = false; + win_emu.buffer_stdout = true; //win_emu.verbose_calls = true; const auto& exe = *win_emu.process().executable; diff --git a/src/common/utils/file_handle.hpp b/src/common/utils/file_handle.hpp new file mode 100644 index 0000000..1c50c78 --- /dev/null +++ b/src/common/utils/file_handle.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include +#include + +namespace utils +{ + class file_handle + { + public: + file_handle() = default; + + file_handle(FILE* file) + : file_(file) + { + } + + ~file_handle() + { + this->release(); + } + + file_handle(const file_handle&) = delete; + file_handle& operator=(const file_handle&) = delete; + + file_handle(file_handle&& obj) noexcept + : file_handle() + { + this->operator=(std::move(obj)); + } + + file_handle& operator=(file_handle&& obj) noexcept + { + if (this != &obj) + { + this->release(); + this->file_ = obj.file_; + obj.file_ = {}; + } + + return *this; + } + + file_handle& operator=(FILE* file) noexcept + { + this->release(); + this->file_ = file; + + return *this; + } + + [[nodiscard]] operator bool() const + { + return this->file_; + } + + [[nodiscard]] operator FILE*() const + { + return this->file_; + } + + private: + FILE* file_{}; + + void release() + { + if (this->file_) + { + (void)fclose(this->file_); + this->file_ = {}; + } + } + }; +} diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 4edd181..35ff949 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -5,9 +5,11 @@ #include "module/module_manager.hpp" #include +#include #include + #define PEB_SEGMENT_SIZE (1 << 20) // 1 MB #define GS_SEGMENT_SIZE (1 << 20) // 1 MB @@ -80,7 +82,7 @@ struct event : ref_counted_object struct file { - utils::nt::handle handle{}; + utils::file_handle handle{}; std::wstring name{}; void serialize(utils::buffer_serializer& buffer) const @@ -92,7 +94,7 @@ struct file void deserialize(utils::buffer_deserializer& buffer) { buffer.read(this->name); - this->handle = INVALID_HANDLE_VALUE; + this->handle = {}; } }; diff --git a/src/windows-emulator/syscall_utils.hpp b/src/windows-emulator/syscall_utils.hpp index 45f0b79..d9f23f3 100644 --- a/src/windows-emulator/syscall_utils.hpp +++ b/src/windows-emulator/syscall_utils.hpp @@ -91,6 +91,15 @@ T resolve_argument(x64_emulator& emu, const size_t index) return static_cast(arg); } +template + requires(std::is_same_v, handle>) +handle resolve_argument(x64_emulator& emu, const size_t index) +{ + handle h{}; + h.bits = resolve_argument(emu, index); + return h; +} + template requires(std::is_same_v>) T resolve_argument(x64_emulator& emu, const size_t index) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index c3670f1..44c1dc8 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -221,44 +221,6 @@ namespace 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) - { - file f{}; - const auto attributes = object_attributes.read(); - f.name = read_unicode_string(c.emu, attributes.ObjectName); - - UNICODE_STRING string{}; - string.Buffer = f.name.data(); - string.Length = static_cast(f.name.size() * 2); - string.MaximumLength = string.Length; - - OBJECT_ATTRIBUTES new_attributes{}; - new_attributes.ObjectName = &string; - new_attributes.Length = sizeof(new_attributes); - - HANDLE h{}; - IO_STATUS_BLOCK status_block{}; - - const auto res = NtOpenFile(&h, desired_access, &new_attributes, &status_block, share_access, open_options); - if (res != STATUS_SUCCESS) - { - return res; - } - - f.handle = h; - - const auto handle = c.proc.files.store(std::move(f)); - file_handle.write(handle.bits); - - 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) @@ -1531,7 +1493,7 @@ namespace return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtWriteFile(const syscall_context& c, const uint64_t file_handle, const uint64_t /*event*/, + 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*/, @@ -1539,20 +1501,73 @@ namespace 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) { - std::string temp_buffer{}; - temp_buffer.resize(length); - c.emu.read_memory(buffer, temp_buffer.data(), temp_buffer.size()); - c.win_emu.logger.info("%.*s", static_cast(temp_buffer.size()), temp_buffer.data()); return STATUS_SUCCESS; } - //puts("NtWriteFile not supported"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; + const auto* f = c.proc.files.get(file_handle); + if (!f) + { + return STATUS_INVALID_HANDLE; + } + + (void)fwrite(temp_buffer.data(), 1, temp_buffer.size(), f->handle); + return STATUS_SUCCESS; + } + + const wchar_t* map_mode(const ACCESS_MASK desired_access, const ULONG create_disposition) + { + const wchar_t* mode = L""; + + switch (create_disposition) + { + case FILE_CREATE: + case FILE_SUPERSEDE: + if (desired_access & GENERIC_WRITE) + { + mode = L"w"; + } + break; + + case FILE_OPEN: + case FILE_OPEN_IF: + if (desired_access & GENERIC_WRITE) + { + mode = L"r+"; + } + else if (desired_access & GENERIC_READ) + { + mode = L"r"; + } + break; + + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + if (desired_access & GENERIC_WRITE) + { + mode = L"w+"; + } + break; + + default: + mode = L""; + break; + } + + if (desired_access & FILE_APPEND_DATA) + { + mode = L"a"; + } + + return mode; } NTSTATUS handle_NtCreateFile(const syscall_context& c, const emulator_object file_handle, @@ -1590,39 +1605,63 @@ namespace file f{}; f.name = std::move(filename); - UNICODE_STRING string{}; - string.Buffer = f.name.data(); - string.Length = static_cast(f.name.size() * 2); - string.MaximumLength = string.Length; - - OBJECT_ATTRIBUTES new_attributes{}; - new_attributes.ObjectName = &string; - new_attributes.Length = sizeof(new_attributes); + if (attributes.RootDirectory) + { + const auto* root = c.proc.files.get(reinterpret_cast(attributes.RootDirectory)); + if (!root) + { + return STATUS_INVALID_HANDLE; + } - HANDLE h{}; + f.name = root->name + f.name; + } - NTSTATUS res{STATUS_SUCCESS}; - io_status_block.access([&](IO_STATUS_BLOCK& block) + if (f.name.ends_with(L"\\")) { - res = NtCreateFile(&h, desired_access, &new_attributes, &block, nullptr, file_attributes, share_access, - create_disposition, create_options, nullptr, 0); - }); + const auto handle = c.proc.files.store(std::move(f)); + file_handle.write(handle.bits); + + return STATUS_SUCCESS; + } + + const auto* mode = map_mode(desired_access, create_disposition); - if (res != STATUS_SUCCESS) + FILE* file{}; + const auto error = _wfopen_s(&file, f.name.c_str(), mode); + + if (!file) { - return res; + 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 = h; + f.handle = file; const auto handle = c.proc.files.store(std::move(f)); file_handle.write(handle.bits); - return res; - + return STATUS_SUCCESS; + } - //printf("Unsupported file: %S\n", filename.c_str()); - //return STATUS_NOT_SUPPORTED; + 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, {}, 0, + share_access, FILE_OPEN, open_options, 0, 0); } NTSTATUS handle_NtQueryInformationJobObject()