mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 08:36:16 +00:00
Basic working file writing
This commit is contained in:
@@ -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;
|
||||
|
||||
74
src/common/utils/file_handle.hpp
Normal file
74
src/common/utils/file_handle.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <type_traits>
|
||||
|
||||
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_ = {};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -5,9 +5,11 @@
|
||||
|
||||
#include "module/module_manager.hpp"
|
||||
#include <utils/nt_handle.hpp>
|
||||
#include <utils/file_handle.hpp>
|
||||
|
||||
#include <x64_emulator.hpp>
|
||||
|
||||
|
||||
#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<utils::nt::invalid_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 = {};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -91,6 +91,15 @@ T resolve_argument(x64_emulator& emu, const size_t index)
|
||||
return static_cast<T>(arg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_same_v<std::remove_cvref_t<T>, handle>)
|
||||
handle resolve_argument(x64_emulator& emu, const size_t index)
|
||||
{
|
||||
handle h{};
|
||||
h.bits = resolve_argument<uint64_t>(emu, index);
|
||||
return h;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_same_v<T, emulator_object<typename T::value_type>>)
|
||||
T resolve_argument(x64_emulator& emu, const size_t index)
|
||||
|
||||
@@ -221,44 +221,6 @@ namespace
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtOpenFile(const syscall_context& c,
|
||||
const emulator_object<uint64_t> file_handle,
|
||||
const ACCESS_MASK desired_access,
|
||||
const emulator_object<OBJECT_ATTRIBUTES> object_attributes,
|
||||
const emulator_object<IO_STATUS_BLOCK> /*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<uint16_t>(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<uint64_t> section_handle,
|
||||
const ACCESS_MASK /*desired_access*/,
|
||||
const emulator_object<OBJECT_ATTRIBUTES> 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> /*io_status_block*/,
|
||||
@@ -1539,20 +1501,73 @@ namespace
|
||||
const emulator_object<LARGE_INTEGER> /*byte_offset*/,
|
||||
const emulator_object<ULONG> /*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<int>(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<uint64_t> 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<uint16_t>(f.name.size() * 2);
|
||||
string.MaximumLength = string.Length;
|
||||
|
||||
OBJECT_ATTRIBUTES new_attributes{};
|
||||
new_attributes.ObjectName = &string;
|
||||
new_attributes.Length = sizeof(new_attributes);
|
||||
|
||||
HANDLE h{};
|
||||
|
||||
NTSTATUS res{STATUS_SUCCESS};
|
||||
io_status_block.access([&](IO_STATUS_BLOCK& block)
|
||||
if (attributes.RootDirectory)
|
||||
{
|
||||
res = NtCreateFile(&h, desired_access, &new_attributes, &block, nullptr, file_attributes, share_access,
|
||||
create_disposition, create_options, nullptr, 0);
|
||||
});
|
||||
const auto* root = c.proc.files.get(reinterpret_cast<uint64_t>(attributes.RootDirectory));
|
||||
if (!root)
|
||||
{
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (res != STATUS_SUCCESS)
|
||||
{
|
||||
return res;
|
||||
f.name = root->name + f.name;
|
||||
}
|
||||
|
||||
f.handle = h;
|
||||
if (f.name.ends_with(L"\\"))
|
||||
{
|
||||
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);
|
||||
|
||||
FILE* file{};
|
||||
const auto error = _wfopen_s(&file, f.name.c_str(), 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.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<uint64_t> file_handle,
|
||||
const ACCESS_MASK desired_access,
|
||||
const emulator_object<OBJECT_ATTRIBUTES> object_attributes,
|
||||
const emulator_object<IO_STATUS_BLOCK> 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()
|
||||
|
||||
Reference in New Issue
Block a user