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 gen_xci_parts_spec1(filepath=None,remote=None,target_cnmt=None,cachefolder=None,keypatch=False,files_list=None): if filepath=="": filepath=None if remote=="": remote=None if remote==None: test=filepath.split('|');TD=None if len(test)<2: filepath=test[0] lib,TD,libpath=get_library_from_path(remote_lib_file,filepath) else: filepath=test[0] TD=test[1] if str(TD).upper()=="NONE": TD=None ID,name,type,size,md5,remote=DrivePrivate.get_Data(filepath,TD=TD,Print=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) if files_list==None: files_list=DriveTools.get_files_from_head(remote,remote.name) 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: metadict,d1,d2=DriveTools.get_cnmt_data(target=cnmtfile,file=remote) ncadata=metadict['ncadata'] for j in range(len(ncadata)): row=ncadata[j] 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 remote.rewind() outheader = sq_tools.gen_nsp_header(files,filesizes) properheadsize=len(outheader) # print(properheadsize) # print(bucketsize) i=0;sum=properheadsize; outfile=os.path.join(cachefolder, "0") outf = open(outfile, 'w+b') outf.write(outheader) written=0 for fi in files: if fi.endswith('nca') or fi.endswith('ncz') : for i in range(len(files_list)): if str(files_list[i][0]).lower() == str(fi).lower(): nca_name=files_list[i][0] off1=files_list[i][1] off2=files_list[i][2] nca_size=files_list[i][3] break data=remote.read_at(off1,nca_size) ncaHeader = NcaHeader() ncaHeader.open(MemoryFile(remote.read_at(off1,0x400), FsType.Crypto.XTS, uhx(Keys.get('header_key')))) crypto1=ncaHeader.getCryptoType() crypto2=ncaHeader.getCryptoType2() if crypto2>crypto1: masterKeyRev=crypto2 if crypto2<=crypto1: masterKeyRev=crypto1 crypto = aes128.AESECB(Keys.keyAreaKey(Keys.getMasterKeyIndex(masterKeyRev), ncaHeader.keyIndex)) hcrypto = aes128.AESXTS(uhx(Keys.get('header_key'))) gc_flag='00'*0x01 crypto1=ncaHeader.getCryptoType() crypto2=ncaHeader.getCryptoType2() if ncaHeader.getRightsId() != 0: ncaHeader.rewind() if crypto2>crypto1: masterKeyRev=crypto2 if crypto2<=crypto1: masterKeyRev=crypto1 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 < ncaHeader.getCryptoType2(): encKeyBlock,crypto1,crypto2=get_new_cryptoblock(ncaHeader,keypatch,encKeyBlock,t) t.close() if ncaHeader.getRightsId() == 0: ncaHeader.rewind() encKeyBlock = ncaHeader.getKeyBlock() if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < ncaHeader.getCryptoType2(): encKeyBlock,crypto1,crypto2=get_new_cryptoblock(ncaHeader,keypatch,encKeyBlock,t) t.close() ncaHeader.rewind() i=0 newheader=get_newheader(MemoryFile(remote.read_at(off1,0xC00)),encKeyBlock,crypto1,crypto2,hcrypto,gc_flag) outf.write(newheader) written+=len(newheader) break else:pass outf.flush() outf.close() tfile=os.path.join(cachefolder, "remote_files.csv") with open(tfile,'w') as csvfile: csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format("step","filepath","size","targetsize","off1","off2","token")) csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format(0,outfile,properheadsize+written,properheadsize,0,properheadsize,"False")) k=0;l=0 for fi in files: 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),"False")) off1=j[1]+0xC00 off2=j[2] targetsize=j[3]-0xC00 URL='https://www.googleapis.com/drive/v3/files/'+remote.ID+'?alt=media' token=remote.access_token csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format(k+2,URL,remote.size,targetsize,off1,off2,token)) break k+=2;l+=1 nspname="test.nsp" try: g=remote.name g0=[pos for pos, char in enumerate(g) if char == '['] g0=(g[0:g0[0]]).strip() titleid=metadict['titleid'] titleversion=metadict['version'] ctype=metadict['ctype'] nspname=f"{g0} [{titleid}] [v{titleversion}] [{ctype}].nsp" except:pass return nspname
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_xci_parts(filepath,cachefolder=None,keepupd=False,id_target=False,keypatch=False,export_type='csv'): 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_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) 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 or test2 in fplist: # print(str(row['NcaId'])+'.nca') files.append(str(row['NcaId'])+'.nca') filesizes.append(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'])) 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 or test2 in fplist: # print(str(row['NcaId'])+'.nca') files.append(str(row['NcaId'])+'.nca') filesizes.append(int(row['Size'])) f.flush() f.close() outheader = sq_tools.gen_nsp_header(files,filesizes) properheadsize=len(outheader) # print(properheadsize) # print(bucketsize) i=0;sum=properheadsize; for file in files: # print(file) # print(filesizes[i]) if i<(len(files)-1): sum+=filesizes[i] i+=1 # print(sum) # print(sum/bucketsize) multiplier=math.ceil(sum/bucketsize) # print(multiplier) remainder = bucketsize*multiplier - sum # print(bucketsize*multiplier) xci=squirrelXCI(filepath) outfile=os.path.join(cachefolder, "0") written=0; outf = open(outfile, 'w+b') outf.write(outheader) written+=len(outheader) for fi in files: for nspF in xci.hfs0: if str(nspF._path)=="secure": for nca in nspF: if nca._path==fi: 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() encKeyBlock = crypto.encrypt(titleKeyDec * 4) if str(keypatch) != "False": if keypatch < nca.header.getCryptoType2(): encKeyBlock,crypto1,crypto2=squirrelXCI.get_new_cryptoblock(nca, keypatch,encKeyBlock,t) if nca.header.getRightsId() == 0: nca.rewind() encKeyBlock = nca.header.getKeyBlock() if str(keypatch) != "False": if keypatch < nca.header.getCryptoType2(): encKeyBlock,crypto1,crypto2=squirrelXCI.get_new_cryptoblock(nca, keypatch,encKeyBlock,t) nca.rewind() i=0 newheader=xci.get_newheader(nca,encKeyBlock,crypto1,crypto2,hcrypto,gc_flag) outf.write(newheader) written+=len(newheader) nca.seek(0xC00) if (str(nca.header.contentType) != 'Content.PROGRAM'): data=nca.read() nca.close() outf.write(data) written+=len(data) else: remainder = bucketsize*multiplier - written data=nca.read(remainder) nca.close() outf.write(data) written+=len(data) break else:pass outf.close() if export_type=='json': files_json=os.path.join(cachefolder, "files.json") d={} d['0']={"step": 0, "filepath":outfile , "size":( bucketsize*multiplier) , "targetsize":( bucketsize*multiplier) , "off1":0, "off2":( bucketsize*multiplier) } for j in files_list: if j[0]==files[-1]: off1=j[1] off2=j[2] targetsize=j[3] d['1']={"step": 1, "filepath":filepath , "size":( os.path.getsize(filepath)) , "targetsize":targetsize, "off1":off1, "off2":off2 } app_json = json.dumps(d, indent=1) with open(files_json, 'w') as json_file: json_file.write(app_json) # print(os.path.getsize(filepath)) else: for j in files_list: if j[0]==files[-1]: off1=j[1] off2=j[2] targetsize=j[3] tfile=os.path.join(cachefolder, "files.csv") i=0; with open(tfile,'w') as csvfile: if i==0: csvfile.write("{}|{}|{}|{}|{}|{}\n".format("step","filepath","size","targetsize","off1","off2")) i+=1 if i==1: csvfile.write("{}|{}|{}|{}|{}|{}\n".format(0,outfile,( bucketsize*multiplier),( bucketsize*multiplier),0,( bucketsize*multiplier))) i+=1 if i==2: csvfile.write("{}|{}|{}|{}|{}|{}".format(1,filepath,( os.path.getsize(filepath)),targetsize,off1,off2)) i+=1
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 gen_xci_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_xci_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 = squirrelXCI(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 xci = squirrelXCI(filepath) outfile = os.path.join(cachefolder, "0") outf = open(outfile, 'w+b') outf.write(outheader) written = 0 for fi in files: 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() 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 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 nspname = "test.nsp" try: g = os.path.basename(filepath) g0 = [pos for pos, char in enumerate(g) if char == '['] g0 = (g[0:g0[0]]).strip() nspname = f"{g0} [{titleid}] [v{titleversion}] [{ctype}].nsp" except: pass return nspname
def gen_xci_parts_spec0(filepath, target_cnmt=None, cachefolder=None, keypatch=False, export_type='csv'): 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) program_name = None 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]) 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 = squirrelXCI(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 or test2 in fplist: # print(str(row['NcaId'])+'.nca') 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 or test2 in fplist: # print(str(row['NcaId'])+'.nca') 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 for file in files: # print(file) # print(filesizes[i]) if i < (len(files) - 1): sum += filesizes[i] i += 1 # print(sum) # print(sum/bucketsize) multiplier = math.ceil(sum / bucketsize) # print(multiplier) remainder = bucketsize * multiplier - sum # print(bucketsize*multiplier) xci = squirrelXCI(filepath) outfile = os.path.join(cachefolder, "0") written = 0 outf = open(outfile, 'w+b') outf.write(outheader) written += len(outheader) movoffset = 0 for fi in files: 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) movoffset += 0xC00 if (str(nca.header.contentType) != 'Content.PROGRAM'): data = nca.read() nca.close() outf.write(data) written += len(data) break else: pass xci.flush() xci.close() outf.close() if export_type == 'json': files_json = os.path.join(cachefolder, "files.json") d = {} d['0'] = { "step": 0, "filepath": outfile, "size": (written), "targetsize": (written), "off1": 0, "off2": (written) } for j in files_list: if j[0] == files[-1]: off1 = j[1] + 0xC00 off2 = j[2] targetsize = j[3] - 0xC00 d['1'] = { "step": 1, "filepath": filepath, "size": (os.path.getsize(filepath)), "targetsize": targetsize, "off1": off1, "off2": off2 } app_json = json.dumps(d, indent=1) with open(files_json, 'w') as json_file: json_file.write(app_json) # print(os.path.getsize(filepath)) else: for j in files_list: if j[0] == files[-1]: off1 = j[1] + 0xC00 off2 = j[2] targetsize = j[3] - 0xC00 tfile = os.path.join(cachefolder, "files.csv") i = 0 while True: with open(tfile, 'w') as csvfile: if i == 0: csvfile.write("{}|{}|{}|{}|{}|{}\n".format( "step", "filepath", "size", "targetsize", "off1", "off2")) i += 1 if i == 1: csvfile.write("{}|{}|{}|{}|{}|{}\n".format( 0, outfile, os.path.getsize(outfile), os.path.getsize(outfile), 0, os.path.getsize(outfile))) i += 1 if i == 2: csvfile.write("{}|{}|{}|{}|{}|{}".format( 1, filepath, (os.path.getsize(filepath)), targetsize, off1, off2)) i += 1 break nspname = "test.nsp" try: g = os.path.basename(filepath) g0 = [pos for pos, char in enumerate(g) if char == '['] g0 = (g[0:g0[0]]).strip() nspname = f"{g0} [{titleid}] [v{titleversion}] [{ctype}].nsp" except: pass return nspname
def xci_to_nsz(filepath,buffer=65536,outfile=None,keepupd=False, level = 17, threads = 0, pos=False, nthreads=False): isthreaded=False if pos!=False: isthreaded=True elif str(pos)=='0': isthreaded=True else: pos=0 pos=int(pos) try: exchangefile.deletefile() except:pass f=squirrelXCI(filepath) for nspF in f.hfs0: if str(nspF._path)=="secure": for ticket in nspF: if str(ticket._path).endswith('.tik'): if isthreaded==False: print('- Titlerights: '+ticket.rightsId) tk=(str(hex(ticket.getTitleKeyBlock()))[2:]).upper() if isthreaded==False: print('- Titlekey: '+tk) exchangefile.add(ticket.rightsId,tk) f.flush() f.close() files_list=sq_tools.ret_xci_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=squirrelXCI(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'])) 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) CHUNK_SZ = buffer if outfile==None: nszPath = filepath[0:-1] + 'z' else: nszPath=outfile nszPath = os.path.abspath(nszPath) 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) if isthreaded==False: t.write('Compressing with level %d and %d threads' % (compressionLevel, threads)) t.write('\n %s -> %s \n' % (filepath, nszPath)) newNsp = nutFs.Pfs0.Pfs0Stream(nszPath,headsize=properheadsize,mode='wb+') xcicontainer = Xci(filepath) # f.compressed_supertrim(buffer,outfile,keepupd,level,threads) for nspF in xcicontainer.hfs0: if str(nspF._path)=="secure": for nca in nspF: if isinstance(nca, nutFs.Nca.Nca) and (nca.header.contentType == nutFs.Type.Content.PROGRAM or nca.header.contentType == nutFs.Type.Content.PUBLIC_DATA): if isNcaPacked(nca): skip=0 else: skip=int(ncaHeaderSize-(((sortedFs(nca))[0]).offset)) cctx = zstandard.ZstdCompressor(level=compressionLevel, threads = threads) newFileName = nca._path[0:-1] + 'z' f = newNsp.add(newFileName, nca.size,t,isthreaded) start = f.tell() nca.seek(0) data=nca.read(ncaHeaderSize) f.write(data) nca.seek(ncaHeaderSize) written = ncaHeaderSize compressor = cctx.stream_writer(f) sections = get_sections(nca) header = b'NCZSECTN' header += len(sections).to_bytes(8, 'little') i = 0 for fs in sections: i += 1 if skip>0: header += (fs.offset+skip).to_bytes(8, 'little') header += (fs.size-skip).to_bytes(8, 'little') header += fs.cryptoType.to_bytes(8, 'little') header += b'\x00' * 8 header += fs.cryptoKey header += fs.cryptoCounter else: 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 c0=0 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 = nca.partition(offset = section.offset, size = section.size, n = None, cryptoType = section.cryptoType, cryptoKey = section.cryptoKey, cryptoCounter = bytearray(section.cryptoCounter), autoOpen = True) if c0==0 and skip>0: o.seek(skip) 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) c0+=1 compressor.flush(zstandard.FLUSH_FRAME) elapsed = time.time() - timestamp minutes = elapsed / 60 seconds = elapsed % 60 speed = 0 if elapsed == 0 else (nca.size / elapsed) written = f.tell() - start if isthreaded==False: t.write('\n * Compressed at %d%% from %s to %s - %s' % (int(written * 100 / nca.size), str(sq_tools.getSize(decompressedBytes)), str(sq_tools.getSize(written)), nca._path)) t.write(' * Compressed in %02d:%02d at speed: %.1f MB/s\n' % (minutes, seconds, speed / 1000000.0)) newNsp.resize(newFileName, written) continue f = newNsp.add(nca._path, nca.size,t,isthreaded) nca.seek(0) while not nca.eof(): buffer = nca.read(CHUNK_SZ) t.update(len(buffer)) f.write(buffer) t.close() newNsp.close() try: exchangefile.deletefile() except:pass if isthreaded==True and nthreads!=False: for i in range(nthreads): tqlist[i].close() return nszPath
def decompress_nsz(remote, ofolder): buf = 64 * 1024 buffer = buf endname = remote.name[:-1] + 'p' output = os.path.join(ofolder, endname) files_list = DriveTools.get_files_from_head(remote, remote.name) remote.rewind() print('Decompressing {}'.format(remote.name)) print('- Parsing headers...') 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] metadict = {} if cnmtfile.endswith('.cnmt.nca'): metadict, d1, d2 = DriveTools.get_cnmt_data(target=cnmtfile, file=remote) ncadata = metadict['ncadata'] 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) totsize = 0 for s in filesizes: totsize += s # Hex.dump(nspheader) # print(totsize) print(files) t = tqdm(total=totsize, unit='B', unit_scale=True, leave=False) with open(output, 'wb') as o: o.write(nspheader) t.update(len(nspheader)) for file in files: if file.endswith('cnmt.nca'): for i in range(len(files_list)): if str(files_list[i][0]).lower() == str(file).lower(): nca_name = files_list[i][0] off1 = files_list[i][1] off2 = files_list[i][2] nca_size = files_list[i][3] break t.write('- Appending {}'.format(nca_name)) data = remote.read_at(off1, nca_size) with open(output, 'ab') as o: o.write(data) t.update(len(data)) elif file.endswith('.nca'): for i in range(len(files_list)): if str(files_list[i][0]).lower() == str(file).lower(): nca_name = files_list[i][0] off1 = files_list[i][1] off2 = files_list[i][2] nca_size = files_list[i][3] t.write('- Appending {}'.format(nca_name)) o = open(output, 'ab+') remote.seek(off1, off2) for data in remote.response.iter_content(chunk_size=buf): o.write(data) t.update(len(data)) o.flush() if not data: o.close() break elif (str(files_list[i][0]).lower())[:-1] == ( str(file).lower())[:-1] and str( files_list[i][0]).endswith('ncz'): ncz_name = files_list[i][0] off1 = files_list[i][1] off2 = files_list[i][2] sz = files_list[i][3] t.write('- Calculating compressed sections for: ' + ncz_name) remote.seek(off1, off2) header = remote.read(0x4000) magic = readInt64(remote) sectionCount = readInt64(remote) sections = [] for i in range(sectionCount): sections.append(Section(remote)) t.write(' Detected {} sections'.format(str(sectionCount))) with open(output, 'rb+') as o: o.seek(0, os.SEEK_END) curr_off = o.tell() t.write('- Appending decompressed {}'.format(ncz_name)) t.write(' Writing nca header') o.write(header) t.update(len(header)) timestamp = time.time() t.write(' Writing decompressed body in plaintext') count = 0 checkstarter = 0 dctx = zstandard.ZstdDecompressor() hd = Private.get_html_header(remote.access_token, remote.position, off2) remote.get_session(hd) reader = dctx.stream_reader(remote.response.raw, read_size=buffer) c = 0 spsize = 0 for s in sections: end = s.offset + s.size if s.cryptoType == 1: #plain text t.write(' * Section {} is plaintext'.format( str(c))) t.write(' %x - %d bytes, Crypto type %d' % ((s.offset), s.size, s.cryptoType)) spsize += s.size end = s.offset + s.size i = s.offset while i < end: chunkSz = buffer if end - i > buffer else end - i chunk = reader.read(chunkSz) if not len(chunk): break o.write(chunk) t.update(len(chunk)) i += chunkSz elif s.cryptoType not in (3, 4): raise IOError('Unknown crypto type: %d' % s.cryptoType) else: t.write(' * Section {} needs decompression'. format(str(c))) t.write(' %x - %d bytes, Crypto type %d' % ((s.offset), s.size, s.cryptoType)) t.write(' Key: %s, IV: %s' % (str(hx(s.cryptoKey)), str(hx(s.cryptoCounter)))) crypto = AESCTR(s.cryptoKey, s.cryptoCounter) spsize += s.size test = int(spsize / (buffer)) i = s.offset while i < end: crypto.seek(i) chunkSz = buffer if end - i > buffer else end - i chunk = reader.read(chunkSz) if not len(chunk): break o.write(crypto.encrypt(chunk)) t.update(len(chunk)) i += chunkSz c += 1 elapsed = time.time() - timestamp minutes = elapsed / 60 seconds = elapsed % 60 speed = 0 if elapsed == 0 else (spsize / elapsed) t.write( '\n Decompressed in %02d:%02d at speed: %.1f MB/s\n' % (minutes, seconds, speed / 1000000.0)) else: for i in range(len(files_list)): if str(files_list[i][0]).lower() == str(file).lower(): file_name = files_list[i][0] off1 = files_list[i][1] off2 = files_list[i][2] file_size = files_list[i][3] break t.write('- Appending {}'.format(file_name)) data = remote.read_at(off1, file_size) with open(output, 'ab') as o: o.write(data) t.update(len(data)) t.close()