Quick & dirty K_USER_SHARED_DATA mapping

This commit is contained in:
momo5502
2024-08-17 19:54:08 +02:00
parent 88fc2e4d75
commit 264513d0a3

View File

@@ -11,6 +11,8 @@
#define STACK_ADDRESS 0x7ffffffde000
#define STACK_SIZE 0x40000
#define KUSD_ADDRESS 0x7ffe0000
#include "unicorn.hpp"
namespace
@@ -25,6 +27,81 @@ namespace
return align_down(value + (alignment - 1), alignment);
}
template <typename T>
class unicorn_object
{
public:
unicorn_object() = default;
unicorn_object(const unicorn& uc, uint64_t address)
: uc_(&uc)
, address_(address)
{
}
uint64_t value() const
{
return this->address_;
}
T* ptr() const
{
return reinterpret_cast<T*>(this->address_);
}
template <typename F>
void access(const F& accessor) const
{
T obj{};
e(uc_mem_read(*this->uc_, this->address_, &obj, sizeof(obj)));
accessor(obj);
e(uc_mem_write(*this->uc_, this->address_, &obj, sizeof(obj)));
}
private:
const unicorn* uc_{};
uint64_t address_{};
};
class unicorn_allocator
{
public:
unicorn_allocator(const unicorn& uc, const uint64_t address, const uint64_t size)
: uc_(&uc)
, address_(address)
, size_(size)
, active_address_(address)
{
}
template <typename T>
unicorn_object<T> reserve()
{
const auto alignment = alignof(T);
const auto potential_start = align_up(this->active_address_, alignment);
const auto potential_end = potential_start + sizeof(T);
const auto total_end = this->address_ + this->size_;
if (potential_end > total_end)
{
throw std::runtime_error("Out of memory");
}
this->active_address_ = potential_end;
return unicorn_object<T>(*this->uc_, potential_start);
}
private:
const unicorn* uc_{};
const uint64_t address_{};
const uint64_t size_{};
uint64_t active_address_{0};
};
void setup_stack(const unicorn& uc, uint64_t stack_base, size_t stack_size)
{
e(uc_mem_map(uc, stack_base, stack_size, UC_PROT_READ | UC_PROT_WRITE));
@@ -33,7 +110,7 @@ namespace
e(uc_reg_write(uc, UC_X86_REG_RSP, &stack_end));
}
void setup_gs_segment(const unicorn& uc, const uint64_t segment_base, const size_t size)
unicorn_allocator setup_gs_segment(const unicorn& uc, const uint64_t segment_base, const uint64_t size)
{
const std::array<uint64_t, 2> value = {
IA32_GS_BASE_MSR,
@@ -42,40 +119,56 @@ namespace
e(uc_reg_write(uc, UC_X86_REG_MSR, value.data()));
e(uc_mem_map(uc, segment_base, size, UC_PROT_READ | UC_PROT_WRITE));
return {uc, segment_base, size};
}
void setup_kusd(const unicorn& uc)
{
/* TODO: Fix
uc_mem_map(uc, KUSD_ADDRESS, sizeof(KUSER_SHARED_DATA), UC_PROT_READ);
unicorn_object<KUSER_SHARED_DATA> kusd_object{uc, KUSD_ADDRESS};
*/
uc_mem_map_ptr(uc, KUSD_ADDRESS, sizeof(KUSER_SHARED_DATA), UC_PROT_READ,
reinterpret_cast<void*>(KUSD_ADDRESS));
}
void setup_teb_and_peb(const unicorn& uc)
{
setup_stack(uc, STACK_ADDRESS, STACK_SIZE);
setup_gs_segment(uc, GS_SEGMENT_ADDR, GS_SEGMENT_SIZE);
auto gs = setup_gs_segment(uc, GS_SEGMENT_ADDR, GS_SEGMENT_SIZE);
constexpr auto teb_address = GS_SEGMENT_ADDR;
const auto peb_address = align_up(teb_address + sizeof(TEB), 0x10);
const auto ldr_address = align_up(peb_address + sizeof(PEB_LDR_DATA), 0x10);
const auto teb_object = gs.reserve<TEB>();
const auto peb_object = gs.reserve<PEB>();
const auto ldr_object = gs.reserve<PEB_LDR_DATA>();
TEB teb{};
teb.NtTib.StackLimit = reinterpret_cast<void*>(STACK_ADDRESS);
teb.NtTib.StackBase = reinterpret_cast<void*>((STACK_ADDRESS + STACK_SIZE));
teb.NtTib.Self = reinterpret_cast<NT_TIB*>(teb_address);
teb.ProcessEnvironmentBlock = reinterpret_cast<PEB*>(peb_address);
teb_object.access([&](TEB& teb)
{
teb.NtTib.StackLimit = reinterpret_cast<void*>(STACK_ADDRESS);
teb.NtTib.StackBase = reinterpret_cast<void*>((STACK_ADDRESS + STACK_SIZE));
teb.NtTib.Self = &teb_object.ptr()->NtTib;
teb.ProcessEnvironmentBlock = peb_object.ptr();
});
PEB peb{};
peb.ImageBaseAddress = nullptr;
peb.Ldr = reinterpret_cast<PEB_LDR_DATA*>(ldr_address);
peb_object.access([&](PEB& peb)
{
peb.ImageBaseAddress = nullptr;
peb.Ldr = ldr_object.ptr();
});
PEB_LDR_DATA ldr{};
ldr.InLoadOrderModuleList.Flink = reinterpret_cast<LIST_ENTRY*>(ldr_address + offsetof(PEB_LDR_DATA, InLoadOrderModuleList));
ldr.InLoadOrderModuleList.Blink = ldr.InLoadOrderModuleList.Flink;
ldr_object.access([&](PEB_LDR_DATA& ldr)
{
ldr.InLoadOrderModuleList.Flink = &ldr_object.ptr()->InLoadOrderModuleList;
ldr.InLoadOrderModuleList.Blink = ldr.InLoadOrderModuleList.Flink;
ldr.InMemoryOrderModuleList.Flink = reinterpret_cast<LIST_ENTRY*>(ldr_address + offsetof(PEB_LDR_DATA, InMemoryOrderModuleList));
ldr.InMemoryOrderModuleList.Blink = ldr.InMemoryOrderModuleList.Flink;
ldr.InMemoryOrderModuleList.Flink = &ldr_object.ptr()->InMemoryOrderModuleList;
ldr.InMemoryOrderModuleList.Blink = ldr.InMemoryOrderModuleList.Flink;
ldr.InInitializationOrderModuleList.Flink = reinterpret_cast<LIST_ENTRY*>(ldr_address + offsetof(PEB_LDR_DATA, InInitializationOrderModuleList));
ldr.InInitializationOrderModuleList.Blink = ldr.InInitializationOrderModuleList.Flink;
e(uc_mem_write(uc, teb_address, &teb, sizeof(teb)));
e(uc_mem_write(uc, peb_address, &peb, sizeof(peb)));
e(uc_mem_write(uc, ldr_address, &ldr, sizeof(ldr)));
ldr.InInitializationOrderModuleList.Flink = &ldr_object.ptr()->InInitializationOrderModuleList;
ldr.InInitializationOrderModuleList.Blink = ldr.InInitializationOrderModuleList.Flink;
});
}
void run()
@@ -85,7 +178,7 @@ namespace
e(uc_mem_map(uc, ADDRESS, 0x1000, UC_PROT_ALL));
e(uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1));
setup_kusd(uc);
setup_teb_and_peb(uc);
e(uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0));