mirror of
https://github.com/jakcron/nstool.git
synced 2024-12-22 10:45:28 +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
|
@ -14,13 +14,13 @@ void NcaHeader::exportBinary()
|
||||||
|
|
||||||
// TODO: properly reconstruct NCA layout? atm in hands of user
|
// 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
|
// 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_start(sizeToBlockNum(mSections[i].offset));
|
||||||
hdr->section(section).set_end(mSections[i].end_blk);
|
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(section).set_key_type(mSections[i].key_type);
|
||||||
hdr->section_hash(section) = mSections[i].hash;
|
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;
|
if (hdr->section(section).start() == 0 && hdr->section(section).end() == 0) continue;
|
||||||
|
|
||||||
// add high level struct
|
// 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++)
|
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;
|
return mUnk0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<NcaHeader::sSection>& NcaHeader::getSections() const
|
const fnd::List<NcaHeader::sSection>& NcaHeader::getSections() const
|
||||||
{
|
{
|
||||||
return mSections;
|
return mSections;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcaHeader::addSection(const sSection & section)
|
void NcaHeader::addSection(const sSection & section)
|
||||||
{
|
{
|
||||||
if (mSections.size() >= kSectionNum)
|
if (mSections.getSize() >= kSectionNum)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Too many NCA sections");
|
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;
|
return mAesKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcaHeader::addKey(const crypto::aes::sAes128Key & key)
|
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");
|
throw fnd::Exception(kModuleName, "Too many NCA aes keys");
|
||||||
}
|
}
|
||||||
|
|
||||||
mAesKeys.push_back(key);
|
mAesKeys.addElement(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcaHeader::clearVariables()
|
void NcaHeader::clearVariables()
|
||||||
|
@ -151,6 +151,34 @@ u32 NcaHeader::sizeToBlockNum(u64 real_size) const
|
||||||
return align(real_size, mBlockSize)/mBlockSize;
|
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()
|
NcaHeader::NcaHeader()
|
||||||
{
|
{
|
||||||
clearVariables();
|
clearVariables();
|
||||||
|
@ -158,7 +186,7 @@ NcaHeader::NcaHeader()
|
||||||
|
|
||||||
NcaHeader::NcaHeader(const NcaHeader & other)
|
NcaHeader::NcaHeader(const NcaHeader & other)
|
||||||
{
|
{
|
||||||
importBinary(other.getBytes());
|
copyFrom(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
NcaHeader::NcaHeader(const u8 * bytes)
|
NcaHeader::NcaHeader(const u8 * bytes)
|
||||||
|
@ -166,9 +194,14 @@ NcaHeader::NcaHeader(const u8 * bytes)
|
||||||
importBinary(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)
|
void NcaHeader::operator=(const NcaHeader & other)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/memory_blob.h>
|
#include <fnd/memory_blob.h>
|
||||||
|
#include <fnd/List.h>
|
||||||
#include <crypto/aes.h>
|
#include <crypto/aes.h>
|
||||||
#include <crypto/sha.h>
|
#include <crypto/sha.h>
|
||||||
#include <nx/ISerialiseableBinary.h>
|
#include <nx/ISerialiseableBinary.h>
|
||||||
|
@ -12,12 +12,33 @@ class NcaHeader : public ISerialiseableBinary
|
||||||
public:
|
public:
|
||||||
struct sSection
|
struct sSection
|
||||||
{
|
{
|
||||||
u32 start_blk;
|
|
||||||
u32 end_blk;
|
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u64 size;
|
u64 size;
|
||||||
u8 key_type;
|
u8 key_type;
|
||||||
crypto::sha::sSha256Hash hash;
|
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;
|
static const size_t kDefaultBlockSize = 0x200;
|
||||||
|
@ -26,7 +47,8 @@ public:
|
||||||
NcaHeader(const NcaHeader& other);
|
NcaHeader(const NcaHeader& other);
|
||||||
NcaHeader(const u8* bytes);
|
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);
|
void operator=(const NcaHeader& other);
|
||||||
|
|
||||||
// to be used after export
|
// to be used after export
|
||||||
|
@ -44,9 +66,9 @@ public:
|
||||||
u64 getProgramId() const;
|
u64 getProgramId() const;
|
||||||
void setProgramId(u64 program_id);
|
void setProgramId(u64 program_id);
|
||||||
u32 getUnk() const;
|
u32 getUnk() const;
|
||||||
const std::vector<sSection>& getSections() const;
|
const fnd::List<sSection>& getSections() const;
|
||||||
void addSection(const sSection& section);
|
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);
|
void addKey(const crypto::aes::sAes128Key& key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -122,10 +144,12 @@ private:
|
||||||
u64 mNcaSize;
|
u64 mNcaSize;
|
||||||
u64 mProgramId;
|
u64 mProgramId;
|
||||||
u32 mUnk0;
|
u32 mUnk0;
|
||||||
std::vector<sSection> mSections;
|
fnd::List<sSection> mSections;
|
||||||
std::vector<crypto::aes::sAes128Key> mAesKeys;
|
fnd::List<crypto::aes::sAes128Key> mAesKeys;
|
||||||
|
|
||||||
void clearVariables();
|
void clearVariables();
|
||||||
u64 blockNumToSize(u32 block_num) const;
|
u64 blockNumToSize(u32 block_num) const;
|
||||||
u32 sizeToBlockNum(u64 real_size) 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
|
const u8 * SacEntry::getBytes() const
|
||||||
|
@ -47,9 +64,20 @@ void SacEntry::exportBinary()
|
||||||
}
|
}
|
||||||
|
|
||||||
void SacEntry::importBinary(const u8 * bytes)
|
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;
|
bool isServer = (bytes[0] & SAC_IS_SERVER) == SAC_IS_SERVER;
|
||||||
size_t nameLen = (bytes[0] & SAC_NAME_LEN_MASK);
|
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)
|
if (nameLen == 0)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "SAC entry has no service name");
|
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);
|
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
|
bool SacEntry::isServer() const
|
||||||
{
|
{
|
||||||
return mIsServer;
|
return mIsServer;
|
||||||
|
@ -99,3 +118,22 @@ void SacEntry::setName(const std::string & name)
|
||||||
|
|
||||||
mName = 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
|
class SacEntry : public ISerialiseableBinary
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
SacEntry();
|
SacEntry();
|
||||||
|
SacEntry(const std::string& name, bool isServer);
|
||||||
SacEntry(const SacEntry& other);
|
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
|
// to be used after export
|
||||||
const u8* getBytes() const;
|
const u8* getBytes() const;
|
||||||
|
@ -40,4 +45,7 @@ private:
|
||||||
// variables
|
// variables
|
||||||
bool mIsServer;
|
bool mIsServer;
|
||||||
std::string mName;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnd::MemoryBlob nca;
|
try
|
||||||
fnd::io::readFile(argv[1], nca);
|
|
||||||
|
|
||||||
u8 sector[kNcaSectorSize];
|
|
||||||
|
|
||||||
// nca test
|
|
||||||
if (argc == 2)
|
|
||||||
{
|
{
|
||||||
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;
|
u8 sector[kNcaSectorSize];
|
||||||
hdr.importBinary(sector);
|
|
||||||
|
|
||||||
printf("NCA Header\n");
|
// nca test
|
||||||
printf(" Size: 0x%" PRIx64 "\n", hdr.getNcaSize());
|
if (argc == 2)
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
const NcaHeader::sSection& section = hdr.getSections()[i];
|
decryptNcaSectorXts(nca, sector, 1, nx::crypto::aes::nca_header_key[0], nx::crypto::aes::nca_header_key[1]);
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue