Fix commandline args

This commit is contained in:
momo5502
2024-09-13 19:06:10 +02:00
parent 370665b520
commit f1127ce170
8 changed files with 159 additions and 85 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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