mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 19:23:56 +00:00
Apply thread attributes
This commit is contained in:
@@ -8,6 +8,19 @@
|
||||
|
||||
#include <x64_emulator.hpp>
|
||||
|
||||
#define PEB_SEGMENT_SIZE (1 << 20) // 1 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
|
||||
#define GDT_LIMIT 0x1000
|
||||
#define GDT_ENTRY_SIZE 0x8
|
||||
|
||||
struct event
|
||||
{
|
||||
bool signaled{};
|
||||
@@ -149,16 +162,8 @@ class emulator_thread
|
||||
public:
|
||||
emulator_thread() = default;
|
||||
|
||||
emulator_thread(x64_emulator& emu, std::vector<std::byte> default_register_set, const uint64_t start_address,
|
||||
const uint64_t argument,
|
||||
const uint64_t stack_size)
|
||||
: emu_ptr(&emu)
|
||||
, stack_size(page_align_up(stack_size))
|
||||
, start_address(start_address)
|
||||
, argument(argument)
|
||||
, last_registers(std::move(default_register_set))
|
||||
{
|
||||
}
|
||||
emulator_thread(x64_emulator& emu, const process_context& context, uint64_t start_address, uint64_t argument,
|
||||
uint64_t stack_size, uint32_t id);
|
||||
|
||||
emulator_thread(const emulator_thread&) = delete;
|
||||
emulator_thread& operator=(const emulator_thread&) = delete;
|
||||
@@ -188,14 +193,14 @@ public:
|
||||
|
||||
x64_emulator* emu_ptr{};
|
||||
|
||||
uint32_t id{};
|
||||
|
||||
uint64_t stack_base{};
|
||||
uint64_t stack_size{};
|
||||
uint64_t start_address{};
|
||||
uint64_t argument{};
|
||||
uint64_t executed_instructions{0};
|
||||
|
||||
uint32_t id{};
|
||||
|
||||
std::optional<emulator_allocator> gs_segment;
|
||||
std::optional<emulator_object<TEB>> teb;
|
||||
|
||||
@@ -211,11 +216,11 @@ public:
|
||||
emu.restore_registers(this->last_registers);
|
||||
}
|
||||
|
||||
void setup_if_necessary(x64_emulator& emu, const process_context& context)
|
||||
void setup_if_necessary(x64_emulator& emu, const process_context& context) const
|
||||
{
|
||||
if (!this->teb.has_value())
|
||||
if (!this->executed_instructions)
|
||||
{
|
||||
this->setup(emu, context);
|
||||
this->setup_registers(emu, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,7 +235,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void setup(x64_emulator& emu, const process_context& context);
|
||||
void setup_registers(x64_emulator& emu, const process_context& context) const;
|
||||
};
|
||||
|
||||
struct process_context
|
||||
@@ -276,6 +281,7 @@ struct process_context
|
||||
|
||||
std::vector<std::byte> default_register_set{};
|
||||
|
||||
uint32_t current_thread_id{0};
|
||||
handle_store<handle_types::thread, emulator_thread> threads{};
|
||||
emulator_thread* active_thread{nullptr};
|
||||
|
||||
@@ -338,11 +344,7 @@ struct process_context
|
||||
handle create_thread(x64_emulator& emu, const uint64_t start_address, const uint64_t argument,
|
||||
const uint64_t stack_size)
|
||||
{
|
||||
emulator_thread t{emu, default_register_set, start_address, argument, stack_size};
|
||||
|
||||
const handle h = this->threads.store(std::move(t));
|
||||
this->threads.get(h)->id = h.value.id;
|
||||
|
||||
return h;
|
||||
emulator_thread t{emu, *this, start_address, argument, stack_size, ++this->current_thread_id};
|
||||
return this->threads.store(std::move(t));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -161,6 +161,20 @@ namespace
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write_attribute(emulator& emu, const PS_ATTRIBUTE& attribute, const T& value)
|
||||
{
|
||||
if (attribute.ReturnLength)
|
||||
{
|
||||
emulator_object<SIZE_T>{emu, attribute.ReturnLength}.write(sizeof(T));
|
||||
}
|
||||
|
||||
if (attribute.Size >= sizeof(T))
|
||||
{
|
||||
emulator_object<T>{emu, attribute.Value}.write(value);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryPerformanceCounter(const syscall_context&,
|
||||
const emulator_object<LARGE_INTEGER> performance_counter,
|
||||
const emulator_object<LARGE_INTEGER> performance_frequency)
|
||||
@@ -866,6 +880,7 @@ namespace
|
||||
{
|
||||
if (info_class == SystemFlushInformation
|
||||
|| info_class == SystemFeatureConfigurationInformation
|
||||
|| info_class == SystemSupportedProcessorArchitectures2
|
||||
|| info_class == SystemFeatureConfigurationSectionInformation)
|
||||
{
|
||||
//printf("Unsupported, but allowed system info class: %X\n", info_class);
|
||||
@@ -1195,6 +1210,7 @@ namespace
|
||||
|| info_class == ProcessTlsInformation
|
||||
|| info_class == ProcessConsoleHostProcess
|
||||
|| info_class == ProcessFaultInformation
|
||||
|| info_class == ProcessDefaultHardErrorMode
|
||||
|| info_class == ProcessRaiseUMExceptionOnInvalidHandleClose)
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
@@ -1908,7 +1924,8 @@ namespace
|
||||
const emulator_object<OBJECT_ATTRIBUTES> object_attributes,
|
||||
const uint64_t process_handle, const uint64_t start_routine,
|
||||
const uint64_t argument, const ULONG create_flags, const SIZE_T zero_bits,
|
||||
const SIZE_T stack_size, const SIZE_T maximum_stack_size)
|
||||
const SIZE_T stack_size, const SIZE_T maximum_stack_size,
|
||||
const emulator_object<PS_ATTRIBUTE_LIST> attribute_list)
|
||||
{
|
||||
if (process_handle != ~0ULL)
|
||||
{
|
||||
@@ -1917,8 +1934,49 @@ namespace
|
||||
|
||||
const auto h = c.proc.create_thread(c.emu, start_routine, argument, stack_size);
|
||||
thread_handle.write(h.bits);
|
||||
|
||||
if (!attribute_list)
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
const auto* thread = c.proc.threads.get(h);
|
||||
|
||||
const emulator_object<PS_ATTRIBUTE> attributes{
|
||||
c.emu, attribute_list.value() + offsetof(PS_ATTRIBUTE_LIST, Attributes)
|
||||
};
|
||||
|
||||
const auto total_length = attribute_list.read().TotalLength;
|
||||
|
||||
constexpr auto entry_size = sizeof(PS_ATTRIBUTE);
|
||||
constexpr auto header_size = sizeof(PS_ATTRIBUTE_LIST) - entry_size;
|
||||
const auto attribute_count = (total_length - header_size) / entry_size;
|
||||
|
||||
for (size_t i = 0; i < attribute_count; ++i)
|
||||
{
|
||||
attributes.access([&](const PS_ATTRIBUTE& attribute)
|
||||
{
|
||||
const auto type = attribute.Attribute & ~PS_ATTRIBUTE_THREAD;
|
||||
|
||||
if (type == PsAttributeClientId)
|
||||
{
|
||||
const auto client_id = thread->teb->read().ClientId;
|
||||
write_attribute(c.emu, attribute, client_id);
|
||||
}
|
||||
else if (type == PsAttributeTebAddress)
|
||||
{
|
||||
write_attribute(c.emu, attribute, thread->teb->ptr());
|
||||
}
|
||||
}, i);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryDebugFilterState()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_dispatcher::setup(const exported_symbols& ntdll_exports, const exported_symbols& win32u_exports)
|
||||
@@ -2018,6 +2076,7 @@ void syscall_dispatcher::add_handlers()
|
||||
add_handler(NtSetSystemInformation);
|
||||
add_handler(NtQueryInformationFile);
|
||||
add_handler(NtCreateThreadEx);
|
||||
add_handler(NtQueryDebugFilterState);
|
||||
|
||||
#undef add_handler
|
||||
|
||||
|
||||
@@ -4,18 +4,6 @@
|
||||
|
||||
#include <unicorn_x64_emulator.hpp>
|
||||
|
||||
#define PEB_SEGMENT_SIZE (1 << 20) // 1 MB
|
||||
|
||||
#define GS_SEGMENT_SIZE (1 << 20) // 1 MB
|
||||
|
||||
#define IA32_GS_BASE_MSR 0xC0000101
|
||||
|
||||
#define KUSD_ADDRESS 0x7ffe0000
|
||||
|
||||
#define GDT_ADDR 0x30000
|
||||
#define GDT_LIMIT 0x1000
|
||||
#define GDT_ENTRY_SIZE 0x8
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
@@ -36,16 +24,13 @@ namespace
|
||||
emu.reg(x64_register::rsp, sp);
|
||||
}
|
||||
|
||||
uint64_t setup_stack(x64_emulator& emu, const size_t stack_size)
|
||||
void setup_stack(x64_emulator& emu, const uint64_t stack_base, const size_t stack_size)
|
||||
{
|
||||
const auto stack_base = emu.allocate_memory(stack_size, memory_permission::read_write);
|
||||
|
||||
const uint64_t stack_end = stack_base + stack_size;
|
||||
emu.reg(x64_register::rsp, stack_end);
|
||||
return stack_base;
|
||||
}
|
||||
|
||||
emulator_allocator setup_gs_segment(x64_emulator& emu, const uint64_t size)
|
||||
void setup_gs_segment(x64_emulator& emu, const emulator_allocator& allocator)
|
||||
{
|
||||
struct msr_value
|
||||
{
|
||||
@@ -53,16 +38,12 @@ namespace
|
||||
uint64_t value;
|
||||
};
|
||||
|
||||
const auto segment_base = emu.allocate_memory(size, memory_permission::read_write);
|
||||
|
||||
const msr_value value{
|
||||
IA32_GS_BASE_MSR,
|
||||
segment_base
|
||||
allocator.get_base()
|
||||
};
|
||||
|
||||
emu.write_register(x64_register::msr, &value, sizeof(value));
|
||||
|
||||
return {emu, segment_base, size};
|
||||
}
|
||||
|
||||
emulator_object<KUSER_SHARED_DATA> setup_kusd(x64_emulator& emu)
|
||||
@@ -218,7 +199,7 @@ namespace
|
||||
context.peb = allocator.reserve<PEB>();
|
||||
|
||||
/* Values of the following fields must be
|
||||
* allocated relative to the process_params themselves.
|
||||
* allocated relative to the process_params themselves
|
||||
* and included in the length:
|
||||
*
|
||||
* CurrentDirectory
|
||||
@@ -329,7 +310,6 @@ namespace
|
||||
case memory_operation::read:
|
||||
return 0;
|
||||
case memory_operation::write:
|
||||
return 1;
|
||||
case memory_operation::exec:
|
||||
return 1;
|
||||
}
|
||||
@@ -460,10 +440,24 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void emulator_thread::setup(x64_emulator& emu, const process_context& context)
|
||||
emulator_thread::emulator_thread(x64_emulator& emu, const process_context& context,
|
||||
const uint64_t start_address,
|
||||
const uint64_t argument,
|
||||
const uint64_t stack_size, const uint32_t id)
|
||||
: emu_ptr(&emu)
|
||||
, stack_size(page_align_up(std::max(stack_size, STACK_SIZE)))
|
||||
, start_address(start_address)
|
||||
, argument(argument)
|
||||
, last_registers(context.default_register_set)
|
||||
, id(id)
|
||||
{
|
||||
this->stack_base = setup_stack(emu, this->stack_size);
|
||||
this->gs_segment = setup_gs_segment(emu, GS_SEGMENT_SIZE);
|
||||
this->stack_base = emu.allocate_memory(this->stack_size, memory_permission::read_write);
|
||||
|
||||
this->gs_segment = emulator_allocator{
|
||||
emu,
|
||||
emu.allocate_memory(GS_SEGMENT_SIZE, memory_permission::read_write),
|
||||
GS_SEGMENT_SIZE,
|
||||
};
|
||||
|
||||
this->teb = this->gs_segment->reserve<TEB>();
|
||||
|
||||
@@ -476,6 +470,12 @@ void emulator_thread::setup(x64_emulator& emu, const process_context& context)
|
||||
teb_obj.NtTib.Self = &this->teb->ptr()->NtTib;
|
||||
teb_obj.ProcessEnvironmentBlock = context.peb.ptr();
|
||||
});
|
||||
}
|
||||
|
||||
void emulator_thread::setup_registers(x64_emulator& emu, const process_context& context) const
|
||||
{
|
||||
setup_stack(emu, this->stack_base, this->stack_size);
|
||||
setup_gs_segment(emu, *this->gs_segment);
|
||||
|
||||
CONTEXT ctx{};
|
||||
ctx.ContextFlags = CONTEXT_ALL;
|
||||
@@ -485,6 +485,7 @@ void emulator_thread::setup(x64_emulator& emu, const process_context& context)
|
||||
|
||||
ctx.Rip = context.rtl_user_thread_start;
|
||||
ctx.Rcx = this->start_address;
|
||||
ctx.Rdx = this->argument;
|
||||
|
||||
const auto ctx_obj = allocate_object_on_stack<CONTEXT>(emu);
|
||||
ctx_obj.write(ctx);
|
||||
@@ -543,7 +544,7 @@ void windows_emulator::setup_process(const std::filesystem::path& application,
|
||||
|
||||
context.default_register_set = emu.save_registers();
|
||||
|
||||
const auto main_thread_id = context.create_thread(emu, context.executable->entry_point, 0, 0x4000);
|
||||
const auto main_thread_id = context.create_thread(emu, context.executable->entry_point, 0, 0);
|
||||
switch_to_thread(emu, context, main_thread_id);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user