2 #include "scsi_structs.h"
6 #include "xbox_ref_log.h"
14 #define printf xbox_ref_printf
16 static uint8_t scsibuffer[2001];
17 static TRC4Context rc4key;
19 // Helper function to log hex dumps cleanly to the console and to the untruncated log file.
20 static void LogHexDump(const char* prefix, const uint8_t* data, DWORD length) {
21 size_t console_limit = 0;
22 if (!data || length == 0) return;
23 if (prefix && strcmp(prefix, "Received Data [Step 3: Read DVD Struct 0xAD]") == 0)
25 xbox_ref_log_hexdump(prefix, data, (size_t)length, console_limit);
28 void UnlockDrive(HANDLE AHandle) {
29 printf("Structure size: %zu\n", sizeof(SCSI_PASS_THROUGH_DIRECT));
30 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER SPTDW;
31 DWORD Size = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
36 uint8_t restable[261];
38 uint8_t shadigest[20];
39 uint8_t shastring[20];
41 // --- STEP 1: INITIAL READ CAPACITY ---
42 ZeroMemory(&SPTDW, sizeof(SPTDW));
43 ZeroMemory(scsibuffer, sizeof(scsibuffer));
44 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
45 SPTDW.Spt.CdbLength = 10;
46 SPTDW.Spt.SenseInfoLength = 32;
47 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
48 SPTDW.Spt.DataTransferLength = 8;
49 SPTDW.Spt.TimeOutValue = 120;
50 SPTDW.Spt.DataBuffer = scsibuffer;
51 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
52 SPTDW.Spt.Cdb[0] = 0x25;
54 LogHexDump("Sending CDB [Step 1: Init Read Cap]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
55 Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
58 LogHexDump("Received Data [Step 1: Init Read Cap]", scsibuffer, SPTDW.Spt.DataTransferLength);
59 unsigned int maxLBA = (scsibuffer[0] << 24) |
60 (scsibuffer[1] << 16) |
61 (scsibuffer[2] << 8) |
63 printf("Initial Max LBA: %u\n", maxLBA);
64 PrintFormattedCapacity(scsibuffer);
66 printf("Fatal error: Initial capacity read failed (Error %lu).\n", GetLastError());
70 // --- STEP 2: MODE SENSE (Page 0x3E) ---
71 memset(&SPTDW, 0, sizeof(SPTDW));
72 memset(scsibuffer, 0, 2000);
73 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
74 SPTDW.Spt.CdbLength = 10;
75 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
76 SPTDW.Spt.DataTransferLength = 28;
77 SPTDW.Spt.TimeOutValue = 120;
78 SPTDW.Spt.DataBuffer = scsibuffer;
79 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
80 SPTDW.Spt.Cdb[0] = 0x5A;
81 SPTDW.Spt.Cdb[2] = 0x3E;
82 SPTDW.Spt.Cdb[8] = 0x1C;
84 LogHexDump("Sending CDB [Step 2: Mode Sense]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
85 Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
86 if (Status) LogHexDump("Received Data [Step 2: Mode Sense]", scsibuffer, SPTDW.Spt.DataTransferLength);
88 // --- STEP 3: READ DVD STRUCTURE (The Challenge Table) ---
89 memset(&SPTDW, 0, sizeof(SPTDW));
90 memset(scsibuffer, 0, 2000);
91 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
92 SPTDW.Spt.CdbLength = 12;
93 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
94 SPTDW.Spt.DataTransferLength = 0x664;
95 SPTDW.Spt.TimeOutValue = 120;
96 SPTDW.Spt.DataBuffer = scsibuffer;
97 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
98 SPTDW.Spt.Cdb[0] = 0xAD;
99 SPTDW.Spt.Cdb[2] = 0xFF; SPTDW.Spt.Cdb[3] = 0x02; SPTDW.Spt.Cdb[4] = 0xFD;
100 SPTDW.Spt.Cdb[5] = 0xFF; SPTDW.Spt.Cdb[6] = 0xFE; SPTDW.Spt.Cdb[8] = 0x06;
101 SPTDW.Spt.Cdb[9] = 0x64; SPTDW.Spt.Cdb[11] = 0xC0;
103 LogHexDump("Sending CDB [Step 3: Read DVD Struct 0xAD]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
104 Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
105 if (Status) LogHexDump("Received Data [Step 3: Read DVD Struct 0xAD]", scsibuffer, SPTDW.Spt.DataTransferLength);
107 // Fallback Logic for Hitachi 4241N Drives
108 if (!Status || scsibuffer[772] != 1 || scsibuffer[773] == 0) {
109 printf("8050L Table Invalid. Attempting Hitachi 0xFD Fallback...\n");
110 memset(&SPTDW, 0, sizeof(SPTDW));
111 memset(scsibuffer, 0, 2000);
112 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
113 SPTDW.Spt.CdbLength = 12;
114 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
115 SPTDW.Spt.DataTransferLength = 0x664;
116 SPTDW.Spt.TimeOutValue = 120;
117 SPTDW.Spt.DataBuffer = scsibuffer;
118 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
120 SPTDW.Spt.Cdb[0] = 0xFD;
121 SPTDW.Spt.Cdb[1] = 0x01;
122 SPTDW.Spt.Cdb[8] = 0x06;
123 SPTDW.Spt.Cdb[9] = 0x64;
125 LogHexDump("Sending CDB [Step 3: Read DVD Struct Fallback 0xFD]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
126 Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
127 if (Status) LogHexDump("Received Data [Step 3: Read DVD Struct Fallback 0xFD]", scsibuffer, SPTDW.Spt.DataTransferLength);
129 if (!Status || scsibuffer[772] != 1) {
130 printf("Fatal error: Invalid host challenge table (Both methods failed).\n");
133 printf("Success: Acquired Hitachi 0xFD Handshake Table!\n");
136 // --- CRYPTO: SHA1 & RC4 ---
137 for (i = 0; i < 0x2C; i++) hash[i] = scsibuffer[0x4A3 + i];
141 SHA1_Update(&ctx, hash, 0x2C);
142 SHA1_Final(shadigest, &ctx);
144 memcpy(shastring, shadigest, 7);
145 RC4Init(&rc4key, shastring, 7);
146 for (i = 0; i <= 260; i++) restable[i] = scsibuffer[774 + i];
147 rc4Decrypt(restable, restable, 0xFD, &rc4key);
150 for (l = 0; l <= 23; l++) {
151 if (restable[l * 11] == 1) {
158 printf("Fatal error: Not enough usable challenge entries.\n");
162 // --- STEP 4: MODE SELECT (First Challenge) ---
163 memset(&SPTDW, 0, sizeof(SPTDW));
164 memset(scsibuffer, 0, 2000);
165 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
166 SPTDW.Spt.CdbLength = 10;
167 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
168 SPTDW.Spt.DataTransferLength = 28;
169 SPTDW.Spt.TimeOutValue = 120;
170 SPTDW.Spt.DataBuffer = scsibuffer;
171 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
172 SPTDW.Spt.Cdb[0] = 0x55; SPTDW.Spt.Cdb[8] = 0x1C;
173 scsibuffer[1] = 0x1A; scsibuffer[8] = 0x3E;
174 scsibuffer[9] = 0x12;
175 scsibuffer[11] = 0x01; scsibuffer[13] = 0xD1; scsibuffer[14] = 0x01;
176 memcpy(&scsibuffer[15], &restable[1 + chalpos[k - 2] * 11], 5);
178 LogHexDump("Sending CDB [Step 4: Mode Select Chal 1]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
179 LogHexDump("Sending Data [Step 4: Mode Select Chal 1]", scsibuffer, SPTDW.Spt.DataTransferLength);
180 DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
182 // --- STEP 5: MODE SENSE (Verify First Challenge) ---
183 memset(&SPTDW, 0, sizeof(SPTDW));
184 memset(scsibuffer, 0, 2000);
185 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
186 SPTDW.Spt.CdbLength = 10;
187 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
188 SPTDW.Spt.DataTransferLength = 28;
189 SPTDW.Spt.TimeOutValue = 120;
190 SPTDW.Spt.DataBuffer = scsibuffer;
191 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
192 SPTDW.Spt.Cdb[0] = 0x5A; SPTDW.Spt.Cdb[2] = 0x3E; SPTDW.Spt.Cdb[8] = 0x1C;
194 LogHexDump("Sending CDB [Step 5: Mode Sense Verify 1]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
195 Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
196 if (Status) LogHexDump("Received Data [Step 5: Mode Sense Verify 1]", scsibuffer, SPTDW.Spt.DataTransferLength);
198 // --- STEP 6: MODE SELECT (Second Challenge) ---
199 memset(&SPTDW, 0, sizeof(SPTDW));
200 memset(scsibuffer, 0, 2000);
201 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
202 SPTDW.Spt.CdbLength = 10;
203 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
204 SPTDW.Spt.DataTransferLength = 28;
205 SPTDW.Spt.TimeOutValue = 120;
206 SPTDW.Spt.DataBuffer = scsibuffer;
207 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
208 SPTDW.Spt.Cdb[0] = 0x55; SPTDW.Spt.Cdb[8] = 0x1C;
209 scsibuffer[1] = 0x1A; scsibuffer[8] = 0x3E;
210 scsibuffer[9] = 0x12;
211 scsibuffer[12] = 0x01; // Marker for second challenge
212 memcpy(&scsibuffer[15], &restable[1 + chalpos[k - 1] * 11], 5);
214 LogHexDump("Sending CDB [Step 6: Mode Select Chal 2]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
215 LogHexDump("Sending Data [Step 6: Mode Select Chal 2]", scsibuffer, SPTDW.Spt.DataTransferLength);
216 DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
218 // --- STEP 7: MODE SENSE (Verify Second Challenge) ---
219 memset(&SPTDW, 0, sizeof(SPTDW));
220 memset(scsibuffer, 0, 2000);
221 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
222 SPTDW.Spt.CdbLength = 10;
223 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
224 SPTDW.Spt.DataTransferLength = 28;
225 SPTDW.Spt.TimeOutValue = 120;
226 SPTDW.Spt.DataBuffer = scsibuffer;
227 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
228 SPTDW.Spt.Cdb[0] = 0x5A; SPTDW.Spt.Cdb[2] = 0x3E; SPTDW.Spt.Cdb[8] = 0x1C;
230 LogHexDump("Sending CDB [Step 7: Mode Sense Verify 2]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
231 Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
232 if (Status) LogHexDump("Received Data [Step 7: Mode Sense Verify 2]", scsibuffer, SPTDW.Spt.DataTransferLength);
234 // --- STEP 8: FINAL MODE SELECT (Partition 1 Unlock) ---
235 memset(&SPTDW, 0, sizeof(SPTDW));
236 memset(scsibuffer, 0, 2000);
237 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
238 SPTDW.Spt.CdbLength = 10;
239 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
240 SPTDW.Spt.DataTransferLength = 28;
241 SPTDW.Spt.TimeOutValue = 120;
242 SPTDW.Spt.DataBuffer = scsibuffer;
243 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
244 SPTDW.Spt.Cdb[0] = 0x55; SPTDW.Spt.Cdb[8] = 0x1C;
245 scsibuffer[1] = 0x1A; scsibuffer[8] = 0x3E;
246 scsibuffer[9] = 0x12;
247 scsibuffer[10] = 0x01; scsibuffer[11] = 0x01; scsibuffer[12] = 0x01;
248 scsibuffer[13] = 0xD1; scsibuffer[14] = 0x01;
249 memcpy(&scsibuffer[15], &restable[1 + chalpos[k - 1] * 11], 5);
251 LogHexDump("Sending CDB [Step 8: Mode Select Part1 Unlock]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
252 LogHexDump("Sending Data [Step 8: Mode Select Part1 Unlock]", scsibuffer, SPTDW.Spt.DataTransferLength);
254 Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
256 printf("Partition 1 Unlocked Successfully.\n");
259 // --- STEP 9: ENABLE STICKY DESCRAMBLING (Mode 0x31) ---
260 printf("Enabling Sticky Descrambling (Mode 0x31)...\n");
261 memset(&SPTDW, 0, sizeof(SPTDW));
262 memset(scsibuffer, 0, 2000);
263 scsibuffer[4] = 0x31; scsibuffer[5] = 0x06; scsibuffer[6] = 0x01;
264 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
265 SPTDW.Spt.CdbLength = 6;
266 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
267 SPTDW.Spt.DataTransferLength = 12;
268 SPTDW.Spt.TimeOutValue = 10;
269 SPTDW.Spt.DataBuffer = scsibuffer;
270 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
271 SPTDW.Spt.Cdb[0] = 0x15;
272 SPTDW.Spt.Cdb[1] = 0x11;
273 SPTDW.Spt.Cdb[4] = 12;
275 LogHexDump("Sending CDB [Step 9: Sticky Descrambling]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
276 LogHexDump("Sending Data [Step 9: Sticky Descrambling]", scsibuffer, SPTDW.Spt.DataTransferLength);
277 DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
279 // --- STEP 10: FINAL CAPACITY VERIFICATION ---
280 memset(&SPTDW, 0, sizeof(SPTDW));
281 memset(scsibuffer, 0, 2000);
282 SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
283 SPTDW.Spt.CdbLength = 10;
284 SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
285 SPTDW.Spt.DataTransferLength = 8;
286 SPTDW.Spt.TimeOutValue = 120;
287 SPTDW.Spt.DataBuffer = scsibuffer;
288 SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
289 SPTDW.Spt.Cdb[0] = 0x25;
291 LogHexDump("Sending CDB [Step 10: Final Verify]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
292 Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
295 LogHexDump("Received Data [Step 10: Final Verify]", scsibuffer, SPTDW.Spt.DataTransferLength);
296 PrintFormattedCapacity(scsibuffer);
301 BOOL AuthenticateXboxMedia(HANDLE hDevice) {
302 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptdw = {0};
305 // We need a small buffer because 0xAD usually expects to return data,
306 // even if our custom handler just uses it as a trigger.
307 uint8_t dummy_buffer[8];
309 sptdw.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
310 sptdw.Spt.CdbLength = 12; // 0xAD is a 12-byte command
311 sptdw.Spt.DataIn = SCSI_IOCTL_DATA_IN;
312 sptdw.Spt.TimeOutValue = 10;
313 sptdw.Spt.DataTransferLength = sizeof(dummy_buffer);
314 sptdw.Spt.DataBuffer = dummy_buffer;
315 sptdw.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
317 // --- The 8050L / 4241N Hook Command ---
318 sptdw.Spt.Cdb[0] = 0xAD; // READ DVD STRUCTURE
319 sptdw.Spt.Cdb[2] = 0xFF;
320 sptdw.Spt.Cdb[3] = 0x02;
321 sptdw.Spt.Cdb[4] = 0xFD; // MAGIC BYTE: Our Gatekeeper at 0x90002670 listens for this
322 sptdw.Spt.Cdb[11] = 0xC0;
324 return DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptdw, sizeof(sptdw), &sptdw, sizeof(sptdw), &bytesReturned, NULL);
328 BOOL ORIGINAL_AuthenticateXboxMedia(HANDLE hDevice) {
329 SCSI_PASS_THROUGH_DIRECT sptd = {0};
331 unsigned char cdb[10] = {0};
333 sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
335 sptd.DataIn = SCSI_IOCTL_DATA_IN;
336 sptd.TimeOutValue = 5;
337 sptd.DataTransferLength = 0; // No data transfer for this command
338 sptd.DataBuffer = NULL;
340 // THE MAGIC LG GDR-8163B UNLOCK COMMAND
341 sptd.Cdb[0] = 0xFF; // Vendor Specific
342 sptd.Cdb[1] = 0x08; // Sub-command: Set Xbox Mode
343 sptd.Cdb[2] = 0x01; // Enable
344 // Note: Some firmwares use 0x01, some use 0xFF. Try 0x01 first.
346 return DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &bytesReturned, NULL);
350 BOOL KickXboxMediaAuth(HANDLE hDevice)
352 if (AuthenticateXboxMedia(hDevice))
355 return ORIGINAL_AuthenticateXboxMedia(hDevice);