diff --git a/PyPS3checker/checker_py3.py b/PyPS3checker/checker_py3.py index 9faeb5e..18e5277 100644 --- a/PyPS3checker/checker_py3.py +++ b/PyPS3checker/checker_py3.py @@ -28,6 +28,7 @@ colorisok = True init(autoreset=True) + class Tee(object): def __init__(self, *files): self.files = files @@ -39,51 +40,55 @@ def write(self, obj): def flush(_): pass + def checkReversed(data): - bytes = data[0x14:(0x14 + 0x4)] # FACEOFF - if bytes == b'\x0F\xAC\xE0\xFF': + bytes = data[0x14 : (0x14 + 0x4)] # FACEOFF + if bytes == b"\x0F\xAC\xE0\xFF": return False - elif bytes == b'\xAC\x0F\xFF\xE0': + elif bytes == b"\xAC\x0F\xFF\xE0": return True - bytes = data[0x1C:(0x1C + 0x4)] # DEADBEEF - if bytes == b'\xDE\xAD\xBE\xEF': + bytes = data[0x1C : (0x1C + 0x4)] # DEADBEEF + if bytes == b"\xDE\xAD\xBE\xEF": return False - elif bytes == b'\xAD\xDE\xEF\xBE': + elif bytes == b"\xAD\xDE\xEF\xBE": return True - bytes = data[0x200:(0x200 + 0x4)] # IFI - if bytes == b'\x49\x46\x49\x00': + bytes = data[0x200 : (0x200 + 0x4)] # IFI + if bytes == b"\x49\x46\x49\x00": return False - elif bytes == b'\x46\x49\x00\x49': + elif bytes == b"\x46\x49\x00\x49": return True - bytes = data[0x3F060:(0x3F060 + 0x4)] # I.DL - if bytes == b'\x7F\x49\x44\x4C': + bytes = data[0x3F060 : (0x3F060 + 0x4)] # I.DL + if bytes == b"\x7F\x49\x44\x4C": return False - elif bytes == b'\x49\x7F\x4C\x44': + elif bytes == b"\x49\x7F\x4C\x44": return True - bytes = data[0xF00014:(0xF00014 + 0x4)] # FACEOFF - if bytes == b'\x0F\xAC\xE0\xFF': + bytes = data[0xF00014 : (0xF00014 + 0x4)] # FACEOFF + if bytes == b"\x0F\xAC\xE0\xFF": return False - elif bytes == b'\xAC\x0F\xFF\xE0': + elif bytes == b"\xAC\x0F\xFF\xE0": return True - bytes = data[0xF0001C:(0xF0001C + 0x4)] # DEADFACE - if bytes == b'\xDE\xAD\xFA\xCE': + bytes = data[0xF0001C : (0xF0001C + 0x4)] # DEADFACE + if bytes == b"\xDE\xAD\xFA\xCE": return False - elif bytes == b'\xAD\xDE\xCE\xFA': + elif bytes == b"\xAD\xDE\xCE\xFA": return True - sys.exit("ERROR: unable to determine if reversed data! Too much curruptions.") - + sys.exit("ERROR: unable to determine if reversed data! Too much corruptions.") + + def isMetldr2(data): - bytes = data[0x820:(0x820 + 0x8)] - if bytes == b'\x6D\x65\x74\x6C\x64\x72\x00\x00': # METLDR + bytes = data[0x820 : (0x820 + 0x8)] + if bytes == b"\x6D\x65\x74\x6C\x64\x72\x00\x00": # METLDR return "false" - elif bytes == b'\x6D\x65\x74\x6C\x64\x72\x2E\x32': # METLDR.2 + elif bytes == b"\x6D\x65\x74\x6C\x64\x72\x2E\x32": # METLDR.2 return "true" - sys.exit("ERROR: unable to determine if NAND or EMMC data! Too much curruptions.") + sys.exit("ERROR: unable to determine if NAND or EMMC data! Too much corruptions.") + def getDatas(file, offset, length): bytes = file[offset:(offset + length)] return bytes + def reverse(data): r_data = [] for i in range(0, len(data), 2): @@ -91,35 +96,41 @@ def reverse(data): r_data.append(data[i]) return bytes(r_data) + def string2hex(data): return "".join("{:02x}".format(ord(chr(c))) for c in data) + def hex2string(data): bytes = [] for i in range(0, len(data), 2): - bytes.append(chr(int(data[i:i+2], 16))) - return ''.join(bytes) + bytes.append(chr(int(data[i : i + 2], 16))) + return "".join(bytes) + def chunks(s, n): # Produce `n`-character chunks from `s`. for start in range(0, len(s), n): yield s[start:start+n] + def print_formatedlines(s, n): c = 0 for chunk in chunks(s, n): if c == 0: tab = " >" else: - tab = " " - print(tab, " ".join(a+b for a,b in zip(chunk[::2], chunk[1::2]))) + tab = " " + print(tab, " ".join(a + b for a, b in zip(chunk[::2], chunk[1::2]))) c += 1 + def getMD5(file, offset, length): h = hashlib.md5() h.update(getDatas(file, offset, length)) return h.hexdigest() + def printcolored(color, text): # available color: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET # available style: DIM, NORMAL, BRIGHT, RESET_ALL @@ -130,6 +141,7 @@ def printcolored(color, text): else: print(text) + def colored(color, text): # available color: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET # available style: DIM, NORMAL, BRIGHT, RESET_ALL @@ -140,62 +152,82 @@ def colored(color, text): else: return text -def printok(): print(colored("green", "OK")) -def printrisklevel(risklevel): - if risklevel == "WARNING": print(colored("yellow", "%s!" % risklevel)) - if risklevel == "DANGER": print(colored("red", "%s!" % risklevel)) +def printok(): + print(colored("green", "OK")) + + +def printrisklevel(risklevel): + if risklevel == "WARNING": + print(colored("yellow", "%s!" % risklevel)) + if risklevel == "DANGER": + print(colored("red", "%s!" % risklevel)) if __name__ == "__main__": release = "v0.11.x" - print() - print() - print() - printcolored("cyan", " ____ ____ ____ _____ _ _ ") - printcolored("cyan", " | _ \\ _ _| _ \\/ ___|___ / ___| |__ ___ ___| | _____ _ __ ") - printcolored("cyan", " | |_) | | | | |_) \\___ \\ |_ \\ / __| '_ \\ / _ \\/ __| |/ / _ \\ '__|") - printcolored("cyan", " | __/| |_| | __/ ___) |__) | (__| | | | __/ (__| < __/ | ") - printcolored("cyan", " |_| \\__, |_| |____/____/ \\___|_| |_|\\___|\\___|_|\\_\\___|_| ") - printcolored("cyan", " |___/ %s " % release) - print() - printcolored("white", " Python checker script for PS3 flash memory dump files") - printcolored("cyan", " Copyright (C) 2015 littlebalup@gmail.com") - print() - print() + printcolored( + "cyan", + r""" + + ____ ____ ____ _____ _ _ + | _ \ _ _| _ \/ ___|___ / ___| |__ ___ ___| | _____ _ __ + | |_) | | | | |_) \___ \ |_ \ / __| '_ \ / _ \/ __| |/ / _ \ '__| + | __/| |_| | __/ ___) |__) | (__| | | | __/ (__| < __/ | + |_| \__, |_| |____/____/ \___|_| |_|\___|\___|_|\_\___|_| + |___/ + + %s + + %s + %s + """ + % ( + release, + colored("white", "Python checker script for PS3 flash memory dump files"), + colored("cyan", "Copyright (C) 2015 littlebalup@gmail.com"), + ), + ) + if len(sys.argv) == 1: - print(textwrap.dedent(""" + print( + textwrap.dedent( + """ Usage: - %s [input_file] + python %s [input_file] - [input_file] Dump filename to check. + [input_file] - Dump filename to check (default: dump.bin) - Examples: - %s mydump.bin - """ % (os.path.basename(sys.argv[0]), os.path.basename(sys.argv[0])))) - sys.exit() + Examples: + python %s dump.bin + + """ + % (os.path.basename(sys.argv[0]), os.path.basename(sys.argv[0])) + ) + ) + sys.exit() startTime = time.time() # get args and set recording lists and counts inputFile = sys.argv[1] if not os.path.isfile(inputFile): - sys.exit("ERROR: input file \"%s\" not found!" % inputFile) + sys.exit('ERROR: input file "%s" not found!' % inputFile) dangerList = [] warningList = [] checkCount = 0 dangerCount = 0 warningCount = 0 - + skipHash = False # parse file - print("Loading file \"%s\" to memory..." % inputFile) - with open(inputFile,"rb") as f: + print('Loading file "%s" to memory...' % inputFile) + with open(inputFile, "rb") as f: rawfiledata = f.read() # parse xml @@ -203,16 +235,16 @@ def printrisklevel(risklevel): sys.exit("ERROR: checklist.xml file not found!") if not os.path.isfile("hashlist.xml"): sys.exit("ERROR: hashlist.xml file not found!") - with open('checklist.xml', 'rt') as f: + with open("checklist.xml", "rt") as f: chktree = ElementTree.parse(f) - with open('hashlist.xml', 'rt') as f: + with open("hashlist.xml", "rt") as f: hashtree = ElementTree.parse(f) # parse file type: isReversed = "" fileSize = len(rawfiledata) flashType = "" - for dump_type in chktree.findall('.//dump_type'): + for dump_type in chktree.findall(".//dump_type"): if fileSize == int(dump_type.attrib.get("size")): if dump_type.attrib.get("metldr2") is not None: if isMetldr2(rawfiledata) != dump_type.attrib.get("metldr2").lower(): @@ -228,13 +260,17 @@ def printrisklevel(risklevel): break if flashType == "": print() - sys.exit("ERROR: unable to determine flash type! It doesn't seem to be a valid dump.") + sys.exit( + "ERROR: unable to determine flash type! It doesn't seem to be a valid dump." + ) print(" Done") # create and start log - cl = open('%s.checklog.txt' % inputFile, 'w') - cl.write("PyPS3checker %s. Check log.\n\n" % release + "Checked file : %s\n" % inputFile) + cl = open("%s.checklog.txt" % inputFile, "w") + cl.write( + "PyPS3checker %s. Check log.\n\n" % release + "Checked file : %s\n" % inputFile + ) # original = sys.stdout sys.stdout = Tee(sys.stdout, cl) @@ -247,38 +283,48 @@ def printrisklevel(risklevel): elif isReversed == False: print(" Reversed : NO") - # SKU identification print() print() print("******* Getting SKU identification datas *******") skufiledata = {} - for entry in chktree.findall('.//%s/skulistdata/' % flashType): - filedata = string2hex(getDatas(rawfiledata, int(entry.attrib.get("offset"), 16), int(entry.attrib.get("size"), 16))) + for entry in chktree.findall(".//%s/skulistdata/" % flashType): + filedata = string2hex( + getDatas( + rawfiledata, + int(entry.attrib.get("offset"), 16), + int(entry.attrib.get("size"), 16), + ) + ) tag = entry.text if tag == "bootldrsize": calc = (int(filedata, 16) * 0x10) + 0x40 filedata = "%X" % calc skufiledata[tag] = filedata.lower() if tag == "idps": - print(" %s = 0x%s" % (tag, filedata[-2:].upper())) #print only last 2 digits + print( + " %s = 0x%s" % (tag, filedata[-2:].upper()) + ) # print only last 2 digits else: print(" %s = 0x%s" % (tag, filedata.upper())) print() - print(" Matching SKU :", end=' ') + print(" Matching SKU :", end=" ") checkCount += 1 ChkResult = False - for node in chktree.findall('.//%s/skumodels' % flashType): + for node in chktree.findall(".//%s/skumodels" % flashType): risklevel = node.attrib.get("risklevel").upper() - for node in chktree.findall('.//%s/skumodels/' % flashType): + for node in chktree.findall(".//%s/skumodels/" % flashType): d = {} - for subnode in chktree.findall(".//%s/skumodels/%s[@id='%s']/" % (flashType, node.tag, node.attrib.get("id"))): + for subnode in chktree.findall( + ".//%s/skumodels/%s[@id='%s']/" + % (flashType, node.tag, node.attrib.get("id")) + ): tag = subnode.attrib.get("type") d[tag] = subnode.text.lower() if d == skufiledata: ChkResult = True printok() - print(" %s"%node.attrib.get("name")) + print(" %s" % node.attrib.get("name")) print(" Minimum version %s" % node.attrib.get("minver")) if node.attrib.get("warn") == "true": warningCount += 1 @@ -301,16 +347,22 @@ def printrisklevel(risklevel): print("******* Getting SDK versions *******") checkCount += 1 ChkResult = True - for node in chktree.findall('.//%s/sdk' % flashType): + for node in chktree.findall(".//%s/sdk" % flashType): risklevel = node.attrib.get("risklevel").upper() - for sdk in chktree.findall('.//%s/sdk/sdk_version' % flashType): - index = rawfiledata.find(hex2string("73646B5F76657273696F6E").encode('latin'), int(sdk.attrib.get("offset"), 16), int(sdk.attrib.get("offset"), 16) + 0x4f0) - addressPos = index - 0xc - address = int(sdk.attrib.get("offset"), 16) + int(string2hex(getDatas(rawfiledata, addressPos, 0x4)), 16) + for sdk in chktree.findall(".//%s/sdk/sdk_version" % flashType): + index = rawfiledata.find( + hex2string("73646B5F76657273696F6E").encode("latin"), + int(sdk.attrib.get("offset"), 16), + int(sdk.attrib.get("offset"), 16) + 0x4F0, + ) + addressPos = index - 0xC + address = int(sdk.attrib.get("offset"), 16) + int( + string2hex(getDatas(rawfiledata, addressPos, 0x4)), 16 + ) ver = getDatas(rawfiledata, address, 0x8) - ver = ver[:-1] #remove useless last 0x0A char - r = re.compile('\\d{3}\\.\\d{3}') #def format - ver = ver.decode('latin') + ver = ver[:-1] # remove useless last 0x0A char + r = re.compile("\\d{3}\\.\\d{3}") # def format + ver = ver.decode("latin") if r.match(ver) is not None: print(" %s : %s" % (sdk.attrib.get("name"), ver)) else: @@ -326,20 +378,26 @@ def printrisklevel(risklevel): print("%s! : unable to get all versions." % risklevel) # Start other checks - for node in chktree.findall('.//%s/' % flashType): + for node in chktree.findall(".//%s/" % flashType): if node.tag not in ["skulistdata", "skumodels", "sdk"]: print() print() print("******* Checking %s *******" % node.tag) - for subnode in chktree.findall('.//%s/%s/' % (flashType, node.tag)): + for subnode in chktree.findall(".//%s/%s/" % (flashType, node.tag)): if subnode.attrib.get("risklevel") is not None: risklevel = subnode.attrib.get("risklevel").upper() if subnode.tag == "binentry": checkCount += 1 - filedata = string2hex(getDatas(rawfiledata, int(subnode.attrib.get("offset"), 16), len(subnode.text)//2)) - print("%s :" % subnode.attrib.get("name"), end=' ') + filedata = string2hex( + getDatas( + rawfiledata, + int(subnode.attrib.get("offset"), 16), + len(subnode.text) // 2, + ) + ) + print("%s :" % subnode.attrib.get("name"), end=" ") if filedata.lower() == subnode.text.lower(): printok() else: @@ -352,25 +410,40 @@ def printrisklevel(risklevel): printrisklevel(risklevel) print(" At offset : 0x%s" % subnode.attrib.get("offset").upper()) if isReversed: - print(" Actual data (reversed from original) :", end='') + print(" Actual data (reversed from original) :", end="") else: - print(" Actual data :", end='') + print(" Actual data :", end="") print_formatedlines(filedata.upper(), 32) - print(" Expected data :", end='') + print(" Expected data :", end="") print_formatedlines(subnode.text.upper(), 32) print() if subnode.tag == "multibinentry": checkCount += 1 ChkResult = False - filedata = string2hex(getDatas(rawfiledata, int(subnode.attrib.get("offset"), 16), int(subnode.attrib.get("length"), 16))) - print("%s :"%subnode.attrib.get("name"), end=' ') - for entry in chktree.findall(".//%s/%s/%s[@name='%s']/"%(flashType, node.tag, subnode.tag, subnode.attrib.get("name"))): + filedata = string2hex( + getDatas( + rawfiledata, + int(subnode.attrib.get("offset"), 16), + int(subnode.attrib.get("length"), 16), + ) + ) + print("%s :" % subnode.attrib.get("name"), end=" ") + for entry in chktree.findall( + ".//%s/%s/%s[@name='%s']/" + % (flashType, node.tag, subnode.tag, subnode.attrib.get("name")) + ): if filedata.lower() == entry.text.lower(): - if subnode.attrib.get("name").endswith("trvk_prg1 SCE") and entry.text == "FFFFFFFF" : + if ( + subnode.attrib.get("name").endswith("trvk_prg1 SCE") + and entry.text == "FFFFFFFF" + ): print("Blank") skipHash = True - elif subnode.attrib.get("name").endswith("trvk_pkg1 SCE") and entry.text == "FFFFFFFF" : + elif ( + subnode.attrib.get("name").endswith("trvk_pkg1 SCE") + and entry.text == "FFFFFFFF" + ): print("Blank") else: printok() @@ -386,25 +459,49 @@ def printrisklevel(risklevel): printrisklevel(risklevel) print(" At offset : 0x%s" % subnode.attrib.get("offset").upper()) if isReversed: - print(" Actual data (reversed from original) :", end='') + print(" Actual data (reversed from original) :", end="") else: - print(" Actual data :", end='') + print(" Actual data :", end="") print_formatedlines(filedata.upper(), 32) - print(" Expected data (one of the list):", end='') - for entry in chktree.findall(".//%s/%s/%s[@name='%s']/"%(flashType, node.tag, subnode.tag, subnode.attrib.get("name"))): + print(" Expected data (one of the list):", end="") + for entry in chktree.findall( + ".//%s/%s/%s[@name='%s']/" + % (flashType, node.tag, subnode.tag, subnode.attrib.get("name")) + ): print_formatedlines(entry.text.upper(), 32) - print - + print() + if subnode.tag == "datafill": checkCount += 1 ChkResult = True - print("%s :" % subnode.attrib.get("name"), end=' ') + print("%s :" % subnode.attrib.get("name"), end=" ") if subnode.attrib.get("ldrsize") is not None: - ldrsize = (int(string2hex(getDatas(rawfiledata, int(subnode.attrib.get("ldrsize"), 16), 0x2)), 16) * 0x10) + 0x40 + ldrsize = ( + int( + string2hex( + getDatas( + rawfiledata, + int(subnode.attrib.get("ldrsize"), 16), + 0x2, + ) + ), + 16, + ) + * 0x10 + ) + 0x40 start = int(subnode.attrib.get("regionstart"), 16) + ldrsize length = int(subnode.attrib.get("regionsize"), 16) - ldrsize elif subnode.attrib.get("sizefrom") is not None: - datasize = int(string2hex(getDatas(rawfiledata, int(subnode.attrib.get("sizefrom"), 16), 0x2)), 16) + datasize = int( + string2hex( + getDatas( + rawfiledata, + int(subnode.attrib.get("sizefrom"), 16), + 0x2, + ) + ), + 16, + ) start = int(subnode.attrib.get("regionstart"), 16) + datasize length = int(subnode.attrib.get("regionsize"), 16) - datasize else: @@ -431,25 +528,49 @@ def printrisklevel(risklevel): warningCount += 1 warningList.append(subnode.attrib.get("name")) printrisklevel(risklevel) - print(" All bytes from offset 0x%X to offset 0x%X should be 0x%s." % (start, start + length, subnode.text.upper())) - print(" Byte at offset 0x%X has value : 0x%s"%(FalseOffset, FalseValue.upper())) + print( + " All bytes from offset 0x%X to offset 0x%X should be 0x%s." + % (start, start + length, subnode.text.upper()) + ) + print( + " Byte at offset 0x%X has value : 0x%s" + % (FalseOffset, FalseValue.upper()) + ) print(" Subsequent bytes in the range may be wrong as well.") print() if subnode.tag == "hash": checkCount += 1 ChkResult = False - print("%s :"%subnode.attrib.get("name"), end=' ') + print("%s :" % subnode.attrib.get("name"), end=" ") + if subnode.attrib.get("name").endswith("trvk_prg1 Hash") and skipHash: checkCount -= 1 print("Skipped") continue + if subnode.attrib.get("sizeoffset") is not None: - size = int(string2hex(getDatas(rawfiledata, int(subnode.attrib.get("sizeoffset"), 16), int(subnode.attrib.get("sizelength"), 16))), 16) + size = int( + string2hex( + getDatas( + rawfiledata, + int(subnode.attrib.get("sizeoffset"), 16), + int(subnode.attrib.get("sizelength"), 16), + ) + ), + 16, + ) + else: size = int(subnode.attrib.get("size"), 16) - hashdata = getMD5(rawfiledata, int(subnode.attrib.get("offset"), 16), size) - for hash in hashtree.findall(".//type[@name='%s']/"%(subnode.attrib.get("type"))): + + hashdata = getMD5( + rawfiledata, int(subnode.attrib.get("offset"), 16), size + ) + + for hash in hashtree.findall( + ".//type[@name='%s']/" % (subnode.attrib.get("type")) + ): if hashdata.lower() == hash.text.lower(): printok() ChkResult = True @@ -457,135 +578,261 @@ def printrisklevel(risklevel): print(" MD5 =", hashdata.upper()) print(" Version =", hash.attrib.get("name")) break + if ChkResult == False: + if risklevel == "DANGER": dangerCount += 1 dangerList.append(subnode.attrib.get("name")) + elif risklevel == "WARNING": warningCount += 1 warningList.append(subnode.attrib.get("name")) + printrisklevel(risklevel) print(" Size = 0x%X" % size) print(" MD5 =", hashdata.upper()) print(" Version = (unknown)") + print() if subnode.tag == "datalist": - print("%s :" % subnode.attrib.get("name"), end=' ') + print("%s :" % subnode.attrib.get("name"), end=" ") if subnode.attrib.get("ldrsize") is not None: - d = string2hex(getDatas(rawfiledata, int(subnode.attrib.get("ldrsize"), 16), 0x2)) + d = string2hex( + getDatas( + rawfiledata, int(subnode.attrib.get("ldrsize"), 16), 0x2 + ) + ) size = (int(d, 16) * 0x10) + 0x40 + else: size = int(subnode.attrib.get("size"), 16) - filedata = getDatas(rawfiledata, int(subnode.attrib.get("offset"), 16), size) - for datatreshold in chktree.findall(".//%s/%s/%s[@name='%s']/" % (flashType, node.tag, subnode.tag, subnode.attrib.get("name"))): + + filedata = getDatas( + rawfiledata, int(subnode.attrib.get("offset"), 16), size + ) + + for datatreshold in chktree.findall( + ".//%s/%s/%s[@name='%s']/" + % (flashType, node.tag, subnode.tag, subnode.attrib.get("name")) + ): checkCount += 1 ChkResult = True r = {} + if datatreshold.attrib.get("key") == "*": - for k,v in Counter(filedata).items(): + + for k, v in Counter(filedata).items(): c = float(v) / size * 100 - if c > float(datatreshold.text.replace(',','.')): + + if c > float(datatreshold.text.replace(",", ".")): ChkResult = False - tag = string2hex([k] if isinstance(k, int) else k).upper() + tag = string2hex( + [k] if isinstance(k, int) else k + ).upper() r[tag] = c else: - _filedata = filedata.decode('latin') - c = float(_filedata.count(chr(int(datatreshold.attrib.get("key"), 16)))) / size * 100 - if c > float(datatreshold.text.replace(',', '.')): + _filedata = filedata.decode("latin") + c = ( + float( + _filedata.count( + chr(int(datatreshold.attrib.get("key"), 16)) + ) + ) + / size + * 100 + ) + + if c > float(datatreshold.text.replace(",", ".")): tag = datatreshold.attrib.get("key").upper() + r[tag] = c + if ChkResult: printok() + else: if risklevel == "DANGER": dangerCount += 1 dangerList.append(subnode.attrib.get("name")) + elif risklevel == "WARNING": warningCount += 1 warningList.append(subnode.attrib.get("name")) + printrisklevel(risklevel) + if datatreshold.attrib.get("key") == "*": print(" Any bytes") + else: - print(" 0x%s bytes" % datatreshold.attrib.get("key").upper()) - print("from offset 0x%s to offset 0x%X should be less than %s%%." % (subnode.attrib.get("offset").upper(), int(subnode.attrib.get("offset"), 16) + size, datatreshold.text.replace(',','.'))) + print( + " 0x%s bytes" % datatreshold.attrib.get("key").upper() + ) + + print( + "from offset 0x%s to offset 0x%X should be less than %s%%." + % ( + subnode.attrib.get("offset").upper(), + int(subnode.attrib.get("offset"), 16) + size, + datatreshold.text.replace(",", "."), + ) + ) + for x in sorted(r.keys()): print(" 0x%s is %.2f%%" % ((x), r[x])) if subnode.tag == "datamatchid": - print(subnode.text, ":", end=' ') + print(subnode.text, ":", end=" ") d = {} - for id in chktree.findall(".//%s/%s//datamatch[@id='%s']" % (flashType, node.tag, subnode.attrib.get("id"))): + + for id in chktree.findall( + ".//%s/%s//datamatch[@id='%s']" + % (flashType, node.tag, subnode.attrib.get("id")) + ): checkCount += 1 + if id.attrib.get("seqrep") is not None: c = 0 + while c != int(id.attrib.get("seqrep"), 16): - filedata = string2hex(getDatas(rawfiledata, int(id.attrib.get("offset"), 16) + c * int(id.attrib.get("length"), 16), int(id.attrib.get("length"), 16))) - tag = "%s at 0x%X" % (id.text, int(id.attrib.get("offset"), 16) + c * int(id.attrib.get("length"), 16)) + filedata = string2hex( + getDatas( + rawfiledata, + int(id.attrib.get("offset"), 16) + + c * int(id.attrib.get("length"), 16), + int(id.attrib.get("length"), 16), + ) + ) + tag = "%s at 0x%X" % ( + id.text, + int(id.attrib.get("offset"), 16) + + c * int(id.attrib.get("length"), 16), + ) d[tag] = filedata.upper() c += 1 + else: - filedata = string2hex(getDatas(rawfiledata, int(id.attrib.get("offset"), 16), int(id.attrib.get("length"), 16))) + filedata = string2hex( + getDatas( + rawfiledata, + int(id.attrib.get("offset"), 16), + int(id.attrib.get("length"), 16), + ) + ) tag = id.text d[tag] = filedata.upper() + if len(set(d.values())) != 1: + if risklevel == "DANGER": dangerCount += 1 dangerList.append("datamatches : %s" % subnode.text) + elif risklevel == "WARNING": warningCount += 1 warningList.append("datamatches : %s" % subnode.text) + printrisklevel(risklevel) print(" Following datas should be the same :") - for id in chktree.findall(".//%s/%s//datamatch[@id='%s']" % (flashType, node.tag, subnode.attrib.get("id"))): + + for id in chktree.findall( + ".//%s/%s//datamatch[@id='%s']" + % (flashType, node.tag, subnode.attrib.get("id")) + ): + if id.attrib.get("nodisp") is not None: - print(" %s at offset 0x%s length 0x%s" % (id.text, id.attrib.get("offset").upper(), id.attrib.get("length").upper())) + print( + " %s at offset 0x%s length 0x%s" + % ( + id.text, + id.attrib.get("offset").upper(), + id.attrib.get("length").upper(), + ) + ) print(" (too long to dilplay)") + elif id.attrib.get("seqrep") is not None: - print(" %s at offset 0x%s length 0x%s, repeted 0x%s time" % (id.text, id.attrib.get("offset").upper(), id.attrib.get("length").upper(), id.attrib.get("seqrep").upper())) + print( + " %s at offset 0x%s length 0x%s, repeted 0x%s time" + % ( + id.text, + id.attrib.get("offset").upper(), + id.attrib.get("length").upper(), + id.attrib.get("seqrep").upper(), + ) + ) print(" (too long to dilplay)") + else: - print(" %s at offset 0x%s length 0x%s" % (id.text, id.attrib.get("offset").upper(), id.attrib.get("length").upper())) + print( + " %s at offset 0x%s length 0x%s" + % ( + id.text, + id.attrib.get("offset").upper(), + id.attrib.get("length").upper(), + ) + ) print_formatedlines(d[id.text], 32) - print + print() + else: printok() if subnode.tag == "repcheck": checkCount += 1 ChkResult = True - print("%s :" % subnode.attrib.get("name"), end=' ') - key = bytes.fromhex(subnode.text) # hex2string(subnode.text) + print("%s :" % subnode.attrib.get("name"), end=" ") + key = bytes.fromhex(subnode.text) # hex2string(subnode.text) beg = 0 index = beg nothing = True indexlist = [] + while index != -1: index = rawfiledata.find(key, beg) + if index != -1 and index != int(subnode.attrib.get("offset"), 16): nothing = False ChkResult = False indexlist.append("0x%X" % index) + elif index == int(subnode.attrib.get("offset"), 16): nothing = False + beg = index + (len(subnode.text) // 2) + if nothing or not ChkResult: + if risklevel == "DANGER": dangerCount += 1 dangerList.append("repcheck : %s" % subnode.attrib.get("name")) + elif risklevel == "WARNING": warningCount += 1 warningList.append("repcheck : %s" % subnode.attrib.get("name")) + printrisklevel(risklevel) + if isReversed: - print(" Following data (reversed) expected at offset 0x%s :" % subnode.attrib.get("offset").upper()) + print( + " Following data (reversed) expected at offset 0x%s :" + % subnode.attrib.get("offset").upper() + ) + else: - print(" Following data expected at offset 0x%s :" % subnode.attrib.get("offset").upper()) + print( + " Following data expected at offset 0x%s :" + % subnode.attrib.get("offset").upper() + ) + print_formatedlines(subnode.text, 32) + if nothing: print(" No matching data found!") print() + else: print(" Repetition(s) found at offset(s) :") print(" ", ", ".join(indexlist)) @@ -593,10 +840,10 @@ def printrisklevel(risklevel): else: printok() - print() print() print("******* Additional information *******") + if flashType == "NOR": HDD = getDatas(rawfiledata, 0xF20204, 0x3C) MAC = string2hex(getDatas(rawfiledata, 0x3F040, 0x6)).upper() @@ -604,47 +851,58 @@ def printrisklevel(risklevel): eCID = getDatas(rawfiledata, 0x3F070, 0x20) board_id = getDatas(rawfiledata, 0x3F090, 0x8) kiban_id = getDatas(rawfiledata, 0x3F098, 0xC) - hdd_split = [i.decode('latin') for i in HDD.split()] + hdd_split = [i.decode("latin") for i in HDD.split()] print("HDD :", *hdd_split) + if flashType == "NAND": MAC = string2hex(getDatas(rawfiledata, 0x90840, 0x6)).upper() CID = string2hex(getDatas(rawfiledata, 0x9086A, 0x6)).upper() eCID = getDatas(rawfiledata, 0x90870, 0x20) board_id = getDatas(rawfiledata, 0x90890, 0x8) kiban_id = getDatas(rawfiledata, 0x90898, 0xC) - if flashType in ['NAND_PS3Xploit', 'EMMC_PS3Xploit'] : - MAC = string2hex(getDatas(rawfiledata, 0x90840-0x40000, 0x6)).upper() - CID = string2hex(getDatas(rawfiledata, 0x9086A-0x40000, 0x6)).upper() - eCID = getDatas(rawfiledata, 0x90870-0x40000, 0x20) - board_id = getDatas(rawfiledata, 0x90890-0x40000, 0x8) - kiban_id = getDatas(rawfiledata, 0x90898-0x40000, 0xC) - print("MAC address :", ":".join(a+b for a,b in zip(MAC[::2], MAC[1::2]))) + + if flashType in ["NAND_PS3Xploit", "EMMC_PS3Xploit"]: + MAC = string2hex(getDatas(rawfiledata, 0x90840 - 0x40000, 0x6)).upper() + CID = string2hex(getDatas(rawfiledata, 0x9086A - 0x40000, 0x6)).upper() + eCID = getDatas(rawfiledata, 0x90870 - 0x40000, 0x20) + board_id = getDatas(rawfiledata, 0x90890 - 0x40000, 0x8) + kiban_id = getDatas(rawfiledata, 0x90898 - 0x40000, 0xC) + + print("MAC address :", ":".join(a + b for a, b in zip(MAC[::2], MAC[1::2]))) print("CID : 0x%s" % CID) - print("eCID : %s" % eCID.decode('latin')) - print("board_id (part of console S/N) : %s" % board_id.decode('latin')) - print("kiban_id (board barcode) : %s" % kiban_id.decode('latin')) - - if CID.startswith("0FFF"): printcolored("cyan", "This is a refurbished console!") - + print("eCID : %s" % eCID.decode("latin")) + print("board_id (part of console S/N) : %s" % board_id.decode("latin")) + print("kiban_id (board barcode) : %s" % kiban_id.decode("latin")) + + if CID.startswith("0FFF"): + printcolored("cyan", "This is a refurbished console!") + print() print() print() print("******* Checks completed *******") print() print("Total number of checks =", checkCount) - print("Number of dangers =", end=' ') - if dangerCount > 0: printcolored("red", dangerCount) - else: printcolored("green", dangerCount) - print("Number of warnings =", end=' ') - if warningCount > 0: printcolored("yellow", warningCount) - else: printcolored("green", warningCount) + print("Number of dangers =", end=" ") if dangerCount > 0: - print + printcolored("red", dangerCount) + else: + printcolored("green", dangerCount) + + print("Number of warnings =", end=" ") + + if warningCount > 0: + printcolored("yellow", warningCount) + else: + printcolored("green", warningCount) + + if dangerCount > 0: + print() print("Following check(s) returned a") printrisklevel("DANGER") printcolored("red", " " + "\n ".join(dangerList)) - + if warningCount > 0: print() print("Following check(s) returned a") @@ -653,29 +911,36 @@ def printrisklevel(risklevel): print() print("All checks done in %.2f seconds." % (time.time() - startTime)) - - if flashType in ['NOR', 'EMMC_PS3Xploit'] : - printcolored("MAGENTA", "\n\n\ - ---------------------------------------------------------------------------- \n\ -| IMPORTANT NOTICE ! |\n\ -| Checks of late CECH-25xxx, CECH-3xxxx and CECH-4xxxx consoles dumps still |\n\ -| under development and may return false results. If you feel it's the case, |\n\ -| please post your *.checklog.txt in a new issue on my github repository: |\n\ -| https://github.com/littlebalup/PyPS3tools/issues |\n\ -| Thanks! It will help me a lot to improve that tool ;) |\n\ - ---------------------------------------------------------------------------- ") - + + if flashType in ["NOR", "EMMC_PS3Xploit"]: + printcolored( + "MAGENTA", + """ + + + ---------------------------------------------------------------------------- + | IMPORTANT NOTICE ! | + | Checks of late CECH-25xxx, CECH-3xxxx and CECH-4xxxx consoles dumps still | + | under development and may return false results. If you feel it's the case, | + | please post your *.checklog.txt in a new issue on my github repository: | + | https://github.com/littlebalup/PyPS3tools/issues | + | Thanks! It will help me a lot to improve that tool ;) | + ---------------------------------------------------------------------------- + + """, + ) cl.close() - with open('%s.checklog.txt' % inputFile) as f: - cleanlog = f.read().replace('\x1B\x5B\x33\x31\x6D\x1B\x5B\x32\x32\x6D', '') - cleanlog = cleanlog.replace('\x1B\x5B\x33\x32\x6D\x1B\x5B\x32\x32\x6D', '') - cleanlog = cleanlog.replace('\x1B\x5B\x33\x33\x6D\x1B\x5B\x32\x32\x6D', '') - cleanlog = cleanlog.replace('\x1B\x5B\x33\x35\x6D\x1B\x5B\x32\x32\x6D', '') - cleanlog = cleanlog.replace('\x1B\x5B\x33\x36\x6D\x1B\x5B\x32\x32\x6D', '') - with open('%s.checklog.txt' % inputFile, "w") as f: + + with open("%s.checklog.txt" % inputFile) as f: + cleanlog = f.read().replace("\x1B\x5B\x33\x31\x6D\x1B\x5B\x32\x32\x6D", "") + cleanlog = cleanlog.replace("\x1B\x5B\x33\x32\x6D\x1B\x5B\x32\x32\x6D", "") + cleanlog = cleanlog.replace("\x1B\x5B\x33\x33\x6D\x1B\x5B\x32\x32\x6D", "") + cleanlog = cleanlog.replace("\x1B\x5B\x33\x35\x6D\x1B\x5B\x32\x32\x6D", "") + cleanlog = cleanlog.replace("\x1B\x5B\x33\x36\x6D\x1B\x5B\x32\x32\x6D", "") + + with open("%s.checklog.txt" % inputFile, "w") as f: f.write(cleanlog) - if dangerCount > 0: sys.exit(3)