mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 19:23:56 +00:00
Merge pull request #27 from momo5502/task/kusd-mmio
Add KUSER_SHARED_DATA MMIO support
This commit is contained in:
@@ -19,6 +19,20 @@ inline void deserialize(utils::buffer_deserializer& buffer, std::chrono::steady_
|
||||
tp = time_point{duration{count}};
|
||||
}
|
||||
|
||||
inline void serialize(utils::buffer_serializer& buffer, const std::chrono::system_clock::time_point& tp)
|
||||
{
|
||||
buffer.write(tp.time_since_epoch().count());
|
||||
}
|
||||
|
||||
inline void deserialize(utils::buffer_deserializer& buffer, std::chrono::system_clock::time_point& tp)
|
||||
{
|
||||
using time_point = std::chrono::system_clock::time_point;
|
||||
using duration = time_point::duration;
|
||||
|
||||
const auto count = buffer.read<duration::rep>();
|
||||
tp = time_point{duration{count}};
|
||||
}
|
||||
|
||||
inline void serialize(utils::buffer_serializer& buffer, const std::filesystem::path& path)
|
||||
{
|
||||
buffer.write_string<wchar_t>(path.wstring());
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
// Externally visible and potentially modifiable state
|
||||
// to trick compiler optimizations
|
||||
__declspec(dllexport) bool do_the_task = true;
|
||||
@@ -178,6 +182,12 @@ bool test_native_exceptions()
|
||||
}
|
||||
}
|
||||
|
||||
void print_time()
|
||||
{
|
||||
const auto epoch_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
printf("Time: %lld\n", epoch_time.count());
|
||||
}
|
||||
|
||||
#define RUN_TEST(func, name) \
|
||||
{ \
|
||||
printf("Running test '" name "': "); \
|
||||
@@ -186,8 +196,14 @@ bool test_native_exceptions()
|
||||
puts(res ? "Success" : "Fail"); \
|
||||
}
|
||||
|
||||
int main(int /*argc*/, const char* /*argv*/[])
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if(argc == 2 && argv[1] == "-time"sv)
|
||||
{
|
||||
print_time();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool valid = true;
|
||||
|
||||
RUN_TEST(test_io, "I/O")
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
#define ASSERT_NOT_TERMINATED(win_emu) \
|
||||
do { \
|
||||
ASSERT_FALSE(win_emu.process().exit_status.has_value()); \
|
||||
ASSERT_FALSE((win_emu).process().exit_status.has_value()); \
|
||||
} while(false)
|
||||
|
||||
|
||||
#define ASSERT_TERMINATED_WITH_STATUS(win_emu, status) \
|
||||
do { \
|
||||
ASSERT_TRUE(win_emu.process().exit_status.has_value()); \
|
||||
ASSERT_EQ(*win_emu.process().exit_status, status); \
|
||||
ASSERT_TRUE((win_emu).process().exit_status.has_value()); \
|
||||
ASSERT_EQ(*(win_emu).process().exit_status, status); \
|
||||
} while(false)
|
||||
|
||||
#define ASSERT_TERMINATED_SUCCESSFULLY(win_emu) \
|
||||
@@ -20,15 +20,20 @@
|
||||
|
||||
namespace test
|
||||
{
|
||||
inline windows_emulator create_sample_emulator(emulator_settings& settings)
|
||||
{
|
||||
settings.application = "./test-sample.exe";
|
||||
return windows_emulator{settings};
|
||||
}
|
||||
|
||||
inline windows_emulator create_sample_emulator()
|
||||
{
|
||||
const emulator_settings settings
|
||||
emulator_settings settings
|
||||
{
|
||||
.application = "./test-sample.exe",
|
||||
.disable_logging = true,
|
||||
.use_relative_time = true,
|
||||
};
|
||||
|
||||
return windows_emulator{settings};
|
||||
return create_sample_emulator(settings);
|
||||
}
|
||||
}
|
||||
|
||||
45
src/windows-emulator-test/time_test.cpp
Normal file
45
src/windows-emulator-test/time_test.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "emulation_test_utils.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
TEST(TimeTest, SystemTimeIsAccurate)
|
||||
{
|
||||
std::string output_buffer{};
|
||||
|
||||
emulator_settings settings{
|
||||
.arguments = {L"-time"},
|
||||
.stdout_callback = [&output_buffer](const std::string_view data)
|
||||
{
|
||||
output_buffer.append(data);
|
||||
},
|
||||
.disable_logging = true,
|
||||
.use_relative_time = false,
|
||||
};
|
||||
|
||||
auto emu = create_sample_emulator(settings);
|
||||
emu.start();
|
||||
|
||||
constexpr auto prefix = "Time: "sv;
|
||||
|
||||
ASSERT_TERMINATED_SUCCESSFULLY(emu);
|
||||
ASSERT_TRUE(output_buffer.starts_with(prefix));
|
||||
|
||||
output_buffer = output_buffer.substr(prefix.size());
|
||||
while (!output_buffer.empty() && (output_buffer.back() == '\n' || output_buffer.back() == '\r'))
|
||||
{
|
||||
output_buffer.pop_back();
|
||||
}
|
||||
|
||||
const auto time = strtoll(output_buffer.c_str(), nullptr, 10);
|
||||
|
||||
using time_point = std::chrono::system_clock::time_point;
|
||||
|
||||
const time_point::duration time_duration(time);
|
||||
const time_point tp(time_duration);
|
||||
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
const auto diff = now - tp;
|
||||
|
||||
ASSERT_LE(diff, std::chrono::hours(1));
|
||||
}
|
||||
}
|
||||
@@ -36,8 +36,10 @@ public:
|
||||
};
|
||||
|
||||
class windows_emulator;
|
||||
struct process_context;
|
||||
|
||||
using x64_emulator_wrapper = object_wrapper<x64_emulator>;
|
||||
using process_context_wrapper = object_wrapper<process_context>;
|
||||
using windows_emulator_wrapper = object_wrapper<windows_emulator>;
|
||||
|
||||
template <typename T>
|
||||
|
||||
222
src/windows-emulator/kusd_mmio.cpp
Normal file
222
src/windows-emulator/kusd_mmio.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
#include "kusd_mmio.hpp"
|
||||
#include "syscall_utils.hpp"
|
||||
#include "windows_emulator.hpp"
|
||||
|
||||
#include <address_utils.hpp>
|
||||
|
||||
constexpr auto KUSD_ADDRESS = 0x7ffe0000ULL;
|
||||
constexpr auto KUSD_SIZE = sizeof(KUSER_SHARED_DATA);
|
||||
constexpr auto KUSD_BUFFER_SIZE = page_align_up(KUSD_SIZE);
|
||||
|
||||
namespace
|
||||
{
|
||||
void setup_kusd(KUSER_SHARED_DATA& kusd, const bool use_relative_time)
|
||||
{
|
||||
memset(&kusd, 0, sizeof(kusd));
|
||||
|
||||
kusd.TickCountMultiplier = 0x0fa00000;
|
||||
kusd.InterruptTime.LowPart = 0x17bd9547;
|
||||
kusd.InterruptTime.High1Time = 0x0000004b;
|
||||
kusd.InterruptTime.High2Time = 0x0000004b;
|
||||
kusd.SystemTime.LowPart = 0x7af9da99;
|
||||
kusd.SystemTime.High1Time = 0x01db27b9;
|
||||
kusd.SystemTime.High2Time = 0x01db27b9;
|
||||
kusd.TimeZoneBias.LowPart = 0x3c773000;
|
||||
kusd.TimeZoneBias.High1Time = -17;
|
||||
kusd.TimeZoneBias.High2Time = -17;
|
||||
kusd.TimeZoneId = 0x00000002;
|
||||
kusd.LargePageMinimum = 0x00200000;
|
||||
kusd.RNGSeedVersion = 0x0000000000000013;
|
||||
kusd.TimeZoneBiasStamp = 0x00000004;
|
||||
kusd.NtBuildNumber = 0x00006c51;
|
||||
kusd.NtProductType = NtProductWinNt;
|
||||
kusd.ProductTypeIsValid = 0x01;
|
||||
kusd.NativeProcessorArchitecture = 0x0009;
|
||||
kusd.NtMajorVersion = 0x0000000a;
|
||||
kusd.BootId = 0x0000000b;
|
||||
kusd.SystemExpirationDate.QuadPart = 0x01dc26860a9ff300;
|
||||
kusd.SuiteMask = 0x00000110;
|
||||
kusd.MitigationPolicies.MitigationPolicies = 0x0a;
|
||||
kusd.MitigationPolicies.NXSupportPolicy = 0x02;
|
||||
kusd.MitigationPolicies.SEHValidationPolicy = 0x02;
|
||||
kusd.CyclesPerYield = 0x0064;
|
||||
kusd.DismountCount = 0x00000006;
|
||||
kusd.ComPlusPackage = 0x00000001;
|
||||
kusd.LastSystemRITEventTickCount = 0x01ec1fd3;
|
||||
kusd.NumberOfPhysicalPages = 0x00bf0958;
|
||||
kusd.FullNumberOfPhysicalPages = 0x0000000000bf0958;
|
||||
kusd.TickCount.TickCount.LowPart = 0x001f7f05;
|
||||
kusd.TickCount.TickCountQuad = 0x00000000001f7f05;
|
||||
kusd.Cookie = 0x1c3471da;
|
||||
kusd.ConsoleSessionForegroundProcessId = 0x00000000000028f4;
|
||||
kusd.TimeUpdateLock = 0x0000000002b28586;
|
||||
kusd.BaselineSystemTimeQpc = 0x0000004b17cd596c;
|
||||
kusd.BaselineInterruptTimeQpc = 0x0000004b17cd596c;
|
||||
kusd.QpcSystemTimeIncrement = 0x8000000000000000;
|
||||
kusd.QpcInterruptTimeIncrement = 0x8000000000000000;
|
||||
kusd.QpcSystemTimeIncrementShift = 0x01;
|
||||
kusd.QpcInterruptTimeIncrementShift = 0x01;
|
||||
kusd.UnparkedProcessorCount = 0x000c;
|
||||
kusd.TelemetryCoverageRound = 0x00000001;
|
||||
kusd.LangGenerationCount = 0x00000003;
|
||||
kusd.InterruptTimeBias = 0x00000015a5d56406;
|
||||
kusd.QpcBias = 0x000000159530c4af;
|
||||
kusd.ActiveProcessorCount = 0x0000000c;
|
||||
kusd.ActiveGroupCount = 0x01;
|
||||
kusd.QpcData.QpcData = 0x0083;
|
||||
kusd.QpcData.QpcBypassEnabled = 0x83;
|
||||
kusd.TimeZoneBiasEffectiveStart.QuadPart = 0x01db276e654cb2ff;
|
||||
kusd.TimeZoneBiasEffectiveEnd.QuadPart = 0x01db280b8c3b2800;
|
||||
kusd.XState.EnabledFeatures = 0x000000000000001f;
|
||||
kusd.XState.EnabledVolatileFeatures = 0x000000000000000f;
|
||||
kusd.XState.Size = 0x000003c0;
|
||||
|
||||
if (use_relative_time)
|
||||
{
|
||||
kusd.QpcFrequency = 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
kusd.QpcFrequency = std::chrono::steady_clock::period::den;
|
||||
}
|
||||
|
||||
constexpr std::wstring_view root_dir{L"C:\\WINDOWS"};
|
||||
memcpy(&kusd.NtSystemRoot.arr[0], root_dir.data(), root_dir.size() * 2);
|
||||
|
||||
kusd.ImageNumberLow = IMAGE_FILE_MACHINE_I386;
|
||||
kusd.ImageNumberHigh = IMAGE_FILE_MACHINE_AMD64;
|
||||
}
|
||||
}
|
||||
|
||||
inline void serialize(utils::buffer_serializer& buffer, const KUSER_SHARED_DATA& kusd)
|
||||
{
|
||||
static_assert(KUSD_SIZE == sizeof(kusd));
|
||||
buffer.write(&kusd, KUSD_SIZE);
|
||||
}
|
||||
|
||||
inline void deserialize(utils::buffer_deserializer& buffer, KUSER_SHARED_DATA& kusd)
|
||||
{
|
||||
buffer.read(&kusd, KUSD_SIZE);
|
||||
}
|
||||
|
||||
kusd_mmio::kusd_mmio(x64_emulator& emu, process_context& process)
|
||||
: emu_(&emu)
|
||||
, process_(&process)
|
||||
{
|
||||
}
|
||||
|
||||
kusd_mmio::~kusd_mmio()
|
||||
{
|
||||
this->deregister_mmio();
|
||||
}
|
||||
|
||||
kusd_mmio::kusd_mmio(utils::buffer_deserializer& buffer)
|
||||
: kusd_mmio(buffer.read<x64_emulator_wrapper>(), buffer.read<process_context_wrapper>())
|
||||
{
|
||||
}
|
||||
|
||||
void kusd_mmio::setup(const bool use_relative_time)
|
||||
{
|
||||
this->use_relative_time_ = use_relative_time;
|
||||
|
||||
setup_kusd(this->kusd_, use_relative_time);
|
||||
this->start_time_ = convert_from_ksystem_time(this->kusd_.SystemTime);
|
||||
|
||||
this->register_mmio();
|
||||
}
|
||||
|
||||
void kusd_mmio::serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->use_relative_time_);
|
||||
buffer.write(this->kusd_);
|
||||
buffer.write(this->start_time_);
|
||||
}
|
||||
|
||||
void kusd_mmio::deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read(this->use_relative_time_);
|
||||
buffer.read(this->kusd_);
|
||||
buffer.read(this->start_time_);
|
||||
|
||||
this->deregister_mmio();
|
||||
this->register_mmio();
|
||||
}
|
||||
|
||||
uint64_t kusd_mmio::read(const uint64_t addr, const size_t size)
|
||||
{
|
||||
uint64_t result{};
|
||||
|
||||
this->update();
|
||||
|
||||
if (addr >= KUSD_SIZE)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto end = addr + size;
|
||||
const auto valid_end = std::min(end, KUSD_SIZE);
|
||||
const auto real_size = valid_end - addr;
|
||||
|
||||
if (real_size > sizeof(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto* kusd_buffer = reinterpret_cast<uint8_t*>(&this->kusd_);
|
||||
memcpy(&result, kusd_buffer + addr, real_size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t kusd_mmio::address()
|
||||
{
|
||||
return KUSD_ADDRESS;
|
||||
}
|
||||
|
||||
void kusd_mmio::update()
|
||||
{
|
||||
auto time = this->start_time_;
|
||||
|
||||
if (this->use_relative_time_)
|
||||
{
|
||||
const auto passed_time = this->process_->executed_instructions;
|
||||
const auto clock_frequency = this->kusd_.QpcFrequency;
|
||||
|
||||
using duration = std::chrono::system_clock::duration;
|
||||
time += duration(passed_time * duration::period::den / clock_frequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
time = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
convert_to_ksystem_time(&this->kusd_.SystemTime, time);
|
||||
}
|
||||
|
||||
void kusd_mmio::register_mmio()
|
||||
{
|
||||
if (this->registered_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->registered_ = true;
|
||||
|
||||
this->emu_->allocate_mmio(KUSD_ADDRESS, KUSD_BUFFER_SIZE,
|
||||
[this](const uint64_t addr, const size_t size)
|
||||
{
|
||||
return this->read(addr, size);
|
||||
}, [this](const uint64_t, const size_t, const uint64_t)
|
||||
{
|
||||
// Writing not supported!
|
||||
});
|
||||
}
|
||||
|
||||
void kusd_mmio::deregister_mmio()
|
||||
{
|
||||
if (this->registered_)
|
||||
{
|
||||
this->registered_ = false;
|
||||
this->emu_->release_memory(KUSD_ADDRESS, KUSD_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
57
src/windows-emulator/kusd_mmio.hpp
Normal file
57
src/windows-emulator/kusd_mmio.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include "std_include.hpp"
|
||||
#include <serialization.hpp>
|
||||
|
||||
#include "x64_emulator.hpp"
|
||||
|
||||
struct process_context;
|
||||
class windows_emulator;
|
||||
|
||||
class kusd_mmio
|
||||
{
|
||||
public:
|
||||
kusd_mmio(x64_emulator& emu, process_context& process);
|
||||
~kusd_mmio();
|
||||
|
||||
kusd_mmio(utils::buffer_deserializer& buffer);
|
||||
|
||||
kusd_mmio(kusd_mmio&&) = delete;
|
||||
kusd_mmio(const kusd_mmio&) = delete;
|
||||
kusd_mmio& operator=(kusd_mmio&& obj) = delete;
|
||||
kusd_mmio& operator=(const kusd_mmio&) = delete;
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const;
|
||||
void deserialize(utils::buffer_deserializer& buffer);
|
||||
|
||||
KUSER_SHARED_DATA& get()
|
||||
{
|
||||
return this->kusd_;
|
||||
}
|
||||
|
||||
const KUSER_SHARED_DATA& get() const
|
||||
{
|
||||
return this->kusd_;
|
||||
}
|
||||
|
||||
static uint64_t address();
|
||||
|
||||
void setup(bool use_relative_time);
|
||||
|
||||
private:
|
||||
x64_emulator* emu_{};
|
||||
process_context* process_{};
|
||||
|
||||
bool registered_{};
|
||||
bool use_relative_time_{};
|
||||
|
||||
KUSER_SHARED_DATA kusd_{};
|
||||
std::chrono::system_clock::time_point start_time_{};
|
||||
|
||||
uint64_t read(uint64_t addr, size_t size);
|
||||
|
||||
void update();
|
||||
|
||||
void register_mmio();
|
||||
void deregister_mmio();
|
||||
};
|
||||
@@ -12,14 +12,13 @@
|
||||
#include <serialization_helper.hpp>
|
||||
|
||||
#include "io_device.hpp"
|
||||
#include "kusd_mmio.hpp"
|
||||
|
||||
#define PEB_SEGMENT_SIZE (20 << 20) // 20 MB
|
||||
#define GS_SEGMENT_SIZE (1 << 20) // 1 MB
|
||||
|
||||
#define IA32_GS_BASE_MSR 0xC0000101
|
||||
|
||||
#define KUSD_ADDRESS 0x7ffe0000
|
||||
|
||||
#define STACK_SIZE 0x40000ULL
|
||||
|
||||
#define GDT_ADDR 0x30000
|
||||
@@ -366,7 +365,7 @@ struct process_context
|
||||
: base_allocator(emu)
|
||||
, peb(emu)
|
||||
, process_params(emu)
|
||||
, kusd(emu)
|
||||
, kusd(emu, *this)
|
||||
, module_manager(emu)
|
||||
{
|
||||
}
|
||||
@@ -384,7 +383,7 @@ struct process_context
|
||||
|
||||
emulator_object<PEB> peb;
|
||||
emulator_object<RTL_USER_PROCESS_PARAMETERS> process_params;
|
||||
emulator_object<KUSER_SHARED_DATA> kusd;
|
||||
kusd_mmio kusd;
|
||||
|
||||
module_manager module_manager;
|
||||
|
||||
|
||||
@@ -175,11 +175,12 @@ void write_attribute(emulator& emu, const PS_ATTRIBUTE& attribute, const T& valu
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto HUNDRED_NANOSECONDS_IN_ONE_SECOND = 10000000LL;
|
||||
constexpr auto EPOCH_DIFFERENCE_1601_TO_1970_SECONDS = 11644473600LL;
|
||||
constexpr auto WINDOWS_EPOCH_DIFFERENCE = EPOCH_DIFFERENCE_1601_TO_1970_SECONDS * HUNDRED_NANOSECONDS_IN_ONE_SECOND;
|
||||
|
||||
inline std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(const LARGE_INTEGER delay_interval)
|
||||
{
|
||||
constexpr auto HUNDRED_NANOSECONDS_IN_ONE_SECOND = 10000000LL;
|
||||
constexpr auto EPOCH_DIFFERENCE_1601_TO_1970_SECONDS = 11644473600LL;
|
||||
|
||||
if (delay_interval.QuadPart <= 0)
|
||||
{
|
||||
const auto relative_time = -delay_interval.QuadPart;
|
||||
@@ -207,3 +208,38 @@ inline std::chrono::steady_clock::time_point convert_delay_interval_to_time_poin
|
||||
|
||||
return std::chrono::steady_clock::now() + duration_until_target;
|
||||
}
|
||||
|
||||
inline KSYSTEM_TIME convert_to_ksystem_time(const std::chrono::system_clock::time_point& tp)
|
||||
{
|
||||
const auto duration = tp.time_since_epoch();
|
||||
const auto ns_duration = std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
|
||||
|
||||
const auto total_ticks = ns_duration.count() / 100 + WINDOWS_EPOCH_DIFFERENCE;
|
||||
|
||||
KSYSTEM_TIME time{};
|
||||
time.LowPart = static_cast<uint32_t>(total_ticks);
|
||||
time.High1Time = static_cast<int32_t>(total_ticks >> 32);
|
||||
time.High2Time = time.High1Time;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
inline void convert_to_ksystem_time(volatile KSYSTEM_TIME* dest, const std::chrono::system_clock::time_point& tp)
|
||||
{
|
||||
const auto time = convert_to_ksystem_time(tp);
|
||||
memcpy(const_cast<KSYSTEM_TIME*>(dest), &time, sizeof(*dest));
|
||||
}
|
||||
|
||||
inline std::chrono::system_clock::time_point convert_from_ksystem_time(const KSYSTEM_TIME& time)
|
||||
{
|
||||
auto totalTicks = (static_cast<int64_t>(time.High1Time) << 32) | time.LowPart;
|
||||
totalTicks -= WINDOWS_EPOCH_DIFFERENCE;
|
||||
|
||||
const auto duration = std::chrono::system_clock::duration(totalTicks * 100);
|
||||
return std::chrono::system_clock::time_point(duration);
|
||||
}
|
||||
|
||||
inline std::chrono::system_clock::time_point convert_from_ksystem_time(const volatile KSYSTEM_TIME& time)
|
||||
{
|
||||
return convert_from_ksystem_time(*const_cast<const KSYSTEM_TIME*>(&time));
|
||||
}
|
||||
|
||||
@@ -35,15 +35,9 @@ namespace
|
||||
|
||||
if (performance_frequency)
|
||||
{
|
||||
int64_t frequency{};
|
||||
c.proc.kusd.access([&](const KUSER_SHARED_DATA& kusd)
|
||||
{
|
||||
frequency = kusd.QpcFrequency;
|
||||
});
|
||||
|
||||
performance_frequency.access([&](LARGE_INTEGER& value)
|
||||
{
|
||||
value.QuadPart = frequency;
|
||||
value.QuadPart = c.proc.kusd.get().QpcFrequency;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -540,12 +534,8 @@ namespace
|
||||
c.emu.allocate_memory(address,
|
||||
c.proc.shared_section_size, memory_permission::read_write);
|
||||
|
||||
size_t windows_dir_size{};
|
||||
c.proc.kusd.access([&](const KUSER_SHARED_DATA& kusd)
|
||||
{
|
||||
const std::wstring_view windows_dir = kusd.NtSystemRoot.arr;
|
||||
windows_dir_size = windows_dir.size() * 2;
|
||||
});
|
||||
const std::wstring_view windows_dir = c.proc.kusd.get().NtSystemRoot.arr;
|
||||
const auto windows_dir_size = windows_dir.size() * 2;
|
||||
|
||||
constexpr auto windows_dir_offset = 0x10;
|
||||
c.emu.write_memory(address + 8, windows_dir_offset);
|
||||
@@ -555,7 +545,7 @@ namespace
|
||||
const emulator_object<UNICODE_STRING> windir_obj{c.emu, obj_address};
|
||||
windir_obj.access([&](UNICODE_STRING& ucs)
|
||||
{
|
||||
const auto dir_address = c.proc.kusd.value() + offsetof(KUSER_SHARED_DATA, NtSystemRoot);
|
||||
const auto dir_address = kusd_mmio::address() + offsetof(KUSER_SHARED_DATA, NtSystemRoot);
|
||||
|
||||
ucs.Buffer = reinterpret_cast<wchar_t*>(dir_address - obj_address);
|
||||
ucs.Length = static_cast<uint16_t>(windows_dir_size);
|
||||
@@ -1995,6 +1985,7 @@ namespace
|
||||
temp_buffer.push_back('\n');
|
||||
}
|
||||
|
||||
c.win_emu.on_stdout(temp_buffer);
|
||||
c.win_emu.logger.info("%.*s", static_cast<int>(temp_buffer.size()), temp_buffer.data());
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
@@ -50,95 +50,6 @@ namespace
|
||||
emu.write_register(x64_register::msr, &value, sizeof(value));
|
||||
}
|
||||
|
||||
emulator_object<KUSER_SHARED_DATA> setup_kusd(x64_emulator& emu, bool use_relative_time)
|
||||
{
|
||||
// TODO: Fix that. Use hooks to feed dynamic data, e.g. time values
|
||||
|
||||
emu.allocate_memory(KUSD_ADDRESS, page_align_up(sizeof(KUSER_SHARED_DATA)), memory_permission::read);
|
||||
|
||||
const emulator_object<KUSER_SHARED_DATA> kusd_object{emu, KUSD_ADDRESS};
|
||||
kusd_object.access([&](KUSER_SHARED_DATA& kusd)
|
||||
{
|
||||
kusd.TickCountMultiplier = 0x0fa00000;
|
||||
kusd.InterruptTime.LowPart = 0x17bd9547;
|
||||
kusd.InterruptTime.High1Time = 0x0000004b;
|
||||
kusd.InterruptTime.High2Time = 0x0000004b;
|
||||
kusd.SystemTime.LowPart = 0x7af9da99;
|
||||
kusd.SystemTime.High1Time = 0x01db27b9;
|
||||
kusd.SystemTime.High2Time = 0x01db27b9;
|
||||
kusd.TimeZoneBias.LowPart = 0x3c773000;
|
||||
kusd.TimeZoneBias.High1Time = -17;
|
||||
kusd.TimeZoneBias.High2Time = -17;
|
||||
kusd.TimeZoneId = 0x00000002;
|
||||
kusd.LargePageMinimum = 0x00200000;
|
||||
kusd.RNGSeedVersion = 0x0000000000000013;
|
||||
kusd.TimeZoneBiasStamp = 0x00000004;
|
||||
kusd.NtBuildNumber = 0x00006c51;
|
||||
kusd.NtProductType = NtProductWinNt;
|
||||
kusd.ProductTypeIsValid = 0x01;
|
||||
kusd.NativeProcessorArchitecture = 0x0009;
|
||||
kusd.NtMajorVersion = 0x0000000a;
|
||||
kusd.BootId = 0x0000000b;
|
||||
kusd.SystemExpirationDate.QuadPart = 0x01dc26860a9ff300;
|
||||
kusd.SuiteMask = 0x00000110;
|
||||
kusd.MitigationPolicies.MitigationPolicies = 0x0a;
|
||||
kusd.MitigationPolicies.NXSupportPolicy = 0x02;
|
||||
kusd.MitigationPolicies.SEHValidationPolicy = 0x02;
|
||||
kusd.CyclesPerYield = 0x0064;
|
||||
kusd.DismountCount = 0x00000006;
|
||||
kusd.ComPlusPackage = 0x00000001;
|
||||
kusd.LastSystemRITEventTickCount = 0x01ec1fd3;
|
||||
kusd.NumberOfPhysicalPages = 0x00bf0958;
|
||||
kusd.FullNumberOfPhysicalPages = 0x0000000000bf0958;
|
||||
kusd.TickCount.TickCount.LowPart = 0x001f7f05;
|
||||
kusd.TickCount.TickCountQuad = 0x00000000001f7f05;
|
||||
kusd.Cookie = 0x1c3471da;
|
||||
kusd.ConsoleSessionForegroundProcessId = 0x00000000000028f4;
|
||||
kusd.TimeUpdateLock = 0x0000000002b28586;
|
||||
kusd.BaselineSystemTimeQpc = 0x0000004b17cd596c;
|
||||
kusd.BaselineInterruptTimeQpc = 0x0000004b17cd596c;
|
||||
kusd.QpcSystemTimeIncrement = 0x8000000000000000;
|
||||
kusd.QpcInterruptTimeIncrement = 0x8000000000000000;
|
||||
kusd.QpcSystemTimeIncrementShift = 0x01;
|
||||
kusd.QpcInterruptTimeIncrementShift = 0x01;
|
||||
kusd.UnparkedProcessorCount = 0x000c;
|
||||
kusd.TelemetryCoverageRound = 0x00000001;
|
||||
kusd.LangGenerationCount = 0x00000003;
|
||||
kusd.InterruptTimeBias = 0x00000015a5d56406;
|
||||
kusd.QpcBias = 0x000000159530c4af;
|
||||
kusd.ActiveProcessorCount = 0x0000000c;
|
||||
kusd.ActiveGroupCount = 0x01;
|
||||
kusd.QpcData.QpcData = 0x0083;
|
||||
kusd.QpcData.QpcBypassEnabled = 0x83;
|
||||
kusd.TimeZoneBiasEffectiveStart.QuadPart = 0x01db276e654cb2ff;
|
||||
kusd.TimeZoneBiasEffectiveEnd.QuadPart = 0x01db280b8c3b2800;
|
||||
kusd.XState.EnabledFeatures = 0x000000000000001f;
|
||||
kusd.XState.EnabledVolatileFeatures = 0x000000000000000f;
|
||||
kusd.XState.Size = 0x000003c0;
|
||||
|
||||
if (use_relative_time)
|
||||
{
|
||||
kusd.QpcFrequency = 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
kusd.QpcFrequency = std::chrono::steady_clock::period::den;
|
||||
}
|
||||
|
||||
constexpr std::wstring_view root_dir{L"C:\\WINDOWS"};
|
||||
memcpy(&kusd.NtSystemRoot.arr[0], root_dir.data(), root_dir.size() * 2);
|
||||
|
||||
kusd.ImageNumberLow = IMAGE_FILE_MACHINE_I386;
|
||||
kusd.ImageNumberHigh = IMAGE_FILE_MACHINE_AMD64;
|
||||
|
||||
memset(&kusd.ProcessorFeatures, 0, sizeof(kusd.ProcessorFeatures));
|
||||
|
||||
// ...
|
||||
});
|
||||
|
||||
return kusd_object;
|
||||
}
|
||||
|
||||
uint64_t copy_string(x64_emulator& emu, emulator_allocator& allocator, const void* base_ptr, const uint64_t offset,
|
||||
const size_t length)
|
||||
{
|
||||
@@ -262,13 +173,16 @@ namespace
|
||||
return canonical(absolute(path).parent_path()).make_preferred();
|
||||
}
|
||||
|
||||
void setup_context(process_context& context, x64_emulator& emu, const emulator_settings& settings)
|
||||
void setup_context(windows_emulator& win_emu, const emulator_settings& settings)
|
||||
{
|
||||
auto& emu = win_emu.emu();
|
||||
auto& context = win_emu.process();
|
||||
|
||||
setup_gdt(emu);
|
||||
|
||||
context.registry = registry_manager(settings.registry_directory);
|
||||
|
||||
context.kusd = setup_kusd(emu, settings.use_relative_time);
|
||||
context.kusd.setup(settings.use_relative_time);
|
||||
|
||||
context.base_allocator = create_allocator(emu, PEB_SEGMENT_SIZE);
|
||||
auto& allocator = context.base_allocator;
|
||||
@@ -776,6 +690,7 @@ windows_emulator::windows_emulator(const emulator_settings& settings,
|
||||
std::unique_ptr<x64_emulator> emu)
|
||||
: windows_emulator(std::move(emu))
|
||||
{
|
||||
this->stdout_callback_ = std::move(settings.stdout_callback);
|
||||
this->use_relative_time_ = settings.use_relative_time;
|
||||
this->logger.disable_output(settings.disable_logging);
|
||||
this->setup_process(settings);
|
||||
@@ -795,7 +710,7 @@ void windows_emulator::setup_process(const emulator_settings& settings)
|
||||
auto& context = this->process();
|
||||
context.module_manager = module_manager(emu); // TODO: Cleanup module manager
|
||||
|
||||
setup_context(context, emu, settings);
|
||||
setup_context(*this, settings);
|
||||
|
||||
context.executable = context.module_manager.map_module(settings.application, this->logger);
|
||||
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
|
||||
std::unique_ptr<x64_emulator> create_default_x64_emulator();
|
||||
|
||||
// TODO: Split up into application and emulator settings
|
||||
struct emulator_settings
|
||||
{
|
||||
std::filesystem::path application{};
|
||||
std::filesystem::path working_directory{};
|
||||
std::filesystem::path registry_directory{"./registry"};
|
||||
std::vector<std::wstring> arguments{};
|
||||
std::function<void(std::string_view)> stdout_callback{};
|
||||
bool disable_logging{false};
|
||||
bool use_relative_time{false};
|
||||
};
|
||||
@@ -86,6 +88,14 @@ public:
|
||||
this->syscall_hooks_.push_back(std::move(callback));
|
||||
}
|
||||
|
||||
void on_stdout(const std::string_view data) const
|
||||
{
|
||||
if (this->stdout_callback_)
|
||||
{
|
||||
this->stdout_callback_(data);
|
||||
}
|
||||
}
|
||||
|
||||
logger logger{};
|
||||
bool verbose{false};
|
||||
bool verbose_calls{false};
|
||||
@@ -105,7 +115,7 @@ private:
|
||||
bool use_relative_time_{false};
|
||||
std::unique_ptr<x64_emulator> emu_{};
|
||||
std::vector<instruction_hook_callback> syscall_hooks_{};
|
||||
|
||||
std::function<void(std::string_view)> stdout_callback_{};
|
||||
|
||||
process_context process_;
|
||||
syscall_dispatcher dispatcher_;
|
||||
|
||||
Reference in New Issue
Block a user