mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-21 04:33:56 +00:00
Fix commandline args
This commit is contained in:
@@ -40,8 +40,8 @@ using edge_generation_hook_callback = std::function<void(const basic_block& curr
|
||||
using instruction_hook_callback = std::function<instruction_hook_continuation()>;
|
||||
|
||||
using interrupt_hook_callback = std::function<void(int interrupt)>;
|
||||
using simple_memory_hook_callback = std::function<void(uint64_t address, size_t size)>;
|
||||
using complex_memory_hook_callback = std::function<void(uint64_t address, size_t size, memory_operation operation)>;
|
||||
using simple_memory_hook_callback = std::function<void(uint64_t address, size_t size, uint64_t value)>;
|
||||
using complex_memory_hook_callback = std::function<void(uint64_t address, size_t size, uint64_t value, memory_operation operation)>;
|
||||
using memory_violation_hook_callback = std::function<memory_violation_continuation(
|
||||
uint64_t address, size_t size, memory_operation operation,
|
||||
memory_violation_type type)>;
|
||||
@@ -133,10 +133,10 @@ private:
|
||||
{
|
||||
assert((static_cast<uint8_t>(operation) & (static_cast<uint8_t>(operation) - 1)) == 0);
|
||||
return this->hook_memory_access(address, size, operation,
|
||||
[c = std::move(callback)](const uint64_t a, const size_t s,
|
||||
[c = std::move(callback)](const uint64_t a, const size_t s, const uint64_t value,
|
||||
memory_operation)
|
||||
{
|
||||
c(a, s);
|
||||
c(a, s, value);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace unicorn
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none)
|
||||
{
|
||||
(*callback)(address, static_cast<uint64_t>(size), operation);
|
||||
(*callback)(address, static_cast<uint64_t>(size), 0, operation);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -176,12 +176,12 @@ namespace unicorn
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
[callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size,
|
||||
const int64_t)
|
||||
const uint64_t value)
|
||||
{
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none)
|
||||
{
|
||||
(*callback)(address, static_cast<uint64_t>(size), operation);
|
||||
(*callback)(address, static_cast<uint64_t>(size), value, operation);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace unicorn
|
||||
function_wrapper<void, uc_engine*, uint64_t, uint32_t> wrapper(
|
||||
[callback](uc_engine*, const uint64_t address, const uint32_t size)
|
||||
{
|
||||
(*callback)(address, size, memory_permission::exec);
|
||||
(*callback)(address, size, 0, memory_permission::exec);
|
||||
});
|
||||
|
||||
unicorn_hook hook{uc};
|
||||
|
||||
@@ -171,7 +171,7 @@ public:
|
||||
{
|
||||
this->hooks_[{addr, size, type}] = scoped_hook(*this->emu_, this->emu_->hook_memory_access(
|
||||
addr, size, map_breakpoint_type(type),
|
||||
[this](uint64_t, size_t, memory_operation)
|
||||
[this](uint64_t, size_t, uint64_t, memory_operation)
|
||||
{
|
||||
this->on_interrupt();
|
||||
}));
|
||||
|
||||
@@ -128,10 +128,13 @@ public:
|
||||
constexpr auto required_alignment = alignof(decltype(str[0]));
|
||||
const auto total_length = str.size() * element_size;
|
||||
|
||||
const auto string_buffer = this->reserve(total_length, required_alignment);
|
||||
const auto string_buffer = this->reserve(total_length + element_size, required_alignment);
|
||||
|
||||
this->emu_->write_memory(string_buffer, str.data(), total_length);
|
||||
|
||||
constexpr std::array<char, element_size> nullbyte{};
|
||||
this->emu_->write_memory(string_buffer + total_length, nullbyte.data(), nullbyte.size());
|
||||
|
||||
result.Buffer = reinterpret_cast<PWCH>(string_buffer);
|
||||
result.Length = static_cast<USHORT>(total_length);
|
||||
result.MaximumLength = result.Length;
|
||||
@@ -159,6 +162,11 @@ public:
|
||||
return this->size_;
|
||||
}
|
||||
|
||||
uint64_t get_next_address() const
|
||||
{
|
||||
return this->active_address_;
|
||||
}
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->address_);
|
||||
@@ -179,3 +187,30 @@ private:
|
||||
uint64_t size_{};
|
||||
uint64_t active_address_{0};
|
||||
};
|
||||
|
||||
inline std::wstring read_unicode_string(const emulator& emu, const UNICODE_STRING ucs)
|
||||
{
|
||||
static_assert(offsetof(UNICODE_STRING, Length) == 0);
|
||||
static_assert(offsetof(UNICODE_STRING, MaximumLength) == 2);
|
||||
static_assert(offsetof(UNICODE_STRING, Buffer) == 8);
|
||||
static_assert(sizeof(UNICODE_STRING) == 16);
|
||||
|
||||
std::wstring result{};
|
||||
result.resize(ucs.Length / 2);
|
||||
|
||||
emu.read_memory(reinterpret_cast<uint64_t>(ucs.Buffer), result.data(), ucs.Length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
inline std::wstring read_unicode_string(const emulator& emu, const emulator_object<UNICODE_STRING> uc_string)
|
||||
{
|
||||
const auto ucs = uc_string.read();
|
||||
return read_unicode_string(emu, ucs);
|
||||
}
|
||||
|
||||
inline std::wstring read_unicode_string(emulator& emu, const UNICODE_STRING* uc_string)
|
||||
{
|
||||
return read_unicode_string(emu, emulator_object<UNICODE_STRING>{emu, uc_string});
|
||||
}
|
||||
|
||||
@@ -71,30 +71,52 @@ namespace
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void watch_object(x64_emulator& emu, emulator_object<T> object)
|
||||
emulator_hook* watch_object(windows_emulator& emu, emulator_object<T> object)
|
||||
{
|
||||
const type_info<T> info{};
|
||||
|
||||
emu.hook_memory_read(object.value(), object.size(),
|
||||
[i = std::move(info), object](const uint64_t address, size_t)
|
||||
{
|
||||
const auto offset = address - object.value();
|
||||
printf("%s: %llX (%s)\n", i.get_type_name().c_str(), offset,
|
||||
i.get_member_name(offset).c_str());
|
||||
});
|
||||
return emu.emu().hook_memory_read(object.value(), object.size(),
|
||||
[i = std::move(info), object, &emu](const uint64_t address, size_t, uint64_t)
|
||||
{
|
||||
const auto rip = emu.emu().read_instruction_pointer();
|
||||
const auto* binary = emu.process().module_manager.find_by_address(rip);
|
||||
|
||||
const auto offset = address - object.value();
|
||||
printf("%s: %llX (%s) at %llX (%s)\n", i.get_type_name().c_str(), offset,
|
||||
i.get_member_name(offset).c_str(), rip,
|
||||
binary ? binary->name.c_str() : "<N/A>");
|
||||
});
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
const std::filesystem::path application =
|
||||
R"(C:\Program Files (x86)\Steam\steamapps\common\Hogwarts Legacy\Phoenix\Binaries\Win64\HogwartsLegacy.exe)";
|
||||
R"(C:\Users\mauri\source\repos\ConsoleApplication6\x64\Release\ConsoleApplication6.exe)";
|
||||
//R"(C:\Program Files (x86)\Steam\steamapps\common\Hogwarts Legacy\Phoenix\Binaries\Win64\HogwartsLegacy.exe)";
|
||||
|
||||
windows_emulator win_emu{application};
|
||||
windows_emulator win_emu{application, {L"Hello", L"World"}};
|
||||
|
||||
watch_object(win_emu.emu(), win_emu.process().teb);
|
||||
watch_object(win_emu.emu(), win_emu.process().peb);
|
||||
watch_object(win_emu.emu(), win_emu.process().process_params);
|
||||
watch_object(win_emu.emu(), win_emu.process().kusd);
|
||||
watch_object(win_emu, win_emu.process().teb);
|
||||
watch_object(win_emu, win_emu.process().peb);
|
||||
watch_object(win_emu, win_emu.process().kusd);
|
||||
auto* params_hook = watch_object(win_emu, win_emu.process().process_params);
|
||||
|
||||
win_emu.emu().hook_memory_write(win_emu.process().peb.value() + offsetof(PEB, ProcessParameters), 0x8,
|
||||
[&](const uint64_t address, size_t, const uint64_t value)
|
||||
{
|
||||
const auto target_address = win_emu.process().peb.value() + offsetof(
|
||||
PEB, ProcessParameters);
|
||||
|
||||
if (address == target_address)
|
||||
{
|
||||
const emulator_object<RTL_USER_PROCESS_PARAMETERS> obj{
|
||||
win_emu.emu(), value
|
||||
};
|
||||
|
||||
win_emu.emu().delete_hook(params_hook);
|
||||
params_hook = watch_object(win_emu, obj);
|
||||
}
|
||||
});
|
||||
|
||||
win_emu.set_verbose(false);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "std_include.hpp"
|
||||
#include "syscalls.hpp"
|
||||
#include "context_frame.hpp"
|
||||
#include "emulator_utils.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
|
||||
@@ -111,28 +112,6 @@ namespace
|
||||
throw std::runtime_error("Unable to determine syscall id: " + std::string(name));
|
||||
}
|
||||
|
||||
std::wstring read_unicode_string(emulator& emu, const emulator_object<UNICODE_STRING> uc_string)
|
||||
{
|
||||
static_assert(offsetof(UNICODE_STRING, Length) == 0);
|
||||
static_assert(offsetof(UNICODE_STRING, MaximumLength) == 2);
|
||||
static_assert(offsetof(UNICODE_STRING, Buffer) == 8);
|
||||
static_assert(sizeof(UNICODE_STRING) == 16);
|
||||
|
||||
const auto ucs = uc_string.read();
|
||||
|
||||
std::wstring result{};
|
||||
result.resize(ucs.Length / 2);
|
||||
|
||||
emu.read_memory(reinterpret_cast<uint64_t>(ucs.Buffer), result.data(), ucs.Length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::wstring read_unicode_string(emulator& emu, const PUNICODE_STRING uc_string)
|
||||
{
|
||||
return read_unicode_string(emu, emulator_object<UNICODE_STRING>{emu, uc_string});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_integral_v<T> || std::is_enum_v<T>)
|
||||
T resolve_argument(x64_emulator& emu, const size_t index)
|
||||
|
||||
@@ -204,7 +204,8 @@ namespace
|
||||
emu.reg<uint16_t>(x64_register::ss, 0x2B);
|
||||
}
|
||||
|
||||
void setup_context(process_context& context, x64_emulator& emu, const std::filesystem::path& file)
|
||||
void setup_context(process_context& context, x64_emulator& emu, const std::filesystem::path& file,
|
||||
const std::vector<std::wstring>& arguments)
|
||||
{
|
||||
setup_stack(emu, STACK_ADDRESS, STACK_SIZE);
|
||||
setup_gdt(emu);
|
||||
@@ -218,7 +219,6 @@ namespace
|
||||
|
||||
context.teb = gs.reserve<TEB>();
|
||||
context.peb = gs.reserve<PEB>();
|
||||
context.process_params = gs.reserve<RTL_USER_PROCESS_PARAMETERS>();
|
||||
|
||||
context.teb.access([&](TEB& teb)
|
||||
{
|
||||
@@ -230,9 +230,25 @@ namespace
|
||||
teb.ProcessEnvironmentBlock = context.peb.ptr();
|
||||
});
|
||||
|
||||
/* Values of the following fields must be
|
||||
* allocated relative to the process_params themselves.
|
||||
* and included in the length:
|
||||
*
|
||||
* CurrentDirectory
|
||||
* DllPath
|
||||
* ImagePathName
|
||||
* CommandLine
|
||||
* WindowTitle
|
||||
* DesktopInfo
|
||||
* ShellInfo
|
||||
* RuntimeData
|
||||
* RedirectionDllName
|
||||
*/
|
||||
|
||||
context.process_params = gs.reserve<RTL_USER_PROCESS_PARAMETERS>();
|
||||
|
||||
context.process_params.access([&](RTL_USER_PROCESS_PARAMETERS& proc_params)
|
||||
{
|
||||
proc_params.Length = sizeof(proc_params);
|
||||
proc_params.Flags = 0x6001 | 0x80000000; // Prevent CsrClientConnectToServer
|
||||
|
||||
proc_params.ConsoleHandle = CONSOLE_HANDLE.h;
|
||||
@@ -240,9 +256,23 @@ namespace
|
||||
proc_params.StandardInput = STDIN_HANDLE.h;
|
||||
proc_params.StandardError = proc_params.StandardOutput;
|
||||
|
||||
|
||||
std::wstring command_line = L"\"" + file.wstring() + L"\"";
|
||||
|
||||
for (const auto& arg : arguments)
|
||||
{
|
||||
command_line.push_back(L' ');
|
||||
command_line.append(arg);
|
||||
}
|
||||
|
||||
gs.make_unicode_string(proc_params.CommandLine, command_line);
|
||||
gs.make_unicode_string(proc_params.CurrentDirectory.DosPath, file.parent_path().wstring());
|
||||
gs.make_unicode_string(proc_params.ImagePathName, file.wstring());
|
||||
gs.make_unicode_string(proc_params.CommandLine, file.wstring());
|
||||
|
||||
const auto total_length = gs.get_next_address() - context.process_params.value();
|
||||
|
||||
proc_params.Length = std::max(sizeof(proc_params), total_length);
|
||||
proc_params.MaximumLength = proc_params.Length;
|
||||
});
|
||||
|
||||
context.peb.access([&](PEB& peb)
|
||||
@@ -435,10 +465,11 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
windows_emulator::windows_emulator(const std::filesystem::path& application, std::unique_ptr<x64_emulator> emu)
|
||||
windows_emulator::windows_emulator(const std::filesystem::path& application, const std::vector<std::wstring>& arguments,
|
||||
std::unique_ptr<x64_emulator> emu)
|
||||
: windows_emulator(std::move(emu))
|
||||
{
|
||||
this->setup_process(application);
|
||||
this->setup_process(application, arguments);
|
||||
}
|
||||
|
||||
windows_emulator::windows_emulator(std::unique_ptr<x64_emulator> emu)
|
||||
@@ -448,14 +479,15 @@ windows_emulator::windows_emulator(std::unique_ptr<x64_emulator> emu)
|
||||
this->setup_hooks();
|
||||
}
|
||||
|
||||
void windows_emulator::setup_process(const std::filesystem::path& application)
|
||||
void windows_emulator::setup_process(const std::filesystem::path& application,
|
||||
const std::vector<std::wstring>& arguments)
|
||||
{
|
||||
auto& emu = this->emu();
|
||||
|
||||
auto& context = this->process();
|
||||
context.module_manager = module_manager(emu); // TODO: Cleanup module manager
|
||||
|
||||
setup_context(context, emu, application);
|
||||
setup_context(context, emu, application, arguments);
|
||||
|
||||
context.executable = context.module_manager.map_module(application);
|
||||
|
||||
@@ -532,40 +564,46 @@ void windows_emulator::setup_hooks()
|
||||
return memory_violation_continuation::resume;
|
||||
});
|
||||
|
||||
this->emu().hook_memory_execution(0, std::numeric_limits<size_t>::max(), [&](const uint64_t address, const size_t)
|
||||
{
|
||||
++this->process().executed_instructions;
|
||||
this->emu().hook_memory_execution(0, std::numeric_limits<size_t>::max(),
|
||||
[&](const uint64_t address, const size_t, const uint64_t)
|
||||
{
|
||||
++this->process().executed_instructions;
|
||||
|
||||
const auto* binary = this->process().module_manager.find_by_address(address);
|
||||
const auto* binary = this->process().module_manager.find_by_address(address);
|
||||
|
||||
if (binary)
|
||||
{
|
||||
const auto export_entry = binary->address_names.find(address);
|
||||
if (export_entry != binary->address_names.end())
|
||||
{
|
||||
printf("Executing function: %s - %s (%llX)\n", binary->name.c_str(), export_entry->second.c_str(),
|
||||
address);
|
||||
}
|
||||
else if (address == binary->entry_point)
|
||||
{
|
||||
printf("Executing entry point: %s (%llX)\n", binary->name.c_str(), address);
|
||||
}
|
||||
}
|
||||
if (binary)
|
||||
{
|
||||
const auto export_entry = binary->address_names.find(address);
|
||||
if (export_entry != binary->address_names.end())
|
||||
{
|
||||
printf("Executing function: %s - %s (%llX)\n", binary->name.c_str(),
|
||||
export_entry->second.c_str(),
|
||||
address);
|
||||
}
|
||||
else if (address == binary->entry_point)
|
||||
{
|
||||
printf("Executing entry point: %s (%llX)\n", binary->name.c_str(),
|
||||
address);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->verbose_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!this->verbose_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto& emu = this->emu();
|
||||
auto& emu = this->emu();
|
||||
|
||||
printf(
|
||||
"Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX - R8: %16llX - R9: %16llX - RDI: %16llX - RSI: %16llX - %s\n",
|
||||
address,
|
||||
emu.reg(x64_register::rax), emu.reg(x64_register::rbx), emu.reg(x64_register::rcx),
|
||||
emu.reg(x64_register::rdx), emu.reg(x64_register::r8), emu.reg(x64_register::r9),
|
||||
emu.reg(x64_register::rdi), emu.reg(x64_register::rsi), binary ? binary->name.c_str() : "<N/A>");
|
||||
});
|
||||
printf(
|
||||
"Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX - R8: %16llX - R9: %16llX - RDI: %16llX - RSI: %16llX - %s\n",
|
||||
address,
|
||||
emu.reg(x64_register::rax), emu.reg(x64_register::rbx),
|
||||
emu.reg(x64_register::rcx),
|
||||
emu.reg(x64_register::rdx), emu.reg(x64_register::r8),
|
||||
emu.reg(x64_register::r9),
|
||||
emu.reg(x64_register::rdi), emu.reg(x64_register::rsi),
|
||||
binary ? binary->name.c_str() : "<N/A>");
|
||||
});
|
||||
}
|
||||
|
||||
void windows_emulator::serialize(utils::buffer_serializer& buffer) const
|
||||
|
||||
@@ -9,7 +9,7 @@ class windows_emulator
|
||||
{
|
||||
public:
|
||||
windows_emulator(std::unique_ptr<x64_emulator> emu = unicorn::create_x64_emulator());
|
||||
windows_emulator(const std::filesystem::path& application,
|
||||
windows_emulator(const std::filesystem::path& application, const std::vector<std::wstring>& arguments = {},
|
||||
std::unique_ptr<x64_emulator> emu = unicorn::create_x64_emulator());
|
||||
|
||||
windows_emulator(windows_emulator&&) = delete;
|
||||
@@ -59,5 +59,5 @@ private:
|
||||
//std::optional<process_context> process_snapshot_{};
|
||||
|
||||
void setup_hooks();
|
||||
void setup_process(const std::filesystem::path& application);
|
||||
void setup_process(const std::filesystem::path& application, const std::vector<std::wstring>& arguments);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user