-
Notifications
You must be signed in to change notification settings - Fork 2
Kernel Internals
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.
| 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.
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 namedSataDiskCreateDevice 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.
| Offset | Field |
|---|---|
0x08 |
DriverObject |
0x14 |
Flags |
0x18 |
DeviceExtension |
0x1C |
DeviceType |
0x20 |
SectorSize |
0x24 |
AlignmentRequirement |
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.
A 13-bucket hash table of chained entries, from NtQueryDirectoryObject's own walk
(0x8008A22C–0x8008A264):
| 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.
Produced by SataDiskInitialize 0x8015DF28–0x8015E0D0. 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 contiguous —
SystemExtends exactly whereSystemAuxbegins, which ends exactly whereSystemPartitionbegins, which ends exactly atPartition1. -
0x130EB0000is 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.
These bite hard, because the Windows form compiles fine and then corrupts memory.
NTSTATUS NtQueryDirectoryObject(
HANDLE DirectoryHandle, // r3
PVOID Buffer, // r4
ULONG Length, // r5
BOOLEAN ReturnSingleEntry, // r6
PULONG Context, // r7
PULONG ReturnLength); // r8Passing 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.
typedef struct _OBJECT_ATTRIBUTES {
HANDLE RootDirectory;
POBJECT_STRING ObjectName;
ULONG Attributes;
} OBJECT_ATTRIBUTES;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).