KUSD MMIO

This commit is contained in:
momo5502
2024-11-23 19:32:14 +01:00
parent 325e8115af
commit 2e2b4ffb2f
5 changed files with 282 additions and 112 deletions

View File

@@ -0,0 +1,218 @@
#include "kusd_mmio.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(windows_emulator& win_emu, const bool use_relative_time, const bool perform_registration)
: use_relative_time_(use_relative_time)
, win_emu_(&win_emu)
{
setup_kusd(this->kusd_, use_relative_time);
if (perform_registration)
{
this->register_mmio();
}
}
kusd_mmio::~kusd_mmio()
{
this->deregister_mmio();
}
kusd_mmio::kusd_mmio(kusd_mmio&& obj) // throws!
: use_relative_time_(obj.use_relative_time_)
, win_emu_(obj.win_emu_)
{
memcpy(&this->kusd_, &obj.kusd_, sizeof(this->kusd_));
if (obj.registered_)
{
obj.deregister_mmio();
this->register_mmio();
}
}
kusd_mmio::kusd_mmio(utils::buffer_deserializer& buffer)
: kusd_mmio(buffer.read<windows_emulator_wrapper>().get(), true, false)
{
}
void kusd_mmio::serialize(utils::buffer_serializer& buffer) const
{
buffer.write(this->use_relative_time_);
buffer.write(this->kusd_);
}
void kusd_mmio::deserialize(utils::buffer_deserializer& buffer)
{
buffer.read(this->use_relative_time_);
buffer.read(this->kusd_);
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::write(const uint64_t /*addr*/, const size_t /*size*/, const uint64_t /*data*/)
{
// Unsupported!
}
void kusd_mmio::update()
{
// TODO
}
void kusd_mmio::register_mmio()
{
if (this->registered_)
{
return;
}
this->registered_ = true;
this->win_emu_->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 addr, const size_t size, const uint64_t data)
{
this->write(addr, size, data);
});
}
void kusd_mmio::deregister_mmio()
{
if (this->registered_)
{
this->registered_ = false;
this->win_emu_->emu().release_memory(KUSD_ADDRESS, KUSD_BUFFER_SIZE);
}
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include "std_include.hpp"
#include <serialization.hpp>
class windows_emulator;
class kusd_mmio
{
public:
kusd_mmio(windows_emulator& win_emu, bool use_relative_time, bool perform_registration = true);
~kusd_mmio();
kusd_mmio(kusd_mmio&& obj);
kusd_mmio(utils::buffer_deserializer& buffer);
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();
private:
bool registered_{};
bool use_relative_time_{};
windows_emulator* win_emu_{};
KUSER_SHARED_DATA kusd_{};
uint64_t read(uint64_t addr, size_t size);
void write(uint64_t addr, size_t size, uint64_t data);
void update();
void register_mmio();
void deregister_mmio();
};

View File

@@ -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,6 @@ struct process_context
: base_allocator(emu)
, peb(emu)
, process_params(emu)
, kusd(emu)
, module_manager(emu)
{
}
@@ -384,7 +382,7 @@ struct process_context
emulator_object<PEB> peb;
emulator_object<RTL_USER_PROCESS_PARAMETERS> process_params;
emulator_object<KUSER_SHARED_DATA> kusd;
std::optional<kusd_mmio> kusd{};
module_manager module_manager;
@@ -423,7 +421,7 @@ struct process_context
buffer.write(this->base_allocator);
buffer.write(this->peb);
buffer.write(this->process_params);
buffer.write(this->kusd);
buffer.write_optional(this->kusd);
buffer.write(this->module_manager);
buffer.write(this->executable->image_base);
@@ -461,7 +459,7 @@ struct process_context
buffer.read(this->base_allocator);
buffer.read(this->peb);
buffer.read(this->process_params);
buffer.read(this->kusd);
buffer.read_optional(this->kusd);
buffer.read(this->module_manager);
const auto executable_base = buffer.read<uint64_t>();

View File

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

View File

@@ -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.emplace(win_emu, settings.use_relative_time);
context.base_allocator = create_allocator(emu, PEB_SEGMENT_SIZE);
auto& allocator = context.base_allocator;
@@ -795,7 +709,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);