mirror of
https://github.com/jakcron/nstool
synced 2024-12-25 06:01:12 +00:00
[nx/ncatool] Update SacEntry and NcaHeader to inherit from ISerialiseableBinary. ncatool is updated accordingly.
This commit is contained in:
parent
74820d9274
commit
e7172949da
5 changed files with 181 additions and 72 deletions
|
@ -14,13 +14,13 @@ void NcaHeader::exportBinary()
|
|||
|
||||
// TODO: properly reconstruct NCA layout? atm in hands of user
|
||||
|
||||
for (size_t i = 0; i < mSections.size(); i++)
|
||||
for (size_t i = 0; i < mSections.getSize(); i++)
|
||||
{
|
||||
// determine section index
|
||||
u8 section = mSections.size() - 1 - i;
|
||||
u8 section = mSections.getSize() - 1 - i;
|
||||
|
||||
hdr->section(section).set_start(mSections[i].start_blk);
|
||||
hdr->section(section).set_end(mSections[i].end_blk);
|
||||
hdr->section(section).set_start(sizeToBlockNum(mSections[i].offset));
|
||||
hdr->section(section).set_end(sizeToBlockNum(mSections[i].offset) + sizeToBlockNum(mSections[i].size));
|
||||
hdr->section(section).set_key_type(mSections[i].key_type);
|
||||
hdr->section_hash(section) = mSections[i].hash;
|
||||
}
|
||||
|
@ -59,12 +59,12 @@ void NcaHeader::importBinary(const u8 * bytes)
|
|||
if (hdr->section(section).start() == 0 && hdr->section(section).end() == 0) continue;
|
||||
|
||||
// add high level struct
|
||||
mSections.push_back({ hdr->section(section).start(), hdr->section(section).end(), blockNumToSize(hdr->section(section).start()), blockNumToSize(hdr->section(section).end()- hdr->section(section).start()), hdr->section(section).key_type(), hdr->section_hash(section) });
|
||||
mSections.addElement({ blockNumToSize(hdr->section(section).start()), blockNumToSize(hdr->section(section).end() - hdr->section(section).start()), hdr->section(section).key_type(), hdr->section_hash(section) });
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < kAesKeyNum; i++)
|
||||
{
|
||||
mAesKeys.push_back(hdr->aes_key(i));
|
||||
mAesKeys.addElement(hdr->aes_key(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,33 +102,33 @@ u32 NcaHeader::getUnk() const
|
|||
return mUnk0;
|
||||
}
|
||||
|
||||
const std::vector<NcaHeader::sSection>& NcaHeader::getSections() const
|
||||
const fnd::List<NcaHeader::sSection>& NcaHeader::getSections() const
|
||||
{
|
||||
return mSections;
|
||||
}
|
||||
|
||||
void NcaHeader::addSection(const sSection & section)
|
||||
{
|
||||
if (mSections.size() >= kSectionNum)
|
||||
if (mSections.getSize() >= kSectionNum)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Too many NCA sections");
|
||||
}
|
||||
mSections.push_back(section);
|
||||
mSections.addElement(section);
|
||||
}
|
||||
|
||||
const std::vector<crypto::aes::sAes128Key>& NcaHeader::getAesKeys() const
|
||||
const fnd::List<crypto::aes::sAes128Key>& NcaHeader::getAesKeys() const
|
||||
{
|
||||
return mAesKeys;
|
||||
}
|
||||
|
||||
void NcaHeader::addKey(const crypto::aes::sAes128Key & key)
|
||||
{
|
||||
if (mAesKeys.size() >= kAesKeyNum)
|
||||
if (mAesKeys.getSize() >= kAesKeyNum)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Too many NCA aes keys");
|
||||
}
|
||||
|
||||
mAesKeys.push_back(key);
|
||||
mAesKeys.addElement(key);
|
||||
}
|
||||
|
||||
void NcaHeader::clearVariables()
|
||||
|
@ -151,6 +151,34 @@ u32 NcaHeader::sizeToBlockNum(u64 real_size) const
|
|||
return align(real_size, mBlockSize)/mBlockSize;
|
||||
}
|
||||
|
||||
bool NcaHeader::isEqual(const NcaHeader & other) const
|
||||
{
|
||||
return (mBlockSize == other.mBlockSize) \
|
||||
&& (mNcaSize == other.mNcaSize) \
|
||||
&& (mProgramId == other.mProgramId) \
|
||||
&& (mUnk0 == other.mUnk0) \
|
||||
&& (mSections == other.mSections) \
|
||||
&& (mAesKeys == other.mAesKeys);
|
||||
}
|
||||
|
||||
void NcaHeader::copyFrom(const NcaHeader & other)
|
||||
{
|
||||
if (other.getSize())
|
||||
{
|
||||
importBinary(other.getBytes(), other.getSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->mBinaryBlob.clear();
|
||||
mBlockSize = other.mBlockSize;
|
||||
mNcaSize = other.mNcaSize;
|
||||
mProgramId = other.mProgramId;
|
||||
mUnk0 = other.mUnk0;
|
||||
mSections = other.mSections;
|
||||
mAesKeys = other.mAesKeys;
|
||||
}
|
||||
}
|
||||
|
||||
NcaHeader::NcaHeader()
|
||||
{
|
||||
clearVariables();
|
||||
|
@ -158,7 +186,7 @@ NcaHeader::NcaHeader()
|
|||
|
||||
NcaHeader::NcaHeader(const NcaHeader & other)
|
||||
{
|
||||
importBinary(other.getBytes());
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
NcaHeader::NcaHeader(const u8 * bytes)
|
||||
|
@ -166,9 +194,14 @@ NcaHeader::NcaHeader(const u8 * bytes)
|
|||
importBinary(bytes);
|
||||
}
|
||||
|
||||
bool NcaHeader::operator==(const NcaHeader & other)
|
||||
bool NcaHeader::operator==(const NcaHeader & other) const
|
||||
{
|
||||
return memcmp(this->getBytes(), other.getBytes(), this->getSize()) == 0;
|
||||
return isEqual(other);
|
||||
}
|
||||
|
||||
bool NcaHeader::operator!=(const NcaHeader & other) const
|
||||
{
|
||||
return !isEqual(other);
|
||||
}
|
||||
|
||||
void NcaHeader::operator=(const NcaHeader & other)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/memory_blob.h>
|
||||
#include <fnd/List.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <nx/ISerialiseableBinary.h>
|
||||
|
@ -12,12 +12,33 @@ class NcaHeader : public ISerialiseableBinary
|
|||
public:
|
||||
struct sSection
|
||||
{
|
||||
u32 start_blk;
|
||||
u32 end_blk;
|
||||
u64 offset;
|
||||
u64 size;
|
||||
u8 key_type;
|
||||
crypto::sha::sSha256Hash hash;
|
||||
|
||||
const sSection& operator=(const sSection& other)
|
||||
{
|
||||
offset = other.offset;
|
||||
size = other.size;
|
||||
key_type = other.key_type;
|
||||
hash = other.hash;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const sSection& other) const
|
||||
{
|
||||
return (offset == other.offset) \
|
||||
&& (size == other.size) \
|
||||
&& (key_type == other.key_type) \
|
||||
&& (hash == other.hash);
|
||||
}
|
||||
|
||||
bool operator!=(const sSection& other) const
|
||||
{
|
||||
return operator==(other);
|
||||
}
|
||||
};
|
||||
|
||||
static const size_t kDefaultBlockSize = 0x200;
|
||||
|
@ -26,7 +47,8 @@ public:
|
|||
NcaHeader(const NcaHeader& other);
|
||||
NcaHeader(const u8* bytes);
|
||||
|
||||
bool operator==(const NcaHeader& other);
|
||||
bool operator==(const NcaHeader& other) const;
|
||||
bool operator!=(const NcaHeader& other) const;
|
||||
void operator=(const NcaHeader& other);
|
||||
|
||||
// to be used after export
|
||||
|
@ -44,9 +66,9 @@ public:
|
|||
u64 getProgramId() const;
|
||||
void setProgramId(u64 program_id);
|
||||
u32 getUnk() const;
|
||||
const std::vector<sSection>& getSections() const;
|
||||
const fnd::List<sSection>& getSections() const;
|
||||
void addSection(const sSection& section);
|
||||
const std::vector<crypto::aes::sAes128Key>& getAesKeys() const;
|
||||
const fnd::List<crypto::aes::sAes128Key>& getAesKeys() const;
|
||||
void addKey(const crypto::aes::sAes128Key& key);
|
||||
|
||||
private:
|
||||
|
@ -122,10 +144,12 @@ private:
|
|||
u64 mNcaSize;
|
||||
u64 mProgramId;
|
||||
u32 mUnk0;
|
||||
std::vector<sSection> mSections;
|
||||
std::vector<crypto::aes::sAes128Key> mAesKeys;
|
||||
fnd::List<sSection> mSections;
|
||||
fnd::List<crypto::aes::sAes128Key> mAesKeys;
|
||||
|
||||
void clearVariables();
|
||||
u64 blockNumToSize(u32 block_num) const;
|
||||
u32 sizeToBlockNum(u64 real_size) const;
|
||||
bool isEqual(const NcaHeader& other) const;
|
||||
void copyFrom(const NcaHeader& other);
|
||||
};
|
||||
|
|
|
@ -6,14 +6,31 @@ SacEntry::SacEntry() :
|
|||
{
|
||||
}
|
||||
|
||||
SacEntry::SacEntry(const SacEntry & other)
|
||||
SacEntry::SacEntry(const std::string & name, bool isServer) :
|
||||
mIsServer(isServer),
|
||||
mName(name)
|
||||
{
|
||||
importBinary(other.getBytes(), other.getSize());
|
||||
exportBinary();
|
||||
}
|
||||
|
||||
SacEntry::SacEntry(const u8 * bytes)
|
||||
SacEntry::SacEntry(const SacEntry & other)
|
||||
{
|
||||
importBinary(bytes);
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
bool SacEntry::operator==(const SacEntry & other) const
|
||||
{
|
||||
return isEqual(other);
|
||||
}
|
||||
|
||||
bool SacEntry::operator!=(const SacEntry & other) const
|
||||
{
|
||||
return !isEqual(other);
|
||||
}
|
||||
|
||||
void SacEntry::operator=(const SacEntry & other)
|
||||
{
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
const u8 * SacEntry::getBytes() const
|
||||
|
@ -47,9 +64,20 @@ void SacEntry::exportBinary()
|
|||
}
|
||||
|
||||
void SacEntry::importBinary(const u8 * bytes)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Unsupported operation. importBinary(const u8* bytes) is not supported for variable size structures.");
|
||||
}
|
||||
|
||||
void SacEntry::importBinary(const u8 * bytes, size_t len)
|
||||
{
|
||||
bool isServer = (bytes[0] & SAC_IS_SERVER) == SAC_IS_SERVER;
|
||||
size_t nameLen = (bytes[0] & SAC_NAME_LEN_MASK);
|
||||
|
||||
if (nameLen+1 > len)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "SAC entry is too small");
|
||||
}
|
||||
|
||||
if (nameLen == 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "SAC entry has no service name");
|
||||
|
@ -66,15 +94,6 @@ void SacEntry::importBinary(const u8 * bytes)
|
|||
mName = std::string((const char*)(mBinaryBlob.getBytes() + 1), nameLen);
|
||||
}
|
||||
|
||||
void SacEntry::importBinary(const u8 * bytes, size_t len)
|
||||
{
|
||||
importBinary(bytes);
|
||||
if (getSize() != len)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "SAC Entry has unexpected size");
|
||||
}
|
||||
}
|
||||
|
||||
bool SacEntry::isServer() const
|
||||
{
|
||||
return mIsServer;
|
||||
|
@ -99,3 +118,22 @@ void SacEntry::setName(const std::string & name)
|
|||
|
||||
mName = name;
|
||||
}
|
||||
|
||||
bool SacEntry::isEqual(const SacEntry & other) const
|
||||
{
|
||||
return (mIsServer == other.mIsServer) \
|
||||
&& (mName == other.mName);
|
||||
}
|
||||
|
||||
void SacEntry::copyFrom(const SacEntry & other)
|
||||
{
|
||||
if (other.getSize())
|
||||
{
|
||||
importBinary(other.getBytes(), other.getSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->mIsServer = other.mIsServer;
|
||||
this->mName = other.mName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,14 @@
|
|||
|
||||
class SacEntry : public ISerialiseableBinary
|
||||
{
|
||||
public:
|
||||
SacEntry();
|
||||
SacEntry(const std::string& name, bool isServer);
|
||||
SacEntry(const SacEntry& other);
|
||||
SacEntry(const u8* bytes);
|
||||
|
||||
bool operator==(const SacEntry& other) const;
|
||||
bool operator!=(const SacEntry& other) const;
|
||||
void operator=(const SacEntry& other);
|
||||
|
||||
// to be used after export
|
||||
const u8* getBytes() const;
|
||||
|
@ -40,4 +45,7 @@ private:
|
|||
// variables
|
||||
bool mIsServer;
|
||||
std::string mName;
|
||||
|
||||
bool isEqual(const SacEntry& other) const;
|
||||
void copyFrom(const SacEntry& other);
|
||||
};
|
|
@ -57,46 +57,52 @@ int main(int argc, char** argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
fnd::MemoryBlob nca;
|
||||
fnd::io::readFile(argv[1], nca);
|
||||
|
||||
u8 sector[kNcaSectorSize];
|
||||
|
||||
// nca test
|
||||
if (argc == 2)
|
||||
try
|
||||
{
|
||||
decryptNcaSectorXts(nca, sector, 1, nx::crypto::aes::nca_header_key[0], nx::crypto::aes::nca_header_key[1]);
|
||||
fnd::MemoryBlob nca;
|
||||
fnd::io::readFile(argv[1], nca);
|
||||
|
||||
NcaHeader hdr;
|
||||
hdr.importBinary(sector);
|
||||
u8 sector[kNcaSectorSize];
|
||||
|
||||
printf("NCA Header\n");
|
||||
printf(" Size: 0x%" PRIx64 "\n", hdr.getNcaSize());
|
||||
printf(" ProgID: 0x%016" PRIx64 "\n", hdr.getProgramId());
|
||||
printf(" Unk0: 0x%" PRIx32 "\n", hdr.getUnk());
|
||||
printf(" Sections:\n");
|
||||
for (size_t i = 0; i < hdr.getSections().size(); i++)
|
||||
// nca test
|
||||
if (argc == 2)
|
||||
{
|
||||
const NcaHeader::sSection& section = hdr.getSections()[i];
|
||||
printf(" %lu:\n", i);
|
||||
printf(" Start Blk: %" PRId32 "\n", section.start_blk);
|
||||
printf(" End Blk: %" PRId32 "\n", section.end_blk);
|
||||
printf(" Offset: 0x%" PRIx64 "\n", section.offset);
|
||||
printf(" Size: 0x%" PRIx64 "\n", section.size);
|
||||
printf(" KeyType: 0x%02x\n", section.key_type);
|
||||
printf(" Hash: ");
|
||||
hexDump(section.hash.bytes, crypto::sha::kSha256HashLen);
|
||||
printf("\n");
|
||||
}
|
||||
printf(" AES Keys:\n");
|
||||
for (size_t i = 0; i < hdr.getAesKeys().size(); i++)
|
||||
{
|
||||
printf(" %lu: ", i);
|
||||
hexDump(hdr.getAesKeys()[i].key, crypto::aes::kAes128KeySize);
|
||||
printf("\n");
|
||||
}
|
||||
decryptNcaSectorXts(nca, sector, 1, nx::crypto::aes::nca_header_key[0], nx::crypto::aes::nca_header_key[1]);
|
||||
|
||||
|
||||
NcaHeader hdr;
|
||||
hdr.importBinary(sector);
|
||||
|
||||
printf("[NCA Header]\n");
|
||||
printf(" Size: 0x%" PRIx64 "\n", hdr.getNcaSize());
|
||||
printf(" ProgID: 0x%016" PRIx64 "\n", hdr.getProgramId());
|
||||
printf(" Unk0: 0x%" PRIx32 "\n", hdr.getUnk());
|
||||
printf(" Sections:\n");
|
||||
for (size_t i = 0; i < hdr.getSections().getSize(); i++)
|
||||
{
|
||||
const NcaHeader::sSection& section = hdr.getSections()[i];
|
||||
printf(" %lu:\n", i);
|
||||
//printf(" Start Blk: %" PRId32 "\n", section.start_blk);
|
||||
//printf(" End Blk: %" PRId32 "\n", section.end_blk);
|
||||
printf(" Offset: 0x%" PRIx64 "\n", section.offset);
|
||||
printf(" Size: 0x%" PRIx64 "\n", section.size);
|
||||
printf(" KeyType: 0x%02x\n", section.key_type);
|
||||
printf(" Hash: ");
|
||||
hexDump(section.hash.bytes, crypto::sha::kSha256HashLen);
|
||||
printf("\n");
|
||||
}
|
||||
printf(" AES Keys:\n");
|
||||
for (size_t i = 0; i < hdr.getAesKeys().getSize(); i++)
|
||||
{
|
||||
printf(" %lu: ", i);
|
||||
hexDump(hdr.getAesKeys()[i].key, crypto::aes::kAes128KeySize);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} catch (const fnd::Exception& e)
|
||||
{
|
||||
printf("[%s%sERROR] %s\n", e.module(), strlen(e.module()) > 0 ? " " : "", e.what());
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue