Skip to content

Kernel Internals

Angelpro09_Dev edited this page Aug 10, 2026 · 3 revisions

Kernel Internals (retail 17559)

Everything here was read off a dump of the live kernel taken from a real console, then verified against runtime behaviour. Addresses are for retail kernel 17559 only.

Functions

Address Function Exported?
0x8015DB18 SataDiskInitialize (entry; ends 0x8015E113, frame 0x3A0, takes no arguments) no
0x8015D820 SataDiskCreateDevice(const char* name, ULONG flags) no
0x8015D9D8 SataDiskAuthenticateDevice no
0x8006AEA0 IoCreateDevice ordinal 55
0x8006B150 IoDeleteDevice ordinal 57
0x8008A1B0 NtQueryDirectoryObject ordinal 229
0x80108E40 XeKeysGetStatus ordinal 575
0x80042DC0 SATA disk DRIVER_OBJECT

The SataDisk* functions are not exported, so they can only be reached by fixed address. Their names come from EatonZ's own retail-17559 source in Xbox-360-Patch-Collection.

Flags

DO_DEVICE_INITIALIZING is 0x10 on Xbox 360, not the 0x80 it is on Windows. From IoCreateDevice:

8006B00C  li  r11, 0x10
8006B01C  stw r11, 0x14(r10)   ; Flags = 0x10
8006B02C  ori r10, r10, 8      ; |= 8 when the device is named

SataDiskCreateDevice then ORs in its flags argument and 4, so a freshly created device reads:

Device flags argument After creation After initialisation
PhysicalDisk 1 0x1D 0x0D
Partition0 1 0x1D 0x0D
Partition1 0 0x1C 0x0C

Observing PhysicalDisk at 0x0D while every partition sat at 0x1C/0x1D is what confirmed the diagnosis on hardware.

Structures

DEVICE_OBJECT (size 0x50, extension follows immediately)

Offset Field
0x08 DriverObject
0x14 Flags
0x18 DeviceExtension
0x1C DeviceType
0x20 SectorSize
0x24 AlignmentRequirement

SATA_DISK_EXTENSION (16 bytes)

IoCreateDevice is called with DeviceExtensionSize = 0x10, so the extension is exactly:

typedef struct _SATA_DISK_EXTENSION {
    LARGE_INTEGER StartingOffset;
    LARGE_INTEGER PartitionLength;
} SATA_DISK_EXTENSION;

This confirms Bad Storage's existing definition is complete, not a partial view.

Object directory

A 13-bucket hash table of chained entries, from NtQueryDirectoryObject's own walk (0x8008A22C0x8008A264):

Offset Field
0x00 next entry in the bucket chain
0x08 name length (USHORT)
0x0C pointer to the name text
0x20 the object body

The 0x20 offset was measured, not assumed: the PhysicalDisk entry sat at 0x3A0A7C88 while ObReferenceObjectByName returned 0x3A0A7CA8 for the same name.

Partition map

Produced by SataDiskInitialize 0x8015DF280x8015E0D0. S is the drive's 512-byte sector count from SataDiskUserAddressableSectors (0x801A61EC).

Device StartingOffset PartitionLength
PhysicalDisk 0 S × 512
Partition0 0 S × 512
Cache0 0x80000 0x80000000
Cache1 0x80080000 0x80000000
DumpPartition 0x100080000 0x20E30000
SystemURLCachePartition 0x100080000 0x6000000
TitleURLCachePartition 0x106080000 0x2000000
SystemExtPartition 0x10C080000 0xCE30000
SystemAuxPartition 0x118EB0000 0x8000000
SystemPartition 0x120EB0000 0x10000000
Partition1 0x130EB0000 S × 512 − 0x130EB0000
WindowsPartition 0 0

Two independent cross-checks say this decoding is right:

  • The layout comes out perfectly contiguousSystemExt ends exactly where SystemAux begins, which ends exactly where SystemPartition begins, which ends exactly at Partition1.
  • 0x130EB0000 is the same content-partition offset Bad Storage already hardcodes.

Cache0 is the original Xbox emulator's work area. Not scratch space in the general sense — it holds the disc cache the emulator plays from (Xbox2/cache000.map and friends, 291 MB each) and the emulated Xbox hard disk, saved/ structure and all. Cluster size 64 KB, about 740 MB of its 2 GB in use with one game installed. An unformatted Cache0 is why an original Xbox game reports a dirty disc on the first run — see Original Xbox Compatibility.

Cache1 at 0x80080000 carries the XTAF magic but does not mount, by name or by forced offset and size. Unexplained, and so far without consequence.

¹ SystemPartition is the original Xbox backward compatibility partition. Three names for one region, which is why it took a while to place: fusefatx calls it x1, FATXplorer calls it the Backwards Compatibility Partition or partition 2, and the kernel calls it SystemPartition. Verified by searching the raw device for the emulator's filenames and finding them at 0x120EB0000 + 0xA002. Mounting it is what gives an unauthenticated drive original Xbox games — see Original Xbox Compatibility.

Xbox API signatures that differ from Windows

These bite hard, because the Windows form compiles fine and then corrupts memory.

NtQueryDirectoryObject — six parameters, no RestartScan

NTSTATUS NtQueryDirectoryObject(
    HANDLE  DirectoryHandle,    // r3
    PVOID   Buffer,             // r4
    ULONG   Length,             // r5
    BOOLEAN ReturnSingleEntry,  // r6
    PULONG  Context,            // r7
    PULONG  ReturnLength);      // r8

Passing the Windows seven-parameter form puts a BOOLEAN where the kernel expects PULONG Context. It then writes through it without a NULL check (stw r11, 0(r23) at 0x8008A2C0) — an unaligned store to address 0 or 1, which black-screens the console.

Also note ReturnSingleEntry here means "ignore Context and start from the first entry", not "return one entry". To iterate, pass FALSE with a real Context.

Each returned entry is {USHORT Length; USHORT MaximumLength; PCHAR Buffer; ULONG TypeWord;} with the name text inline at +0x0C — not two STRINGs.

OBJECT_ATTRIBUTES — 12 bytes

typedef struct _OBJECT_ATTRIBUTES {
    HANDLE          RootDirectory;
    POBJECT_STRING  ObjectName;
    ULONG           Attributes;
} OBJECT_ATTRIBUTES;

Dumping kernel memory

The kernel/hypervisor region lives in the Xenon's encrypted memory. The CPU decrypts it on cache-line fill; DMA does not.

Handing a kernel address straight to WriteFile produces a file of pure noise — all 256 byte values roughly equally frequent, ~0.4% zeros — while reporting complete success. Copy word by word with the CPU into an ordinary buffer first, then write that. A good dump is ~26% zeros with thousands of 4E800020 (blr) and 7D8802A6 (mflr r12).

Clone this wiki locally