[Kernel] - Change OddObj to X_DISPATCH_HEADER

- Change OddObj to X_DISPATCH_HEADER
- Add unknown X_KWAIT_REASON flag
- Fixed InitializeGuestObject mistake
- Replaces unknowns in kthread using nukernel as reference
This commit is contained in:
The-Little-Wolf
2026-04-11 12:47:06 -07:00
committed by Radosław Gliński
parent c2674b19d2
commit dc4db67f9c
9 changed files with 74 additions and 61 deletions

View File

@@ -1527,15 +1527,17 @@ void KernelState::InitializeKernelGuestGlobals() {
SetProcessTLSVars(system_process, 32, 0, 0);
uint32_t oddobject_offset =
kernel_guest_globals_ + offsetof(KernelGuestGlobals, OddObj);
kernel_guest_globals_ +
offsetof(KernelGuestGlobals, XboxKernelDefaultObject);
// init unknown object
block->OddObj.field0 = 0x1000000;
block->OddObj.field4 = 1;
block->OddObj.points_to_self =
oddobject_offset + offsetof(X_UNKNOWN_TYPE_REFED, points_to_self);
block->OddObj.points_to_prior = block->OddObj.points_to_self;
block->XboxKernelDefaultObject.type = DISPATCHER_AUTO_RESET_EVENT;
block->XboxKernelDefaultObject.signal_state = 1;
block->XboxKernelDefaultObject.wait_list.flink_ptr =
oddobject_offset + offsetof(X_DISPATCH_HEADER, wait_list.flink_ptr);
block->XboxKernelDefaultObject.wait_list.blink_ptr =
block->XboxKernelDefaultObject.wait_list.flink_ptr;
// init thread object
block->ExThreadObjectType.pool_tag = 0x65726854;

View File

@@ -96,21 +96,13 @@ struct TerminateNotification {
// a bit like the timers on KUSER_SHARED on normal win32
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
struct X_TIME_STAMP_BUNDLE {
// according to Nukernl these are BE
uint64_t interrupt_time;
// i assume system_time is in 100 ns intervals like on win32
uint64_t system_time;
uint32_t tick_count;
uint32_t padding;
};
struct X_UNKNOWN_TYPE_REFED {
xe::be<uint32_t> field0;
xe::be<uint32_t> field4;
// this is definitely a LIST_ENTRY?
xe::be<uint32_t> points_to_self; // this field points to itself
xe::be<uint32_t>
points_to_prior; // points to the previous field, which points to itself
};
static_assert_size(X_UNKNOWN_TYPE_REFED, 16);
struct KernelGuestGlobals {
X_OBJECT_TYPE ExThreadObjectType;
@@ -125,7 +117,7 @@ struct KernelGuestGlobals {
X_OBJECT_TYPE ObSymbolicLinkObjectType;
// a constant buffer that some object types' "unknown_size_or_object" field
// points to
X_UNKNOWN_TYPE_REFED OddObj;
X_DISPATCH_HEADER XboxKernelDefaultObject;
X_KPROCESS idle_process; // X_PROCTYPE_IDLE. runs in interrupt contexts. is
// also the context the kernel starts in?
X_KPROCESS title_process; // X_PROCTYPE_TITLE

View File

@@ -676,7 +676,7 @@ struct X_POOL_ALLOC_HEADER {
};
uint32_t xeAllocatePoolTypeWithTag(PPCContext* context, uint32_t size,
uint32_t tag, uint32_t zero) {
uint32_t tag, uint32_t pool_selector) {
if (size <= 0xFD8) {
uint32_t adjusted_size = size + sizeof(X_POOL_ALLOC_HEADER);
@@ -694,9 +694,9 @@ uint32_t xeAllocatePoolTypeWithTag(PPCContext* context, uint32_t size,
}
dword_result_t ExAllocatePoolTypeWithTag_entry(dword_t size, dword_t tag,
dword_t zero,
dword_t pool_selector,
const ppc_context_t& context) {
return xeAllocatePoolTypeWithTag(context, size, tag, zero);
return xeAllocatePoolTypeWithTag(context, size, tag, pool_selector);
}
DECLARE_XBOXKRNL_EXPORT1(ExAllocatePoolTypeWithTag, kMemory, kImplemented);

View File

@@ -50,7 +50,7 @@ uint32_t xeMmAllocatePhysicalMemoryEx(uint32_t flags, uint32_t region_size,
dword_result_t xeMmQueryStatistics(
pointer_t<X_MM_QUERY_STATISTICS_RESULT> stats_ptr);
uint32_t xeAllocatePoolTypeWithTag(PPCContext* context, uint32_t size,
uint32_t tag, uint32_t zero);
uint32_t tag, uint32_t pool_selector);
void xeFreePool(PPCContext* context, uint32_t base_address);

View File

@@ -544,7 +544,7 @@ static_assert_size(X_RTL_CRITICAL_SECTION, 28);
void xeRtlInitializeCriticalSection(X_RTL_CRITICAL_SECTION* cs,
uint32_t cs_ptr) {
cs->header.type = 1; // EventSynchronizationObject (auto reset)
cs->header.type = X_DISPATCHER_FLAGS::DISPATCHER_AUTO_RESET_EVENT;
cs->header.absolute = 0; // spin count div 256
cs->header.signal_state = 0;
cs->lock_count = -1;
@@ -567,7 +567,7 @@ X_STATUS xeRtlInitializeCriticalSectionAndSpinCount(X_RTL_CRITICAL_SECTION* cs,
spin_count_div_256 = 255;
}
cs->header.type = 1; // EventSynchronizationObject (auto reset)
cs->header.type = X_DISPATCHER_FLAGS::DISPATCHER_AUTO_RESET_EVENT;
cs->header.absolute = spin_count_div_256;
cs->header.signal_state = 0;
cs->lock_count = -1;

View File

@@ -692,12 +692,12 @@ DECLARE_XBOXKRNL_EXPORT2(NtClearEvent, kThreading, kImplemented,
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff552150(v=vs.85).aspx
void KeInitializeSemaphore_entry(pointer_t<X_KSEMAPHORE> semaphore_ptr,
dword_t count, dword_t limit) {
semaphore_ptr->header.type = 5; // SemaphoreObject
semaphore_ptr->header.type = X_DISPATCHER_FLAGS::DISPATCHER_SEMAPHORE;
semaphore_ptr->header.signal_state = (uint32_t)count;
semaphore_ptr->limit = (uint32_t)limit;
auto sem = XObject::GetNativeObject<XSemaphore>(kernel_state(), semaphore_ptr,
5 /* SemaphoreObject */);
auto sem = XObject::GetNativeObject<XSemaphore>(
kernel_state(), semaphore_ptr, X_DISPATCHER_FLAGS::DISPATCHER_SEMAPHORE);
if (!sem) {
assert_always();
return;
@@ -1014,7 +1014,7 @@ dword_result_t KeWaitForMultipleObjects_entry(
dword_t count, lpdword_t objects_ptr, dword_t wait_type,
dword_t wait_reason, dword_t processor_mode, dword_t alertable,
lpqword_t timeout_ptr, lpvoid_t wait_block_array_ptr) {
assert_true(wait_type <= 1);
assert_true(wait_type <= X_KWAIT_REASON::WaitAny);
assert_true(count <= 64);
object_ref<XObject> objects[64];
@@ -1049,7 +1049,7 @@ uint32_t xeNtWaitForMultipleObjectsEx(uint32_t count, xe::be<uint32_t>* handles,
uint32_t wait_type, uint32_t wait_mode,
uint32_t alertable,
uint64_t* timeout_ptr) {
assert_true(wait_type <= 1);
assert_true(wait_type <= X_KWAIT_REASON::WaitAny);
assert_true(count <= 64);
object_ref<XObject> objects[64];
@@ -1091,7 +1091,8 @@ dword_result_t NtWaitForMultipleObjectsEx_entry(
dword_t count, lpdword_t handles, dword_t wait_type, dword_t wait_mode,
dword_t alertable, lpqword_t timeout_ptr) {
uint64_t timeout = timeout_ptr ? static_cast<uint64_t>(*timeout_ptr) : 0u;
if (!count || count > 64 || (wait_type != 1 && wait_type)) {
if (!count || count > 64 ||
(wait_type != X_KWAIT_REASON::WaitAny && wait_type)) {
return X_STATUS_INVALID_PARAMETER;
}
return xeNtWaitForMultipleObjectsEx(count, handles, wait_type, wait_mode,
@@ -1871,7 +1872,7 @@ dword_result_t KeSetPriorityThread_entry(pointer_t<X_KTHREAD> thread_ptr,
return 0;
}
if (thread_ptr->header.type != 6) {
if (thread_ptr->header.type != X_DISPATCHER_FLAGS::DISPATCHER_THREAD) {
XELOGW("{}: Invalid object type: {}", __func__, thread_ptr->header.type);
}

View File

@@ -34,10 +34,21 @@ class KernelState;
template <typename T>
class object_ref;
enum X_DISPATCHER_FLAGS : uint8_t {
DISPATCHER_MANUAL_RESET_EVENT = 0,
DISPATCHER_AUTO_RESET_EVENT = 1, // EventSynchronizationObject
DISPATCHER_MUTANT = 2,
DISPATCHER_QUEUE = 4,
DISPATCHER_SEMAPHORE = 5, // SemaphoreObject
DISPATCHER_THREAD = 6,
DISPATCHER_MANUAL_RESET_TIMER = 8,
DISPATCHER_AUTO_RESET_TIMER = 9,
};
// https://www.nirsoft.net/kernel_struct/vista/DISPATCHER_HEADER.html
typedef struct {
struct {
uint8_t type;
uint8_t type; // X_DISPATCHER_FLAGS
union {
uint8_t abandoned;

View File

@@ -180,21 +180,25 @@ static uint8_t GetFakeCpuNumber(uint8_t proc_mask) {
void XThread::InitializeGuestObject() {
auto guest_thread = guest_object<X_KTHREAD>();
auto thread_guest_ptr = guest_object();
guest_thread->header.type = 6;
guest_thread->header.type = X_DISPATCHER_FLAGS::DISPATCHER_THREAD;
guest_thread->suspend_count =
(creation_params_.creation_flags & X_CREATE_SUSPENDED) ? 1 : 0;
guest_thread->unk_10 = (thread_guest_ptr + 0x10);
guest_thread->unk_14 = (thread_guest_ptr + 0x10);
guest_thread->mutants_list.flink_ptr = (thread_guest_ptr + 0x10);
guest_thread->mutants_list.blink_ptr = (thread_guest_ptr + 0x10);
auto timer_wait_header_list_entry = memory()->HostToGuestVirtual(
&guest_thread->wait_timeout_timer.header.wait_list);
guest_thread->wait_timeout_block.wait_list_entry.flink_ptr =
thread_guest_ptr + 0x20;
timer_wait_header_list_entry;
guest_thread->wait_timeout_block.wait_list_entry.blink_ptr =
thread_guest_ptr + 0x20;
timer_wait_header_list_entry;
guest_thread->wait_timeout_block.thread = thread_guest_ptr;
uint32_t v6 = thread_guest_ptr + 0x18;
guest_thread->wait_timeout_block.wait_result_xstatus = 0x0100;
guest_thread->wait_timeout_block.wait_type = 0x0201;
guest_thread->wait_timeout_block.object = v6;
guest_thread->wait_timeout_block.object =
memory()->HostToGuestVirtual(&guest_thread->wait_timeout_timer);
guest_thread->wait_timeout_block.wait_result_xstatus = X_STATUS_TIMEOUT;
guest_thread->wait_timeout_block.wait_type = X_KWAIT_REASON::WaitAny;
guest_thread->stack_base = (this->stack_base_);
guest_thread->stack_limit = (this->stack_limit_);
guest_thread->stack_kernel = (this->stack_base_ - 240);

View File

@@ -48,17 +48,6 @@ enum IRQL_FLAGS : uint8_t {
IRQL_HIGHEST = 124
};
enum X_DISPATCHER_FLAGS {
DISPATCHER_MANUAL_RESET_EVENT = 0,
DISPATCHER_AUTO_RESET_EVENT = 1,
DISPATCHER_MUTANT = 2,
DISPATCHER_QUEUE = 4,
DISPATCHER_SEMAPHORE = 5,
DISPATCHER_THREAD = 6,
DISPATCHER_MANUAL_RESET_TIMER = 8,
DISPATCHER_AUTO_RESET_TIMER = 9,
};
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/ntos/ke/kthread_state.htm
enum X_KTHREAD_STATE_FLAGS : uint8_t {
KTHREAD_STATE_INITIALIZED = 0,
@@ -222,12 +211,22 @@ struct X_KPCR {
uint8_t unk_2AC[0x2C]; // 0x2AC
};
#ifdef WAIT_ANY
#undef WAIT_ANY
#endif
enum : uint16_t {
WAIT_ALL = 0,
WAIT_ANY = 1,
struct X_KMUTANT {
X_DISPATCH_HEADER header; // 0x0
X_LIST_ENTRY unk_list; // 0x10
TypedGuestPointer<X_KTHREAD> owner; // 0x18
bool abandoned; // 0x1C
// these might just be padding
uint8_t unk_1D; // 0x1D
uint8_t unk_1E; // 0x1E
uint8_t unk_1F; // 0x1F
};
static_assert_size(X_KMUTANT, 0x20);
enum X_KWAIT_REASON : uint16_t {
WaitAll = 0,
WaitAny = 1,
WaitUnk3 = 3,
};
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/ntos/ke_x/kwait_block.htm
@@ -243,7 +242,7 @@ struct X_KWAIT_BLOCK {
// is satisfied
xe::be<uint16_t> wait_result_xstatus;
// WAIT_ALL or WAIT_ANY
xe::be<uint16_t> wait_type;
xe::be<X_KWAIT_REASON> wait_type;
};
static_assert_size(X_KWAIT_BLOCK, 0x18);
@@ -258,9 +257,9 @@ struct X_KTIMER {
static_assert_size(X_KTIMER, 0x28);
struct X_KTHREAD {
X_DISPATCH_HEADER header; // 0x0
xe::be<uint32_t> unk_10; // 0x10
xe::be<uint32_t> unk_14; // 0x14
X_DISPATCH_HEADER header; // 0x0
util::X_TYPED_LIST<X_KMUTANT, offsetof(X_KMUTANT, unk_list)>
mutants_list; // 0x10
X_KTIMER wait_timeout_timer; // 0x18
X_KWAIT_BLOCK wait_timeout_block; // 0x40
uint8_t unk_58[0x4]; // 0x58
@@ -295,7 +294,11 @@ struct X_KTHREAD {
xe::be<uint32_t> msr_mask; // 0x9C
xe::be<X_STATUS> wait_result; // 0xA0
uint8_t wait_irql; // 0xA4
uint8_t unk_A5[0xB]; // 0xA5
uint8_t processor_mode; // 0xA5
uint8_t wait_next; // 0xA6
uint8_t wait_reason; // 0xA7
TypedGuestPointer<X_KWAIT_BLOCK> wait_blocks; // 0xA8
uint8_t unk_AC[4]; // 0xAC
int32_t apc_disable_count; // 0xB0
xe::be<int32_t> quantum; // 0xB4
uint8_t saturation_increment; // 0xB8