From 337a5eff25c934f96c7f6fd0651872a51c58df6c Mon Sep 17 00:00:00 2001 From: jakcron Date: Thu, 6 Jul 2017 13:30:27 +1000 Subject: [PATCH] [nx] Add ISerialiseableInterface, which AciHeader and NcaHeader inherit from. Also added SacEntry. --- lib/nx/AciHeader.cpp | 44 +++++++++++++-- lib/nx/AciHeader.h | 19 +++++-- lib/nx/ISerialiseableBinary.h | 17 ++++++ lib/nx/NcaHeader.cpp | 29 ++++++++-- lib/nx/NcaHeader.h | 14 +++-- lib/nx/SacEntry.cpp | 101 ++++++++++++++++++++++++++++++++++ lib/nx/SacEntry.h | 43 +++++++++++++++ lib/nx/nx.vcxproj | 3 + lib/nx/nx.vcxproj.filters | 9 +++ 9 files changed, 260 insertions(+), 19 deletions(-) create mode 100644 lib/nx/ISerialiseableBinary.h create mode 100644 lib/nx/SacEntry.cpp create mode 100644 lib/nx/SacEntry.h diff --git a/lib/nx/AciHeader.cpp b/lib/nx/AciHeader.cpp index ae54d56..61b00fc 100644 --- a/lib/nx/AciHeader.cpp +++ b/lib/nx/AciHeader.cpp @@ -19,20 +19,45 @@ void AciHeader::calculateSectionOffsets() mKc.offset = mSac.offset + align(mSac.size, kAciAlignSize); } +AciHeader::AciHeader() +{ + clearVariables(); +} + +AciHeader::AciHeader(const AciHeader & other) +{ + importBinary(other.getBytes(), other.getSize()); +} + +AciHeader::AciHeader(const u8 * bytes) +{ + importBinary(bytes); +} + +bool AciHeader::operator==(const AciHeader & other) +{ + return memcmp(this->getBytes(), other.getBytes(), this->getSize()); +} + +void AciHeader::operator=(const AciHeader & other) +{ + this->importBinary(other.getBytes(), other.getSize()); +} + const u8 * AciHeader::getBytes() const { - return mBinaryBlob.data(); + return mBinaryBlob.getBytes(); } size_t AciHeader::getSize() const { - return mBinaryBlob.size(); + return mBinaryBlob.getSize(); } void AciHeader::exportBinary() { mBinaryBlob.alloc(sizeof(sAciHeader)); - sAciHeader* hdr = (sAciHeader*)mBinaryBlob.data(); + sAciHeader* hdr = (sAciHeader*)mBinaryBlob.getBytes(); // set type switch (mType) @@ -65,9 +90,9 @@ void AciHeader::importBinary(const u8 * bytes) clearVariables(); mBinaryBlob.alloc(sizeof(sAciHeader)); - memcpy(mBinaryBlob.data(), bytes, sizeof(sAciHeader)); + memcpy(mBinaryBlob.getBytes(), bytes, sizeof(sAciHeader)); - sAciHeader* hdr = (sAciHeader*)mBinaryBlob.data(); + sAciHeader* hdr = (sAciHeader*)mBinaryBlob.getBytes(); if (memcmp(hdr->signature(), kAciStructSig.c_str(), 4) == 0) { @@ -91,6 +116,15 @@ void AciHeader::importBinary(const u8 * bytes) mKc.size = hdr->kc().size(); } +void AciHeader::importBinary(const u8 * bytes, size_t len) +{ + if (len < sizeof(sAciHeader)) + { + throw fnd::Exception(kModuleName, "ACI header too small"); + } + importBinary(bytes); +} + AciHeader::AciType AciHeader::getAciType() const { return mType; diff --git a/lib/nx/AciHeader.h b/lib/nx/AciHeader.h index 101baac..c1e0195 100644 --- a/lib/nx/AciHeader.h +++ b/lib/nx/AciHeader.h @@ -1,9 +1,10 @@ #pragma once +#include #include #include -#include +#include -class AciHeader +class AciHeader : public ISerialiseableBinary { public: enum AciType @@ -18,6 +19,13 @@ public: size_t size; }; + AciHeader(); + AciHeader(const AciHeader& other); + AciHeader(const u8* bytes); + + bool operator==(const AciHeader& other); + void operator=(const AciHeader& other); + // to be used after export const u8* getBytes() const; size_t getSize() const; @@ -25,6 +33,7 @@ public: // export/import binary void exportBinary(); void importBinary(const u8* bytes); + void importBinary(const u8* bytes, size_t len); // variables AciType getAciType() const; @@ -56,13 +65,13 @@ private: { private: u32 offset_; // aligned by 0x10 from the last one - u32 size_; + u32 mSize; public: u32 offset() const { return le_word(offset_); } void set_offset(u32 offset) { offset_ = le_word(offset); } - u32 size() const { return le_word(size_); } - void set_size(u32 size) { size_ = le_word(size); } + u32 size() const { return le_word(mSize); } + void set_size(u32 size) { mSize = le_word(size); } } fac_, sac_, kc_; u8 reserved_3[8]; public: diff --git a/lib/nx/ISerialiseableBinary.h b/lib/nx/ISerialiseableBinary.h new file mode 100644 index 0000000..dc594bd --- /dev/null +++ b/lib/nx/ISerialiseableBinary.h @@ -0,0 +1,17 @@ +#pragma once +#include + +class ISerialiseableBinary +{ +public: + virtual bool operator==(const ISerialiseableBinary& other) = 0; + virtual void operator=(const ISerialiseableBinary& other) = 0; + + virtual const u8* getBytes() const = 0; + virtual size_t getSize() const = 0; + + virtual void exportBinary() = 0; + virtual void importBinary(const u8* bytes) = 0; + virtual void importBinary(const u8* bytes, size_t len) = 0; +}; + diff --git a/lib/nx/NcaHeader.cpp b/lib/nx/NcaHeader.cpp index 30b793c..8ed9a47 100644 --- a/lib/nx/NcaHeader.cpp +++ b/lib/nx/NcaHeader.cpp @@ -4,7 +4,7 @@ void NcaHeader::exportBinary() { mBinaryBlob.alloc(sizeof(sNcaHeader)); - sNcaHeader* hdr = (sNcaHeader*)mBinaryBlob.data(); + sNcaHeader* hdr = (sNcaHeader*)mBinaryBlob.getBytes(); hdr->set_signature(kNcaSig.c_str()); hdr->set_block_size(kDefaultBlockSize); @@ -36,9 +36,9 @@ void NcaHeader::importBinary(const u8 * bytes) clearVariables(); mBinaryBlob.alloc(sizeof(sNcaHeader)); - memcpy(mBinaryBlob.data(), bytes, sizeof(sNcaHeader)); + memcpy(mBinaryBlob.getBytes(), bytes, sizeof(sNcaHeader)); - sNcaHeader* hdr = (sNcaHeader*)mBinaryBlob.data(); + sNcaHeader* hdr = (sNcaHeader*)mBinaryBlob.getBytes(); if (memcmp(hdr->signature(), kNcaSig.c_str(), 4) != 0) { @@ -68,6 +68,15 @@ void NcaHeader::importBinary(const u8 * bytes) } } +void NcaHeader::importBinary(const u8 * bytes, size_t len) +{ + if (len < sizeof(sNcaHeader)) + { + throw fnd::Exception(kModuleName, "NCA header size is too small"); + } + importBinary(bytes); +} + u64 NcaHeader::getNcaSize() const { return mNcaSize; @@ -157,12 +166,22 @@ NcaHeader::NcaHeader(const u8 * bytes) importBinary(bytes); } +bool NcaHeader::operator==(const NcaHeader & other) +{ + return memcmp(this->getBytes(), other.getBytes(), this->getSize()) == 0; +} + +void NcaHeader::operator=(const NcaHeader & other) +{ + this->importBinary(other.getBytes(), other.getSize()); +} + const u8 * NcaHeader::getBytes() const { - return mBinaryBlob.data(); + return mBinaryBlob.getBytes(); } size_t NcaHeader::getSize() const { - return mBinaryBlob.size(); + return mBinaryBlob.getSize(); } \ No newline at end of file diff --git a/lib/nx/NcaHeader.h b/lib/nx/NcaHeader.h index e4267a3..35addec 100644 --- a/lib/nx/NcaHeader.h +++ b/lib/nx/NcaHeader.h @@ -1,12 +1,13 @@ #pragma once +#include +#include #include #include #include #include -#include -#include +#include -class NcaHeader +class NcaHeader : public ISerialiseableBinary { public: struct sSection @@ -19,10 +20,15 @@ public: crypto::sha::sSha256Hash hash; }; + static const size_t kDefaultBlockSize = 0x200; + NcaHeader(); NcaHeader(const NcaHeader& other); NcaHeader(const u8* bytes); + bool operator==(const NcaHeader& other); + void operator=(const NcaHeader& other); + // to be used after export const u8* getBytes() const; size_t getSize() const; @@ -30,6 +36,7 @@ public: // export/import binary void exportBinary(); void importBinary(const u8* bytes); + void importBinary(const u8* bytes, size_t len); // variables u64 getNcaSize() const; @@ -45,7 +52,6 @@ public: private: const std::string kModuleName = "NCA_HEADER"; const std::string kNcaSig = "NCA2"; - static const size_t kDefaultBlockSize = 0x200; static const size_t kSectionNum = 4; static const size_t kAesKeyNum = 4; diff --git a/lib/nx/SacEntry.cpp b/lib/nx/SacEntry.cpp new file mode 100644 index 0000000..edfa335 --- /dev/null +++ b/lib/nx/SacEntry.cpp @@ -0,0 +1,101 @@ +#include "SacEntry.h" + +SacEntry::SacEntry() : + mIsServer(false), + mName("") +{ +} + +SacEntry::SacEntry(const SacEntry & other) +{ + importBinary(other.getBytes(), other.getSize()); +} + +SacEntry::SacEntry(const u8 * bytes) +{ + importBinary(bytes); +} + +const u8 * SacEntry::getBytes() const +{ + return mBinaryBlob.getBytes(); +} + +size_t SacEntry::getSize() const +{ + return mBinaryBlob.getSize(); +} + +void SacEntry::exportBinary() +{ + try { + mBinaryBlob.alloc(mName.size() + 1); + } + catch (const fnd::Exception& e) + { + throw fnd::Exception(kModuleName, "Failed to allocate memory for SacEntry: " + std::string(e.what())); + } + + if (mName.length() > kMaxServiceNameLen) + { + throw fnd::Exception(kModuleName, "Service name string too long (max 8 chars)"); + } + + // copy data into binary blob + mBinaryBlob[0] = (mIsServer ? SAC_IS_SERVER : 0) | (mName.length() & SAC_NAME_LEN_MASK); + memcpy(mBinaryBlob.getBytes() + 1, mName.c_str(), mName.length()); +} + +void SacEntry::importBinary(const u8 * bytes) +{ + bool isServer = (bytes[0] & SAC_IS_SERVER) == SAC_IS_SERVER; + size_t nameLen = (bytes[0] & SAC_NAME_LEN_MASK); + if (nameLen == 0) + { + throw fnd::Exception(kModuleName, "SAC entry has no service name"); + } + else if (nameLen > kMaxServiceNameLen) + { + throw fnd::Exception(kModuleName, "Service name string too long (max 8 chars)"); + } + + mBinaryBlob.alloc(nameLen + 1); + memcpy(mBinaryBlob.getBytes(), bytes, mBinaryBlob.getSize()); + + mIsServer = isServer; + 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; +} + +void SacEntry::setIsServer(bool isServer) +{ + mIsServer = isServer; +} + +const std::string & SacEntry::getName() const +{ + return mName; +} + +void SacEntry::setName(const std::string & name) +{ + if (name.length() > kMaxServiceNameLen) + { + throw fnd::Exception(kModuleName, "Service name string too long (max 8 chars)"); + } + + mName = name; +} diff --git a/lib/nx/SacEntry.h b/lib/nx/SacEntry.h new file mode 100644 index 0000000..644a02d --- /dev/null +++ b/lib/nx/SacEntry.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include +#include + +class SacEntry : public ISerialiseableBinary +{ + SacEntry(); + SacEntry(const SacEntry& other); + SacEntry(const u8* bytes); + + // to be used after export + const u8* getBytes() const; + size_t getSize() const; + + // export/import binary + void exportBinary(); + void importBinary(const u8* bytes); + void importBinary(const u8* bytes, size_t len); + + // variables + bool isServer() const; + void setIsServer(bool isServer); + const std::string& getName() const; + void setName(const std::string& name); +private: + const std::string kModuleName = "SAC_ENTRY"; + static const size_t kMaxServiceNameLen = 8; + + enum SacEntryFlag + { + SAC_IS_SERVER = BIT(7), + SAC_NAME_LEN_MASK = BIT(7)-1 + }; + + // raw binary + fnd::MemoryBlob mBinaryBlob; + + // variables + bool mIsServer; + std::string mName; +}; \ No newline at end of file diff --git a/lib/nx/nx.vcxproj b/lib/nx/nx.vcxproj index 0969761..82f5dae 100644 --- a/lib/nx/nx.vcxproj +++ b/lib/nx/nx.vcxproj @@ -20,12 +20,15 @@ + + + 15.0 diff --git a/lib/nx/nx.vcxproj.filters b/lib/nx/nx.vcxproj.filters index a1a9994..f57d62b 100644 --- a/lib/nx/nx.vcxproj.filters +++ b/lib/nx/nx.vcxproj.filters @@ -24,6 +24,12 @@ Header Files + + Header Files + + + Header Files + @@ -32,5 +38,8 @@ Source Files + + Source Files + \ No newline at end of file