]> FriiDump Source - friidump.git/blob - libfriidump/xbox_ref/unlock.c
FriiDump 0.5.3.16: finalize release identity and documentation
[friidump.git] / libfriidump / xbox_ref / unlock.c
1 #include "unlock.h"
2 #include "scsi_structs.h"
3 #include "rc4.h"
4 #include "sha1.h"
5 #include "utils.h"
6 #include "xbox_ref_log.h"
7
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <windows.h>
12 #include <stddef.h>
13
14 #define printf xbox_ref_printf
15
16 static uint8_t scsibuffer[2001];
17 static TRC4Context rc4key;
18
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)
24         console_limit = 32;
25     xbox_ref_log_hexdump(prefix, data, (size_t)length, console_limit);
26 }
27
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);
32     DWORD Returned;
33     BOOL Status;
34     int i, k, l;
35     int chalpos[11];
36     uint8_t restable[261];
37     uint8_t hash[0x2C];
38     uint8_t shadigest[20];
39     uint8_t shastring[20];
40
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;
53
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);
56     
57     if (Status) {
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)  | 
62                                scsibuffer[3];
63         printf("Initial Max LBA: %u\n", maxLBA);
64         PrintFormattedCapacity(scsibuffer);
65     } else {
66         printf("Fatal error: Initial capacity read failed (Error %lu).\n", GetLastError());
67         return;
68     }
69
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;
83     
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);
87
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;
102     
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);
106
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);
119         
120         SPTDW.Spt.Cdb[0] = 0xFD; 
121         SPTDW.Spt.Cdb[1] = 0x01; 
122         SPTDW.Spt.Cdb[8] = 0x06;
123         SPTDW.Spt.Cdb[9] = 0x64;
124
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);
128
129         if (!Status || scsibuffer[772] != 1) {
130             printf("Fatal error: Invalid host challenge table (Both methods failed).\n");
131             return;
132         }
133         printf("Success: Acquired Hitachi 0xFD Handshake Table!\n");
134     }
135
136     // --- CRYPTO: SHA1 & RC4 ---
137     for (i = 0; i < 0x2C; i++) hash[i] = scsibuffer[0x4A3 + i];
138     {
139         SHA1_CTX ctx;
140         SHA1_Init(&ctx);
141         SHA1_Update(&ctx, hash, 0x2C);
142         SHA1_Final(shadigest, &ctx);
143     }
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);
148
149     k = 0;
150     for (l = 0; l <= 23; l++) {
151         if (restable[l * 11] == 1) {
152             chalpos[k] = l;
153             k++;
154         }
155     }
156
157     if (k < 2) {
158         printf("Fatal error: Not enough usable challenge entries.\n");
159         return;
160     }
161
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);
177     
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);
181
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;
193     
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);
197     
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);
213     
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);
217
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;
229     
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);
233
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);
250     
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);
253     
254     Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
255     if (Status) {
256         printf("Partition 1 Unlocked Successfully.\n");
257     }
258
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;
274     
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);
278
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;
290     
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);
293     
294     if (Status) {
295         LogHexDump("Received Data [Step 10: Final Verify]", scsibuffer, SPTDW.Spt.DataTransferLength);
296         PrintFormattedCapacity(scsibuffer);
297     }
298 }
299
300 // AI CODE
301 BOOL AuthenticateXboxMedia(HANDLE hDevice) {
302     SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptdw = {0};
303     DWORD bytesReturned;
304     
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]; 
308
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);
316
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;
323
324     return DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptdw, sizeof(sptdw), &sptdw, sizeof(sptdw), &bytesReturned, NULL);
325 }
326
327 // ORIGINAL CODE
328 BOOL ORIGINAL_AuthenticateXboxMedia(HANDLE hDevice) {
329     SCSI_PASS_THROUGH_DIRECT sptd = {0};
330     DWORD bytesReturned;
331     unsigned char cdb[10] = {0};
332
333     sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
334     sptd.CdbLength = 10;
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;
339
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.
345
346     return DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &bytesReturned, NULL);
347 }
348
349
350 BOOL KickXboxMediaAuth(HANDLE hDevice)
351 {
352     if (AuthenticateXboxMedia(hDevice))
353         return TRUE;
354
355     return ORIGINAL_AuthenticateXboxMedia(hDevice);
356 }