Editing Talk:SC Communication

Jump to navigation Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
== The easy peasy lemon squeasy way (UART) (CXR/CXRF/SW) ==
== The easy peasy lemon squeasy way (UART) (CXR/CXRF/SW?) ==
 
{{boxcode|height=400px|title=SysconAUTH.py|code=<syntaxhighlight lang=python>
# Python 2 + 3 compatible


<syntaxhighlight lang="Python">
from binascii import unhexlify as uhx
from binascii import unhexlify as uhx
from Crypto.Cipher import AES # pycryptodome
from Crypto.Cipher import AES
import os
import serial # pyserial
import string
import sys
import sys
import time
 
# Auth1: 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
class PS3UART(object):
    ser = serial.Serial()
sc2tb = uhx('71f03f184c01c5ebc3f6a22a42ba9525')  # Syscon to TestBench Key    (0x130 xor 0x4578)
    type = ''
tb2sc = uhx('907e730f4d4e0a0b7b75f030eb1d9d36')  # TestBench to Syscon Key    (0x130 xor 0x4588)
           
value = uhx('3350BD7820345C29056A223BA220B323')  # 0x45B8
    sc2tb = uhx('71f03f184c01c5ebc3f6a22a42ba9525')  # Syscon to TestBench Key    (0x130 xor 0x4578)
zero  = uhx('00000000000000000000000000000000')
    tb2sc = uhx('907e730f4d4e0a0b7b75f030eb1d9d36')  # TestBench to Syscon Key    (0x130 xor 0x4588)
    value = uhx('3350BD7820345C29056A223BA220B323')  # 0x45B8
auth1r_header = uhx('10100000FFFFFFFF0000000000000000')
    zero  = uhx('00000000000000000000000000000000')
auth2_header  = uhx('10010000000000000000000000000000')
 
    auth1r_header = uhx('10100000FFFFFFFF0000000000000000')
def aes_decrypt_cbc(key, iv, input):
    auth2_header  = uhx('10010000000000000000000000000000')
    return AES.new(key, AES.MODE_CBC, iv).decrypt(input)
   
 
    def aes_decrypt_cbc(self, key, iv, in_data):
def aes_encrypt_cbc(key, iv, input):
        return AES.new(key, AES.MODE_CBC, iv).decrypt(in_data)
    return AES.new(key, AES.MODE_CBC, iv).encrypt(input)
   
    def aes_encrypt_cbc(self, key, iv, in_data):
        return AES.new(key, AES.MODE_CBC, iv).encrypt(in_data)
 
    def __init__(self, port, type):
        self.ser.port = port
        if(type == 'CXR' or type == 'SW'):
            self.ser.baudrate = 57600
        elif(type == 'CXRF'):
            self.ser.baudrate = 115200
        else:
            assert(False)
        self.type = type
        self.ser.timeout = 0.1
        self.ser.open()
        assert(self.ser.isOpen())
        self.ser.flush()
       
    def __del__(self):
        self.ser.close()
       
    def send(self, data):
        self.ser.write(data.encode('ascii'))   
                           
    def receive(self):
        return self.ser.read(self.ser.inWaiting())
       
    def command(self, com, wait = 1, verbose = False):
        if(verbose):
            print('Command: ' + com)
       
        if(self.type == 'CXR'):       
            length = len(com)
            checksum = sum(bytearray(com, 'ascii')) % 0x100
            if(length <= 10):
                self.send('C:{:02X}:{}\r\n'.format(checksum, com))
            else:
                j = 10
                self.send('C:{:02X}:{}'.format(checksum, com[0:j]))
                for i in range(length - j, 15, -15):
                    self.send(com[j:j+15])
                    j += 15
                self.send(com[j:] + '\r\n')
        elif(self.type == 'SW'):   
            length = len(com)
            if(length >= 0x40):
                if(self.command('SETCMDLONG FF FF')[0] != 0):
                    return (0xFFFFFFFF, ['Setcmdlong'])       
            checksum = sum(bytearray(com, 'ascii')) % 0x100
            self.send('{}:{:02X}\r\n'.format(com, checksum))
        else:
            self.send(com + '\r\n')
           
        time.sleep(wait)
        answer = self.receive().decode('ascii').strip()
        if(verbose):
            print('Answer: ' + answer)
       
        if(self.type == 'CXR'):
            answer = answer.split(':')
            if(len(answer) != 3):
                return (0xFFFFFFFF, ['Answer length'])
            checksum = sum(bytearray(answer[2], 'ascii')) % 0x100
            if(answer[0] != 'R' and answer[0] != 'E'):
                return (0xFFFFFFFF, ['Magic'])
            if(answer[1] != '{:02X}'.format(checksum)):
                return (0xFFFFFFFF, ['Checksum'])   
            data = answer[2].split(' ')
            if(answer[0] == 'R' and len(data) < 2 or answer[0] == 'E' and len(data) != 2):
                return (0xFFFFFFFF, ['Data length'])
            if(data[0] != 'OK' or len(data) < 2):
                return (int(data[1], 16), [])
            else:
                return (int(data[1], 16), data[2:])   
        elif(self.type == 'SW'):
            answer = answer.split('\n')
            for i in range(0, len(answer)):
                answer[i] = answer[i].replace('\n', '').rsplit(':', 1)
                if(len(answer[i]) != 2):
                    return (0xFFFFFFFF, ['Answer length'])
                checksum = sum(bytearray(answer[i][0], 'ascii')) % 0x100
                if(answer[i][1] != '{:02X}'.format(checksum)):
                    return (0xFFFFFFFF, ['Checksum'])
                answer[i][0] += '\n'
            ret = answer[-1][0].replace('\n', '').split(' ')
            if(len(ret) < 2 or len(ret[1]) != 8 and not all(c in string.hexdigits for c in ret[1])):
                return (0, [x[0] for x in answer])
            elif(len(answer) == 1):       
                return (int(ret[1], 16), ret[2:])
            else:
                return (int(ret[1], 16), [x[0] for x in answer[:-1]])
        else:
            return (0, [answer])
           
    def auth(self):
        if(self.type == 'CXR' or self.type == 'SW'):
            auth1r = self.command('AUTH1 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
            if(auth1r[0] == 0 and auth1r[1] != []):
                auth1r = uhx(auth1r[1][0])
                if(auth1r[0:0x10] == self.auth1r_header):
                    data = self.aes_decrypt_cbc(self.sc2tb, self.zero, auth1r[0x10:0x40])
                    if(data[0x8:0x10] == self.zero[0x0:0x8] and data[0x10:0x20] == self.value and data[0x20:0x30] == self.zero):
                        new_data = data[0x8:0x10] + data[0x0:0x8] + self.zero + self.zero
                        auth2_body = self.aes_encrypt_cbc(self.tb2sc, self.zero, new_data)
                        auth2r = self.command('AUTH2 ' + ''.join('{:02X}'.format(c) for c in bytearray(self.auth2_header + auth2_body)))
                        if(auth2r[0] == 0):
                            return 'Auth successful'
                        else:
                            return 'Auth failed'
                    else:
                        return 'Auth1 response body invalid'
                else:
                    return 'Auth1 response header invalid'
            else:
                return 'Auth1 response invalid'
        else:
            scopen = self.command('scopen')
            if('SC_READY' in scopen[1][0]):
                auth1r = self.command('10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
                auth1r = auth1r[1][0].split('\r')[1][1:]
                if(len(auth1r) == 128):
                    auth1r = uhx(auth1r)
                    if(auth1r[0:0x10] == self.auth1r_header):
                        data = self.aes_decrypt_cbc(self.sc2tb, self.zero, auth1r[0x10:0x40])
                        if(data[0x8:0x10] == self.zero[0x0:0x8] and data[0x10:0x20] == self.value and data[0x20:0x30] == self.zero):
                            new_data = data[0x8:0x10] + data[0x0:0x8] + self.zero + self.zero
                            auth2_body = self.aes_encrypt_cbc(self.tb2sc, self.zero, new_data)
                            auth2r = self.command(''.join('{:02X}'.format(c) for c in bytearray(self.auth2_header + auth2_body)))
                            if('SC_SUCCESS' in auth2r[1][0]):
                                return 'Auth successful'
                            else:
                                return 'Auth failed'
                        else:
                            return 'Auth1 response body invalid'
                    else:
                        return 'Auth1 response header invalid'
                else:
                    return 'Auth1 response invalid'
            else:
                return 'scopen response invalid'
   
 
def main(argc, argv):
def main(argc, argv):
     if(argc < 3):
     if argc == 2 and len(sys.argv[1]) == 128:
        print(os.path.basename(__file__) + ' <serial port> <sc type ["CXR", "CXRF", "SW"]>')
         auth1r = uhx(sys.argv[1])
        sys.exit(1)
         if auth1r[0:0x10] == auth1r_header:
    ps3 = PS3UART(argv[1], argv[2])
             data = aes_decrypt_cbc(sc2tb, zero, auth1r[0x10:0x40])
    raw_input_c = vars(__builtins__).get('raw_input', input)
             if data[0x8:0x10] == zero[0x0:0x8] and data[0x10:0x20] == value and data[0x20:0x30] == zero:
    while True:
                #print "".join("{:02X}".format(ord(c)) for c in (auth1r_header + data))
         in_data = raw_input_c('> ')
                new_data = data[0x8:0x10] + data[0x0:0x8] + zero + zero
         if(in_data.lower() == 'auth'):
                auth2_body = aes_encrypt_cbc(tb2sc, zero, new_data)
             print(ps3.auth())
                 print "".join("{:02X}".format(ord(c)) for c in (auth2_header + auth2_body))
             continue
        if(in_data.lower() == 'exit'):
            break
        ret = ps3.command(in_data)
        if(argv[2] == 'CXR'):
            print('{:08X}'.format(ret[0]) + ' ' +  ' '.join(ret[1]))
        elif(argv[2] == 'SW'):
            if(len(ret[1]) > 0 and '\n' not in ret[1][0]):
                 print('{:08X}'.format(ret[0]) + ' ' + ' '.join(ret[1]))
             else:
             else:
                 print('{:08X}'.format(ret[0]) + '\n' + ''.join(ret[1]))
                 print "Auth1 response body invalid"
         else:
         else:
             print(ret[1][0])
             print "Auth1 response header invalid"
               
    else:
        print "Argument (Auth1 response) missing"
if __name__ == '__main__':
if __name__ == '__main__':
     main(len(sys.argv), sys.argv)
     main(len(sys.argv), sys.argv)
</syntaxhighlight>}}
</syntaxhighlight>


* Credits to M4j0r for the RE of this important info
* Credits to M4j0r for the RE of this important info
=== Example Scripts ===
{{boxcode|height=400px|title=SysconEEPdumpCXR.py|code=<syntaxhighlight lang=python>
# Python 2 compatible
if(len(sys.argv) < 3):
    print os.path.basename(__file__) + ' <serial port> <output file>'
    sys.exit(1)
ps3 = PS3UART(sys.argv[1], 'CXR')
print "Version: " + ps3.command("VER")[1][0]
print ps3.auth()
f = open(sys.argv[2], 'wb')
block_size = 0x40
print "Dumping NVS"
failed = []
for i in xrange(0x2C00, 0x7400, block_size): # 0x7400 for CXR713, 0x4400 for CXR714
    print "Reading 0x{:04X}".format(i)
    data = ps3.command("R8 {:08X} {:02X}".format(i, block_size))
    ret = data[0]
    if ret == 0:
        f.write((data[1][0]).decode('hex'))
    else:
        print "Failed: " + str(ret)
        failed += [i]
        f.write(("A"*block_size*2).decode('hex'))
   
f.close()
time.sleep(2)
print "\nRetrying failed offsets"
for i in failed:
    print "Reading 0x{:04X}".format(i)
    for j in xrange(0, block_size, block_size/4):
        while True:
            data = ps3.command("R8 {:08X} {:02X}".format(i+j, block_size/4))
            ret = data[0]
            if ret == 0:
                print data[1][0]
                break
            time.sleep(2)
</syntaxhighlight>}}
{{boxcode|height=400px|title=SysconEEPdumpCXRF.py|code=<syntaxhighlight lang=python>
# Python 2 + 3 compatible
if(len(sys.argv) < 3):
    print(os.path.basename(__file__) + ' <serial port> <output file>')
    sys.exit(1)
 
ps3 = PS3UART(sys.argv[1], 'CXRF')
print('Version: ' + ps3.command('version')[1][0].split('\n')[1])
print(ps3.auth())
f = open(sys.argv[2], 'wb')
block_size = 0x40
print('Dumping NVS')
for i in range(0x2C00, 0x7400, block_size):
    print('Reading 0x{:04X}'.format(i))
    data = ps3.command('r {:08X} {:02X}'.format(i, block_size))
    data = data[1][0].split('\n')
    if len(data) != 9:
        print('Failed')
        continue
    for i in range(3, 7):
        temp = data[i][0:-2].replace(' ', '')
        f.write(bytearray.fromhex(temp))
     
f.close()
</syntaxhighlight>}}
{{boxcode|height=400px|title=SysconEEPdumpSW.py|code=<syntaxhighlight lang=python>
# Python 2 + 3 compatible
if(len(sys.argv) < 3):
    print(os.path.basename(__file__) + ' <serial port> <output file>')
    sys.exit(1)
 
ps3 = PS3UART(sys.argv[1], 'SW')
print('Version: ' + ps3.command('VER')[1][0])
print(ps3.auth())
f = open(sys.argv[2], 'wb')
block_size = 0x40
print('Dumping NVS')
for i in range(0x0, 0x1400, block_size):
    print('Reading 0x{:04X}'.format(i))
    data = ps3.command('EEP GET {:08X} {:02X}'.format(i, block_size))
    ret = data[0]
    temp = ''
    if ret == 0:
        for i in range(2, len(data[1])):
            temp += data[1][i][2:-2].replace(' ', '')
        f.write(bytearray.fromhex(temp))
    else:
        print('Failed: ' + str(ret))
     
f.close()
</syntaxhighlight>}}
{{boxcode|height=400px|title=SysconEEPpatchCXR.py|code=<syntaxhighlight lang=python>
# Python 2 compatible
if(len(sys.argv) < 3):
    print os.path.basename(__file__) + ' <serial port> <patch file>'
    sys.exit(1)
ps3 = PS3UART(sys.argv[1], 'CXR')
f = open(sys.argv[2], 'rb')
patch = f.read()
f.close()
print "Version: " + ps3.command("VER")[1][0]
print ps3.auth()
patch_area_1 = 0x2800
patch_area_2 = 0x4400 # 0x7400 for CXR713, 0x4400 for CXR714
block_size = 0x40
print "First region"
for i in xrange(0, 0x400, block_size):
    print hex(ps3.command("EEP SET " + hex(i+patch_area_1)[2:] + " " + hex(block_size)[2:] + " " + patch[i:i+block_size].encode('hex'))[0])
print ""
print "Second region"
for i in xrange(0x400, 0x1000, block_size):
    print hex(ps3.command("EEP SET " + hex(i+patch_area_2-0x400)[2:] + " " + hex(block_size)[2:] + " " + patch[i:i+block_size].encode('hex'))[0])
</syntaxhighlight>}}


== IDs ==
== IDs ==
Line 368: Line 93:
</pre>
</pre>


* Although this service is not used on Slim and some Phat consoles anymore, it is working (only on consoles with a CXR (Mullion) Syscon).
* Although this service is not used on Slim and some Phat consoles anymore, it is working.
* It seems it have the same restrictions as NVS service.
* It seems it have the same restrictions as NVS service.


Line 387: Line 112:
</pre>
</pre>


* Although this service is not used on Slim and some Phat consoles anymore, it is working (only on consoles with a CXR (Mullion) Syscon).
* Although this service is not used on Slim and some Phat consoles anymore, it is working.
* It seems it have the same restrictions as NVS service.
* It seems it have the same restrictions as NVS service.


Line 818: Line 543:
See :
See :


* https://www.psdevwiki.com/ps3/File:C1kVeMD.png
* https://imgur.com/a/Iwv4d
* https://www.psdevwiki.com/ps3/File:NBkrqqZ.png
* https://imgur.com/a/48gsT
* database : https://www.sendspace.com/file/6awfi9
* database : https://www.sendspace.com/file/6awfi9


For proof
For proof
Please note that all contributions to PS3 Developer wiki are considered to be released under the GNU Free Documentation License 1.2 (see PS3 Developer wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following hCaptcha:

Cancel Editing help (opens in new window)

Template used on this page: