Skip to content

Commit fc6b795

Browse files
authored
added meta_only argument to open() functions, to only open cmnt sections (#10)
1 parent d549c25 commit fc6b795

10 files changed

Lines changed: 69 additions & 48 deletions

File tree

py/ns_extract_meta.py

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from nstools.nut import Keys
1111

1212
from nstools.Fs import factory
13-
from nstools.Fs import Pfs0, Nca, Type
13+
from nstools.Fs import Pfs0, Xci, Nsp, Nca, Type
1414

1515
from nstools.lib import FsTools
1616

@@ -44,6 +44,38 @@ def send_hook(message_content):
4444
except:
4545
pass
4646

47+
def get_cnmts(container):
48+
cnmts = []
49+
if isinstance(container, Nsp.Nsp):
50+
try:
51+
cnmt = container.cnmt()
52+
cnmts.append(cnmt)
53+
except Exception as e:
54+
print(e)
55+
56+
elif isinstance(container, Xci.Xci):
57+
container = container.hfs0['secure']
58+
for nspf in container:
59+
if isinstance(nspf, Nca.Nca) and nspf.header.contentType == Type.Content.META:
60+
cnmts.append(nspf)
61+
62+
return cnmts
63+
64+
def extract_meta_from_cnmt(cnmt_sections):
65+
for section in cnmt_sections:
66+
if isinstance(section, Pfs0.Pfs0):
67+
Cnmt = section.getCnmt()
68+
print(f'\n:: CNMT: {Cnmt._path}\n')
69+
print(f'Title ID: {Cnmt.titleId.upper()}')
70+
print(f'Version: {Cnmt.version}')
71+
print(f'Title Type: {Cnmt.titleType}')
72+
73+
for entry in Cnmt.contentEntries:
74+
entryType = FsTools.get_metacontent_type(hx(entry.type.to_bytes(length=(min(entry.type.bit_length(), 1) + 7) // 8, byteorder = 'big')))
75+
print(f'\n:{Cnmt.titleId} - Content.{entryType}')
76+
print(f'> NCA ID: {entry.ncaId}')
77+
print(f'> HASH: {entry.hash.hex()}')
78+
4779
def scan_file():
4880
ipath = os.path.abspath(INCP_PATH)
4981
if not os.path.isfile(ipath):
@@ -52,28 +84,11 @@ def scan_file():
5284
return
5385

5486
container = factory(Path(ipath).resolve())
55-
container.open(ipath, 'rb')
56-
if ipath.lower().endswith(('.xci', '.xcz')):
57-
container = container.hfs0['secure']
87+
container.open(ipath, 'rb', meta_only=True)
5888
try:
59-
for nspf in container:
60-
if isinstance(nspf, Nca.Nca) and nspf.header.contentType == Type.Content.META:
61-
for section in nspf:
62-
if isinstance(section, Pfs0.Pfs0):
63-
Cnmt = section.getCnmt()
64-
65-
titleType = FsTools.parse_cnmt_type_n(hx(Cnmt.titleType.to_bytes(length=(min(Cnmt.titleType.bit_length(), 1) + 7) // 8, byteorder = 'big')))
66-
67-
print(f'\n:: CNMT: {Cnmt._path}\n')
68-
print(f'Title ID: {Cnmt.titleId.upper()}')
69-
print(f'Version: {Cnmt.version}')
70-
print(f'Title Type: {titleType}')
71-
72-
for entry in Cnmt.contentEntries:
73-
entryType = FsTools.get_metacontent_type(hx(entry.type.to_bytes(length=(min(entry.type.bit_length(), 1) + 7) // 8, byteorder = 'big')))
74-
print(f'\n:{Cnmt.titleId} - Content.{entryType}')
75-
print(f'> NCA ID: {entry.ncaId}')
76-
print(f'> HASH: {entry.hash.hex()}')
89+
for cnmt in get_cnmts(container):
90+
extract_meta_from_cnmt(cnmt)
91+
7792
finally:
7893
container.close()
7994

py/nstools/Fs/BaseFs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ def hasBktr(self):
9696
return (False if self.bktrSubsection is None else True) and self.bktrSubsection.isValid()
9797

9898

99-
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
100-
r = super(BaseFs, self).open(path, mode, cryptoType, cryptoKey, cryptoCounter)
99+
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only=False):
100+
r = super(BaseFs, self).open(path, mode, cryptoType, cryptoKey, cryptoCounter, meta_only)
101101

102102
if self.bktr1Buffer:
103103
try:

py/nstools/Fs/Cnmt.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ def __init__(self, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cr
3838
self.metaEntries = []
3939

4040

41-
def open(self, file = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
42-
super(Cnmt, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter)
41+
def open(self, file = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only = False):
42+
super(Cnmt, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter, meta_only)
4343
self.rewind()
4444

4545
self.titleId = hx(self.read(8)[::-1]).decode()

py/nstools/Fs/File.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def enableBufferedIO(self, size, align = 0):
5151
self._bufferOffset = None
5252
self._relativePos = 0x0
5353

54-
def partition(self, offset = 0x0, size = None, n = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, autoOpen = True):
54+
def partition(self, offset = 0x0, size = None, n = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, autoOpen = True, meta_only = False):
5555
if not n:
5656
n = File()
5757
#Print.info('partition: ' + str(self) + ', ' + str(n))
@@ -69,7 +69,7 @@ def partition(self, offset = 0x0, size = None, n = None, cryptoType = -1, crypto
6969

7070
#Print.info('created partition for %s %x, size = %d' % (n.__class__.__name__, offset, size))
7171
if autoOpen == True:
72-
n.open(None, None, cryptoType, cryptoKey, cryptoCounter)
72+
n.open(None, None, cryptoType, cryptoKey, cryptoCounter, meta_only)
7373

7474
return n
7575

@@ -206,7 +206,7 @@ def setupCrypto(self, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
206206
self.cryptoType = Type.Crypto.NONE
207207

208208

209-
def open(self, path, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
209+
def open(self, path, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only=False):
210210
if path != None:
211211
if self.isOpen():
212212
self.close()

py/nstools/Fs/Hfs0.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ class Hfs0(Pfs0):
111111
def __init__(self, buffer, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
112112
super(Hfs0, self).__init__(buffer, path, mode, cryptoType, cryptoKey, cryptoCounter)
113113

114-
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
115-
r = super(BaseFs, self).open(path, mode, cryptoType, cryptoKey, cryptoCounter)
114+
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only = False):
115+
r = super(BaseFs, self).open(path, mode, cryptoType, cryptoKey, cryptoCounter, meta_only)
116116
self.rewind()
117117

118118
self.magic = self.read(0x4);
@@ -144,12 +144,15 @@ def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, crypto
144144

145145
self.readInt32() # junk data
146146

147+
if meta_only and (name != 'secure' and not 'cnmt' in name):
148+
continue
149+
147150
f = factory(Path(name))
148151

149152
f._path = name
150153
f.offset = offset
151154
f.size = size
152-
self.files.append(self.partition(offset + headerSize, f.size, f))
155+
self.files.append(self.partition(offset + headerSize, f.size, f, meta_only=meta_only))
153156

154157
self.files.reverse()
155158

py/nstools/Fs/Nca.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ def __init__(self, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cr
6767

6868
super(NcaHeader, self).__init__(path, mode, cryptoType, cryptoKey, cryptoCounter)
6969

70-
def open(self, file = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
71-
super(NcaHeader, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter)
70+
def open(self, file = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only=False):
71+
super(NcaHeader, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter, meta_only)
7272
self.rewind()
7373
self.signature1 = self.read(0x100)
7474
self.signature2 = self.read(0x100)
@@ -214,8 +214,8 @@ def __iter__(self):
214214
def __getitem__(self, key):
215215
return self.sectionFilesystems[key]
216216

217-
def open(self, file = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
218-
super(Nca, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter)
217+
def open(self, file = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only=False):
218+
super(Nca, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter, meta_only)
219219

220220
self.header = NcaHeader()
221221
self.partition(0x0, 0xC00, self.header, Type.Crypto.XTS, uhx(Keys.get('header_key')))

py/nstools/Fs/Nsp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ def setPath(self, path):
199199
def getPath(self):
200200
return self.path or ''
201201

202-
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
203-
super(Nsp, self).open(path or self.path, mode, cryptoType, cryptoKey, cryptoCounter)
202+
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only=False):
203+
super(Nsp, self).open(path or self.path, mode, cryptoType, cryptoKey, cryptoCounter, meta_only)
204204

205205
return True
206206

py/nstools/Fs/Pfs0.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ def getStringTableSize(self):
228228
def getFirstFileOffset(self):
229229
return self.files[0].offset
230230

231-
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
232-
r = super(Pfs0, self).open(path, mode, cryptoType, cryptoKey, cryptoCounter)
231+
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only=False):
232+
r = super(Pfs0, self).open(path, mode, cryptoType, cryptoKey, cryptoCounter, meta_only)
233233
self.rewind()
234234
#self.setupCrypto()
235235
#Print.info('cryptoType = ' + hex(self.cryptoType))
@@ -265,6 +265,9 @@ def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, crypto
265265

266266
self.readInt32() # junk data
267267

268+
if meta_only and not 'cnmt' in name:
269+
continue
270+
268271
f = factory(Path(name))
269272

270273
f._path = name
@@ -286,10 +289,10 @@ def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, crypto
286289
except:
287290
pass
288291

289-
for i in range(fileCount):
290-
if self.files[i] != ticket:
292+
for file in self.files:
293+
if file != ticket:
291294
try:
292-
self.files[i].open(None, None)
295+
file.open(None, None)
293296
except:
294297
pass
295298

py/nstools/Fs/Ticket.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ def __init__(self, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cr
3131
self.signatureSizes[Type.TicketSignature.RSA_2048_SHA256] = 0x100
3232
self.signatureSizes[Type.TicketSignature.ECDSA_SHA256] = 0x3C
3333

34-
def open(self, file = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
35-
super(Ticket, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter)
34+
def open(self, file = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only = False):
35+
super(Ticket, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter, meta_only)
3636
self.rewind()
3737
self.signatureType = self.readInt32()
3838
try:

py/nstools/Fs/Xci.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,16 +308,16 @@ def readHeader(self):
308308
self.gamecardCert = GamecardCertificate(self.partition(0x7000, 0x200))
309309

310310

311-
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
312-
r = super(Xci, self).open(path, mode, cryptoType, cryptoKey, cryptoCounter)
311+
def open(self, path = None, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, meta_only=False):
312+
r = super(Xci, self).open(path, mode, cryptoType, cryptoKey, cryptoCounter, meta_only)
313313
if self.isFullXci():
314314
self.readKeyArea()
315315
self.headerOffset = 0x1000
316316
self.seek(self.headerOffset)
317317
self.readHeader()
318318
self.seek(self.hfs0Offset + self.headerOffset)
319319
self.hfs0 = Hfs0(None, cryptoKey = None)
320-
self.partition(self.hfs0Offset + self.headerOffset, None, self.hfs0, cryptoKey = None)
320+
self.partition(self.hfs0Offset + self.headerOffset, None, self.hfs0, cryptoKey = None, meta_only = meta_only)
321321

322322
def unpack(self, path, extractregex="*"):
323323
os.makedirs(str(path), exist_ok=True)

0 commit comments

Comments
 (0)