{"id":4195,"date":"2013-10-20T21:39:46","date_gmt":"2013-10-21T04:39:46","guid":{"rendered":"http:\/\/multimedia.cx\/eggs\/?p=4195"},"modified":"2015-06-16T21:28:55","modified_gmt":"2015-06-17T04:28:55","slug":"xbox-sphinx-protocol","status":"publish","type":"post","link":"https:\/\/multimedia.cx\/eggs\/xbox-sphinx-protocol\/","title":{"rendered":"Xbox Sphinx Protocol"},"content":{"rendered":"<p>I&#8217;ve gone down the rabbit hole of trying to read the Xbox DVD drive from Linux. Honestly, I&#8217;m trying to remember why I even care at this point. Perhaps it&#8217;s just my metagame of trying to understand how games and related technologies operate. In <a href=\"http:\/\/multimedia.cx\/eggs\/interfacing-to-an-xbox-optical-drive\/\">my last post of the matter<\/a>, I determined that it is possible to hook an Xbox drive up to a PC using a standard 40-pin IDE interface and read data sectors. However, I learned that just because the Xbox optical drive is reading an Xbox disc, that doesn&#8217;t mean it&#8217;s just going to read the sectors in response to a host request.<\/p>\n<p><em>Oh goodness, no. The drive is going to make the host <strong>work<\/strong> for those sectors.<\/em><\/p>\n<p>To help understand the concept of locked\/unlocked sectors on an Xbox disc, I offer this simplistic diagram:<\/p>\n<p><center><br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/multimedia.cx\/eggs\/wp-content\/uploads\/2013\/10\/Xbox-Locked-Disc.png\" alt=\"Xbox locked disc diagram\" width=\"366\" height=\"229\" class=\"aligncenter size-full wp-image-4197\" srcset=\"https:\/\/multimedia.cx\/eggs\/wp-content\/uploads\/2013\/10\/Xbox-Locked-Disc.png 366w, https:\/\/multimedia.cx\/eggs\/wp-content\/uploads\/2013\/10\/Xbox-Locked-Disc-300x187.png 300w\" sizes=\"auto, (max-width: 366px) 100vw, 366px\" \/><br \/>\n<\/center><\/p>\n<p>Any DVD drive (including the Xbox drive) is free to read those first 6992 sectors (about 14 MB of data) which just contain a short DVD video asking the user to insert the disc into a proper Xbox console. Reading the remaining sectors involves performing a sequence of SCSI commands that I have taken to calling the &#8220;Sphinx Protocol&#8221; for reasons I will explain later in this post.<\/p>\n<p><strong>References<\/strong><br \/>\nDoing a little Googling after my last post on the matter produced <a href=\"http:\/\/home.comcast.net\/~admiral_powerslave\/\">this site hosting deep, technical Xbox information<\/a>. It even has a page about exactly what I am trying to achieve: <a href=\"http:\/\/home.comcast.net\/~admiral_powerslave\/xbdvdtopc.html\">Use an Xbox DVD Drive in Your PC<\/a>. The page provides a tool named <a href=\"http:\/\/home.comcast.net\/~admiral_powerslave\/files\/dvdunlocker.zip\">dvdunlocker<\/a> written by &#8220;The Specialist&#8221; to perform the necessary unlocking. The archive includes a compiled Windows binary as well as its source code. The source code is written in Delphi Pascal and leverages Windows SCSI APIs. Still, it is well commented and provides a roadmap, which I will try to describe in this post.<\/p>\n<p><strong>Sphinx Protocol<\/strong><br \/>\nHere is a rough flowchart of the steps that are (probably) involved in the unlocking of those remaining sectors. I reverse engineered this based on the Pascal tool described in the previous section. <strong>Disclaimer:<\/strong> at the time of this writing, I haven&#8217;t tested all of the steps due to some Linux kernel problems, described later.<\/p>\n<p><!--more--><\/p>\n<p><center><br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/multimedia.cx\/eggs\/wp-content\/uploads\/2013\/10\/Xbox-SCSI-Unlock-Protocol.png\" alt=\"Xbox SCSI Unlock Protocol\" width=\"533\" height=\"673\" class=\"aligncenter size-full wp-image-4198\" srcset=\"https:\/\/multimedia.cx\/eggs\/wp-content\/uploads\/2013\/10\/Xbox-SCSI-Unlock-Protocol.png 533w, https:\/\/multimedia.cx\/eggs\/wp-content\/uploads\/2013\/10\/Xbox-SCSI-Unlock-Protocol-237x300.png 237w\" sizes=\"auto, (max-width: 533px) 100vw, 533px\" \/><br \/>\n<\/center><\/p>\n<p>Concerning the challenge\/response table that the drive sends back, it&#8217;s large (0x664 \/ 1636 bytes), and not all of the bytes&#8217; meanings are known. However, these are the bytes that seem to be necessary (all multi-byte numbers are big endian):<\/p>\n<pre>\r\n bytes 0-1        Size of mode page payload data (should be 0x0662)\r\n bytes 2-771      Unknown\r\n byte  772        Should be 1\r\n byte  773        Number of entries in challenge\/response table\r\n bytes 774-1026   Encrypted challenge\/response table\r\n bytes 1027-1186  Unknown\r\n bytes 1187-1230  Key basis (44 bytes)\r\n bytes 1231-1635  Unknown\r\n<\/pre>\n<p>The challenge\/response table is the interesting part, but it&#8217;s encrypted with <a href=\"http:\/\/en.wikipedia.org\/wiki\/RC4\">RC4 a.k.a. ARCFOUR<\/a>. The key is derived from the 44 bytes I have labeled &#8220;key basis&#8221;&#8211; cryptographic literature probably has a better term for it; chime in if you know what that might be. An <a href=\"http:\/\/en.wikipedia.org\/wiki\/SHA-1\">SHA-1 hash<\/a> is computed over the 44 bytes.<\/p>\n<p>The resulting SHA-1 hash &#8212; the first part of it, to be exact &#8212; is fed as the key into the RC4 decryption. The output of SHA-1 contains 160 bits of information. 160 \/ 8 = 20 bytes of information. To express this as a printable hex digest requires 40 characters. The SHA-1 hash is converted to a hex digest and then the first 7 of the characters are fed into the RC4 initialization function as the key. Then, the RC4 decrypter does its work on the 253 bytes of the challenge\/response table.<\/p>\n<p><em>So that&#8217;s why I took to calling this the <strong>&#8220;Sphinx Protocol&#8221;<\/strong> &#8212; I felt like I was being challenged with a bizarre riddle. Perhaps that describes a lot of cryptosystems, though you have to admit it sounds kind of cool.<\/em><\/p>\n<p>The challenge\/response table contains 23 11-byte records. The format of this table is (again, multi-byte numbers are big-endian):<\/p>\n<pre>\r\n byte  0     This is 1 if this challenge\/response pair is valid\r\n byte  1     Challenge ID\r\n bytes 2-5   Challenge\r\n byte  6     Response ID\r\n bytes 7-10  Response\r\n<\/pre>\n<p><strong>Example<\/strong><br \/>\nIt&#8217;s useful to note that the challenge\/response table and associated key is different for every disc (at least all the ones I have looked at). So this might be data that comes from the disc, since the values will always be the same for a given disc.<\/p>\n<p>Let&#8217;s examine Official Xbox Magazine disc #16 (Indiana Jones and The Emperor&#8217;s Tomb):<\/p>\n<p><center><br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/multimedia.cx\/eggs\/wp-content\/uploads\/2013\/10\/xbox-magazine-16-indiana-jones.jpg\" alt=\"Xbox Magazine #16 featuring Indiana Jones\" width=\"250\" height=\"225\" class=\"aligncenter size-full wp-image-4207\" \/><br \/>\n<\/center><\/p>\n<p>Before I decrypt the challenge\/response table, it looks like this:<\/p>\n<pre>\r\n   0: 180, 172: 0xEB100059;  66: 0xD56AFB56\r\n   1:  34,  71: 0x8F9BF03A; 192: 0xC32CBDF8\r\n   2: 226, 216: 0xA29B77F2;  12: 0x4474A6F1\r\n   3:  72, 122: 0x9F5ABF33; 255: 0xC5E3C304\r\n   4:   1, 103: 0x76142ADA; 233: 0xDE145D42 ****\r\n   5:  49, 193: 0xA1CD6192; 189: 0x2169DBA5\r\n   6: 182, 250: 0x9977894F;  96: 0x5A929E2B\r\n   7: 148,  71: 0x6DD10A54; 115: 0xF0BDAC4F\r\n   8:  12,  45: 0x5D5EB6FD; 148: 0x84E60A00\r\n   9:  99, 121: 0xFEAED372; 201: 0xDA9986F9\r\n  10: 172, 230: 0xE6C0D0B4; 214: 0x9050C250\r\n  11:  84,  65: 0x95CB8775; 104: 0x550886C6\r\n  12: 210,  65: 0x1ED23619; 171: 0x6DF4A35B\r\n  13:   2, 155: 0xD0AAE1E0; 130: 0x00D1FFCF\r\n  14:  40,   2: 0x172EFEB8; 159: 0x37E03E50\r\n  15:  49,  15: 0x43E5E378; 223: 0x267F9C9A\r\n  16: 240, 173: 0x357D5D1C; 250: 0x24965D67\r\n  17:  80, 184: 0x5E7AF1A3;  81: 0x3A8F69A7\r\n  18: 154, 186: 0x6626BEAC; 245: 0xE639540A\r\n  19: 231, 249: 0xFABAAFB7; 227: 0x4C686A07\r\n  20: 150, 186: 0x9A6D7AA3; 133: 0x25971CF0\r\n  21: 236, 192: 0x5CD97DD4; 247: 0x26655EFB\r\n  22:  68, 173: 0xE2D372E4; 207: 0x103FBF94\r\nthere are 1 valid pairs in the list: 4\r\n<\/pre>\n<p>My best clue that it&#8217;s not right is that there is only 1 valid entry (denoted by my tool using ****). The source I reverse engineered for this data indicates that there needs to be at least 2 valid pairs. After running the RC4 decryption on the table, it looks like this and I get far more valid pairs:<\/p>\n<pre>\r\n   0:   1, 174: 0xBD628255;   0: 0x9F0A31AF ****\r\n   1:   2, 176: 0x3151B341;   2: 0x9C87C180\r\n   2:   3, 105: 0x018879E5;   1: 0xFF068B5C\r\n   3:   2,   7: 0x1F316AAF;   3: 0xF420D3ED\r\n   4:   3,  73: 0xC2EBFBE9;   0: 0x17062B5B\r\n   5: 252, 163: 0xFF14B5CB; 236: 0xAF813FBC\r\n   6:   2, 233: 0x5EE95C49;   1: 0x37AA5511\r\n   7:   1, 126: 0xBD628255;   0: 0x5BA3FBD4 ****\r\n   8:   3,   4: 0xB68BFEE6;   3: 0xA8F3B918\r\n   9:   3,  32: 0xEA614943;   2: 0xA678D715\r\n  10:   2, 248: 0x1BDD374E;   0: 0x8D2AC2C7\r\n  11:   3,  17: 0x0EABCE81;   2: 0xC90A7242\r\n  12:   1, 186: 0xBD628255;   0: 0xC4820242 ****\r\n  13:   3, 145: 0xB178F942;   3: 0x4D78AD62\r\n  14:   3,  37: 0x4A6CE5E2;   2: 0xBF94E1C6\r\n  15:   1, 102: 0xBD628255;   0: 0xFFB83D8D ****\r\n  16:   3, 122: 0xF97B0905;   1: 0x38533125\r\n  17:   3, 197: 0x57A6865D;   2: 0xA61D31EF\r\n  18:   3,  27: 0xC7227D7C;   2: 0xA3F9BA1E\r\n  19:   1,  16: 0xBD628255;   0: 0x8557CCC8 ****\r\n  20:   2,  53: 0x1DA9D156;   3: 0xC9051754\r\n  21:   2,  90: 0x3CD66BEE;   3: 0xFD851D3E\r\n  22:   1, 252: 0xBD628255;   0: 0xB3F22701 ****\r\nthere are 6 valid pairs in the list: 0 7 12 15 19 22\r\n<\/pre>\n<p>So, hopefully, I have the decryption correct.<\/p>\n<p>Also of note is that you only get one chance to get this unlocking correct&#8211; fail, and the drive won&#8217;t return a valid DVD structure block again. You will either need to reboot the Xbox or eject &#038; close the tray before you get to try again.<\/p>\n<p><strong>Problems Making It Work In Linux<\/strong><br \/>\nThere are a couple of ways to play with SCSI protocols under Linux. In more recent kernels, block devices are named \/dev\/sda, \/dev\/sdb, etc. Each of these block devices has a corresponding character device named \/dev\/sg0, \/dev\/sg1, etc. &#8216;sg&#8217; stands for SCSI generic. This character devices can be opened as readable and\/or writable and SCSI commands can be freely written with write() and data retrieved with read(). Pretty powerful.<\/p>\n<p>Except that the one machine I still possess which supports 40-pin IDE\/ATAPI devices is running Linux kernel 2.6.24 which dates back to early 2008 and it still enumerates the IDE block devices as \/dev\/hda, \/dev\/hdb, etc. There are no corresponding \/dev\/sgX character devices. What to do? It seems that a program can still issue SCSI commands using <a href=\"http:\/\/www.tldp.org\/HOWTO\/SCSI-Generic-HOWTO\/sg_io.html\">an ioctl() facility named SG_IO<\/a>.<\/p>\n<p>I was able to make the SG_IO ioctl() work for the most part (except for the discovery that the Xbox drive doesn&#8217;t respond to a basic SCSI Inquiry command). However, I ran into a serious limitation&#8211; a program can only open a \/dev\/hdX block device in read-only mode if the device corresponds to a read-only drive like, for example, a DVD-ROM drive. This means that a program can&#8217;t issue SCSI mode select commands to the drive, which counts as writing. This means that my tool can&#8217;t unlock the drive.<\/p>\n<p><strong>Current Status<\/strong><br \/>\nSo this is where my experiment is blocked right now. I have been trying to compile various Linux kernels to remedy the situation. But I always seem to find myself stuck in one of 2 situations, depending on the configuration options I choose: Either the drives are enumerated with the \/dev\/hdX convention and I am stuck in read-only mode (with no mode select); or the drives are enumerated with \/dev\/sdX along with corresponding \/dev\/sgN character devices, in which case the kernel does not recognize the Xbox DVD-ROM drive.<\/p>\n<p>This makes me wonder if there&#8217;s a discrepancy between the legacy ATA\/ATAPI drivers (which sees the drive) and the newer SATA\/PATA subsystem (which doesn&#8217;t see the drive). I also wonder about hacking the kernel logic to allow SCSI mode select logic to proceed to the device for a read-only file handle.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The secrets (maybe) of unlocking an Xbox disc using an Xbox optical drive<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[25,79],"tags":[],"class_list":["post-4195","post","type-post","status-publish","format-standard","hentry","category-drm","category-xbox"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/posts\/4195","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/comments?post=4195"}],"version-history":[{"count":17,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/posts\/4195\/revisions"}],"predecessor-version":[{"id":4394,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/posts\/4195\/revisions\/4394"}],"wp:attachment":[{"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/media?parent=4195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/categories?post=4195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/tags?post=4195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}