Prepare filesystem support

This commit is contained in:
momo5502
2025-01-21 18:00:11 +01:00
parent 739cbbf549
commit 24bebc4ee2
11 changed files with 145 additions and 53 deletions

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -0,0 +1 @@
#include "std_include.hpp"

View 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();
}
};

View File

@@ -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);

View File

@@ -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_{};

View File

@@ -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)
{
}

View File

@@ -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)
{

View 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);

View File

@@ -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_{};