diff --git a/.gitignore b/.gitignore index 0f4e2ab3..3f9a3b89 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ py/ztools/pythac py/ztools/hactool.exe py/ztools/nstool.exe py/badfiles.txt +py/mlist.txt diff --git a/py/English CHANGELOG.txt b/py/English CHANGELOG.txt index 6c6a051a..7a4c89bb 100644 --- a/py/English CHANGELOG.txt +++ b/py/English CHANGELOG.txt @@ -21,6 +21,22 @@ Luca Fraga's github: https://github.com/LucaFraga --------------- 0. Changelog --------------- +v0.89- Adds patcher for linked account requirement: + - Added patcher for linked-account flag in control nacp + * Patcher was added to Advanced mode, option 5 "patch a linked account requirement" + * The file is patched directly without generating a copy or any extraction + * The patcher can patched several files in batch + * The patcher will skip files that don't need a linked account + * You can see if a file needs a linked account in the nacp reader: + If "StartupUserAccount==RequiredWithNetworkServiceAccountAvailable" + * Patcher patches this value to take an unlinked account: + (StartupUserAccount==Required) + * If "RequiredNetworkServiceLicenseOnLaunch" is enabled it will also patched + - Take into account that current verification will ping the control nca as modified + - For now files with this patch won't be included in the verification and upcoming + restore mode due to the small number of games with this patching requirement + - Fixed issue that impeded raw-extaction from working properly + - Added <,<>,> to the list of banned characters for filenames v0.88- Bugfixes and new stuff - Fixes direct creation of fat32 files, to reflect that the new modes create split nsp or xci files for fat32 sd cards directly if set in the config. diff --git a/py/English Readme.txt b/py/English Readme.txt index 95fd9a66..7fe0d38d 100644 --- a/py/English Readme.txt +++ b/py/English Readme.txt @@ -5,38 +5,59 @@ https://github.com/julesontheroad/NSC_BUILDER NSC_Builder is the merged Project that continues xci_builder and Nut_Batch_Cleaner. -NSC_Builder is based both in the works of Blawar’s nut.py and Luca Fraga’s hacbuild and powered by “squirrel” a nut’s fork with added functions that removes the CDN based functions from nut while tweaks the title-rights modification functions and adds some useful ones for file management. -From version v0.8 the program doesn’t rely on hacbuild for xci generation and new code was made for a better integration on squirrel. +NSC_Builder is based both in the works of Blawar’s nut.py and Luca Fraga’s hacbuild and powered by “squirrel” a nut’s fork with added functions that removes the CDN based functions from nut while tweaks the title-rights modification functions and adds some useful ones for file management. +From version v0.8 the program doesn’t rely on hacbuild for xci generation and new code was made for a better integration on squirrel. -Squirrel will get a new github repository soon and be packed as exe for NSCB from beta v0.8. Old squirrel code can be seen in the NSCB main repository, new code will be published in it’s own repository at the end of NSCB beta phase after some cleanup it’s done on it’s code. +Squirrel will get a new github repository soon and be packed as exe for NSCB from beta v0.8. Old squirrel code can be seen in the NSCB main repository, new code will be published in it’s own repository at the end of NSCB beta phase after some cleanup it’s done on it’s code. -## 2. What’s the meaning of “REMOVING TITLE RIGHTS”. -When you remove the titlerights encryption from nsp files you can install the games without any need of tickets, which leaves a smaller trackable footprint on your console, providing you aren’t sending telemetry data to Nintendo. +## 2. What’s the meaning of “REMOVING TITLE RIGHTS”. +When you remove the titlerights encryption from nsp files you can install the games without any need of tickets, which leaves a smaller trackable footprint on your console, providing you aren’t sending telemetry data to Nintendo. It also helps in the conversion from nsp to xci files allowing to not install tickets externally. ## 3. What can I do with this program? Current version of the program allows you to: + 1.- Make multi-content xci or nsp files. + 2.- Erase titlerights encryption from nsp files. -3.- Build xci files without the “update partition” which means they take less space on your storage. + +3.- Build xci files without the “update partition” which means they take less space on your storage. + 4.- Take off deltas from updates + 5.- Split multi content back into xci or nsp files + 6.- Change the packing of the content between xci and nsp + 7.- Lower the Required System Version to the actual encryption of the game. + 8.- Lower the masterkey needed to decrypt a game. -9.- Check out information from a xci and nsp, including the Firmware needed to be able to execute it, the game info, the size of the nca content… + +9.- Check out information from a xci and nsp, including the Firmware needed to be able to execute it, the game info, the size of the nca content… + 10.- Check data from nacp and cnmt files without extracting them from nsp\xci + 10.- Repack xci and nsp content in formats compatible with fat32 + 11.- Mass build xci files and nsp files in single and multi content format + 12.- Rename nsp,xci files to match it's content + 13.- Verify nsp, nsx, xci y nca files + 14.- Output information in text format + 15.- Extract content of nsp files and secure partition of xci files + 16.- Set jobs for later in multi mode + 17.- Separate jobs by based-titleid in multi mode + 18.- Remove bad characters from filenames (sanitize) or convert asian names to romaji + 19.- Extract nca file contents for base games and dlcs or extract ncas as plaintext + 20.- Joiner for xc*,ns* and *0 fat32 files ## 4. Batch modes: @@ -47,23 +68,23 @@ The batch has 2 modes: - manual mode: you double click the batch and you can build a list of files to process. -The behavior of the auto-mode is configured trough the “Configuration menu in manual mode”. +The behavior of the auto-mode is configured trough the “Configuration menu in manual mode”. ## 5. Manual mode options: -- MODE 0: Configuration mode. Let’s you configure the way the program works in both auto and manual mode. -- MODE 1: Indidual packing. Let’s you process a list of files and pack them individually +- MODE 0: Configuration mode. Let’s you configure the way the program works in both auto and manual mode. +- MODE 1: Indidual packing. Let’s you process a list of files and pack them individually * Pack as nsp\xci * Supertrimm xci files * Rename xci or nsp files * Rebuild nsp files in cnmt order and add cnmt.xml * Verify nsp,xci files -- MODE 2: Multi packing. Let’s you pack a list of files in a single xci or nsp file. +- MODE 2: Multi packing. Let’s you pack a list of files in a single xci or nsp file. * Separate files by basedid * Set up jobs for later * Process previous jobs -- MODE 3: Multi-Content-Splitter. Let’s you separate content to nsp and xci files. -- MODE 4: File-Info. Let’s you see and export several info about nsp and xci files +- MODE 3: Multi-Content-Splitter. Let’s you separate content to nsp and xci files. +- MODE 4: File-Info. Let’s you see and export several info about nsp and xci files * 1. Data about included files in nsp\xci * 2. Data about content ids in file * 3. Nut info as implemented by nut by blawar @@ -72,7 +93,7 @@ The behavior of the auto-mode is configured trough the * 6. Read nacp file from control nca * 7. Read npdm file from program nca * 8. Verify files with ability of detecting NSCB changes over them -- MODE 5: Database Mode. Let’s you mass output information +- MODE 5: Database Mode. Let’s you mass output information - MODE 6: Advanced Mode. * 1. Extracts all contents from a nsp\xci * 2. Extracts all contents from a nsp\xci in raw mode @@ -90,25 +111,25 @@ The behavior of the auto-mode is configured trough the - Repack folder's files individually (single-content file) - Repack folder's files together (multi-content file) #### RSV patching configuration -- Patch Required System Version if it’s bigger than encryption -- Don’t patch Required System Version if it’s bigger than encryption +- Patch Required System Version if it’s bigger than encryption +- Don’t patch Required System Version if it’s bigger than encryption #### KEYGENERATION configuration - Set the maximum keygeneration (encryption) the files are allowed to have. ### Global options. (Affects how the program works globally) #### Text and background COLOR -- Let’s you choose the colours of the cmd window +- Let’s you choose the colours of the cmd window #### WORK FOLDER's name -- Let’s you choose the name of the work folder +- Let’s you choose the name of the work folder #### OUTPUT FOLDER's name -- Let’s you choose the name and location of the output folder +- Let’s you choose the name and location of the output folder #### DELTA files treatment -- Let’s you choose if you’re going to pack delta NCA files or not. Set to false by default. +- Let’s you choose if you’re going to pack delta NCA files or not. Set to false by default. #### ZIP configuration (currently unused) -- Let’s you choose if you want to create a zip storing some file information. Set to false by default. +- Let’s you choose if you want to create a zip storing some file information. Set to false by default. #### AUTO-EXIT configuration -- Let’s you choose if the cmd window closes after completing the job. +- Let’s you choose if the cmd window closes after completing the job. #### KEY-GENERATION PROMPT -- Let’s you choose if you want to see a prompt asking you to patch RSV and keygeneration in manual mode. +- Let’s you choose if you want to see a prompt asking you to patch RSV and keygeneration in manual mode. #### File stream BUFFER - Buffer for file-stream operations #### file FAT32\EXFAT options @@ -140,9 +161,9 @@ https://gbatemp.net/attachments/2-0-0-8-1-0-zip.170607/ To install multi-nsp you need a installer compatible with them. Reported compatible installers are: - SX OS rom-menu - SX OS installer -- Blawar’s tinfoil: +- Blawar’s tinfoil: https://github.com/digableinc/tinfoil -- Blawar’s lithium: +- Blawar’s lithium: https://github.com/blawar/lithium ## 8. Requirements @@ -156,7 +177,7 @@ https://github.com/blawar/lithium ## 9. Limitations - You can't make multi-content xci files with more than 8 games. It'll give error when loading in horizon. I suspect it may be a qlauncher limitation so it could work with theme mods but INTRO didn't test it. -Note: This means “games”, updates and dl car not hold by that limitation. +Note: This means “games”, updates and dl car not hold by that limitation. - Title-rights remove dlcs give a message prompt of incomplete content for some games from 6.0 onwards, that message can be skipped and the dlcs will work fine despite the prompt. ## 7. Thanks and credits to @@ -187,4 +208,4 @@ Thx to 0mn0 and the old SH crew for always being helpful. Thx to evOLved, Cinnabar and a certain dragon for their help and good suggestions. -Also thanks to all members from gbatemp, elotrolado.net and my friends at discord ;) \ No newline at end of file +Also thanks to all members from gbatemp, elotrolado.net and my friends at discord ;) diff --git a/py/NSCB.bat b/py/NSCB.bat index e28b0a09..43952f37 100644 --- a/py/NSCB.bat +++ b/py/NSCB.bat @@ -3,7 +3,7 @@ set "prog_dir=%~dp0" set "bat_name=%~n0" set "ofile_name=%bat_name%_options.cmd" -Title NSC_Builder v0.88 -- Profile: %ofile_name% -- by JulesOnTheRoad +Title NSC_Builder v0.89 -- Profile: %ofile_name% -- by JulesOnTheRoad set "list_folder=%prog_dir%lists" ::----------------------------------------------------- ::EDIT THIS VARIABLE TO LINK OTHER OPTION FILE @@ -2732,8 +2732,8 @@ ECHO --------------------------------------------------------------------------- ECHO ============================= BY JULESONTHEROAD ============================= ECHO ------------------------------------------------------------------------------------- ECHO " POWERED BY SQUIRREL " -ECHO " BASED IN THE WORK OF BLAWAR AND LUCA FRAGA " -ECHO VERSION 0.88 (NEW) +ECHO " BASED ON THE WORK OF BLAWAR AND LUCA FRAGA " +ECHO VERSION 0.89 (NEW) ECHO ------------------------------------------------------------------------------------- ECHO Program's github: https://github.com/julesontheroad/NSC_BUILDER ECHO Blawar's github: https://github.com/blawar diff --git a/py/ztools/ADV.bat b/py/ztools/ADV.bat index 1baaf9c9..736aec33 100644 --- a/py/ztools/ADV.bat +++ b/py/ztools/ADV.bat @@ -174,6 +174,7 @@ echo Input "1" to extract all files from nsp\xci echo Input "2" for raw extraction (Use in case a nca gives magic error) echo Input "3" to extract all nca files as plaintext echo Input "4" to extract nca contents from nsp\xci +echo Input "5" to patch a linked account requirement echo. ECHO ****************************************** echo Or Input "b" to return to the list options @@ -187,12 +188,16 @@ if /i "%bs%"=="1" goto extract if /i "%bs%"=="2" goto raw_extract if /i "%bs%"=="3" goto ext_plaintext if /i "%bs%"=="4" goto ext_fromnca +if /i "%bs%"=="5" goto patch_lnkacc if %vrepack%=="none" goto s_cl_wrongchoice :extract cls call :program_logo +echo ******************************************************** +echo EXTRACT ALL FILES FROM A NSP\XCI +echo ******************************************************** CD /d "%prog_dir%" for /f "tokens=*" %%f in (advlist.txt) do ( @@ -210,6 +215,9 @@ goto s_exit_choice :raw_extract cls call :program_logo +echo ******************************************************** +echo EXTRACT ALL FILES FROM A NSP\XCI IN RAW MODE +echo ******************************************************** CD /d "%prog_dir%" for /f "tokens=*" %%f in (advlist.txt) do ( @@ -227,6 +235,9 @@ goto s_exit_choice :ext_plaintext cls call :program_logo +echo ******************************************************** +echo EXTRACT ALL FILES FROM A NSP\XCI AS PLAINTEXT +echo ******************************************************** CD /d "%prog_dir%" for /f "tokens=*" %%f in (advlist.txt) do ( @@ -244,6 +255,9 @@ goto s_exit_choice :ext_fromnca cls call :program_logo +echo ******************************************************** +echo EXTRACT INTERNAL NCA FILES FROM A NSP\XCI +echo ******************************************************** CD /d "%prog_dir%" for /f "tokens=*" %%f in (advlist.txt) do ( @@ -258,6 +272,26 @@ ECHO *********** ALL FILES WERE PROCESSED! ************* ECHO --------------------------------------------------- goto s_exit_choice +:patch_lnkacc +cls +call :program_logo +echo ******************************************************** +echo PATCH A LINKED ACCOUNT REQUIREMENT +echo ******************************************************** +CD /d "%prog_dir%" +for /f "tokens=*" %%f in (advlist.txt) do ( + +%pycommand% "%nut%" %buffer% -tfile "%prog_dir%advlist.txt" --remlinkacc "" + +more +1 "advlist.txt">"advlist.txt.new" +move /y "advlist.txt.new" "advlist.txt" >nul +call :contador_NF +) +ECHO --------------------------------------------------- +ECHO *********** ALL FILES WERE PROCESSED! ************* +ECHO --------------------------------------------------- +goto s_exit_choice + :s_exit_choice if exist advlist.txt del advlist.txt @@ -320,8 +354,8 @@ ECHO --------------------------------------------------------------------------- ECHO ============================= BY JULESONTHEROAD ============================= ECHO ------------------------------------------------------------------------------------- ECHO " POWERED BY SQUIRREL " -ECHO " BASED IN THE WORK OF BLAWAR AND LUCA FRAGA " -ECHO VERSION 0.88 +ECHO " BASED ON THE WORK OF BLAWAR AND LUCA FRAGA " +ECHO VERSION 0.89 ECHO ------------------------------------------------------------------------------------- ECHO Program's github: https://github.com/julesontheroad/NSC_BUILDER ECHO Blawar's github: https://github.com/blawar diff --git a/py/ztools/Fs/Nacp.py b/py/ztools/Fs/Nacp.py index eff6f7d8..812307c4 100644 --- a/py/ztools/Fs/Nacp.py +++ b/py/ztools/Fs/Nacp.py @@ -193,8 +193,7 @@ def par_getStartupUserAccount(self, data, feed =''): StartupUserAccount = 'Unknown' message=('- StartupUserAccount: ' + str(StartupUserAccount));print(message);feed+=message+'\n' return feed - - + def getStartupUserAccount(self): self.seek(0x3025) b = self.readInt8('little') diff --git a/py/ztools/Fs/Nca.py b/py/ztools/Fs/Nca.py index da08d7cb..d6dbe285 100644 --- a/py/ztools/Fs/Nca.py +++ b/py/ztools/Fs/Nca.py @@ -27,6 +27,7 @@ import sq_tools import pykakasi from Fs.pyNCA3 import NCA3 +import io MEDIA_SIZE = 0x200 RSA_PUBLIC_EXPONENT = 0x10001 @@ -2265,6 +2266,144 @@ def read_nacp(self,feed=''): except:continue return feed +#PATCH NETWORK LICENSE + def patch_netlicense(self): + if str(self.header.contentType) == 'Content.CONTROL': + offset=self.get_nacp_offset() + for f in self: + nacp = Nacp() + print('CURRENT VALUES:') + f.seek(offset+0x3025) + startup_acc=f.readInt8('little') + netlicense=f.readInt8('little') + f.seek(offset+0x3213) + netlicense=f.readInt8('little') + nacp.par_getStartupUserAccount(startup_acc) + nacp.par_getRequiredNetworkServiceLicenseOnLaunch(netlicense) + if netlicense==0 and startup_acc<2: + print(str(self._path)+" doesn't need a linked account") + return False + else: + print(' -> '+str(self._path)+" needs a linked account. Patching...") + print('NEW VALUES:') + if startup_acc==2: + f.seek(offset+0x3025) + f.writeInt8(1) + if netlicense==1: + f.seek(offset+0x3213) + f.writeInt8(0) + f.seek(offset+0x3025) + nacp.par_getStartupUserAccount(f.readInt8('little')) + f.seek(offset+0x3213) + netlicense=f.readInt8('little') + nacp.par_getRequiredNetworkServiceLicenseOnLaunch(f.readInt8('little')) + return True + def redo_lvhashes(self): + if str(self.header.contentType) == 'Content.CONTROL': + #offset=self.get_nacp_offset() + for fs in self.sectionFilesystems: + pfs0=fs + sectionHeaderBlock = fs.buffer + inmemoryfile = io.BytesIO(sectionHeaderBlock) + self.seek(fs.offset) + pfs0Offset=fs.offset + leveldata,hash,masterhashsize,superhashoffset=self.prIVFCData(inmemoryfile) + return leveldata,superhashoffset + + def set_lv_hash(self,j,leveldata): + if str(self.header.contentType) == 'Content.CONTROL': + for fs in self.sectionFilesystems: + levelnumb=leveldata[j][0] + lvoffs=leveldata[j][1] + levelsize=leveldata[j][2] + lvbsize=leveldata[j][3] + fs.seek(lvoffs) + data = fs.read(lvbsize) + newhash=(str(sha256(data).hexdigest())) + fs.seek((j-1)*0x4000) + hashlv=(hx(fs.read(32))).decode('utf-8') + if str(hashlv) != str(newhash): + fs.seek((j-1)*0x4000) + sha=bytes.fromhex(newhash) + fs.write(sha) + print('Old lv'+str(j)+' hash: '+str(hashlv)) + print('New lv'+str(j)+' hash: '+str(newhash)) + + def set_lvsuperhash(self,leveldata,superhashoffset): + if str(self.header.contentType) == 'Content.CONTROL': + for fs in self.sectionFilesystems: + memlv0 = io.BytesIO(fs.read((leveldata[0][2])*(len(leveldata)-1))) + memlv0.seek(0);newlvdata=memlv0.read() + memlv0.seek(0);ndat=memlv0.read(0x4000) + superhash=(str(sha256(ndat).hexdigest())) + self.header.seek(0x400+superhashoffset) + test = hx((self.header.read(32))).decode('utf-8');print('-OLD IVFC_Hash: '+str(test)) + self.header.seek(0x400+superhashoffset) + self.header.write(bytes.fromhex(superhash)) + self.header.seek(0x400+superhashoffset) + newivfchash = hx((self.header.read(32))).decode('utf-8');print('-NEW IVFC_Hash: '+str(newivfchash)) + fs.seek(0) + fs.write(newlvdata) + + def prIVFCData(self,inmemoryfile): + #Hex.dump(inmemoryfile.read()) + inmemoryfile.seek(0) + version=int.from_bytes(inmemoryfile.read(0x2), byteorder='little', signed=True);print('-Version: '+str(version)) + fstype=int.from_bytes(inmemoryfile.read(0x1), byteorder='little', signed=True);print('-FileSystemtype: '+str(fstype)) + hashtype=int.from_bytes(inmemoryfile.read(0x1), byteorder='little', signed=True);print('-HashType: '+str(hashtype)) + enctype=int.from_bytes(inmemoryfile.read(0x1), byteorder='little', signed=True);print('-EncType: '+str(enctype)) + nulldata=inmemoryfile.read(0x3) + magic=inmemoryfile.read(0x4);print('-Magic: '+str(magic)) + magicnumber=int.from_bytes(inmemoryfile.read(0x4), byteorder='little', signed=True);print('-MagicNumber: '+str(magicnumber)) + masterhashsize=int.from_bytes(inmemoryfile.read(0x4), byteorder='little', signed=True)*0x200;print('-MasterHashSize: '+str(masterhashsize)) + numberLevels=int.from_bytes(inmemoryfile.read(0x4), byteorder='little', signed=True);print('-Number: '+str(numberLevels)) + leveldata=list();c=24 + for i in range(numberLevels-1): + lvoffs=int.from_bytes(inmemoryfile.read(0x8), byteorder='little', signed=True);print('-level'+str(i)+' offs: '+str(lvoffs)) + lvsize=int.from_bytes(inmemoryfile.read(0x8), byteorder='little', signed=True);print('-level'+str(i)+' size: '+str(lvsize)) + lvbsize=2**int.from_bytes(inmemoryfile.read(0x4), byteorder='little', signed=True);print('-level'+str(i)+' block size: '+str(lvbsize)) + treserved=int.from_bytes(inmemoryfile.read(0x4), byteorder='little', signed=True);print('-level'+str(i)+' Reserved: '+str(treserved)) + leveldata.append([i,lvoffs,lvsize,lvbsize]) + c=c+24 + inmemoryfile.read(32);c=c+32 + hash = hx((inmemoryfile.read(32))).decode('utf-8');print('-IVFC_Hash: '+str(hash)) + return leveldata,hash,masterhashsize,c + + def pr_ivfcsuperhash(self, file = None, mode = 'rb'): + crypto1=self.header.getCryptoType() + crypto2=self.header.getCryptoType2() + if crypto1 == 2: + if crypto1 > crypto2: + masterKeyRev=crypto1 + else: + masterKeyRev=crypto2 + else: + masterKeyRev=crypto2 + decKey = Keys.decryptTitleKey(self.header.titleKeyDec, Keys.getMasterKeyIndex(masterKeyRev)) + for f in self.sectionFilesystems: + #print(f.fsType);print(f.cryptoType) + if f.fsType == Type.Fs.ROMFS and f.cryptoType == Type.Crypto.CTR: + ncaHeader = NcaHeader() + self.header.rewind() + ncaHeader = self.header.read(0x400) + #Hex.dump(ncaHeader) + pfs0=f + #Hex.dump(pfs0.read()) + sectionHeaderBlock = f.buffer + + levelOffset = int.from_bytes(sectionHeaderBlock[0x18:0x20], byteorder='little', signed=False) + levelSize = int.from_bytes(sectionHeaderBlock[0x20:0x28], byteorder='little', signed=False) + + pfs0Header = pfs0.read(levelSize) + if sectionHeaderBlock[8:12] == b'IVFC': + data = pfs0Header; + Hex.dump(pfs0Header) + print(str('1: ')+hx(sectionHeaderBlock[0xc8:0xc8+0x20]).decode('utf-8')) + print(str('2: ')+str(sha256(data).hexdigest())) + superhash=str(sha256(data).hexdigest()) + return superhash + + def verify_hash_nca(self,buffer,origheader,didverify,feed): verdict=True; basename=str(os.path.basename(os.path.abspath(self._path))) if feed == False: diff --git a/py/ztools/Fs/Nsp.py b/py/ztools/Fs/Nsp.py index db395bba..b23399a3 100644 --- a/py/ztools/Fs/Nsp.py +++ b/py/ztools/Fs/Nsp.py @@ -361,6 +361,74 @@ def unlock(self): self.hasValidTicket = True self.move() + + # ................................................... + # Patch requrements for network account + # ................................................... + def gen_ctrl_list(self): + print('- Seeking control nca files...') + ctrl_list=list() + for nca in self: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + ctrl_list.append(nca._path) + else: + pass + return ctrl_list + + def patch_netlicense(self,item=False): + for nca in self: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + check=nca.patch_netlicense() + return check + + def reb_lv_hashes(self,item=False): + for nca in self: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + print('-------------------------------------------------') + print('Get Current IVFC level data:') + print('-------------------------------------------------') + leveldata,superhashoffset=nca.redo_lvhashes() + return leveldata,superhashoffset + + def set_lv_hash(self,j,leveldata,item=False): + for nca in self: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + print('-------------------------------------------------') + print('Rebuild hashes for IVFC level '+str(j)+':') + print('-------------------------------------------------') + nca.set_lv_hash(j,leveldata) + + def set_lvsuperhash(self,leveldata,superhashoffset,item=False): + for nca in self: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + print('-------------------------------------------------') + print('Rebuild IVFC superhash:') + print('-------------------------------------------------') + nca.set_lvsuperhash(leveldata,superhashoffset) + + def ctrl_upd_hblock_hash(self,item=False): + for nca in self: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + print('-------------------------------------------------') + print('Rebuild nca hash-table:') + print('-------------------------------------------------') + oldhash=nca.header.get_hblock_hash();print('- Old nca sblock hash: '+str(hx(oldhash))) + newhash=nca.header.calculate_hblock_hash();print('- New nca sblock hash: '+str(hx(newhash))) + nca.header.set_hblock_hash(newhash) + + # ................................................... + def setMasterKeyRev(self, newMasterKeyRev): if not Titles.contains(self.titleId): raise IOError('No title key found in database! ' + self.titleId) diff --git a/py/ztools/Fs/Xci.py b/py/ztools/Fs/Xci.py index 45e7906d..ed315ade 100644 --- a/py/ztools/Fs/Xci.py +++ b/py/ztools/Fs/Xci.py @@ -7040,4 +7040,81 @@ def verify_key(self,nca,ticket): else: return True - \ No newline at end of file + # ................................................... + # Patch requrements for network account + # ................................................... + def gen_ctrl_list(self): + print('- Seeking control nca files... ') + ctrl_list=list() + for nspF in self.hfs0: + if str(nspF._path)=="secure": + for nca in nspF: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + ctrl_list.append(nca._path) + else: + pass + return ctrl_list + + def patch_netlicense(self,item=False): + for nspF in self.hfs0: + if str(nspF._path)=="secure": + for nca in nspF: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + check=nca.patch_netlicense() + return check + + def reb_lv_hashes(self,item=False): + for nspF in self.hfs0: + if str(nspF._path)=="secure": + for nca in nspF: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + print('-------------------------------------------------') + print('Get Current IVFC level data:') + print('-------------------------------------------------') + leveldata,superhashoffset=nca.redo_lvhashes() + return leveldata,superhashoffset + + def set_lv_hash(self,j,leveldata,item=False): + for nspF in self.hfs0: + if str(nspF._path)=="secure": + for nca in nspF: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + print('-------------------------------------------------') + print('Rebuild hashes for IVFC level '+str(j)+':') + print('-------------------------------------------------') + nca.set_lv_hash(j,leveldata) + + def set_lvsuperhash(self,leveldata,superhashoffset,item=False): + for nspF in self.hfs0: + if str(nspF._path)=="secure": + for nca in nspF: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + print('-------------------------------------------------') + print('Rebuild IVFC superhash:') + print('-------------------------------------------------') + nca.set_lvsuperhash(leveldata,superhashoffset) + + def ctrl_upd_hblock_hash(self,item=False): + for nspF in self.hfs0: + if str(nspF._path)=="secure": + for nca in nspF: + if type(nca) == Nca: + if str(nca.header.contentType) == 'Content.CONTROL': + if item == False or nca._path == item: + print('-------------------------------------------------') + print('Rebuild nca hash-table:') + print('-------------------------------------------------') + oldhash=nca.header.get_hblock_hash();print('- Old nca sblock hash: '+str(hx(oldhash))) + newhash=nca.header.calculate_hblock_hash();print('- New nca sblock hash: '+str(hx(newhash))) + nca.header.set_hblock_hash(newhash) + + # ................................................... \ No newline at end of file diff --git a/py/ztools/JOINER.bat b/py/ztools/JOINER.bat index 185663fb..1391740e 100644 --- a/py/ztools/JOINER.bat +++ b/py/ztools/JOINER.bat @@ -262,8 +262,8 @@ ECHO --------------------------------------------------------------------------- ECHO ============================= BY JULESONTHEROAD ============================= ECHO ------------------------------------------------------------------------------------- ECHO " POWERED BY SQUIRREL " -ECHO " BASED IN THE WORK OF BLAWAR AND LUCA FRAGA " -ECHO VERSION 0.88 +ECHO " BASED ON THE WORK OF BLAWAR AND LUCA FRAGA " +ECHO VERSION 0.89 ECHO ------------------------------------------------------------------------------------- ECHO Program's github: https://github.com/julesontheroad/NSC_BUILDER ECHO Blawar's github: https://github.com/blawar diff --git a/py/ztools/LEGACY.bat b/py/ztools/LEGACY.bat index 209b568c..cd1f364f 100644 --- a/py/ztools/LEGACY.bat +++ b/py/ztools/LEGACY.bat @@ -2,7 +2,7 @@ :TOP_INIT CD /d "%prog_dir%" set "bat_name=%~n0" -Title NSC_Builder v0.88 -- Profile: %ofile_name% -- by JulesOnTheRoad +Title NSC_Builder v0.89 -- Profile: %ofile_name% -- by JulesOnTheRoad ::Check if user is dragging a folder or a file if "%~1"=="" goto manual @@ -2246,8 +2246,8 @@ ECHO --------------------------------------------------------------------------- ECHO ============================= BY JULESONTHEROAD ============================= ECHO ------------------------------------------------------------------------------------- ECHO " POWERED BY SQUIRREL " -ECHO " BASED IN THE WORK OF BLAWAR AND LUCA FRAGA " -ECHO VERSION 0.88 (LEGACY) +ECHO " BASED ON THE WORK OF BLAWAR AND LUCA FRAGA " +ECHO VERSION 0.89 (LEGACY) ECHO ------------------------------------------------------------------------------------- ECHO Program's github: https://github.com/julesontheroad/NSC_BUILDER ECHO Blawar's github: https://github.com/blawar diff --git a/py/ztools/NSCB_config.bat b/py/ztools/NSCB_config.bat index bd3de935..9c060aaf 100644 --- a/py/ztools/NSCB_config.bat +++ b/py/ztools/NSCB_config.bat @@ -1132,7 +1132,7 @@ ECHO ============================= BY JULESONTHEROAD =================== ECHO ------------------------------------------------------------------------------------- ECHO " POWERED BY SQUIRREL " ECHO " BASED IN THE WORK OF BLAWAR AND LUCA FRAGA " -ECHO VERSION 0.88 +ECHO VERSION 0.89 ECHO ------------------------------------------------------------------------------------- ECHO Program's github: https://github.com/julesontheroad/NSC_BUILDER ECHO Blawar's github: https://github.com/blawar diff --git a/py/ztools/info.bat b/py/ztools/info.bat index f18d3f1b..a84591b5 100644 --- a/py/ztools/info.bat +++ b/py/ztools/info.bat @@ -296,8 +296,8 @@ ECHO --------------------------------------------------------------------------- ECHO ============================= BY JULESONTHEROAD ============================= ECHO ------------------------------------------------------------------------------------- ECHO " POWERED BY SQUIRREL " -ECHO " BASED IN THE WORK OF BLAWAR AND LUCA FRAGA " -ECHO VERSION 0.88 +ECHO " BASED ON THE WORK OF BLAWAR AND LUCA FRAGA " +ECHO VERSION 0.89 ECHO ------------------------------------------------------------------------------------- ECHO Program's github: https://github.com/julesontheroad/NSC_BUILDER ECHO Blawar's github: https://github.com/blawar diff --git a/py/ztools/squirrel.py b/py/ztools/squirrel.py index e2c9f901..5a5d7d9f 100644 --- a/py/ztools/squirrel.py +++ b/py/ztools/squirrel.py @@ -122,6 +122,7 @@ parser.add_argument('--seteshop_nca', nargs='+', help='Set a single nca as eshop') parser.add_argument('--setcgame_nca', nargs='+', help='Set a single nca as card') parser.add_argument('--cardstate', nargs='+', help='Returns value for isgamecard flag from an nca') + parser.add_argument('--remlinkacc', nargs='+', help='Removelinkedaccount') # NSP Copy functions parser.add_argument('-x', '--extract', nargs='+', help='Extracts all files from nsp or xci') @@ -525,6 +526,98 @@ f.close() except BaseException as e: Print.error('Exception: ' + str(e)) + + # ................................................... + # Set value for network account + # ................................................... + if args.remlinkacc: + if args.text_file: + tfile=args.text_file + with open(tfile,"r+", encoding='utf8') as filelist: + filename = filelist.readline() + filename=os.path.abspath(filename.rstrip('\n')) + else: + for inpt in args.text_file: + filename=inpt + try: + if filename.endswith('.nsp') or filename.endswith('.nsx'): + f = Fs.Nsp(filename,'r+b') + ctrl_list=f.gen_ctrl_list() + f.flush() + f.close() + for item in ctrl_list: + print('-------------------------------------------------') + print('Processing: '+str(item)) + print('-------------------------------------------------') + f = Fs.Nsp(filename,'r+b') + check=f.patch_netlicense() + f.flush() + f.close() + if check == True: + f = Fs.Nsp(filename, 'r+b') + leveldata,superhashoffset=f.reb_lv_hashes(item) + f.flush() + f.close() + n=len(leveldata)-1 + for i in range(len(leveldata)): + j=n-i + if j==0: + break + f = Fs.Nsp(filename, 'r+b') + superhash=f.set_lv_hash(j,leveldata,item) + f.flush() + f.close() + f = Fs.Nsp(filename, 'r+b') + f.set_lvsuperhash(leveldata,superhashoffset,item) + f.flush() + f.close() + f = Fs.Nsp(filename, 'r+b') + f.ctrl_upd_hblock_hash(item) + f.flush() + f.close() + elif filename.endswith('.xci'): + f = Fs.factory(filename) + f.open(filename, 'r+b') + ctrl_list=f.gen_ctrl_list() + f.flush() + f.close() + for item in ctrl_list: + print('-------------------------------') + print('Processing: '+str(item)) + print('-------------------------------') + f = Fs.factory(filename) + f.open(filename, 'r+b') + check=f.patch_netlicense(item) + f.flush() + f.close() + if check == True: + f = Fs.factory(filename) + f.open(filename, 'r+b') + leveldata,superhashoffset=f.reb_lv_hashes(item) + f.flush() + f.close() + n=len(leveldata)-1 + for i in range(len(leveldata)): + j=n-i + if j==0: + break + f = Fs.factory(filename) + f.open(filename, 'r+b') + superhash=f.set_lv_hash(j,leveldata,item) + f.flush() + f.close() + f = Fs.factory(filename) + f.open(filename, 'r+b') + f.set_lvsuperhash(leveldata,superhashoffset,item) + f.flush() + f.close() + f = Fs.factory(filename) + f.open(filename, 'r+b') + f.ctrl_upd_hblock_hash(item) + f.flush() + f.close() + except BaseException as e: + Print.error('Exception: ' + str(e)) # COPY FUNCTIONS # ................................................... @@ -4470,7 +4563,7 @@ filepath = os.path.join(ofolder, files_list[i][0]) fp = open(filepath, 'w+b') s=files_list[i][3] - if buffer>s: + if int(buffer)>s: buf=s else: buf=buffer @@ -4515,7 +4608,7 @@ filepath = os.path.join(ofolder, files_list[i][0]) fp = open(filepath, 'w+b') s=files_list[i][3] - if buffer>s: + if int(buffer)>s: buf=s else: buf=buffer @@ -6121,7 +6214,7 @@ endname=converter.do(endname) endname=endname[0].upper()+endname[1:] endname = (re.sub(r'[\/\\\:\*\?]+', '', endname)) - 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)