diff --git a/README.md b/README.md
index cadc32b..34f3a86 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,34 @@ The DLL is not a system module. It should be loaded, executed, and then unloaded
**For those who do not code and just want to download/use Bad Storage:** it is built into the latest version of XeUnshackle, so just download that and it is all you need. Make sure to format your drive using FATXplorer as well.
+## Fork: unauthenticated disk support
+
+This fork adds support for disks that never passed the console's security-sector check — no
+Microsoft signature, no SSD Maker, no HDD Maker. Format the drive as a normal Xbox 360 hard disk
+with FATXplorer and it mounts.
+
+It works by finishing the partition device initialisation that `SataDiskInitialize` skips when
+authentication fails, rather than trying to defeat the authentication check itself (which cannot
+work — that gate is evaluated once at boot, before any exploit payload runs).
+
+Capacity comes from the drive's own reported sector count rather than any declared model size, so
+there is no retail-style size ceiling. Tested from a 240 GB SSD up to 1 TB mechanical disks.
+
+It can also reformat the disk from the console itself by holding LT, which recovers a drive already
+flashed by SSD Maker even without its `undo.bin`.
+
+Note that a disk set up this way cannot serve an exploit entry point that reads from the internal
+drive, such as BadAvatarHDD — an unauthenticated disk has no readable filesystem until the bypass
+has run, and the bypass needs an exploit to already be running. USB-based entry points are
+unaffected.
+
+Requires a retail console on kernel 17559 with Bad Update + XeUnshackle. See the
+[wiki](https://github.com/Angelpro09xd/BadStorage/wiki) for how it works, the kernel internals it relies on, and its limitations.
+
+Upstream Bad Storage behaviour is unchanged: on an authenticated, BSTOR-formatted disk this fork
+does exactly what it always did.
+
+
# Compiling
The recommended development environment is:
diff --git a/src/BadStorage-DLL/BadStorage/BadStorage.cpp b/src/BadStorage-DLL/BadStorage/BadStorage.cpp
index 1539f27..17b3bb6 100644
--- a/src/BadStorage-DLL/BadStorage/BadStorage.cpp
+++ b/src/BadStorage-DLL/BadStorage/BadStorage.cpp
@@ -3,6 +3,8 @@
#include "stdafx.h"
#include "BadStorage.h"
+#include "UnauthenticatedDisk.h"
+#include "FatxFormat.h"
VOID Print(const PCHAR Format, ...)
{
@@ -144,20 +146,68 @@ EXTERN_C BOOLEAN Execute(PBOOLEAN IsRetailFormatted)
return FALSE;
}
+ //Held left trigger means "reformat this disk". Checked before anything else, because on an
+ //SSD Maker flashed drive the disk still authenticates at its flashed size and the code below
+ //would happily carry on using the smaller layout.
+ if (IsFormatRequested())
+ {
+ Print("Left trigger held, reformatting the internal disk.");
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage: Formatting internal disk, do not power off.", 0);
+
+ if (FormatInternalDisk())
+ {
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage: Disk formatted at full size. Reboot and run the exploit again.", 0);
+ }
+ else
+ {
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage FAILURE: Format did not complete.", 0);
+ }
+ return FALSE;
+ }
+
if ((XboxHardwareInfo->Flags & XBOX_HW_FLAG_HDD) != XBOX_HW_FLAG_HDD)
{
//If this value got filled in, it means there is a disk.
if (*(PULONG)SataDiskUserAddressableSectors_Offset == 0)
{
+ //Nothing was identified on the SATA bus at all. That is a lower-level problem than
+ //authentication, so there is nothing to recover here.
Print("No disk.");
XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"BadStorage FAILURE: No internal disk connected.", 0);
+ return FALSE;
}
- else
+
+ //A disk is present and identified, it just never passed the security-sector check, so the
+ //kernel left every partition device object half-initialised. Finish them off.
+ Print("Disk did not authenticate, initialising its partition devices.");
+
+ ULONG initialisedCount = 0;
+ if (!InitializeUnauthenticatedDisk(&initialisedCount))
{
- Print("Disk not genuine.");
- XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"BadStorage FAILURE: Disk not genuine/flashed. Flash using FATXplorer.", 0);
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage FAILURE: Could not initialise the internal disk.", 0);
+ return FALSE;
}
- return FALSE;
+
+ //Tell the dashboard the hard disk is there now.
+ XContent_DEVICEADDREMOVETASK addTask;
+ addTask.pszDevicePath = PARTITION_1_PATH;
+ addTask.Action = DEVICESTATE_ADD;
+ addTask.DeviceType = XCONTENTDEVICETYPE_HDD;
+ if (!((pfnXContentDeviceProcessAddRemove)XContentDeviceProcessAddRemove_Offset)(&addTask))
+ {
+ Print("XContent::DeviceProcessAddRemove (add) returned FALSE.");
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"BadStorage FAILURE: Failed to process HDD addition.", 0);
+ return FALSE;
+ }
+
+ ((pfnBroadcastStorageDevicesChanged)BroadcastStorageDevicesChanged_Offset)();
+
+ //The remainder of Bad Storage resizes a BSTOR formatted disk. A retail-formatted disk is
+ //fully usable at this point, so stop here.
+ Print("Unauthenticated disk mounted (%u partition devices initialised).", initialisedCount);
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage: Auth bypass active - internal disk mounted.", 0);
+ if (IsRetailFormatted != NULL) *IsRetailFormatted = TRUE;
+ return TRUE;
}
PDEVICE_OBJECT phyDiskDeviceObject = NULL;
@@ -208,8 +258,29 @@ EXTERN_C BOOLEAN Execute(PBOOLEAN IsRetailFormatted)
if (!CheckBSTOR(diskHandle))
{
if (IsRetailFormatted != NULL) *IsRetailFormatted = TRUE;
- //Opting to not show this to avoid it being annoying.
- //XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"BadStorage FAILURE: Disk is not formatted for Bad Storage. Reformat using FATXplorer.", 0);
+
+ //A disk flashed by SSD Maker authenticates, but it does so by presenting itself as an
+ //official Xbox 360 drive, so the console only ever sees that model's capacity. Point out
+ //when that is costing a meaningful amount of space.
+ //
+ //Deliberately only a message. The partition length cannot simply be raised here: FATX does
+ //not record its own volume size, so the kernel derives the cluster count - and with it the
+ //size of the allocation table - from the partition length the driver reports. Enlarging the
+ //partition under a volume that was formatted smaller moves where the data area is expected
+ //to start and corrupts the whole thing. Bad Storage can enlarge a BSTOR volume safely only
+ //because FATXplorer sizes its allocation table for the full capacity up front.
+ LONGLONG driveSize = (LONGLONG)(*(PULONG)SataDiskUserAddressableSectors_Offset) * 512;
+ LONGLONG claimed = p1DiskPartitionInfo->StartingOffset.QuadPart + p1DiskPartitionInfo->PartitionLength.QuadPart;
+ LONGLONG unused = driveSize - claimed;
+
+ //A quarter of the drive is enough to be worth telling someone about.
+ if (unused > driveSize / 4)
+ {
+ Print("Drive is %I64d MB but only %I64d MB is in use; %I64d MB unreachable because of the flashed disk identity.",
+ driveSize / (1024 * 1024), claimed / (1024 * 1024), unused / (1024 * 1024));
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage: Drive is larger than its flashed size. Reformat with FATXplorer to use all of it.", 0);
+ }
+
goto cleanupAndExit;
}
diff --git a/src/BadStorage-DLL/BadStorage/BadStorage.h b/src/BadStorage-DLL/BadStorage/BadStorage.h
index e03316e..11de84e 100644
--- a/src/BadStorage-DLL/BadStorage/BadStorage.h
+++ b/src/BadStorage-DLL/BadStorage/BadStorage.h
@@ -41,4 +41,7 @@ const UCHAR BADSTORAGE_DID_PATCH_DATA[8] = { 0x3B, 0xC0, 0x00, 0x01, 0x48, 0x00,
const PCHAR PHYSICAL_DISK_PATH = "\\Device\\Harddisk0\\PhysicalDisk";
const PCHAR PARTITION_0_PATH = "\\Device\\Harddisk0\\Partition0";
const PCHAR PARTITION_1_PATH = "\\Device\\Harddisk0\\Partition1";
-const PCHAR PARTITION_1_PATH_FILE = "\\Device\\Harddisk0\\Partition1\\";
\ No newline at end of file
+const PCHAR PARTITION_1_PATH_FILE = "\\Device\\Harddisk0\\Partition1\\";
+
+//Defined in BadStorage.cpp; declared here so other translation units can log too.
+VOID Print(const PCHAR Format, ...);
diff --git a/src/BadStorage-DLL/BadStorage/BadStorage.vcxproj b/src/BadStorage-DLL/BadStorage/BadStorage.vcxproj
index 5eeeba7..55fa8b7 100644
--- a/src/BadStorage-DLL/BadStorage/BadStorage.vcxproj
+++ b/src/BadStorage-DLL/BadStorage/BadStorage.vcxproj
@@ -158,6 +158,8 @@
+
+
@@ -166,6 +168,8 @@
Create
+
+
diff --git a/src/BadStorage-DLL/BadStorage/FatxFormat.cpp b/src/BadStorage-DLL/BadStorage/FatxFormat.cpp
new file mode 100644
index 0000000..7b4dfa6
--- /dev/null
+++ b/src/BadStorage-DLL/BadStorage/FatxFormat.cpp
@@ -0,0 +1,212 @@
+// On-console FATX formatting for Bad Storage.
+// Copyright © 2026. Licensed under the same MIT terms as Bad Storage.
+
+#include "stdafx.h"
+#include "FatxFormat.h"
+#include "BadStorage.h"
+#include "UnauthenticatedDisk.h"
+
+//Written in chunks so the FAT can be cleared without allocating anything large.
+#define FORMAT_CHUNK_SIZE 0x10000
+static BYTE g_FormatChunk[FORMAT_CHUNK_SIZE];
+
+//One entry per partition the retail layout defines. Offsets are absolute byte positions on the
+//drive, so everything is written through PhysicalDisk rather than through the partitions
+//themselves - which is essential here, because while the disk still authenticates as a smaller
+//model the partition devices do not even span the area being written.
+typedef struct _FORMAT_PARTITION {
+ const CHAR* Name;
+ LONGLONG Offset;
+ LONGLONG Length; //0 means "everything left on the drive"
+} FORMAT_PARTITION;
+
+BOOLEAN IsFormatRequested(void)
+{
+ //Any connected pad counts, so it does not matter which port is used.
+ for (DWORD i = 0; i < 4; i++)
+ {
+ XINPUT_STATE state;
+ ZeroMemory(&state, sizeof(state));
+ if (XInputGetState(i, &state) == ERROR_SUCCESS)
+ {
+ //Well past the trigger's resting position, so a resting pad cannot trip it.
+ if (state.Gamepad.bLeftTrigger > 200) return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+//Opens the whole drive for writing. Partitions are deliberately not used - see the note above.
+static HANDLE OpenPhysicalDiskForWrite(void)
+{
+ OBJECT_STRING str;
+ RtlInitAnsiString(&str, PHYSICAL_DISK_PATH);
+
+ OBJECT_ATTRIBUTES oa;
+ InitializeObjectAttributes(&oa, &str, OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ HANDLE handle;
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status = NtOpenFile(&handle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &oa, &iosb,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
+ if (!NT_SUCCESS(status))
+ {
+ Print("Could not open the disk for writing: 0x%08X", status);
+ return INVALID_HANDLE_VALUE;
+ }
+ return handle;
+}
+
+static BOOLEAN WriteAt(HANDLE Disk, LONGLONG Offset, PVOID Buffer, ULONG Length)
+{
+ IO_STATUS_BLOCK iosb;
+ LARGE_INTEGER offset;
+ offset.QuadPart = Offset;
+
+ NTSTATUS status = NtWriteFile(Disk, NULL, NULL, NULL, &iosb, Buffer, Length, &offset);
+ if (!NT_SUCCESS(status))
+ {
+ Print("Write failed at %I64d (%u bytes): 0x%08X", Offset, Length, status);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//Clears a span by writing zeroes over it.
+static BOOLEAN ZeroRange(HANDLE Disk, LONGLONG Offset, LONGLONG Length)
+{
+ ZeroMemory(g_FormatChunk, sizeof(g_FormatChunk));
+
+ LONGLONG written = 0;
+ while (written < Length)
+ {
+ ULONG chunk = (ULONG)((Length - written) > FORMAT_CHUNK_SIZE ? FORMAT_CHUNK_SIZE : (Length - written));
+ if (!WriteAt(Disk, Offset + written, g_FormatChunk, chunk)) return FALSE;
+ written += chunk;
+ }
+ return TRUE;
+}
+
+/*
+ Writes one FATX volume.
+
+ Layout, matching what a retail-formatted partition reads back as:
+ 0x0000 volume header
+ 0x1000 allocation table
+ 0x1000 + fatSize data area, cluster 1 first, holding the root directory
+
+ The cluster count depends on the size of the allocation table, which itself depends on the
+ cluster count, so it is solved by iterating twice - which is enough to settle.
+*/
+static BOOLEAN FormatPartition(HANDLE Disk, const CHAR* Name, LONGLONG Offset, LONGLONG Length)
+{
+ const ULONG clusterBytes = FATX_SECTORS_PER_CLUSTER * 512;
+
+ ULONG clusterCount = (ULONG)((Length - FATX_HEADER_SIZE) / clusterBytes);
+ ULONG entrySize = (clusterCount >= FATX_FAT16_CLUSTER_LIMIT) ? 4 : 2;
+ LONGLONG fatSize = ((LONGLONG)clusterCount * entrySize + 0xFFF) & ~0xFFFLL;
+
+ //Settle it now that the table's size is known.
+ clusterCount = (ULONG)((Length - FATX_HEADER_SIZE - fatSize) / clusterBytes);
+ entrySize = (clusterCount >= FATX_FAT16_CLUSTER_LIMIT) ? 4 : 2;
+ fatSize = ((LONGLONG)clusterCount * entrySize + 0xFFF) & ~0xFFFLL;
+
+ LONGLONG dataStart = Offset + FATX_HEADER_SIZE + fatSize;
+
+ Print("Formatting %s at %I64d, %I64d MB, %u clusters, %u-bit table (%I64d KB)",
+ Name, Offset, Length / (1024 * 1024), clusterCount, entrySize * 8, fatSize / 1024);
+
+ //Header. Unused space in it reads as 0xFF on a retail volume.
+ ZeroMemory(g_FormatChunk, FATX_HEADER_SIZE);
+ memset(g_FormatChunk, 0xFF, FATX_HEADER_SIZE);
+ PULONG header = (PULONG)g_FormatChunk;
+ header[0] = FATX_MAGIC;
+ //Derived from the drive's own reported size so two partitions never share an id.
+ header[1] = (ULONG)(Offset >> 12) ^ (ULONG)Length ^ 0x5A4D0000;
+ header[2] = FATX_SECTORS_PER_CLUSTER;
+ header[3] = FATX_ROOT_CLUSTER;
+ if (!WriteAt(Disk, Offset, g_FormatChunk, FATX_HEADER_SIZE)) return FALSE;
+
+ //Allocation table: everything free except the reserved entry and the root directory's chain.
+ if (!ZeroRange(Disk, Offset + FATX_HEADER_SIZE, fatSize)) return FALSE;
+
+ ZeroMemory(g_FormatChunk, FORMAT_CHUNK_SIZE);
+ if (entrySize == 4)
+ {
+ PULONG fat = (PULONG)g_FormatChunk;
+ fat[0] = FATX_FAT_RESERVED0;
+ fat[1] = FATX_FAT_END_OF_CHAIN;
+ }
+ else
+ {
+ PUSHORT fat = (PUSHORT)g_FormatChunk;
+ fat[0] = (USHORT)FATX_FAT_RESERVED0;
+ fat[1] = (USHORT)FATX_FAT_END_OF_CHAIN;
+ }
+ if (!WriteAt(Disk, Offset + FATX_HEADER_SIZE, g_FormatChunk, 0x1000)) return FALSE;
+
+ //Root directory. An unused FATX directory entry starts with 0xFF.
+ memset(g_FormatChunk, 0xFF, clusterBytes > FORMAT_CHUNK_SIZE ? FORMAT_CHUNK_SIZE : clusterBytes);
+ if (!WriteAt(Disk, dataStart, g_FormatChunk, clusterBytes)) return FALSE;
+
+ return TRUE;
+}
+
+BOOLEAN FormatInternalDisk(void)
+{
+ ULONG sectors = *(PULONG)SataDiskUserAddressableSectors_Offset;
+ if (sectors == 0)
+ {
+ Print("No disk identified, nothing to format.");
+ return FALSE;
+ }
+
+ LONGLONG driveSize = (LONGLONG)sectors * 512;
+ if (driveSize <= (LONGLONG)UD_CONTENT_PARTITION_OFFSET)
+ {
+ Print("Disk is too small for the standard partition layout.");
+ return FALSE;
+ }
+
+ Print("Formatting the internal disk: %I64d MB. Everything on it will be lost.",
+ driveSize / (1024 * 1024));
+
+ HANDLE disk = OpenPhysicalDiskForWrite();
+ if (disk == INVALID_HANDLE_VALUE) return FALSE;
+
+ BOOLEAN ok = TRUE;
+
+ //Invalidate the security sector first. Until this is gone the disk keeps authenticating as
+ //whatever model it was flashed as, and the partitions get sized to that model again on the
+ //next boot no matter how the filesystems look.
+ Print("Clearing the security sector at 0x%X.", SECURITY_SECTOR_OFFSET);
+ if (!ZeroRange(disk, SECURITY_SECTOR_OFFSET, SECURITY_SECTOR_LENGTH)) ok = FALSE;
+
+ //Same layout the kernel itself uses, so a formatted disk matches what the bypass will publish.
+ static const FORMAT_PARTITION partitions[] = {
+ { "Cache0", UD_CACHE0_OFFSET, UD_CACHE_LENGTH },
+ { "Cache1", UD_CACHE1_OFFSET, UD_CACHE_LENGTH },
+ { "SystemURLCachePartition", UD_SYSTEM_URL_CACHE_OFFSET, UD_SYSTEM_URL_CACHE_LENGTH },
+ { "TitleURLCachePartition", UD_TITLE_URL_CACHE_OFFSET, UD_TITLE_URL_CACHE_LENGTH },
+ { "SystemExtPartition", UD_SYSTEM_EXT_OFFSET, UD_SYSTEM_EXT_LENGTH },
+ { "SystemAuxPartition", UD_SYSTEM_AUX_OFFSET, UD_SYSTEM_AUX_LENGTH },
+ { "SystemPartition", UD_SYSTEM_PARTITION_OFFSET, UD_SYSTEM_PARTITION_LENGTH },
+ { "Partition1", UD_CONTENT_PARTITION_OFFSET, 0 },
+ };
+
+ for (int i = 0; ok && i < (int)(sizeof(partitions) / sizeof(partitions[0])); i++)
+ {
+ LONGLONG length = partitions[i].Length != 0
+ ? partitions[i].Length
+ : driveSize - partitions[i].Offset;
+
+ if (!FormatPartition(disk, partitions[i].Name, partitions[i].Offset, length)) ok = FALSE;
+ }
+
+ NtClose(disk);
+
+ if (ok) Print("Format complete. Reboot, then run the exploit again to pick up the full size.");
+ else Print("Format did not complete.");
+
+ return ok;
+}
diff --git a/src/BadStorage-DLL/BadStorage/FatxFormat.h b/src/BadStorage-DLL/BadStorage/FatxFormat.h
new file mode 100644
index 0000000..e27532e
--- /dev/null
+++ b/src/BadStorage-DLL/BadStorage/FatxFormat.h
@@ -0,0 +1,78 @@
+// On-console FATX formatting for Bad Storage.
+// Copyright © 2026. Licensed under the same MIT terms as Bad Storage.
+
+#pragma once
+
+/*
+ Formats the internal disk from the console itself, so the result is guaranteed to match what
+ the kernel expects without needing a PC.
+
+ Why this exists
+ ---------------
+ A drive flashed by SSD Maker presents itself as an official Xbox 360 model, so the console only
+ ever sees that model's capacity - a 240 GB SSD flashed as a 120 GB disk gives about 107 GiB of
+ content partition instead of 218 GiB. Reformatting with FATXplorer on a PC fixes that, but
+ undoing an SSD Maker flash normally wants the undo.bin that was produced at flash time, and not
+ everyone still has it.
+
+ Two things have to happen, not one
+ ----------------------------------
+ Simply writing fresh FATX volumes is not enough. The security sector still declares the smaller
+ model, so on the next boot the disk authenticates, the bypass never engages, and
+ SataDiskInitialize sizes the partitions to the flashed identity again regardless of what the
+ filesystem looks like.
+
+ So this also invalidates the security sector. Once it no longer authenticates, the bypass takes
+ over and lays out the partitions across the whole drive.
+
+ That means the sequence is:
+
+ 1. Hold LT at boot -> security sector wiped, partitions formatted for the full drive
+ 2. Reboot
+ 3. Disk no longer authenticates -> bypass runs -> full capacity available
+
+ This is destructive. Everything on the disk is lost.
+
+ Verifying the result
+ --------------------
+ After formatting, connect the drive to a PC and open it in FATXplorer. If it shows a valid
+ volume at the full size, the layout is right. Do that before putting anything on it.
+*/
+
+#include "XenonExports.h"
+
+// FATX volume header, at offset 0 of every partition. Values are big-endian DWORDs, matching what
+// a retail-formatted partition reads back as.
+#define FATX_MAGIC 0x58544146 // 'X','T','A','F'
+#define FATX_HEADER_SIZE 0x1000
+#define FATX_SECTORS_PER_CLUSTER 32 // 16 KB clusters, what retail uses
+#define FATX_ROOT_CLUSTER 1
+
+// A FAT holding this many clusters or more needs 32-bit entries instead of 16-bit.
+#define FATX_FAT16_CLUSTER_LIMIT 0xFFF0
+
+#define FATX_FAT_RESERVED0 0xFFFFFFF8 // media descriptor
+#define FATX_FAT_END_OF_CHAIN 0xFFFFFFFF
+
+// Byte offset of the sector the kernel authenticates against, and how much of it it reads.
+// Taken from SataDiskAuthenticateDevice itself (0x8015D9E4 onwards): it loads 0x2000 as a 64-bit
+// offset, asks for 0x200 bytes via IoSynchronousFsdRequest on the PhysicalDisk device, feeds the
+// result to XeKeysSetKey and compares the digest.
+//
+// Note this is NOT "sixteen sectors from the end of the drive". That was an unverified guess in
+// the project notes, and wiping there does nothing at all - the disk keeps authenticating.
+#define SECURITY_SECTOR_OFFSET 0x2000
+#define SECURITY_SECTOR_LENGTH 0x200
+
+/*
+ Wipes the security sector and writes fresh FATX volumes sized for the whole drive.
+
+ Returns TRUE only if every partition was written. On failure it stops at the first error rather
+ than leaving a partially formatted disk behind unreported.
+*/
+BOOLEAN FormatInternalDisk(void);
+
+/*
+ TRUE while the left trigger is held. Used to gate the format behind a deliberate action.
+*/
+BOOLEAN IsFormatRequested(void);
diff --git a/src/BadStorage-DLL/BadStorage/UnauthenticatedDisk.cpp b/src/BadStorage-DLL/BadStorage/UnauthenticatedDisk.cpp
new file mode 100644
index 0000000..715c844
--- /dev/null
+++ b/src/BadStorage-DLL/BadStorage/UnauthenticatedDisk.cpp
@@ -0,0 +1,156 @@
+// Unauthenticated disk support for Bad Storage.
+// Copyright © 2026. Licensed under the same MIT terms as Bad Storage.
+
+#include "stdafx.h"
+#include "UnauthenticatedDisk.h"
+#include "BadStorage.h"
+
+// Directory entry names are counted, not NUL-terminated.
+static BOOLEAN NameEquals(const CHAR* Buffer, USHORT Length, const CHAR* Expected)
+{
+ USHORT i = 0;
+ for (; i < Length; i++)
+ {
+ if (Expected[i] == '\0' || Buffer[i] != Expected[i]) return FALSE;
+ }
+ return Expected[i] == '\0';
+}
+
+// The geometry SataDiskInitialize would have written for a given partition.
+// Returns FALSE for names that are not hard disk partitions.
+static BOOLEAN GetPartitionGeometry(const CHAR* Name, USHORT NameLength, LONGLONG DiskSize, PLONGLONG Offset, PLONGLONG Length)
+{
+ if (NameEquals(Name, NameLength, "Partition0")) { *Offset = 0; *Length = DiskSize; }
+ else if (NameEquals(Name, NameLength, "Partition1")) { *Offset = UD_CONTENT_PARTITION_OFFSET; *Length = DiskSize - UD_CONTENT_PARTITION_OFFSET; }
+ else if (NameEquals(Name, NameLength, "Cache0")) { *Offset = UD_CACHE0_OFFSET; *Length = UD_CACHE_LENGTH; }
+ else if (NameEquals(Name, NameLength, "Cache1")) { *Offset = UD_CACHE1_OFFSET; *Length = UD_CACHE_LENGTH; }
+ else if (NameEquals(Name, NameLength, "DumpPartition")) { *Offset = UD_DUMP_OFFSET; *Length = UD_DUMP_LENGTH; }
+ else if (NameEquals(Name, NameLength, "SystemURLCachePartition")) { *Offset = UD_SYSTEM_URL_CACHE_OFFSET; *Length = UD_SYSTEM_URL_CACHE_LENGTH; }
+ else if (NameEquals(Name, NameLength, "TitleURLCachePartition")) { *Offset = UD_TITLE_URL_CACHE_OFFSET; *Length = UD_TITLE_URL_CACHE_LENGTH; }
+ else if (NameEquals(Name, NameLength, "SystemExtPartition")) { *Offset = UD_SYSTEM_EXT_OFFSET; *Length = UD_SYSTEM_EXT_LENGTH; }
+ else if (NameEquals(Name, NameLength, "SystemAuxPartition")) { *Offset = UD_SYSTEM_AUX_OFFSET; *Length = UD_SYSTEM_AUX_LENGTH; }
+ else if (NameEquals(Name, NameLength, "SystemPartition")) { *Offset = UD_SYSTEM_PARTITION_OFFSET; *Length = UD_SYSTEM_PARTITION_LENGTH; }
+ else if (NameEquals(Name, NameLength, "WindowsPartition")) { *Offset = 0; *Length = 0; }
+ else return FALSE;
+
+ return TRUE;
+}
+
+// Confirms a device really did become reachable by name.
+static BOOLEAN DeviceResolves(const PSZ Path)
+{
+ PDEVICE_OBJECT device = NULL;
+ OBJECT_STRING str;
+ RtlInitAnsiString(&str, Path);
+
+ NTSTATUS status = ObReferenceObjectByName(&str, 0, IoDeviceObjectType, NULL, (PVOID*)&device);
+ if (!NT_SUCCESS(status) || device == NULL)
+ {
+ Print("%s did not resolve: 0x%08X", Path, status);
+ return FALSE;
+ }
+
+ ObDereferenceObject(device);
+ return TRUE;
+}
+
+BOOLEAN InitializeUnauthenticatedDisk(ULONG* FixedCount)
+{
+ if (FixedCount != NULL) *FixedCount = 0;
+
+ // The drive's own reported capacity. Zero means the console never identified a disk at all,
+ // which is a lower-level problem than authentication and not something this can repair.
+ ULONG sectors = *(PULONG)SataDiskUserAddressableSectors_Offset;
+ if (sectors == 0)
+ {
+ Print("No disk identified, nothing to initialise.");
+ return FALSE;
+ }
+
+ LONGLONG diskSize = (LONGLONG)sectors * 512;
+ Print("Unauthenticated disk: %I64d bytes (%I64d MB).", diskSize, diskSize / (1024 * 1024));
+
+ // A disk smaller than the fixed system partition area cannot use this layout.
+ if (diskSize <= (LONGLONG)UD_CONTENT_PARTITION_OFFSET)
+ {
+ Print("Disk is too small for the standard partition layout.");
+ return FALSE;
+ }
+
+ // The partition devices are unreachable by name while DO_DEVICE_INITIALIZING is set, so go
+ // through the object directory instead.
+ PVOID directory = NULL;
+ OBJECT_STRING directoryStr;
+ RtlInitAnsiString(&directoryStr, HARDDISK0_DIRECTORY_PATH);
+
+ NTSTATUS status = ObReferenceObjectByName(&directoryStr, 0, ObDirectoryObjectType, NULL, &directory);
+ if (!NT_SUCCESS(status) || directory == NULL)
+ {
+ Print("ObReferenceObjectByName failed on %s: 0x%08X", HARDDISK0_DIRECTORY_PATH, status);
+ return FALSE;
+ }
+
+ ULONG fixed = 0;
+ PULONG buckets = (PULONG)directory;
+
+ for (ULONG bucket = 0; bucket < OBJECT_DIRECTORY_BUCKETS; bucket++)
+ {
+ ULONG entry = buckets[bucket];
+
+ // Bounded so a corrupted chain cannot spin forever.
+ for (ULONG depth = 0; entry != 0 && depth < 32; depth++)
+ {
+ USHORT nameLength = *(PUSHORT)(entry + OBJDIR_ENTRY_NAMELEN);
+ PCHAR nameBuffer = *(PCHAR*)(entry + OBJDIR_ENTRY_NAMEBUF);
+ ULONG next = *(PULONG)(entry + OBJDIR_ENTRY_NEXT);
+
+ if (nameLength != 0 && nameLength < 64 && nameBuffer != NULL)
+ {
+ PDEVICE_OBJECT device = (PDEVICE_OBJECT)(entry + OBJDIR_ENTRY_TO_OBJECT);
+
+ // Only touch devices still stuck mid-initialisation. On an authenticated disk
+ // there are none, so this whole loop does nothing.
+ if ((device->Flags & DO_DEVICE_INITIALIZING_360) == DO_DEVICE_INITIALIZING_360)
+ {
+ LONGLONG offset = 0, length = 0;
+ if (GetPartitionGeometry(nameBuffer, nameLength, diskSize, &offset, &length))
+ {
+ PPARTITION_INFORMATION info = &((PSATA_DISK_EXTENSION)device->DeviceExtension)->PartitionInformation;
+ info->StartingOffset.QuadPart = offset;
+ info->PartitionLength.QuadPart = length;
+
+ // The kernel's own final step for each device. Its instruction is
+ // "rlwinm rX, rX, 0, 28, 26", a wrapped mask whose only effect is to
+ // clear this bit.
+ device->Flags &= ~DO_DEVICE_INITIALIZING_360;
+
+ fixed++;
+ Print("Initialised %.*s: offset %I64d, length %I64d", nameLength, nameBuffer, offset, length);
+ }
+ }
+ }
+
+ entry = next;
+ }
+ }
+
+ ObDereferenceObject(directory);
+
+ if (FixedCount != NULL) *FixedCount = fixed;
+
+ if (fixed == 0)
+ {
+ Print("No uninitialised partition devices found.");
+ return FALSE;
+ }
+
+ // These two are what the dashboard actually needs, so they decide success.
+ if (!DeviceResolves(PARTITION_0_PATH) || !DeviceResolves(PARTITION_1_PATH))
+ {
+ Print("Partitions were written but still do not resolve.");
+ return FALSE;
+ }
+
+ Print("Initialised %u partition devices.", fixed);
+ return TRUE;
+}
diff --git a/src/BadStorage-DLL/BadStorage/UnauthenticatedDisk.h b/src/BadStorage-DLL/BadStorage/UnauthenticatedDisk.h
new file mode 100644
index 0000000..fb73240
--- /dev/null
+++ b/src/BadStorage-DLL/BadStorage/UnauthenticatedDisk.h
@@ -0,0 +1,100 @@
+// Unauthenticated disk support for Bad Storage.
+// Copyright © 2026. Licensed under the same MIT terms as Bad Storage.
+
+#pragma once
+
+/*
+ Lets a disk that never passed the console's security-sector check be used as internal storage.
+
+ Background
+ ----------
+ During boot, SataDiskInitialize does two separate things, in this order:
+
+ 1. BEFORE the authentication gate, it creates all twelve hard disk device objects
+ (PhysicalDisk, Partition0, Partition1, Cache0/1, DumpPartition, SystemPartition, ...)
+ by calling SataDiskCreateDevice -> IoCreateDevice.
+
+ 2. AFTER the gate, it fills in each device's PartitionInformation and clears
+ DO_DEVICE_INITIALIZING on it.
+
+ When SataDiskAuthenticateDevice fails, the gate branches straight to the function epilogue,
+ so step 2 never runs. The device objects therefore exist, but with a zeroed
+ PartitionInformation and DO_DEVICE_INITIALIZING still set. A device in that state makes
+ ObReferenceObjectByName return STATUS_NO_SUCH_DEVICE (0xC000000E) - note that this is *not*
+ STATUS_OBJECT_NAME_NOT_FOUND: the name resolves fine, it is the device that gets refused.
+
+ PhysicalDisk is the one exception and stays usable, because it is completed before the gate.
+
+ Approach
+ --------
+ Patching SataDiskAuthenticateDevice to return TRUE does not help. That gate is evaluated once,
+ early in boot, long before any exploit payload runs, and there is no warm reboot that would
+ re-run it while keeping patches in memory. (XeUnshackle already applies exactly that patch as
+ part of its Freeboot set, and it still is not enough.)
+
+ Instead, this finishes the initialisation the gate skipped: reach the device objects by walking
+ the \Device\Harddisk0 object directory - they cannot be reached by name, precisely because of
+ the flag - write each partition's geometry, and clear DO_DEVICE_INITIALIZING.
+
+ Everything written here is what SataDiskInitialize's own post-gate block computes; it was
+ recovered by disassembling that block instruction by instruction. Two independent checks say
+ the values are right: the resulting layout is perfectly contiguous, and Partition1's offset
+ comes out as 0x130EB0000, the same constant Bad Storage already hardcodes.
+
+ Scope
+ -----
+ This addresses authentication only. It requires a disk the console can already talk to and
+ identify, i.e. one that answers the ATA commands and reports its sector count. A drive whose
+ controller the console cannot negotiate with at all leaves SataDiskUserAddressableSectors at
+ zero, and there is nothing here to complete.
+*/
+
+#include "XenonExports.h"
+
+// On this kernel DO_DEVICE_INITIALIZING is 0x10, not the 0x80 it is on Windows.
+// From IoCreateDevice at 0x8006B00C: "li r11, 0x10" then "stw r11, 0x14(r10)".
+#define DO_DEVICE_INITIALIZING_360 0x10
+
+// The object directory is a 13-bucket hash table of chained entries.
+// From NtQueryDirectoryObject's own walk at 0x8008A22C-0x8008A264.
+#define OBJECT_DIRECTORY_BUCKETS 13
+
+// Offsets within a directory entry, same source.
+#define OBJDIR_ENTRY_NEXT 0x00
+#define OBJDIR_ENTRY_NAMELEN 0x08
+#define OBJDIR_ENTRY_NAMEBUF 0x0C
+
+// Distance from a directory entry to the object body it refers to.
+// Measured on hardware rather than assumed: the PhysicalDisk entry sat at 0x3A0A7C88 while
+// ObReferenceObjectByName returned 0x3A0A7CA8 for the same name.
+#define OBJDIR_ENTRY_TO_OBJECT 0x20
+
+// Byte offset of the content partition, and the fixed geometry of the system partitions.
+// All derived from SataDiskInitialize 0x8015DF28-0x8015E0D0.
+#define UD_CACHE0_OFFSET 0x80000ULL
+#define UD_CACHE1_OFFSET 0x80080000ULL
+#define UD_CACHE_LENGTH 0x80000000ULL
+#define UD_DUMP_OFFSET 0x100080000ULL
+#define UD_DUMP_LENGTH 0x20E30000ULL
+#define UD_SYSTEM_URL_CACHE_OFFSET 0x100080000ULL
+#define UD_SYSTEM_URL_CACHE_LENGTH 0x6000000ULL
+#define UD_TITLE_URL_CACHE_OFFSET 0x106080000ULL
+#define UD_TITLE_URL_CACHE_LENGTH 0x2000000ULL
+#define UD_SYSTEM_EXT_OFFSET 0x10C080000ULL
+#define UD_SYSTEM_EXT_LENGTH 0xCE30000ULL
+#define UD_SYSTEM_AUX_OFFSET 0x118EB0000ULL
+#define UD_SYSTEM_AUX_LENGTH 0x8000000ULL
+#define UD_SYSTEM_PARTITION_OFFSET 0x120EB0000ULL
+#define UD_SYSTEM_PARTITION_LENGTH 0x10000000ULL
+#define UD_CONTENT_PARTITION_OFFSET 0x130EB0000ULL
+
+#define HARDDISK0_DIRECTORY_PATH "\\Device\\Harddisk0"
+
+/*
+ Completes the partition device objects the authentication gate left half-initialised.
+
+ Returns TRUE only if Partition0 and Partition1 both resolve by name afterwards, which is the
+ real proof that the devices became usable. Safe to call when nothing needs fixing: devices that
+ are already initialised are skipped, so a second call is a no-op.
+*/
+BOOLEAN InitializeUnauthenticatedDisk(ULONG* FixedCount);
diff --git a/src/BadStorage-DLL/BadStorage/XenonExports.h b/src/BadStorage-DLL/BadStorage/XenonExports.h
index 80d1028..6fcbbef 100644
--- a/src/BadStorage-DLL/BadStorage/XenonExports.h
+++ b/src/BadStorage-DLL/BadStorage/XenonExports.h
@@ -765,6 +765,7 @@ EXTERN_C
extern PXBOX_KRNL_VERSION XboxKrnlVersion;
extern PXBOX_HARDWARE_INFO XboxHardwareInfo;
extern PVOID IoDeviceObjectType;
+ extern PVOID ObDirectoryObjectType;
HRESULT
WINAPI
diff --git a/src/BadStorage-XEX/BadStorage/BadStorage.cpp b/src/BadStorage-XEX/BadStorage/BadStorage.cpp
index 967b483..75c1eff 100644
--- a/src/BadStorage-XEX/BadStorage/BadStorage.cpp
+++ b/src/BadStorage-XEX/BadStorage/BadStorage.cpp
@@ -3,6 +3,8 @@
#include "stdafx.h"
#include "BadStorage.h"
+#include "UnauthenticatedDisk.h"
+#include "FatxFormat.h"
VOID Print(const PCHAR Format, ...)
{
@@ -136,19 +138,66 @@ VOID __cdecl main()
return;
}
+ //Held left trigger means "reformat this disk". Checked before anything else, because on an
+ //SSD Maker flashed drive the disk still authenticates at its flashed size and the code below
+ //would happily carry on using the smaller layout.
+ if (IsFormatRequested())
+ {
+ Print("Left trigger held, reformatting the internal disk.");
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage: Formatting internal disk, do not power off.", 0);
+
+ if (FormatInternalDisk())
+ {
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage: Disk formatted at full size. Reboot and run the exploit again.", 0);
+ }
+ else
+ {
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage FAILURE: Format did not complete.", 0);
+ }
+ return;
+ }
+
if ((XboxHardwareInfo->Flags & XBOX_HW_FLAG_HDD) != XBOX_HW_FLAG_HDD)
{
//If this value got filled in, it means there is a disk.
if (*(PULONG)SataDiskUserAddressableSectors_Offset == 0)
{
+ //Nothing was identified on the SATA bus at all. That is a lower-level problem than
+ //authentication, so there is nothing to recover here.
Print("No disk.");
XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"BadStorage FAILURE: No internal disk connected.", 0);
+ return;
}
- else
+
+ //A disk is present and identified, it just never passed the security-sector check, so the
+ //kernel left every partition device object half-initialised. Finish them off.
+ Print("Disk did not authenticate, initialising its partition devices.");
+
+ ULONG initialisedCount = 0;
+ if (!InitializeUnauthenticatedDisk(&initialisedCount))
{
- Print("Disk not genuine.");
- XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"BadStorage FAILURE: Disk not genuine/flashed. Flash using FATXplorer.", 0);
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage FAILURE: Could not initialise the internal disk.", 0);
+ return;
}
+
+ //Tell the dashboard the hard disk is there now.
+ XContent_DEVICEADDREMOVETASK addTask;
+ addTask.pszDevicePath = PARTITION_1_PATH;
+ addTask.Action = DEVICESTATE_ADD;
+ addTask.DeviceType = XCONTENTDEVICETYPE_HDD;
+ if (!((pfnXContentDeviceProcessAddRemove)XContentDeviceProcessAddRemove_Offset)(&addTask))
+ {
+ Print("XContent::DeviceProcessAddRemove (add) returned FALSE.");
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"BadStorage FAILURE: Failed to process HDD addition.", 0);
+ return;
+ }
+
+ ((pfnBroadcastStorageDevicesChanged)BroadcastStorageDevicesChanged_Offset)();
+
+ //The remainder of Bad Storage resizes a BSTOR formatted disk. A retail-formatted disk is
+ //fully usable at this point, so stop here.
+ Print("Unauthenticated disk mounted (%u partition devices initialised).", initialisedCount);
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage: Auth bypass active - internal disk mounted.", 0);
return;
}
@@ -199,7 +248,32 @@ VOID __cdecl main()
if (!CheckBSTOR(diskHandle))
{
- XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"BadStorage FAILURE: Disk is not formatted for Bad Storage. Reformat using FATXplorer.", 0);
+ //A disk flashed by SSD Maker authenticates, but it does so by presenting itself as an
+ //official Xbox 360 drive, so the console only ever sees that model's capacity. Point out
+ //when that is costing a meaningful amount of space.
+ //
+ //Deliberately only a message. The partition length cannot simply be raised here: FATX does
+ //not record its own volume size, so the kernel derives the cluster count - and with it the
+ //size of the allocation table - from the partition length the driver reports. Enlarging the
+ //partition under a volume that was formatted smaller moves where the data area is expected
+ //to start and corrupts the whole thing. Bad Storage can enlarge a BSTOR volume safely only
+ //because FATXplorer sizes its allocation table for the full capacity up front.
+ LONGLONG driveSize = (LONGLONG)(*(PULONG)SataDiskUserAddressableSectors_Offset) * 512;
+ LONGLONG claimed = p1DiskPartitionInfo->StartingOffset.QuadPart + p1DiskPartitionInfo->PartitionLength.QuadPart;
+ LONGLONG unused = driveSize - claimed;
+
+ //A quarter of the drive is enough to be worth telling someone about.
+ if (unused > driveSize / 4)
+ {
+ Print("Drive is %I64d MB but only %I64d MB is in use; %I64d MB unreachable because of the flashed disk identity.",
+ driveSize / (1024 * 1024), claimed / (1024 * 1024), unused / (1024 * 1024));
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"Bad Storage: Drive is larger than its flashed size. Reformat with FATXplorer to use all of it.", 0);
+ }
+ else
+ {
+ XNotifyQueueUI(XNOTIFYUI_TYPE_AVOID_REVIEW, XUSER_INDEX_ANY, XNOTIFYUI_PRIORITY_HIGH, L"BadStorage FAILURE: Disk is not formatted for Bad Storage. Reformat using FATXplorer.", 0);
+ }
+
goto cleanupAndExit;
}
diff --git a/src/BadStorage-XEX/BadStorage/BadStorage.h b/src/BadStorage-XEX/BadStorage/BadStorage.h
index e03316e..11de84e 100644
--- a/src/BadStorage-XEX/BadStorage/BadStorage.h
+++ b/src/BadStorage-XEX/BadStorage/BadStorage.h
@@ -41,4 +41,7 @@ const UCHAR BADSTORAGE_DID_PATCH_DATA[8] = { 0x3B, 0xC0, 0x00, 0x01, 0x48, 0x00,
const PCHAR PHYSICAL_DISK_PATH = "\\Device\\Harddisk0\\PhysicalDisk";
const PCHAR PARTITION_0_PATH = "\\Device\\Harddisk0\\Partition0";
const PCHAR PARTITION_1_PATH = "\\Device\\Harddisk0\\Partition1";
-const PCHAR PARTITION_1_PATH_FILE = "\\Device\\Harddisk0\\Partition1\\";
\ No newline at end of file
+const PCHAR PARTITION_1_PATH_FILE = "\\Device\\Harddisk0\\Partition1\\";
+
+//Defined in BadStorage.cpp; declared here so other translation units can log too.
+VOID Print(const PCHAR Format, ...);
diff --git a/src/BadStorage-XEX/BadStorage/BadStorage.vcxproj b/src/BadStorage-XEX/BadStorage/BadStorage.vcxproj
index ffc38e2..279a3e7 100644
--- a/src/BadStorage-XEX/BadStorage/BadStorage.vcxproj
+++ b/src/BadStorage-XEX/BadStorage/BadStorage.vcxproj
@@ -141,6 +141,8 @@
+
+
@@ -149,6 +151,8 @@
Create
+
+
diff --git a/src/BadStorage-XEX/BadStorage/FatxFormat.cpp b/src/BadStorage-XEX/BadStorage/FatxFormat.cpp
new file mode 100644
index 0000000..7b4dfa6
--- /dev/null
+++ b/src/BadStorage-XEX/BadStorage/FatxFormat.cpp
@@ -0,0 +1,212 @@
+// On-console FATX formatting for Bad Storage.
+// Copyright © 2026. Licensed under the same MIT terms as Bad Storage.
+
+#include "stdafx.h"
+#include "FatxFormat.h"
+#include "BadStorage.h"
+#include "UnauthenticatedDisk.h"
+
+//Written in chunks so the FAT can be cleared without allocating anything large.
+#define FORMAT_CHUNK_SIZE 0x10000
+static BYTE g_FormatChunk[FORMAT_CHUNK_SIZE];
+
+//One entry per partition the retail layout defines. Offsets are absolute byte positions on the
+//drive, so everything is written through PhysicalDisk rather than through the partitions
+//themselves - which is essential here, because while the disk still authenticates as a smaller
+//model the partition devices do not even span the area being written.
+typedef struct _FORMAT_PARTITION {
+ const CHAR* Name;
+ LONGLONG Offset;
+ LONGLONG Length; //0 means "everything left on the drive"
+} FORMAT_PARTITION;
+
+BOOLEAN IsFormatRequested(void)
+{
+ //Any connected pad counts, so it does not matter which port is used.
+ for (DWORD i = 0; i < 4; i++)
+ {
+ XINPUT_STATE state;
+ ZeroMemory(&state, sizeof(state));
+ if (XInputGetState(i, &state) == ERROR_SUCCESS)
+ {
+ //Well past the trigger's resting position, so a resting pad cannot trip it.
+ if (state.Gamepad.bLeftTrigger > 200) return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+//Opens the whole drive for writing. Partitions are deliberately not used - see the note above.
+static HANDLE OpenPhysicalDiskForWrite(void)
+{
+ OBJECT_STRING str;
+ RtlInitAnsiString(&str, PHYSICAL_DISK_PATH);
+
+ OBJECT_ATTRIBUTES oa;
+ InitializeObjectAttributes(&oa, &str, OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ HANDLE handle;
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status = NtOpenFile(&handle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &oa, &iosb,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
+ if (!NT_SUCCESS(status))
+ {
+ Print("Could not open the disk for writing: 0x%08X", status);
+ return INVALID_HANDLE_VALUE;
+ }
+ return handle;
+}
+
+static BOOLEAN WriteAt(HANDLE Disk, LONGLONG Offset, PVOID Buffer, ULONG Length)
+{
+ IO_STATUS_BLOCK iosb;
+ LARGE_INTEGER offset;
+ offset.QuadPart = Offset;
+
+ NTSTATUS status = NtWriteFile(Disk, NULL, NULL, NULL, &iosb, Buffer, Length, &offset);
+ if (!NT_SUCCESS(status))
+ {
+ Print("Write failed at %I64d (%u bytes): 0x%08X", Offset, Length, status);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//Clears a span by writing zeroes over it.
+static BOOLEAN ZeroRange(HANDLE Disk, LONGLONG Offset, LONGLONG Length)
+{
+ ZeroMemory(g_FormatChunk, sizeof(g_FormatChunk));
+
+ LONGLONG written = 0;
+ while (written < Length)
+ {
+ ULONG chunk = (ULONG)((Length - written) > FORMAT_CHUNK_SIZE ? FORMAT_CHUNK_SIZE : (Length - written));
+ if (!WriteAt(Disk, Offset + written, g_FormatChunk, chunk)) return FALSE;
+ written += chunk;
+ }
+ return TRUE;
+}
+
+/*
+ Writes one FATX volume.
+
+ Layout, matching what a retail-formatted partition reads back as:
+ 0x0000 volume header
+ 0x1000 allocation table
+ 0x1000 + fatSize data area, cluster 1 first, holding the root directory
+
+ The cluster count depends on the size of the allocation table, which itself depends on the
+ cluster count, so it is solved by iterating twice - which is enough to settle.
+*/
+static BOOLEAN FormatPartition(HANDLE Disk, const CHAR* Name, LONGLONG Offset, LONGLONG Length)
+{
+ const ULONG clusterBytes = FATX_SECTORS_PER_CLUSTER * 512;
+
+ ULONG clusterCount = (ULONG)((Length - FATX_HEADER_SIZE) / clusterBytes);
+ ULONG entrySize = (clusterCount >= FATX_FAT16_CLUSTER_LIMIT) ? 4 : 2;
+ LONGLONG fatSize = ((LONGLONG)clusterCount * entrySize + 0xFFF) & ~0xFFFLL;
+
+ //Settle it now that the table's size is known.
+ clusterCount = (ULONG)((Length - FATX_HEADER_SIZE - fatSize) / clusterBytes);
+ entrySize = (clusterCount >= FATX_FAT16_CLUSTER_LIMIT) ? 4 : 2;
+ fatSize = ((LONGLONG)clusterCount * entrySize + 0xFFF) & ~0xFFFLL;
+
+ LONGLONG dataStart = Offset + FATX_HEADER_SIZE + fatSize;
+
+ Print("Formatting %s at %I64d, %I64d MB, %u clusters, %u-bit table (%I64d KB)",
+ Name, Offset, Length / (1024 * 1024), clusterCount, entrySize * 8, fatSize / 1024);
+
+ //Header. Unused space in it reads as 0xFF on a retail volume.
+ ZeroMemory(g_FormatChunk, FATX_HEADER_SIZE);
+ memset(g_FormatChunk, 0xFF, FATX_HEADER_SIZE);
+ PULONG header = (PULONG)g_FormatChunk;
+ header[0] = FATX_MAGIC;
+ //Derived from the drive's own reported size so two partitions never share an id.
+ header[1] = (ULONG)(Offset >> 12) ^ (ULONG)Length ^ 0x5A4D0000;
+ header[2] = FATX_SECTORS_PER_CLUSTER;
+ header[3] = FATX_ROOT_CLUSTER;
+ if (!WriteAt(Disk, Offset, g_FormatChunk, FATX_HEADER_SIZE)) return FALSE;
+
+ //Allocation table: everything free except the reserved entry and the root directory's chain.
+ if (!ZeroRange(Disk, Offset + FATX_HEADER_SIZE, fatSize)) return FALSE;
+
+ ZeroMemory(g_FormatChunk, FORMAT_CHUNK_SIZE);
+ if (entrySize == 4)
+ {
+ PULONG fat = (PULONG)g_FormatChunk;
+ fat[0] = FATX_FAT_RESERVED0;
+ fat[1] = FATX_FAT_END_OF_CHAIN;
+ }
+ else
+ {
+ PUSHORT fat = (PUSHORT)g_FormatChunk;
+ fat[0] = (USHORT)FATX_FAT_RESERVED0;
+ fat[1] = (USHORT)FATX_FAT_END_OF_CHAIN;
+ }
+ if (!WriteAt(Disk, Offset + FATX_HEADER_SIZE, g_FormatChunk, 0x1000)) return FALSE;
+
+ //Root directory. An unused FATX directory entry starts with 0xFF.
+ memset(g_FormatChunk, 0xFF, clusterBytes > FORMAT_CHUNK_SIZE ? FORMAT_CHUNK_SIZE : clusterBytes);
+ if (!WriteAt(Disk, dataStart, g_FormatChunk, clusterBytes)) return FALSE;
+
+ return TRUE;
+}
+
+BOOLEAN FormatInternalDisk(void)
+{
+ ULONG sectors = *(PULONG)SataDiskUserAddressableSectors_Offset;
+ if (sectors == 0)
+ {
+ Print("No disk identified, nothing to format.");
+ return FALSE;
+ }
+
+ LONGLONG driveSize = (LONGLONG)sectors * 512;
+ if (driveSize <= (LONGLONG)UD_CONTENT_PARTITION_OFFSET)
+ {
+ Print("Disk is too small for the standard partition layout.");
+ return FALSE;
+ }
+
+ Print("Formatting the internal disk: %I64d MB. Everything on it will be lost.",
+ driveSize / (1024 * 1024));
+
+ HANDLE disk = OpenPhysicalDiskForWrite();
+ if (disk == INVALID_HANDLE_VALUE) return FALSE;
+
+ BOOLEAN ok = TRUE;
+
+ //Invalidate the security sector first. Until this is gone the disk keeps authenticating as
+ //whatever model it was flashed as, and the partitions get sized to that model again on the
+ //next boot no matter how the filesystems look.
+ Print("Clearing the security sector at 0x%X.", SECURITY_SECTOR_OFFSET);
+ if (!ZeroRange(disk, SECURITY_SECTOR_OFFSET, SECURITY_SECTOR_LENGTH)) ok = FALSE;
+
+ //Same layout the kernel itself uses, so a formatted disk matches what the bypass will publish.
+ static const FORMAT_PARTITION partitions[] = {
+ { "Cache0", UD_CACHE0_OFFSET, UD_CACHE_LENGTH },
+ { "Cache1", UD_CACHE1_OFFSET, UD_CACHE_LENGTH },
+ { "SystemURLCachePartition", UD_SYSTEM_URL_CACHE_OFFSET, UD_SYSTEM_URL_CACHE_LENGTH },
+ { "TitleURLCachePartition", UD_TITLE_URL_CACHE_OFFSET, UD_TITLE_URL_CACHE_LENGTH },
+ { "SystemExtPartition", UD_SYSTEM_EXT_OFFSET, UD_SYSTEM_EXT_LENGTH },
+ { "SystemAuxPartition", UD_SYSTEM_AUX_OFFSET, UD_SYSTEM_AUX_LENGTH },
+ { "SystemPartition", UD_SYSTEM_PARTITION_OFFSET, UD_SYSTEM_PARTITION_LENGTH },
+ { "Partition1", UD_CONTENT_PARTITION_OFFSET, 0 },
+ };
+
+ for (int i = 0; ok && i < (int)(sizeof(partitions) / sizeof(partitions[0])); i++)
+ {
+ LONGLONG length = partitions[i].Length != 0
+ ? partitions[i].Length
+ : driveSize - partitions[i].Offset;
+
+ if (!FormatPartition(disk, partitions[i].Name, partitions[i].Offset, length)) ok = FALSE;
+ }
+
+ NtClose(disk);
+
+ if (ok) Print("Format complete. Reboot, then run the exploit again to pick up the full size.");
+ else Print("Format did not complete.");
+
+ return ok;
+}
diff --git a/src/BadStorage-XEX/BadStorage/FatxFormat.h b/src/BadStorage-XEX/BadStorage/FatxFormat.h
new file mode 100644
index 0000000..e27532e
--- /dev/null
+++ b/src/BadStorage-XEX/BadStorage/FatxFormat.h
@@ -0,0 +1,78 @@
+// On-console FATX formatting for Bad Storage.
+// Copyright © 2026. Licensed under the same MIT terms as Bad Storage.
+
+#pragma once
+
+/*
+ Formats the internal disk from the console itself, so the result is guaranteed to match what
+ the kernel expects without needing a PC.
+
+ Why this exists
+ ---------------
+ A drive flashed by SSD Maker presents itself as an official Xbox 360 model, so the console only
+ ever sees that model's capacity - a 240 GB SSD flashed as a 120 GB disk gives about 107 GiB of
+ content partition instead of 218 GiB. Reformatting with FATXplorer on a PC fixes that, but
+ undoing an SSD Maker flash normally wants the undo.bin that was produced at flash time, and not
+ everyone still has it.
+
+ Two things have to happen, not one
+ ----------------------------------
+ Simply writing fresh FATX volumes is not enough. The security sector still declares the smaller
+ model, so on the next boot the disk authenticates, the bypass never engages, and
+ SataDiskInitialize sizes the partitions to the flashed identity again regardless of what the
+ filesystem looks like.
+
+ So this also invalidates the security sector. Once it no longer authenticates, the bypass takes
+ over and lays out the partitions across the whole drive.
+
+ That means the sequence is:
+
+ 1. Hold LT at boot -> security sector wiped, partitions formatted for the full drive
+ 2. Reboot
+ 3. Disk no longer authenticates -> bypass runs -> full capacity available
+
+ This is destructive. Everything on the disk is lost.
+
+ Verifying the result
+ --------------------
+ After formatting, connect the drive to a PC and open it in FATXplorer. If it shows a valid
+ volume at the full size, the layout is right. Do that before putting anything on it.
+*/
+
+#include "XenonExports.h"
+
+// FATX volume header, at offset 0 of every partition. Values are big-endian DWORDs, matching what
+// a retail-formatted partition reads back as.
+#define FATX_MAGIC 0x58544146 // 'X','T','A','F'
+#define FATX_HEADER_SIZE 0x1000
+#define FATX_SECTORS_PER_CLUSTER 32 // 16 KB clusters, what retail uses
+#define FATX_ROOT_CLUSTER 1
+
+// A FAT holding this many clusters or more needs 32-bit entries instead of 16-bit.
+#define FATX_FAT16_CLUSTER_LIMIT 0xFFF0
+
+#define FATX_FAT_RESERVED0 0xFFFFFFF8 // media descriptor
+#define FATX_FAT_END_OF_CHAIN 0xFFFFFFFF
+
+// Byte offset of the sector the kernel authenticates against, and how much of it it reads.
+// Taken from SataDiskAuthenticateDevice itself (0x8015D9E4 onwards): it loads 0x2000 as a 64-bit
+// offset, asks for 0x200 bytes via IoSynchronousFsdRequest on the PhysicalDisk device, feeds the
+// result to XeKeysSetKey and compares the digest.
+//
+// Note this is NOT "sixteen sectors from the end of the drive". That was an unverified guess in
+// the project notes, and wiping there does nothing at all - the disk keeps authenticating.
+#define SECURITY_SECTOR_OFFSET 0x2000
+#define SECURITY_SECTOR_LENGTH 0x200
+
+/*
+ Wipes the security sector and writes fresh FATX volumes sized for the whole drive.
+
+ Returns TRUE only if every partition was written. On failure it stops at the first error rather
+ than leaving a partially formatted disk behind unreported.
+*/
+BOOLEAN FormatInternalDisk(void);
+
+/*
+ TRUE while the left trigger is held. Used to gate the format behind a deliberate action.
+*/
+BOOLEAN IsFormatRequested(void);
diff --git a/src/BadStorage-XEX/BadStorage/UnauthenticatedDisk.cpp b/src/BadStorage-XEX/BadStorage/UnauthenticatedDisk.cpp
new file mode 100644
index 0000000..715c844
--- /dev/null
+++ b/src/BadStorage-XEX/BadStorage/UnauthenticatedDisk.cpp
@@ -0,0 +1,156 @@
+// Unauthenticated disk support for Bad Storage.
+// Copyright © 2026. Licensed under the same MIT terms as Bad Storage.
+
+#include "stdafx.h"
+#include "UnauthenticatedDisk.h"
+#include "BadStorage.h"
+
+// Directory entry names are counted, not NUL-terminated.
+static BOOLEAN NameEquals(const CHAR* Buffer, USHORT Length, const CHAR* Expected)
+{
+ USHORT i = 0;
+ for (; i < Length; i++)
+ {
+ if (Expected[i] == '\0' || Buffer[i] != Expected[i]) return FALSE;
+ }
+ return Expected[i] == '\0';
+}
+
+// The geometry SataDiskInitialize would have written for a given partition.
+// Returns FALSE for names that are not hard disk partitions.
+static BOOLEAN GetPartitionGeometry(const CHAR* Name, USHORT NameLength, LONGLONG DiskSize, PLONGLONG Offset, PLONGLONG Length)
+{
+ if (NameEquals(Name, NameLength, "Partition0")) { *Offset = 0; *Length = DiskSize; }
+ else if (NameEquals(Name, NameLength, "Partition1")) { *Offset = UD_CONTENT_PARTITION_OFFSET; *Length = DiskSize - UD_CONTENT_PARTITION_OFFSET; }
+ else if (NameEquals(Name, NameLength, "Cache0")) { *Offset = UD_CACHE0_OFFSET; *Length = UD_CACHE_LENGTH; }
+ else if (NameEquals(Name, NameLength, "Cache1")) { *Offset = UD_CACHE1_OFFSET; *Length = UD_CACHE_LENGTH; }
+ else if (NameEquals(Name, NameLength, "DumpPartition")) { *Offset = UD_DUMP_OFFSET; *Length = UD_DUMP_LENGTH; }
+ else if (NameEquals(Name, NameLength, "SystemURLCachePartition")) { *Offset = UD_SYSTEM_URL_CACHE_OFFSET; *Length = UD_SYSTEM_URL_CACHE_LENGTH; }
+ else if (NameEquals(Name, NameLength, "TitleURLCachePartition")) { *Offset = UD_TITLE_URL_CACHE_OFFSET; *Length = UD_TITLE_URL_CACHE_LENGTH; }
+ else if (NameEquals(Name, NameLength, "SystemExtPartition")) { *Offset = UD_SYSTEM_EXT_OFFSET; *Length = UD_SYSTEM_EXT_LENGTH; }
+ else if (NameEquals(Name, NameLength, "SystemAuxPartition")) { *Offset = UD_SYSTEM_AUX_OFFSET; *Length = UD_SYSTEM_AUX_LENGTH; }
+ else if (NameEquals(Name, NameLength, "SystemPartition")) { *Offset = UD_SYSTEM_PARTITION_OFFSET; *Length = UD_SYSTEM_PARTITION_LENGTH; }
+ else if (NameEquals(Name, NameLength, "WindowsPartition")) { *Offset = 0; *Length = 0; }
+ else return FALSE;
+
+ return TRUE;
+}
+
+// Confirms a device really did become reachable by name.
+static BOOLEAN DeviceResolves(const PSZ Path)
+{
+ PDEVICE_OBJECT device = NULL;
+ OBJECT_STRING str;
+ RtlInitAnsiString(&str, Path);
+
+ NTSTATUS status = ObReferenceObjectByName(&str, 0, IoDeviceObjectType, NULL, (PVOID*)&device);
+ if (!NT_SUCCESS(status) || device == NULL)
+ {
+ Print("%s did not resolve: 0x%08X", Path, status);
+ return FALSE;
+ }
+
+ ObDereferenceObject(device);
+ return TRUE;
+}
+
+BOOLEAN InitializeUnauthenticatedDisk(ULONG* FixedCount)
+{
+ if (FixedCount != NULL) *FixedCount = 0;
+
+ // The drive's own reported capacity. Zero means the console never identified a disk at all,
+ // which is a lower-level problem than authentication and not something this can repair.
+ ULONG sectors = *(PULONG)SataDiskUserAddressableSectors_Offset;
+ if (sectors == 0)
+ {
+ Print("No disk identified, nothing to initialise.");
+ return FALSE;
+ }
+
+ LONGLONG diskSize = (LONGLONG)sectors * 512;
+ Print("Unauthenticated disk: %I64d bytes (%I64d MB).", diskSize, diskSize / (1024 * 1024));
+
+ // A disk smaller than the fixed system partition area cannot use this layout.
+ if (diskSize <= (LONGLONG)UD_CONTENT_PARTITION_OFFSET)
+ {
+ Print("Disk is too small for the standard partition layout.");
+ return FALSE;
+ }
+
+ // The partition devices are unreachable by name while DO_DEVICE_INITIALIZING is set, so go
+ // through the object directory instead.
+ PVOID directory = NULL;
+ OBJECT_STRING directoryStr;
+ RtlInitAnsiString(&directoryStr, HARDDISK0_DIRECTORY_PATH);
+
+ NTSTATUS status = ObReferenceObjectByName(&directoryStr, 0, ObDirectoryObjectType, NULL, &directory);
+ if (!NT_SUCCESS(status) || directory == NULL)
+ {
+ Print("ObReferenceObjectByName failed on %s: 0x%08X", HARDDISK0_DIRECTORY_PATH, status);
+ return FALSE;
+ }
+
+ ULONG fixed = 0;
+ PULONG buckets = (PULONG)directory;
+
+ for (ULONG bucket = 0; bucket < OBJECT_DIRECTORY_BUCKETS; bucket++)
+ {
+ ULONG entry = buckets[bucket];
+
+ // Bounded so a corrupted chain cannot spin forever.
+ for (ULONG depth = 0; entry != 0 && depth < 32; depth++)
+ {
+ USHORT nameLength = *(PUSHORT)(entry + OBJDIR_ENTRY_NAMELEN);
+ PCHAR nameBuffer = *(PCHAR*)(entry + OBJDIR_ENTRY_NAMEBUF);
+ ULONG next = *(PULONG)(entry + OBJDIR_ENTRY_NEXT);
+
+ if (nameLength != 0 && nameLength < 64 && nameBuffer != NULL)
+ {
+ PDEVICE_OBJECT device = (PDEVICE_OBJECT)(entry + OBJDIR_ENTRY_TO_OBJECT);
+
+ // Only touch devices still stuck mid-initialisation. On an authenticated disk
+ // there are none, so this whole loop does nothing.
+ if ((device->Flags & DO_DEVICE_INITIALIZING_360) == DO_DEVICE_INITIALIZING_360)
+ {
+ LONGLONG offset = 0, length = 0;
+ if (GetPartitionGeometry(nameBuffer, nameLength, diskSize, &offset, &length))
+ {
+ PPARTITION_INFORMATION info = &((PSATA_DISK_EXTENSION)device->DeviceExtension)->PartitionInformation;
+ info->StartingOffset.QuadPart = offset;
+ info->PartitionLength.QuadPart = length;
+
+ // The kernel's own final step for each device. Its instruction is
+ // "rlwinm rX, rX, 0, 28, 26", a wrapped mask whose only effect is to
+ // clear this bit.
+ device->Flags &= ~DO_DEVICE_INITIALIZING_360;
+
+ fixed++;
+ Print("Initialised %.*s: offset %I64d, length %I64d", nameLength, nameBuffer, offset, length);
+ }
+ }
+ }
+
+ entry = next;
+ }
+ }
+
+ ObDereferenceObject(directory);
+
+ if (FixedCount != NULL) *FixedCount = fixed;
+
+ if (fixed == 0)
+ {
+ Print("No uninitialised partition devices found.");
+ return FALSE;
+ }
+
+ // These two are what the dashboard actually needs, so they decide success.
+ if (!DeviceResolves(PARTITION_0_PATH) || !DeviceResolves(PARTITION_1_PATH))
+ {
+ Print("Partitions were written but still do not resolve.");
+ return FALSE;
+ }
+
+ Print("Initialised %u partition devices.", fixed);
+ return TRUE;
+}
diff --git a/src/BadStorage-XEX/BadStorage/UnauthenticatedDisk.h b/src/BadStorage-XEX/BadStorage/UnauthenticatedDisk.h
new file mode 100644
index 0000000..fb73240
--- /dev/null
+++ b/src/BadStorage-XEX/BadStorage/UnauthenticatedDisk.h
@@ -0,0 +1,100 @@
+// Unauthenticated disk support for Bad Storage.
+// Copyright © 2026. Licensed under the same MIT terms as Bad Storage.
+
+#pragma once
+
+/*
+ Lets a disk that never passed the console's security-sector check be used as internal storage.
+
+ Background
+ ----------
+ During boot, SataDiskInitialize does two separate things, in this order:
+
+ 1. BEFORE the authentication gate, it creates all twelve hard disk device objects
+ (PhysicalDisk, Partition0, Partition1, Cache0/1, DumpPartition, SystemPartition, ...)
+ by calling SataDiskCreateDevice -> IoCreateDevice.
+
+ 2. AFTER the gate, it fills in each device's PartitionInformation and clears
+ DO_DEVICE_INITIALIZING on it.
+
+ When SataDiskAuthenticateDevice fails, the gate branches straight to the function epilogue,
+ so step 2 never runs. The device objects therefore exist, but with a zeroed
+ PartitionInformation and DO_DEVICE_INITIALIZING still set. A device in that state makes
+ ObReferenceObjectByName return STATUS_NO_SUCH_DEVICE (0xC000000E) - note that this is *not*
+ STATUS_OBJECT_NAME_NOT_FOUND: the name resolves fine, it is the device that gets refused.
+
+ PhysicalDisk is the one exception and stays usable, because it is completed before the gate.
+
+ Approach
+ --------
+ Patching SataDiskAuthenticateDevice to return TRUE does not help. That gate is evaluated once,
+ early in boot, long before any exploit payload runs, and there is no warm reboot that would
+ re-run it while keeping patches in memory. (XeUnshackle already applies exactly that patch as
+ part of its Freeboot set, and it still is not enough.)
+
+ Instead, this finishes the initialisation the gate skipped: reach the device objects by walking
+ the \Device\Harddisk0 object directory - they cannot be reached by name, precisely because of
+ the flag - write each partition's geometry, and clear DO_DEVICE_INITIALIZING.
+
+ Everything written here is what SataDiskInitialize's own post-gate block computes; it was
+ recovered by disassembling that block instruction by instruction. Two independent checks say
+ the values are right: the resulting layout is perfectly contiguous, and Partition1's offset
+ comes out as 0x130EB0000, the same constant Bad Storage already hardcodes.
+
+ Scope
+ -----
+ This addresses authentication only. It requires a disk the console can already talk to and
+ identify, i.e. one that answers the ATA commands and reports its sector count. A drive whose
+ controller the console cannot negotiate with at all leaves SataDiskUserAddressableSectors at
+ zero, and there is nothing here to complete.
+*/
+
+#include "XenonExports.h"
+
+// On this kernel DO_DEVICE_INITIALIZING is 0x10, not the 0x80 it is on Windows.
+// From IoCreateDevice at 0x8006B00C: "li r11, 0x10" then "stw r11, 0x14(r10)".
+#define DO_DEVICE_INITIALIZING_360 0x10
+
+// The object directory is a 13-bucket hash table of chained entries.
+// From NtQueryDirectoryObject's own walk at 0x8008A22C-0x8008A264.
+#define OBJECT_DIRECTORY_BUCKETS 13
+
+// Offsets within a directory entry, same source.
+#define OBJDIR_ENTRY_NEXT 0x00
+#define OBJDIR_ENTRY_NAMELEN 0x08
+#define OBJDIR_ENTRY_NAMEBUF 0x0C
+
+// Distance from a directory entry to the object body it refers to.
+// Measured on hardware rather than assumed: the PhysicalDisk entry sat at 0x3A0A7C88 while
+// ObReferenceObjectByName returned 0x3A0A7CA8 for the same name.
+#define OBJDIR_ENTRY_TO_OBJECT 0x20
+
+// Byte offset of the content partition, and the fixed geometry of the system partitions.
+// All derived from SataDiskInitialize 0x8015DF28-0x8015E0D0.
+#define UD_CACHE0_OFFSET 0x80000ULL
+#define UD_CACHE1_OFFSET 0x80080000ULL
+#define UD_CACHE_LENGTH 0x80000000ULL
+#define UD_DUMP_OFFSET 0x100080000ULL
+#define UD_DUMP_LENGTH 0x20E30000ULL
+#define UD_SYSTEM_URL_CACHE_OFFSET 0x100080000ULL
+#define UD_SYSTEM_URL_CACHE_LENGTH 0x6000000ULL
+#define UD_TITLE_URL_CACHE_OFFSET 0x106080000ULL
+#define UD_TITLE_URL_CACHE_LENGTH 0x2000000ULL
+#define UD_SYSTEM_EXT_OFFSET 0x10C080000ULL
+#define UD_SYSTEM_EXT_LENGTH 0xCE30000ULL
+#define UD_SYSTEM_AUX_OFFSET 0x118EB0000ULL
+#define UD_SYSTEM_AUX_LENGTH 0x8000000ULL
+#define UD_SYSTEM_PARTITION_OFFSET 0x120EB0000ULL
+#define UD_SYSTEM_PARTITION_LENGTH 0x10000000ULL
+#define UD_CONTENT_PARTITION_OFFSET 0x130EB0000ULL
+
+#define HARDDISK0_DIRECTORY_PATH "\\Device\\Harddisk0"
+
+/*
+ Completes the partition device objects the authentication gate left half-initialised.
+
+ Returns TRUE only if Partition0 and Partition1 both resolve by name afterwards, which is the
+ real proof that the devices became usable. Safe to call when nothing needs fixing: devices that
+ are already initialised are skipped, so a second call is a no-op.
+*/
+BOOLEAN InitializeUnauthenticatedDisk(ULONG* FixedCount);
diff --git a/src/BadStorage-XEX/BadStorage/XenonExports.h b/src/BadStorage-XEX/BadStorage/XenonExports.h
index 80d1028..6fcbbef 100644
--- a/src/BadStorage-XEX/BadStorage/XenonExports.h
+++ b/src/BadStorage-XEX/BadStorage/XenonExports.h
@@ -765,6 +765,7 @@ EXTERN_C
extern PXBOX_KRNL_VERSION XboxKrnlVersion;
extern PXBOX_HARDWARE_INFO XboxHardwareInfo;
extern PVOID IoDeviceObjectType;
+ extern PVOID ObDirectoryObjectType;
HRESULT
WINAPI