Created
July 22, 2012 21:19
-
-
Save landaire/3161073 to your computer and use it in GitHub Desktop.
Ruby implementation of Redline99's "X" value decryption code (Xbox 360)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# xval.rb - Ruby implementation of Redline99's "X" value decryption code for the Xbox 360 by CLK | |
# See https://gist.github.com/2669789 for Python code | |
require 'optparse' | |
require 'openssl' | |
# Define our constants | |
FLAG_SSB_NONE = 0x0000 | |
FLAG_SSB_AUTH_EX_FAILURE = 0x0001 | |
FLAG_SSB_AUTH_EX_NO_TABLE = 0x0002 | |
FLAG_SSB_AUTH_EX_RESERVED = 0x0004 | |
FLAG_SSB_INVALID_DVD_GEOMETRY = 0x0008 | |
FLAG_SSB_INVALID_DVD_DMI = 0x0010 | |
FLAG_SSB_DVD_KEYVAULT_PAIR_MISMATCH = 0x0020 | |
FLAG_SSB_CRL_DATA_INVALID = 0x0040 | |
FLAG_SSB_CRL_CERTIFICATE_REVOKED = 0x0080 | |
FLAG_SSB_UNAUTHORIZED_INSTALL = 0x0100 | |
FLAG_SSB_KEYVAULT_POLICY_VIOLATION = 0x0200 | |
FLAG_SSB_CONSOLE_BANNED = 0x0400 | |
FLAG_SSB_ODD_VIOLATION = 0x0800 | |
def DecryptXval(serial, xval) | |
# Remove dashes from the xval | |
xval = xval.delete('-') | |
# Convert the xval to a byte array | |
xval = xval.scan(/../).map(&:hex) | |
# Conver that back into a string | |
xval = xval.pack('c*') | |
# Make sure that the serial/xval lengths are good | |
fail if serial.length != 0xC | |
fail if xval.length != 0x8 | |
# Get the DES key (bytes 0-8 of the hash) | |
serial.encode!("ascii") | |
deskey = OpenSSL::HMAC.digest("sha1", serial + "\0", "XBOX360SSB")[0, 8] | |
fail if deskey.length != 0x8 | |
# Decrypt the X value | |
cipher = OpenSSL::Cipher::Cipher.new("des-ecb") | |
cipher.decrypt | |
cipher.key = deskey | |
# Must set the padding to 0 | |
cipher.padding = 0 | |
ciphertext = cipher.update(xval) + cipher.final | |
return ciphertext | |
end | |
def GetResults(result) | |
xval = result.unpack('LL*') | |
xval_h = xval[0] | |
xval_l = xval[1] | |
if(xval_h == 0 && xval_l == 0) # nothing is flagged in secdata.bin, all is good from this standpoint | |
return "Secdata is Clean" | |
elsif(xval_h == 0xFFFFFFFF && xval_l == 0xFFFFFFFF) # secdata was prob tampered with | |
return "Secdata is invalid" | |
elsif (xval_h != 0 && xval_l != 0) # most likely the serial or xval is incorrect | |
return "Secdata decryption error. Check your serial number and X value to ensure they are correct" | |
else # the high dword = 0 and low dword not 0 | |
# afaik best check. have to look at disassembly more | |
if(xval_l & FLAG_SSB_AUTH_EX_FAILURE) | |
return "AuthEx Challenge Failure" # AP25 related | |
end | |
if(xval_l & FLAG_SSB_AUTH_EX_NO_TABLE) | |
return "AuthEx Table missing" # AP25 related | |
end | |
if(xval_l & FLAG_SSB_AUTH_EX_RESERVED) | |
return "AuthEx Reserved Flag" # AP25 related | |
end | |
if(xval_l & FLAG_SSB_INVALID_DVD_GEOMETRY) | |
return "Invalid DVD Geometry" | |
end | |
if(xval_l & FLAG_SSB_INVALID_DVD_DMI) | |
return "Invalid DVD DMI" | |
end | |
if(xval_l & FLAG_SSB_DVD_KEYVAULT_PAIR_MISMATCH) | |
return "DVD Keyvault Pair Mismatch" | |
end | |
if(xval_l & FLAG_SSB_CRL_DATA_INVALID) | |
return "Invalid CRL Data" | |
end | |
if(xval_l & FLAG_SSB_CRL_CERTIFICATE_REVOKED) | |
return "CRL Certificate Revoked" | |
end | |
if(xval_l & FLAG_SSB_UNAUTHORIZED_INSTALL) | |
return "Unauthorized Install" | |
end | |
if(xval_l & FLAG_SSB_KEYVAULT_POLICY_VIOLATION) | |
return "Keyvault Policy Violation" | |
end | |
if(xval_l & FLAG_SSB_CONSOLE_BANNED) | |
return "Console Banned" | |
end | |
if(xval_l & FLAG_SSB_ODD_VIOLATION) | |
return "ODD Violation" | |
end | |
if(xval_l & 0xFFFFF000) # mask for bits we dont have a description for, | |
# note: we are not looking at the hi dword yet | |
return "Unknown Violation(s)" | |
end | |
end | |
end | |
# Parse the input arguments | |
options = {} | |
optparser = OptionParser.new do |opts| | |
opts.banner = "Usage: xval.rb [options]" | |
# Serial switch | |
opts.on('-s', '--serial SERIAL', 'Console serial number') do |v| | |
options[:serial] = v | |
end | |
# X value switch | |
opts.on('-x', '--xval XVAL', '"X:" Value shown on the dashboard') do |v| | |
options[:xval] = v | |
end | |
# Help switch | |
opts.on( '-h', '--help', 'Display this screen' ) do | |
puts opts | |
exit | |
end | |
end | |
# Parse the args and clear ARGV | |
optparser.parse! | |
# Make sure that we were given some args | |
if (options.length == 0) | |
puts optparser | |
return | |
elsif (options[:serial] == nil) | |
puts "No serial number passed" | |
puts optparser | |
return | |
elsif (options[:xval] == nil) | |
puts "No X value passed" | |
puts optparser | |
return | |
end | |
# Get some results | |
puts GetResults(DecryptXval(options[:serial], options[:xval])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment