mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Prepare filesystem support
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
template <typename Traits>
|
||||
struct UNICODE_STRING
|
||||
@@ -62,9 +63,9 @@ inline std::string w_to_u8(const std::wstring_view w_view)
|
||||
}
|
||||
|
||||
#ifndef OS_WINDOWS
|
||||
inline int open_unicode(FILE** handle, const std::u16string& fileName, const std::u16string& mode)
|
||||
inline int open_unicode(FILE** handle, const std::filesystem::path& fileName, const std::u16string& mode)
|
||||
{
|
||||
*handle = fopen(u16_to_u8(fileName).c_str(), u16_to_u8(mode).c_str());
|
||||
*handle = fopen(fileName.string().c_str(), u16_to_u8(mode).c_str());
|
||||
return errno;
|
||||
}
|
||||
#else
|
||||
@@ -73,8 +74,8 @@ inline std::wstring u16_to_w(const std::u16string& u16str)
|
||||
return std::wstring(reinterpret_cast<const wchar_t*>(u16str.data()), u16str.size());
|
||||
}
|
||||
|
||||
inline auto open_unicode(FILE** handle, const std::u16string& fileName, const std::u16string& mode)
|
||||
inline auto open_unicode(FILE** handle, const std::filesystem::path& fileName, const std::u16string& mode)
|
||||
{
|
||||
return _wfopen_s(handle, u16_to_w(fileName).c_str(), u16_to_w(mode).c_str());
|
||||
return _wfopen_s(handle, fileName.wstring().c_str(), u16_to_w(mode).c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -39,7 +39,10 @@ namespace utils
|
||||
|
||||
static std::filesystem::path canonicalize_path(const std::filesystem::path& key)
|
||||
{
|
||||
auto path = key.lexically_normal().wstring();
|
||||
auto key_string = key.u16string();
|
||||
std::ranges::replace(key_string, u'\\', '/');
|
||||
|
||||
auto path = std::filesystem::path(key).lexically_normal().wstring();
|
||||
return utils::string::to_lower_consume(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ CALL :collect_dll wininet.dll
|
||||
CALL :collect_dll winmm.dll
|
||||
CALL :collect_dll ws2_32.dll
|
||||
CALL :collect_dll wsock32.dll
|
||||
CALL :collect_dll msvcp140.dll
|
||||
|
||||
CALL :collect_dll locale.nls
|
||||
|
||||
|
||||
1
src/windows-emulator/file_system.cpp
Normal file
1
src/windows-emulator/file_system.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "std_include.hpp"
|
||||
85
src/windows-emulator/file_system.hpp
Normal file
85
src/windows-emulator/file_system.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
#include "std_include.hpp"
|
||||
#include <utils/path_key.hpp>
|
||||
|
||||
class file_system
|
||||
{
|
||||
public:
|
||||
static constexpr std::u16string_view nt_prefix = u"\\??\\";
|
||||
|
||||
file_system(std::filesystem::path root, std::u16string working_dir)
|
||||
: root_(std::move(root)),
|
||||
working_dir_(std::move(working_dir))
|
||||
{
|
||||
}
|
||||
|
||||
static std::filesystem::path canonicalize_windows_path(const std::filesystem::path& file)
|
||||
{
|
||||
const auto wide_file = file.u16string();
|
||||
|
||||
if (!wide_file.starts_with(nt_prefix))
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
return canonicalize_windows_path(wide_file.substr(nt_prefix.size()));
|
||||
}
|
||||
|
||||
static std::filesystem::path canonicalize(const std::filesystem::path& path)
|
||||
{
|
||||
return utils::path_key::canonicalize_path(canonicalize_windows_path(path));
|
||||
}
|
||||
|
||||
static std::filesystem::path canonicalize_drive_letter(const std::filesystem::path& path)
|
||||
{
|
||||
auto canonical_path = canonicalize(path);
|
||||
if (canonical_path.empty() || !path.has_root_path())
|
||||
{
|
||||
return canonical_path;
|
||||
}
|
||||
|
||||
return adapt_drive_component(canonical_path);
|
||||
}
|
||||
|
||||
std::filesystem::path translate(const std::filesystem::path& win_path) const
|
||||
{
|
||||
const auto absolute_win_dir = make_absolute_windows_path(win_path.u16string());
|
||||
return this->root_ / canonicalize_drive_letter(absolute_win_dir);
|
||||
}
|
||||
|
||||
void set_working_directory(std::u16string working_dir)
|
||||
{
|
||||
this->working_dir_ = std::move(working_dir);
|
||||
}
|
||||
|
||||
const std::u16string& get_working_directory() const
|
||||
{
|
||||
return this->working_dir_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::filesystem::path root_;
|
||||
std::u16string working_dir_;
|
||||
|
||||
std::u16string make_absolute_windows_path(const std::u16string& path) const
|
||||
{
|
||||
if (!path.starts_with(nt_prefix) && (path.size() < 2 || path[1] != ':'))
|
||||
{
|
||||
return this->working_dir_ + u'/' + path;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static std::filesystem::path adapt_drive_component(const std::filesystem::path& original_path)
|
||||
{
|
||||
auto root_name = original_path.root_name().u16string();
|
||||
|
||||
if (!root_name.empty() && root_name.back() == u':')
|
||||
{
|
||||
root_name.pop_back();
|
||||
}
|
||||
|
||||
return root_name + original_path.root_directory().u16string() + original_path.relative_path().u16string();
|
||||
}
|
||||
};
|
||||
@@ -5,18 +5,7 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
std::filesystem::path canonicalize_module_path(const std::filesystem::path& file)
|
||||
{
|
||||
constexpr std::u16string_view nt_prefix = u"\\??\\";
|
||||
const auto wide_file = file.u16string();
|
||||
|
||||
if (!wide_file.starts_with(nt_prefix))
|
||||
{
|
||||
return canonical(absolute(file));
|
||||
}
|
||||
|
||||
return canonicalize_module_path(wide_file.substr(nt_prefix.size()));
|
||||
}
|
||||
}
|
||||
|
||||
namespace utils
|
||||
@@ -64,26 +53,32 @@ namespace utils
|
||||
}
|
||||
}
|
||||
|
||||
module_manager::module_manager(emulator& emu)
|
||||
: emu_(&emu)
|
||||
module_manager::module_manager(emulator& emu, file_system& file_sys)
|
||||
: emu_(&emu),
|
||||
file_sys_(&file_sys)
|
||||
{
|
||||
}
|
||||
|
||||
mapped_module* module_manager::map_module(const std::filesystem::path& file, logger& logger)
|
||||
mapped_module* module_manager::map_module(const std::filesystem::path& file, const logger& logger)
|
||||
{
|
||||
auto canonical_file = canonicalize_module_path(file);
|
||||
return this->map_local_module(this->file_sys_->translate(file), logger);
|
||||
}
|
||||
|
||||
for (auto& mod : this->modules_)
|
||||
mapped_module* module_manager::map_local_module(const std::filesystem::path& file, const logger& logger)
|
||||
{
|
||||
auto local_file = canonical(absolute(file));
|
||||
|
||||
for (auto& mod : this->modules_ | std::views::values)
|
||||
{
|
||||
if (mod.second.path == canonical_file)
|
||||
if (mod.path == file)
|
||||
{
|
||||
return &mod.second;
|
||||
return &mod;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto mod = map_module_from_file(*this->emu_, std::move(canonical_file));
|
||||
auto mod = map_module_from_file(*this->emu_, std::move(local_file));
|
||||
|
||||
logger.log("Mapped %s at 0x%" PRIx64 "\n", mod.path.generic_string().c_str(), mod.image_base);
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
#pragma once
|
||||
#include "mapped_module.hpp"
|
||||
#include <emulator.hpp>
|
||||
|
||||
#include "mapped_module.hpp"
|
||||
#include "../file_system.hpp"
|
||||
|
||||
class logger;
|
||||
|
||||
class module_manager
|
||||
{
|
||||
public:
|
||||
using module_map = std::map<uint64_t, mapped_module>;
|
||||
module_manager(emulator& emu);
|
||||
module_manager(emulator& emu, file_system& file_sys);
|
||||
|
||||
mapped_module* map_module(const std::filesystem::path& file, logger& logger);
|
||||
mapped_module* map_module(const std::filesystem::path& file, const logger& logger);
|
||||
mapped_module* map_local_module(const std::filesystem::path& file, const logger& logger);
|
||||
|
||||
mapped_module* find_by_address(const uint64_t address)
|
||||
{
|
||||
@@ -45,6 +48,7 @@ class module_manager
|
||||
|
||||
private:
|
||||
emulator* emu_{};
|
||||
file_system* file_sys_{};
|
||||
|
||||
module_map modules_{};
|
||||
|
||||
|
||||
@@ -529,12 +529,12 @@ class emulator_thread : ref_counted_object
|
||||
|
||||
struct process_context
|
||||
{
|
||||
process_context(x64_emulator& emu)
|
||||
process_context(x64_emulator& emu, file_system& file_sys)
|
||||
: base_allocator(emu),
|
||||
peb(emu),
|
||||
process_params(emu),
|
||||
kusd(emu, *this),
|
||||
mod_manager(emu)
|
||||
mod_manager(emu, file_sys)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1530,7 +1530,7 @@ namespace
|
||||
if (!f->enumeration_state || query_flags & SL_RESTART_SCAN)
|
||||
{
|
||||
f->enumeration_state.emplace(file_enumeration_state{});
|
||||
f->enumeration_state->files = scan_directory(f->name);
|
||||
f->enumeration_state->files = scan_directory(c.win_emu.file_sys.translate(f->name));
|
||||
}
|
||||
|
||||
auto& enum_state = *f->enumeration_state;
|
||||
@@ -2585,7 +2585,8 @@ namespace
|
||||
const emulator_object<LCID> default_locale_id,
|
||||
const emulator_object<LARGE_INTEGER> /*default_casing_table_size*/)
|
||||
{
|
||||
const auto locale_file = utils::io::read_file(R"(C:\Windows\System32\locale.nls)");
|
||||
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;
|
||||
@@ -2825,14 +2826,14 @@ namespace
|
||||
if (create_disposition & FILE_CREATE)
|
||||
{
|
||||
std::error_code ec{};
|
||||
std::filesystem::create_directory(f.name, ec);
|
||||
std::filesystem::create_directory(c.win_emu.file_sys.translate(f.name), ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
else if (!std::filesystem::is_directory(f.name))
|
||||
else if (!std::filesystem::is_directory(c.win_emu.file_sys.translate(f.name)))
|
||||
{
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
@@ -2854,7 +2855,7 @@ namespace
|
||||
|
||||
FILE* file{};
|
||||
|
||||
const auto error = open_unicode(&file, f.name, mode);
|
||||
const auto error = open_unicode(&file, c.win_emu.file_sys.translate(f.name), mode);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
|
||||
@@ -268,18 +268,9 @@ namespace
|
||||
command_line.append(arg);
|
||||
}
|
||||
|
||||
std::u16string current_folder{};
|
||||
if (!settings.working_directory.empty())
|
||||
{
|
||||
current_folder = canonicalize_path(settings.working_directory).u16string() + u"\\";
|
||||
}
|
||||
else
|
||||
{
|
||||
current_folder = canonicalize_path(settings.application).parent_path().u16string() + u"\\";
|
||||
}
|
||||
|
||||
allocator.make_unicode_string(proc_params.CommandLine, command_line);
|
||||
allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, current_folder);
|
||||
allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath,
|
||||
win_emu.file_sys.get_working_directory());
|
||||
allocator.make_unicode_string(proc_params.ImagePathName,
|
||||
canonicalize_path(settings.application).u16string());
|
||||
|
||||
@@ -831,10 +822,15 @@ std::unique_ptr<x64_emulator> create_default_x64_emulator()
|
||||
return unicorn::create_x64_emulator();
|
||||
}
|
||||
|
||||
windows_emulator::windows_emulator(emulator_settings settings, emulator_callbacks callbacks,
|
||||
windows_emulator::windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks,
|
||||
std::unique_ptr<x64_emulator> emu)
|
||||
: windows_emulator(std::move(emu))
|
||||
{
|
||||
if (!settings.working_directory.empty())
|
||||
{
|
||||
this->file_sys.set_working_directory(settings.working_directory.u16string());
|
||||
}
|
||||
|
||||
this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging;
|
||||
this->use_relative_time_ = settings.use_relative_time;
|
||||
this->log.disable_output(settings.disable_logging || this->silent_until_main_);
|
||||
@@ -843,8 +839,9 @@ windows_emulator::windows_emulator(emulator_settings settings, emulator_callback
|
||||
}
|
||||
|
||||
windows_emulator::windows_emulator(std::unique_ptr<x64_emulator> emu)
|
||||
: emu_(std::move(emu)),
|
||||
process_(*emu_)
|
||||
: file_sys(R"(C:\Users\mahe.WIBU\Desktop\emulator\src\tools\root)", u"C:\\"),
|
||||
emu_(std::move(emu)),
|
||||
process_(*emu_, file_sys)
|
||||
{
|
||||
this->setup_hooks();
|
||||
}
|
||||
@@ -854,14 +851,15 @@ void windows_emulator::setup_process(const emulator_settings& settings)
|
||||
auto& emu = this->emu();
|
||||
|
||||
auto& context = this->process();
|
||||
context.mod_manager = module_manager(emu); // TODO: Cleanup module manager
|
||||
context.mod_manager = module_manager(emu, this->file_sys); // TODO: Cleanup module manager
|
||||
|
||||
setup_context(*this, settings);
|
||||
|
||||
context.executable = context.mod_manager.map_module(settings.application, this->log);
|
||||
context.executable = context.mod_manager.map_local_module(settings.application, this->log);
|
||||
|
||||
context.peb.access(
|
||||
[&](PEB64& peb) { peb.ImageBaseAddress = reinterpret_cast<std::uint64_t*>(context.executable->image_base); });
|
||||
context.peb.access([&](PEB64& peb) {
|
||||
peb.ImageBaseAddress = reinterpret_cast<std::uint64_t*>(context.executable->image_base); //
|
||||
});
|
||||
|
||||
context.ntdll = context.mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log);
|
||||
context.win32u = context.mod_manager.map_module(R"(C:\Windows\System32\win32u.dll)", this->log);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "syscall_dispatcher.hpp"
|
||||
#include "process_context.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "file_system.hpp"
|
||||
|
||||
std::unique_ptr<x64_emulator> create_default_x64_emulator();
|
||||
|
||||
@@ -47,7 +48,7 @@ class windows_emulator
|
||||
{
|
||||
public:
|
||||
windows_emulator(std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
|
||||
windows_emulator(emulator_settings settings, emulator_callbacks callbacks = {},
|
||||
windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks = {},
|
||||
std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
|
||||
|
||||
windows_emulator(windows_emulator&&) = delete;
|
||||
@@ -130,6 +131,8 @@ class windows_emulator
|
||||
{
|
||||
return this->callbacks_;
|
||||
}
|
||||
|
||||
file_system file_sys;
|
||||
|
||||
private:
|
||||
emulator_callbacks callbacks_{};
|
||||
|
||||
Reference in New Issue
Block a user