xqemu / xqemu-manager

Simple graphical user interface to manage XQEMU
http://xqemu.com
GNU General Public License v2.0
34 stars 10 forks source link

Retrieve state of virtual Xbox via memory inspection #19

Open JayFoxRox opened 6 years ago

JayFoxRox commented 6 years ago

Keep in mind that XQEMU is LLE and we can't always assume that it's running the official MS bios / kernel / licensed games. Anything which makes such assumptions is part of HLE. HLE in XQEMU and its UI should always be entirely optional and it must be possible to disable such features (or they must handle non-MS code gracefully).


Following is some code which could be used to get information about the running XBE. For more information, check http://xboxdevwiki.net/Xbe which also has a link to the file format at the bottom.

Function to do HMP commands via QMP:

def read(self, addr, size):
  cmd = {
      "execute": "human-monitor-command", 
      "arguments": { "command-line": "x /%dxb %d" % (size,addr) }
  }
  response = self.run_cmd(cmd)
  lines = response['return'].replace('\r', '').split('\n')
  data_string = ' '.join(l.partition(': ')[2] for l in lines).strip()
  data = bytes(int(b, 16) for b in data_string.split(' '))
  return data

Code to read, parse and print XBE fields:

base = 0x00010000
if t.read(base, 4) == b'XBEH':
  xbe_timestamp = int.from_bytes(t.read(base + 0x114, 4), 'little')
  ts = datetime.datetime.utcfromtimestamp(xbe_timestamp)
  print("XBE Timestamp: %s (0x%08X)" % (str(ts), xbe_timestamp))

  cert_address = int.from_bytes(t.read(base + 0x118, 4), 'little')

  cert_timestamp = int.from_bytes(t.read(cert_address + 0x4, 4), 'little')
  ts = datetime.datetime.utcfromtimestamp(cert_timestamp)
  print("XBE Certificate Timestamp: %s (0x%08X)" % (str(ts), cert_timestamp))

  title_id = int.from_bytes(t.read(cert_address + 0x8, 4), 'little')
  a = title_id >> 24
  b = (title_id >> 16) & 0xFF
  i = title_id & 0xFFFF
  print('XBE Title-ID: 0x%X (%c%c-%03d)' % (title_id, a, b, i))

  title_name = t.read(cert_address + 0xC, 40 * 2).decode('utf-8')
  print("XBE Title-Name: '%s'" % title_name)
else:
  print("No XBE found")

Output:

XBE Timestamp: 2001-12-12 19:15:05 (0x3C17ACB9)
XBE Certificate Timestamp: 2002-03-04 15:58:09 (0x3C839991)
XBE Title-ID: 0x4D530007 (MS-007)
XBE Title-Name: 'Azurik - Rise of Perathia'

The primary use of this information would probably be that it could be displayed as part of the UI (possibly move it into the QEMU window title). This would be immediately visible for use in bug reports.

If we allow some kind of telemetry or motivate users to report often, we can also use this information to create a complete set of XBE header dumps / complete gameset, possibly discovering undumped DVDs. A sneaky way to get telemetry could be rich presence (which I don't want for XQEMU) or pairing players for network games in the future (which I want, regardless of telemetry).


The memory-read gadget can also retrieve kernel information for bug reports. Otherwise, it's quite limited in use, because the UI can get information directly through our hardware-emulation.

Reminder: Xbox RAM contains copyrighted or otherwise protected material during runtime. So I'd advise against doing full crashdumps. We should selectively dump the metadata we need, much like the code above does.