def gen_multi_file_header(prlist, filelist): oflist = [] osizelist = [] ototlist = [] files = [] totSize = 0 for i in range(len(prlist)): for j in prlist[i][4]: el = j[0] if el.endswith('.nca'): oflist.append(j[0]) #print(j[0]) totSize = totSize + j[1] #print(j[1]) ototlist.append(j[0]) sec_hashlist = list() GClist = list() # print(filelist) for file in oflist: for filepath in filelist: if filepath.endswith('.nsp') or filepath.endswith('.nsz'): try: f = squirrelNSP(filepath) sha, size, gamecard = f.file_hash(file) if sha != False: sec_hashlist.append(sha) osizelist.append(size) GClist.append([file, gamecard]) f.flush() f.close() except BaseException as e: Print.error('Exception: ' + str(e)) if filepath.endswith('.xci') or filepath.endswith('.xcz'): try: f = squirrelXCI(filepath) sha, size, gamecard = f.file_hash(file) if sha != False: sec_hashlist.append(sha) osizelist.append(size) GClist.append([file, gamecard]) f.flush() f.close() except BaseException as e: Print.error('Exception: ' + str(e)) xci_header, game_info, sig_padding, xci_certificate, root_header, upd_header, norm_header, sec_header, rootSize, upd_multiplier, norm_multiplier, sec_multiplier = sq_tools.get_xciheader( oflist, osizelist, sec_hashlist) totSize = len(xci_header) + len(game_info) + len(sig_padding) + len( xci_certificate) + rootSize outheader = xci_header outheader += game_info outheader += sig_padding outheader += xci_certificate outheader += root_header outheader += upd_header outheader += norm_header outheader += sec_header properheadsize = len(outheader) return outheader, properheadsize, totSize, oflist
def file_verification(filename,hash=False): if not os.path.exists(cachefolder): os.makedirs(cachefolder) tempfolder=os.path.join(cachefolder, 'temp') if not os.path.exists(tempfolder): os.makedirs(tempfolder) verdict=False;isrestored=False;cnmt_is_patched=False if filename.endswith('.nsp') or filename.endswith('.nsx') or filename.endswith('.nsz') or filename.endswith('.xcz') or filename.endswith('.xci'): try: if filename.endswith('.nsp') or filename.endswith('.nsx') or filename.endswith('.nsz'): f = squirrelNSP(filename, 'rb') elif filename.endswith('.xci') or filename.endswith('.xcz'): f = factory(filename) f.open(filename, 'rb') check,feed=f.verify() if filename.endswith('.nsp') or filename.endswith('.nsx') or filename.endswith('.nsz'): verdict,headerlist,feed=f.verify_sig(feed,tempfolder,cnmt='nocheck') else: verdict,headerlist,feed=f.verify_sig(feed,tempfolder) output_type='nsp';multi=False;cnmtcount=0 if verdict == True: isrestored=True for i in range(len(headerlist)): entry=headerlist[i] if str(entry[0]).endswith('.cnmt.nca'): cnmtcount+=1 if cnmt_is_patched==False: status=entry[2] if status=='patched': cnmt_is_patched=True if entry[1]!=False: if int(entry[-1])==1: output_type='xci' isrestored=False else: pass if isrestored == False: if cnmt_is_patched !=True: print('\nFILE VERIFICATION CORRECT.\n -> FILE WAS MODIFIED BUT ORIGIN IS CONFIRMED AS LEGIT\n') else: print('\nFILE VERIFICATION CORRECT. \n -> FILE WAS MODIFIED AND CNMT PATCHED\n') else: print("\nFILE VERIFICATION CORRECT. FILE IS SAFE.\n") if verdict == False: print("\nFILE VERIFICATION INCORRECT. \n -> UNCONFIRMED ORIGIN FILE HAS BEEN TAMPERED WITH\n") if hash==True and verdict==True: if filename.endswith('.nsp') or filename.endswith('.nsx') or filename.endswith('.xci'): verdict,feed=f.verify_hash_nca(65536,headerlist,verdict,feed) elif filename.endswith('.nsz'): verdict,feed=f.nsz_hasher(65536,headerlist,verdict,feed) elif filename.endswith('.xcz'): verdict,feed=f.xcz_hasher(65536,headerlist,verdict,feed) f.flush() f.close() except BaseException as e: Print.error('Exception: ' + str(e)) return verdict,isrestored,cnmt_is_patched
def install_conv_st1(filepath, outfolder, keypatch='false'): tname = str(os.path.basename(filepath))[:-3] + 'nsp' tmpfile = os.path.join(outfolder, tname) if filepath.endswith('xci'): f = factory(filepath) f.open(filepath, 'rb') elif filepath.endswith('nsp'): f = squirrelNSP(filepath, 'rb') f.c_nsp_direct(65536, tmpfile, outfolder, keypatch=keypatch) f.flush() f.close()
def generate_and_transfer_st1(filepath,outfolder,keypatch='false'): tname=str(os.path.basename(filepath))[:-3]+'xci' tmpfile=os.path.join(outfolder,tname) if filepath.endswith('xci') or filepath.endswith('xcz'): f = factory(filepath) f.open(filepath, 'rb') elif filepath.endswith('nsp') or filepath.endswith('nsz'): f = squirrelNSP(filepath, 'rb') f.c_xci_direct(65536,tmpfile,outfolder,metapatch='true',keypatch=keypatch) f.flush() f.close()
def get_DB_dict(filepath): installedsize=0 if filepath.endswith('xci') or filepath.endswith('xcz'): f = factory(filepath) f.open(filepath, 'rb') dict=f.return_DBdict() f.flush() f.close() elif filepath.endswith('nsp') or filepath.endswith('nsz') or filepath.endswith('nsx'): f = squirrelNSP(filepath) dict=f.return_DBdict() f.flush() f.close() return dict
def calculate_name(filelist, romanize=True, ext='.xci'): from Fs import Nsp as squirrelNSP from Fs import Xci as squirrelXCI import re prlist = list() for filepath in filelist: if filepath.endswith('.nsp'): try: c = list() f = squirrelNSP(filepath) contentlist = f.get_content(False, False, True) f.flush() f.close() if len(prlist) == 0: for i in contentlist: prlist.append(i) else: for j in range(len(contentlist)): notinlist = False for i in range(len(prlist)): if contentlist[j][1] == prlist[i][1]: if contentlist[j][6] > prlist[i][6]: del prlist[i] prlist.append(contentlist[j]) notinlist = False elif contentlist[j][6] == prlist[i][6]: notinlist = False else: notinlist = True if notinlist == True: prlist.append(contentlist[j]) except BaseException as e: nutPrint.error('Exception: ' + str(e)) if filepath.endswith('.xci'): try: c = list() f = squirrelXCI(filepath) contentlist = f.get_content(False, False, True) f.flush() f.close() if len(prlist) == 0: for i in contentlist: prlist.append(i) else: for j in range(len(contentlist)): notinlist = False for i in range(len(prlist)): if contentlist[j][1] == prlist[i][1]: if contentlist[j][6] > prlist[i][6]: del prlist[i] prlist.append(contentlist[j]) notinlist = False elif contentlist[j][6] == prlist[i][6]: notinlist = False else: notinlist = True if notinlist == True: prlist.append(contentlist[j]) except BaseException as e: nutPrint.error('Exception: ' + str(e)) basecount = 0 basename = '' basever = '' baseid = '' basefile = '' updcount = 0 updname = '' updver = '' updid = '' updfile = '' dlccount = 0 dlcname = '' dlcver = '' dlcid = '' dlcfile = '' ccount = '' bctag = '' updtag = '' dctag = '' for i in range(len(prlist)): if prlist[i][5] == 'BASE': basecount += 1 if baseid == "": basefile = str(prlist[i][0]) baseid = str(prlist[i][1]) basever = '[v' + str(prlist[i][6]) + ']' if prlist[i][5] == 'UPDATE': updcount += 1 endver = str(prlist[i][6]) if updid == "": updfile = str(prlist[i][0]) updid = str(prlist[i][1]) updver = '[v' + str(prlist[i][6]) + ']' if prlist[i][5] == 'DLC': dlccount += 1 if dlcid == "": dlcfile = str(prlist[i][0]) dlcid = str(prlist[i][1]) dlcver = '[v' + str(prlist[i][6]) + ']' if basecount != 0: bctag = str(basecount) + 'G' else: bctag = '' if updcount != 0: if bctag != '': updtag = '+' + str(updcount) + 'U' else: updtag = str(updcount) + 'U' else: updtag = '' if dlccount != 0: if bctag != '' or updtag != '': dctag = '+' + str(dlccount) + 'D' else: dctag = str(dlccount) + 'D' else: dctag = '' ccount = '(' + bctag + updtag + dctag + ')' if baseid != "": if basefile.endswith('.xci'): f = squirrelXCI(basefile) elif basefile.endswith('.nsp'): f = squirrelNSP(basefile) ctitl = f.get_title(baseid) f.flush() f.close() if ctitl == 'DLC' or ctitl == '-': ctitl = '' elif updid != "": if updfile.endswith('.xci'): f = squirrelXCI(updfile) elif updfile.endswith('.nsp'): f = squirrelNSP(updfile) ctitl = f.get_title(updid) f.flush() f.close() if ctitl == 'DLC' or ctitl == '-': ctitl = '' elif dlcid != "": ctitl = get_title if dlcfile.endswith('.xci'): f = squirrelXCI(dlcfile) elif dlcfile.endswith('.nsp'): f = squirrelNSP(dlcfile) ctitl = f.get_title(dlcid) f.flush() f.close() else: ctitl = 'UNKNOWN' baseid = '[' + baseid.upper() + ']' updid = '[' + updid.upper() + ']' dlcid = '[' + dlcid.upper() + ']' if ccount == '(1G)' or ccount == '(1U)' or ccount == '(1D)': ccount = '' if baseid != "[]": if updver != "": endname = ctitl + ' ' + baseid + ' ' + updver + ' ' + ccount else: endname = ctitl + ' ' + baseid + ' ' + basever + ' ' + ccount elif updid != "[]": endname = ctitl + ' ' + updid + ' ' + updver + ' ' + ccount else: endname = ctitl + ' ' + dlcid + ' ' + dlcver + ' ' + ccount if romanize == True: import pykakasi kakasi = pykakasi.kakasi() kakasi.setMode("H", "a") kakasi.setMode("K", "a") kakasi.setMode("J", "a") kakasi.setMode("s", True) kakasi.setMode("E", "a") kakasi.setMode("a", None) kakasi.setMode("C", False) converter = kakasi.getConverter() endname = converter.do(endname) endname = endname[0].upper() + endname[1:] endname = (re.sub(r'[\/\\\:\*\?]+', '', endname)) endname = re.sub(r'[™©®`~^´ªº¢#£€¥$ƒ±¬½¼♡«»±•²‰œæƳ☆<<>>|]', '', endname) endname = re.sub(r'[Ⅰ]', 'I', endname) endname = re.sub(r'[Ⅱ]', 'II', endname) endname = re.sub(r'[Ⅲ]', 'III', endname) endname = re.sub(r'[Ⅳ]', 'IV', endname) endname = re.sub(r'[Ⅴ]', 'V', endname) endname = re.sub(r'[Ⅵ]', 'VI', endname) endname = re.sub(r'[Ⅶ]', 'VII', endname) endname = re.sub(r'[Ⅷ]', 'VIII', endname) endname = re.sub(r'[Ⅸ]', 'IX', endname) endname = re.sub(r'[Ⅹ]', 'X', endname) endname = re.sub(r'[Ⅺ]', 'XI', endname) endname = re.sub(r'[Ⅻ]', 'XII', endname) endname = re.sub(r'[Ⅼ]', 'L', endname) endname = re.sub(r'[Ⅽ]', 'C', endname) endname = re.sub(r'[Ⅾ]', 'D', endname) endname = re.sub(r'[Ⅿ]', 'M', endname) endname = re.sub(r'[—]', '-', endname) endname = re.sub(r'[√]', 'Root', endname) endname = re.sub(r'[àâá@äå]', 'a', endname) endname = re.sub(r'[ÀÂÁÄÅ]', 'A', endname) endname = re.sub(r'[èêéë]', 'e', endname) endname = re.sub(r'[ÈÊÉË]', 'E', endname) endname = re.sub(r'[ìîíï]', 'i', endname) endname = re.sub(r'[ÌÎÍÏ]', 'I', endname) endname = re.sub(r'[òôóöø]', 'o', endname) endname = re.sub(r'[ÒÔÓÖØ]', 'O', endname) endname = re.sub(r'[ùûúü]', 'u', endname) endname = re.sub(r'[ÙÛÚÜ]', 'U', endname) endname = re.sub(r'[’]', "'", endname) endname = re.sub(r'[“”]', '"', endname) endname = re.sub(' {3,}', ' ', endname) re.sub(' {2,}', ' ', endname) try: endname = endname.replace("( ", "(") endname = endname.replace(" )", ")") endname = endname.replace("[ ", "[") endname = endname.replace(" ]", "]") endname = endname.replace("[ (", "[(") endname = endname.replace(") ]", ")]") endname = endname.replace("[]", "") endname = endname.replace("()", "") endname = endname.replace('" ', '"') endname = endname.replace(' "', '"') endname = endname.replace(" !", "!") endname = endname.replace(" ?", "?") endname = endname.replace(" ", " ") endname = endname.replace(" ", " ") endname = endname.replace('"', '') endname = endname.replace(')', ') ') endname = endname.replace(']', '] ') endname = endname.replace("[ (", "[(") endname = endname.replace(") ]", ")]") endname = endname.replace(" ", " ") except: pass if endname[-1] == ' ': endname = endname[:-1] endname = endname + ext return endname, prlist
def compress(filePath, ofolder=None, level=17, threads=0, delta=False, ofile=None, buffer=65536, pos=False, nthreads=False): isthreaded = False if pos != False: isthreaded = True elif str(pos) == '0': isthreaded = True else: pos = 0 pos = int(pos) files_list = sq_tools.ret_nsp_offsets(filePath) files = list() filesizes = list() if isthreaded == True and nthreads != False: tqlist = list() for i in range(nthreads): tq = tqdm(total=0, unit='B', unit_scale=True, leave=False, position=i) tqlist.append(tq) fplist = list() for k in range(len(files_list)): entry = files_list[k] fplist.append(entry[0]) for i in range(len(files_list)): entry = files_list[i] cnmtfile = entry[0] if cnmtfile.endswith('.cnmt.nca'): f = squirrelNSP(filePath, 'rb') titleid, titleversion, base_ID, keygeneration, rightsId, RSV, RGV, ctype, metasdkversion, exesdkversion, hasHtmlManual, Installedsize, DeltaSize, ncadata = f.get_data_from_cnmt( cnmtfile) f.flush() f.close() for j in range(len(ncadata)): row = ncadata[j] # print(row) if row['NCAtype'] != 'Meta': test1 = str(row['NcaId']) + '.nca' test2 = str(row['NcaId']) + '.ncz' if test1 in fplist or test2 in fplist: # print(str(row['NcaId'])+'.nca') files.append(str(row['NcaId']) + '.nca') filesizes.append(int(row['Size'])) else: # print(str(row['NcaId'])+'.cnmt.nca') files.append(str(row['NcaId']) + '.cnmt.nca') filesizes.append(int(row['Size'])) for k in range(len(files_list)): entry = files_list[k] fp = entry[0] sz = int(entry[3]) if fp.endswith('xml'): files.append(fp) filesizes.append(sz) for k in range(len(files_list)): entry = files_list[k] fp = entry[0] sz = int(entry[3]) if fp.endswith('.tik'): files.append(fp) filesizes.append(sz) for k in range(len(files_list)): entry = files_list[k] fp = entry[0] sz = int(entry[3]) if fp.endswith('.cert'): files.append(fp) filesizes.append(sz) nspheader = sq_tools.gen_nsp_header(files, filesizes) properheadsize = len(nspheader) compressionLevel = int(level) container = nutFs.factory(filePath) container.open(filePath, 'rb') CHUNK_SZ = buffer if ofolder is None and ofile is None: nszPath = filePath[0:-1] + 'z' elif ofolder is not None: nszPath = os.path.join(ofolder, os.path.basename(filePath[0:-1] + 'z')) elif ofile is not None: nszPath = ofile tsize = properheadsize for sz in filesizes: tsize += sz if isthreaded == True: from colorama import Fore colors = Fore.__dict__ k = 0 l = pos for col in colors: if l > len(colors): l = l - len(colors) color = colors[col] if k == (l + 1): break else: k += 1 t = tqdm(total=tsize, unit='B', unit_scale=True, leave=False, position=pos, bar_format="{l_bar}%s{bar}%s{r_bar}" % (color, Fore.RESET)) else: t = tqdm(total=tsize, unit='B', unit_scale=True, leave=False, position=0) # nszPath = os.path.abspath(nszPath) nszPath = Path(filePath) nszPath = os.path.join(nszPath.parents[0], os.path.basename(filePath[0:-1] + 'z')) if isthreaded == False: t.write('\n Compressing with level %d and %d threads' % (compressionLevel, threads)) t.write('%s -> %s \n' % (filePath, nszPath)) newNsp = nutFs.Pfs0.Pfs0Stream(nszPath, headsize=properheadsize) for file in files: for nspf in container: if nspf._path == file: if isinstance( nspf, nutFs.Nca.Nca ) and nspf.header.contentType == nutFs.Type.Content.DATA and delta == False: if isthreaded == False: t.write('-> Skipping delta fragment') continue if isinstance(nspf, nutFs.Nca.Nca) and ( nspf.header.contentType == nutFs.Type.Content.PROGRAM or nspf.header.contentType == nutFs.Type.Content.PUBLIC_DATA): if isNcaPacked(nspf): cctx = zstandard.ZstdCompressor(level=compressionLevel, threads=threads) newFileName = nspf._path[0:-1] + 'z' f = newNsp.add(newFileName, nspf.size, t, isthreaded) start = f.tell() nspf.seek(0) f.write(nspf.read(ncaHeaderSize)) written = ncaHeaderSize compressor = cctx.stream_writer(f) sections = get_sections(nspf) header = b'NCZSECTN' header += len(sections).to_bytes(8, 'little') i = 0 for fs in sections: i += 1 header += fs.offset.to_bytes(8, 'little') header += fs.size.to_bytes(8, 'little') header += fs.cryptoType.to_bytes(8, 'little') header += b'\x00' * 8 header += fs.cryptoKey header += fs.cryptoCounter f.write(header) written += len(header) timestamp = time.time() decompressedBytes = ncaHeaderSize totsize = 0 for fs in sections: totsize += fs.size for section in sections: #print('offset: %x\t\tsize: %x\t\ttype: %d\t\tiv%s' % (section.offset, section.size, section.cryptoType, str(hx(section.cryptoCounter)))) o = nspf.partition(offset=section.offset, size=section.size, n=None, cryptoType=section.cryptoType, cryptoKey=section.cryptoKey, cryptoCounter=bytearray( section.cryptoCounter), autoOpen=True) while not o.eof(): buffer = o.read(CHUNK_SZ) t.update(len(buffer)) if len(buffer) == 0: raise IOError('read failed') written += compressor.write(buffer) decompressedBytes += len(buffer) compressor.flush(zstandard.FLUSH_FRAME) elapsed = time.time() - timestamp minutes = elapsed / 60 seconds = elapsed % 60 speed = 0 if elapsed == 0 else (nspf.size / elapsed) written = f.tell() - start if isthreaded == False: t.write( '\n * Compressed at %d%% from %s to %s - %s' % (int(written * 100 / nspf.size), str(sq_tools.getSize(decompressedBytes)), str(sq_tools.getSize(written)), nspf._path)) t.write( ' * Compressed in %02d:%02d at speed: %.1f MB/s\n' % (minutes, seconds, speed / 1000000.0)) newNsp.resize(newFileName, written) continue else: print('not packed!') f = newNsp.add(nspf._path, nspf.size, t, isthreaded) nspf.seek(0) while not nspf.eof(): buffer = nspf.read(CHUNK_SZ) t.update(len(buffer)) f.write(buffer) t.close() newNsp.close() if isthreaded == True and nthreads != False: for i in range(nthreads): tqlist[i].close()
def get_header_size(filepath): properheadsize=0;sz=0 if filepath.endswith('xci') or filepath.endswith('xcz'): files_list=sq_tools.ret_xci_offsets(filepath) files=list();filesizes=list() fplist=list() for k in range(len(files_list)): entry=files_list[k] fplist.append(entry[0]) for i in range(len(files_list)): entry=files_list[i] cnmtfile=entry[0] if cnmtfile.endswith('.cnmt.nca'): f=squirrelXCI(filepath) titleid,titleversion,base_ID,keygeneration,rightsId,RSV,RGV,ctype,metasdkversion,exesdkversion,hasHtmlManual,Installedsize,DeltaSize,ncadata=f.get_data_from_cnmt(cnmtfile) for j in range(len(ncadata)): row=ncadata[j] # print(row) if row['NCAtype']!='Meta': test1=str(row['NcaId'])+'.nca';test2=str(row['NcaId'])+'.ncz' if test1 in fplist or test2 in fplist: # print(str(row['NcaId'])+'.nca') files.append(str(row['NcaId'])+'.nca') filesizes.append(int(row['Size'])) sz+=int(row['Size']) elif row['NCAtype']=='Meta': # print(str(row['NcaId'])+'.cnmt.nca') files.append(str(row['NcaId'])+'.cnmt.nca') filesizes.append(int(row['Size'])) sz+=int(row['Size']) sec_hashlist=list() try: for file in files: sha,size,gamecard=f.file_hash(file) # print(sha) if sha != False: sec_hashlist.append(sha) except BaseException as e: Print.error('Exception: ' + str(e)) f.flush() f.close() xci_header,game_info,sig_padding,xci_certificate,root_header,upd_header,norm_header,sec_header,rootSize,upd_multiplier,norm_multiplier,sec_multiplier=sq_tools.get_xciheader(files,filesizes,sec_hashlist) outheader=xci_header outheader+=game_info outheader+=sig_padding outheader+=xci_certificate outheader+=root_header outheader+=upd_header outheader+=norm_header outheader+=sec_header elif filepath.endswith('nsp') or filepath.endswith('nsz'): files_list=sq_tools.ret_nsp_offsets(filepath) files=list();filesizes=list() fplist=list() for k in range(len(files_list)): entry=files_list[k] fplist.append(entry[0]) for i in range(len(files_list)): entry=files_list[i] cnmtfile=entry[0] if cnmtfile.endswith('.cnmt.nca'): f=squirrelNSP(filepath) titleid,titleversion,base_ID,keygeneration,rightsId,RSV,RGV,ctype,metasdkversion,exesdkversion,hasHtmlManual,Installedsize,DeltaSize,ncadata=f.get_data_from_cnmt(cnmtfile) f.flush() f.close() for j in range(len(ncadata)): row=ncadata[j] # print(row) if row['NCAtype']!='Meta': test1=str(row['NcaId'])+'.nca';test2=str(row['NcaId'])+'.ncz' if test1 in fplist or test2 in fplist: # print(str(row['NcaId'])+'.nca') files.append(str(row['NcaId'])+'.nca') filesizes.append(int(row['Size'])) sz+=int(row['Size']) elif row['NCAtype']=='Meta': # print(str(row['NcaId'])+'.cnmt.nca') files.append(str(row['NcaId'])+'.cnmt.nca') filesizes.append(int(row['Size'])) sz+=int(row['Size']) f.flush() f.close() outheader = sq_tools.gen_nsp_header(files,filesizes) properheadsize=len(outheader) return properheadsize,keygeneration,sz
def gen_nsp_parts_spec1(filepath,target_cnmt=None,cachefolder=None,keypatch=False): if keypatch!=False: try: keypatch=int(keypatch) except: keypatch=False if cachefolder==None: cachefolder=os.path.join(ztools_dir, '_mtp_cache_') if not os.path.exists(cachefolder): os.makedirs(cachefolder) else: for f in os.listdir(cachefolder): fp = os.path.join(cachefolder, f) try: shutil.rmtree(fp) except OSError: os.remove(fp) files_list=sq_tools.ret_nsp_offsets(filepath) files=list();filesizes=list() fplist=list() for k in range(len(files_list)): entry=files_list[k] fplist.append(entry[0]) if target_cnmt==None: for i in range(len(files_list)): entry=files_list[i] cnmtfile=entry[0] if cnmtfile.endswith('.cnmt.nca'): target_cnmt=cnmtfile break for i in range(len(files_list)): entry=files_list[i] cnmtfile=entry[0] if cnmtfile.endswith('.cnmt.nca') and target_cnmt==cnmtfile: f=squirrelNSP(filepath) titleid,titleversion,base_ID,keygeneration,rightsId,RSV,RGV,ctype,metasdkversion,exesdkversion,hasHtmlManual,Installedsize,DeltaSize,ncadata=f.get_data_from_cnmt(cnmtfile) f.flush() f.close() for j in range(len(ncadata)): row=ncadata[j] # print(row) if row['NCAtype']!='Meta' and row['NCAtype']!='Program': test1=str(row['NcaId'])+'.nca';test2=str(row['NcaId'])+'.ncz' if test1 in fplist: files.append(str(row['NcaId'])+'.nca') filesizes.append(int(row['Size'])) elif test2 in fplist: files.append(str(row['NcaId'])+'.ncz') for k in range(len(files_list)): entry=files_list[k] if entry[0]==test2: filesizes.append(int(entry[3])) break for j in range(len(ncadata)): row=ncadata[j] if row['NCAtype']=='Meta': # print(str(row['NcaId'])+'.cnmt.nca') files.append(str(row['NcaId'])+'.cnmt.nca') filesizes.append(int(row['Size'])) for j in range(len(ncadata)): row=ncadata[j] # print(row) if row['NCAtype']=='Program': test1=str(row['NcaId'])+'.nca';test2=str(row['NcaId'])+'.ncz' if test1 in fplist: files.append(str(row['NcaId'])+'.nca') filesizes.append(int(row['Size'])) elif test2 in fplist: files.append(str(row['NcaId'])+'.ncz') for k in range(len(files_list)): entry=files_list[k] if entry[0]==test2: filesizes.append(int(entry[3])) break break f.flush() f.close() outheader = sq_tools.gen_nsp_header(files,filesizes) properheadsize=len(outheader) # print(properheadsize) # print(bucketsize) i=0;sum=properheadsize; nsp=squirrelNSP(filepath) outfile=os.path.join(cachefolder, "0") outf = open(outfile, 'w+b') outf.write(outheader) written=0 for fi in files: for nca in nsp: if nca._path==fi: nca=Nca(nca) crypto1=nca.header.getCryptoType() crypto2=nca.header.getCryptoType2() if crypto2>crypto1: masterKeyRev=crypto2 if crypto2<=crypto1: masterKeyRev=crypto1 crypto = aes128.AESECB(Keys.keyAreaKey(Keys.getMasterKeyIndex(masterKeyRev), nca.header.keyIndex)) hcrypto = aes128.AESXTS(uhx(Keys.get('header_key'))) gc_flag='00'*0x01 crypto1=nca.header.getCryptoType() crypto2=nca.header.getCryptoType2() if nca.header.getRightsId() != 0: nca.rewind() if crypto2>crypto1: masterKeyRev=crypto2 if crypto2<=crypto1: masterKeyRev=crypto1 from mtp_tools import get_nca_ticket check,titleKey=get_nca_ticket(filepath,fi) if check==False: sys.exit("Can't verify titleckey") titleKeyDec = Keys.decryptTitleKey(titleKey, Keys.getMasterKeyIndex(int(masterKeyRev))) encKeyBlock = crypto.encrypt(titleKeyDec * 4) if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2(): encKeyBlock,crypto1,crypto2=squirrelNSP.get_new_cryptoblock(squirrelNSP,nca,keypatch,encKeyBlock,t) t.close() if nca.header.getRightsId() == 0: nca.rewind() encKeyBlock = nca.header.getKeyBlock() if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2(): encKeyBlock,crypto1,crypto2=squirrelNSP.get_new_cryptoblock(squirrelNSP,nca,keypatch,encKeyBlock,t) t.close() nca.rewind() i=0 newheader=nsp.get_newheader(nca,encKeyBlock,crypto1,crypto2,hcrypto,gc_flag) outf.write(newheader) written+=len(newheader) nca.seek(0xC00) break else:pass
def groupncabyid_and_idoffset(filepath, ofolder, export, buffer=65536, fat='exfat', fx='files', nodecompress=False): if filepath.endswith('.nsp') or filepath.endswith( '.nsx') or filepath.endswith('.nsz'): container = squirrelNSP(filepath, 'rb') elif filepath.endswith('.xci') or filepath.endswith('.xcz'): container = factory(filepath) container.open(filepath, 'rb') contentlist = list() ncalist = list() completefilelist = list() for nspF in container.hfs0: if str(nspF._path) == "secure": for file in nspF: completefilelist.append(str(file._path)) for nspF in container.hfs0: if str(nspF._path) == "secure": for nca in nspF: if type(nca) == Nca: if str(nca.header.contentType) == 'Content.META': crypto1 = nca.header.getCryptoType() crypto2 = nca.header.getCryptoType2() if crypto1 == 2: if crypto1 > crypto2: keygen = nca.header.getCryptoType() else: keygen = nca.header.getCryptoType2() else: keygen = nca.header.getCryptoType2() ncalist = list() for f in nca: for cnmt in f: nca.rewind() f.rewind() cnmt.rewind() titleid = cnmt.readInt64() titleversion = cnmt.read(0x4) cnmt.rewind() cnmt.seek(0xE) offset = cnmt.readInt16() content_entries = cnmt.readInt16() meta_entries = cnmt.readInt16() content_type = str(cnmt._path) content_type = content_type[:-22] titleid2 = str( hx(titleid.to_bytes(8, byteorder='big'))) titleid2 = titleid2[2:-1] cnmt.seek(0x20) if content_type == 'Application': original_ID = titleid2 cnmt.readInt64() ttag = '' CTYPE = 'BASE' elif content_type == 'Patch': original_ID = cnmt.readInt64() original_ID = str( hx( original_ID.to_bytes( 8, byteorder='big'))) original_ID = original_ID[2:-1] ttag = ' [UPD]' CTYPE = 'UPDATE' elif content_type == 'AddOnContent': original_ID = cnmt.readInt64() original_ID = str( hx( original_ID.to_bytes( 8, byteorder='big'))) original_ID = original_ID[2:-1] ttag = ' [DLC]' CTYPE = 'DLC' else: original_ID = cnmt.readInt64() original_ID = str( hx( original_ID.to_bytes( 8, byteorder='big'))) original_ID = original_ID[2:-1] cnmt.seek(0x20 + offset) for i in range(content_entries): vhash = cnmt.read(0x20) NcaId = cnmt.read(0x10) size = cnmt.read(0x6) ncatype = cnmt.read(0x1) idoffset = cnmt.read(0x1) idoffset = int.from_bytes( idoffset, byteorder='little', signed=True) #************************************************************** version = str( int.from_bytes(titleversion, byteorder='little')) version = '[v' + version + ']' titleid3 = '[' + titleid2 + ']' nca_name = str(hx(NcaId)) nca_name = nca_name[2:-1] + '.nca' ncz_name = nca_name[:-1] + 'z' if nca_name in completefilelist or ncz_name in completefilelist: ncalist.append([nca_name, idoffset]) nca_meta = str(nca._path) if nca_meta in completefilelist: ncalist.append([nca_meta, 0]) target = str(nca._path) tit_name, editor, ediver, SupLg, regionstr, isdemo = container.inf_get_title( target, offset, content_entries, original_ID) tit_name = (re.sub( r'[\/\\\:\*\?\!\"\<\>\|\.\s™©®()\~]+', ' ', tit_name)) tit_name = tit_name.strip() if tit_name == 'DLC' and ( str(titleid2).endswith('000') or str(titleid2).endswith('800')): tit_name = '-' editor = '-' tid = '[' + titleid2 + ']' filename = tit_name + ' ' + tid + ' ' + version titlerights = titleid2 + str( '0' * 15) + str(crypto2) contentlist.append([ filename, titleid2, titlerights, keygen, ncalist, CTYPE, tit_name, tid, version ]) ''' for i in contentlist: print("") print('Filename: '+i[0]) print('TitleID: '+i[1]) print('TitleRights: '+i[2]) print('Keygen: '+str(i[3])) for j in i[4]: print (j) ''' newcontentlist = [] counter = 0 for i in contentlist: idoffsets = [] files = i[4] metafile = None for j in files: if j[0].endswith('.cnmt'): metafile = j[0] break for j in files: if j[-1] not in idoffsets: idoffsets.append(j[-1]) for j in idoffsets: entry = copy.deepcopy(contentlist[counter]) newfiles = [] for k in files: if k[-1] == j: newfiles.append(k[0]) if not metafile in newfiles: newfiles.append(metafile) filename = entry[-3] + ' ' + ( entry[-2])[:-2] + str(j) + ' ' + version entry[0] = filename entry[4] = newfiles newcontentlist.append(entry) counter += 1 for nspF in container.hfs0: if str(nspF._path) == "secure": for file in nspF: if type(file) == Ticket or file._path.endswith('.cert'): test = file._path test = test[0:32] for i in newcontentlist: if i[2] == test: i[4].append(file._path) elif file._path.endswith('.xml'): test = file._path test = test[0:-4] + '.nca' for i in newcontentlist: if test in i[4]: i[4].append(file._path) for i in newcontentlist: if export == 'nsp': container.cd_spl_nsp(buffer, i[0], ofolder, i[4], fat, fx, nodecompress) if export == 'xci': if i[5] != 'BASE': container.cd_spl_nsp(buffer, i[0], ofolder, i[4], fat, fx, nodecompress) else: container.cd_spl_xci(buffer, i[0], ofolder, i[4], fat, fx, nodecompress) if export == 'both': if i[5] != 'BASE': container.cd_spl_nsp(buffer, i[0], ofolder, i[4], fat, fx, nodecompress) else: container.cd_spl_nsp(buffer, i[0], ofolder, i[4], fat, fx, nodecompress) container.cd_spl_xci(buffer, i[0], ofolder, i[4], fat, fx, nodecompress) # def exchange_id_offset(filepath,original_idoffset,new_idoffset): # def split_multiprogram_by_id(filepath,ofolder,output_format): # write_cnmt_titleid # write_cnmt_updateid
def gen_mxci_parts(input_files, cachefolder=None, keypatch=False): from listmanager import calculate_name if keypatch != False: try: keypatch = int(keypatch) except: keypatch = False if cachefolder == None: cachefolder = os.path.join(ztools_dir, '_mtp_cache_') if not os.path.exists(cachefolder): os.makedirs(cachefolder) else: for f in os.listdir(cachefolder): fp = os.path.join(cachefolder, f) try: shutil.rmtree(fp) except OSError: os.remove(fp) end_name, prlist = calculate_name(input_files, romanize=True, ext='.xci') print(f"Calculated name {end_name}") outheader, properheadsize, sz, files = gen_multi_file_header( prlist, input_files) properheadsize = len(outheader) outfile = os.path.join(cachefolder, "0") outf = open(outfile, 'w+b') outf.write(outheader) # print(properheadsize) # print(bucketsize) i = 0 sum = properheadsize for fi in files: for filepath in input_files: if filepath.endswith('xci'): xci = squirrelXCI(filepath) written = 0 for nspF in xci.hfs0: if str(nspF._path) == "secure": for nca in nspF: if nca._path == fi: nca = Nca(nca) crypto1 = nca.header.getCryptoType() crypto2 = nca.header.getCryptoType2() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 crypto = aes128.AESECB( Keys.keyAreaKey( Keys.getMasterKeyIndex(masterKeyRev), nca.header.keyIndex)) hcrypto = aes128.AESXTS( uhx(Keys.get('header_key'))) gc_flag = '00' * 0x01 crypto1 = nca.header.getCryptoType() crypto2 = nca.header.getCryptoType2() if nca.header.getRightsId() != 0: nca.rewind() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 from mtp_tools import get_nca_ticket check, titleKey = get_nca_ticket( filepath, fi) if check == False: sys.exit("Can't verify titleckey") titleKeyDec = Keys.decryptTitleKey( titleKey, Keys.getMasterKeyIndex( int(masterKeyRev))) encKeyBlock = crypto.encrypt(titleKeyDec * 4) if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2( ): encKeyBlock, crypto1, crypto2 = squirrelXCI.get_new_cryptoblock( squirrelXCI, nca, keypatch, encKeyBlock, t) t.close() if nca.header.getRightsId() == 0: nca.rewind() encKeyBlock = nca.header.getKeyBlock() if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2( ): encKeyBlock, crypto1, crypto2 = squirrelXCI.get_new_cryptoblock( squirrelXCI, nca, keypatch, encKeyBlock, t) t.close() nca.rewind() i = 0 newheader = xci.get_newheader( nca, encKeyBlock, crypto1, crypto2, hcrypto, gc_flag) outf.write(newheader) written += len(newheader) nca.seek(0xC00) break else: pass xci.flush() xci.close() elif filepath.endswith('nsp'): nsp = squirrelNSP(filepath) written = 0 for nca in nsp: if nca._path == fi: nca = Nca(nca) crypto1 = nca.header.getCryptoType() crypto2 = nca.header.getCryptoType2() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 crypto = aes128.AESECB( Keys.keyAreaKey( Keys.getMasterKeyIndex(masterKeyRev), nca.header.keyIndex)) hcrypto = aes128.AESXTS(uhx(Keys.get('header_key'))) gc_flag = '00' * 0x01 crypto1 = nca.header.getCryptoType() crypto2 = nca.header.getCryptoType2() if nca.header.getRightsId() != 0: nca.rewind() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 from mtp_tools import get_nca_ticket check, titleKey = get_nca_ticket(filepath, fi) if check == False: sys.exit("Can't verify titleckey") titleKeyDec = Keys.decryptTitleKey( titleKey, Keys.getMasterKeyIndex(int(masterKeyRev))) encKeyBlock = crypto.encrypt(titleKeyDec * 4) if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2(): encKeyBlock, crypto1, crypto2 = squirrelNSP.get_new_cryptoblock( squirrelNSP, nca, keypatch, encKeyBlock, t) t.close() if nca.header.getRightsId() == 0: nca.rewind() encKeyBlock = nca.header.getKeyBlock() if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2(): encKeyBlock, crypto1, crypto2 = squirrelNSP.get_new_cryptoblock( squirrelNSP, nca, keypatch, encKeyBlock, t) t.close() nca.rewind() i = 0 newheader = nsp.get_newheader(nca, encKeyBlock, crypto1, crypto2, hcrypto, gc_flag) outf.write(newheader) written += len(newheader) nca.seek(0xC00) break else: pass nsp.flush() nsp.close() outf.flush() outf.close() tfile = os.path.join(cachefolder, "files.csv") with open(tfile, 'w') as csvfile: csvfile.write("{}|{}|{}|{}|{}|{}\n".format("step", "filepath", "size", "targetsize", "off1", "off2")) csvfile.write("{}|{}|{}|{}|{}|{}\n".format(0, outfile, properheadsize + written, properheadsize, 0, properheadsize)) k = 0 l = 0 for fi in files: for filepath in input_files: if filepath.endswith('xci'): files_list = sq_tools.ret_xci_offsets(filepath) elif filepath.endswith('nsp'): files_list = sq_tools.ret_nsp_offsets(filepath) for j in files_list: if j[0] == fi: csvfile.write("{}|{}|{}|{}|{}|{}\n".format( k + 1, outfile, properheadsize + written, 0xC00, (properheadsize + l * 0xC00), (properheadsize + (l * 0xC00) + 0xC00))) off1 = j[1] + 0xC00 off2 = j[2] targetsize = j[3] - 0xC00 csvfile.write("{}|{}|{}|{}|{}|{}\n".format( k + 2, filepath, (os.path.getsize(filepath)), targetsize, off1, off2)) break k += 2 l += 1 return end_name