diff --git a/lib/libnx/include/nx/AciHeader.h b/lib/libnx/include/nx/AciHeader.h index 9cf616e..71734d0 100644 --- a/lib/libnx/include/nx/AciHeader.h +++ b/lib/libnx/include/nx/AciHeader.h @@ -78,6 +78,8 @@ namespace nx void setAciType(AciType type); bool isProduction() const; void setIsProduction(bool isProduction); + bool isUnqualifiedApproval() const; + void setIsUnqualifiedApproval(bool isUnqualifiedApproval); const sSection& getFacPos() const; void setFacSize(size_t size); const sSection& getSacPos() const; @@ -103,6 +105,7 @@ namespace nx size_t mHeaderOffset; AciType mType; bool mIsProduction; + bool mIsUnqualifiedApproval; sSection mFac, mSac, mKc; void calculateSectionOffsets(); diff --git a/lib/libnx/include/nx/aci.h b/lib/libnx/include/nx/aci.h index 85f7cc5..0295bf3 100644 --- a/lib/libnx/include/nx/aci.h +++ b/lib/libnx/include/nx/aci.h @@ -12,56 +12,34 @@ namespace nx const std::string kAciStructSig = "ACI0"; const std::string kAciDescStructSig = "ACID"; static const size_t kAciAlignSize = 0x10; + + enum Flags + { + FLAG_PRODUCTION, + FLAG_UNQUALIFIED_APPROVAL + }; } #pragma pack(push,1) struct sAciHeader { - private: - byte_t signature_[4]; - uint32_t size_; // includes prefacing signature, set only in ACID made by SDK (it enables easy resigning) + char signature[4]; + le_uint32_t size; // includes prefacing signature, set only in ACID made by SDK (it enables easy resigning) byte_t reserved_0[4]; - uint32_t flags_; // set in ACID only - uint64_t program_id_; // set only in ACI0 (since ACID is generic) - uint64_t program_id_max_; + le_uint32_t flags; // set in ACID only + union uProgramIdInfo + { + struct sRestrictProgramId + { + le_uint64_t min; + le_uint64_t max; + } program_id_restrict; + le_uint64_t program_id; + } program_id_info; struct sAciSection { - private: - uint32_t offset_; // aligned by 0x10 from the last one - uint32_t size_; - public: - uint32_t offset() const { return le_word(offset_); } - void set_offset(uint32_t offset) { offset_ = le_word(offset); } - - uint32_t size() const { return le_word(size_); } - void set_size(uint32_t size) { size_ = le_word(size); } - } fac_, sac_, kc_; - public: - const char* signature() const { return (const char*)signature_; } - void set_signature(const char* signature) { memcpy(signature_, signature, 4); } - - uint32_t size() const { return le_word(size_); } - void set_size(uint32_t size) { size_ = le_word(size); } - - uint32_t flags() const { return le_word(flags_); } - void set_flags(uint32_t flags) { flags_ = le_word(flags); } - - uint64_t program_id() const { return le_dword(program_id_); } - void set_program_id(uint64_t program_id) { program_id_ = le_dword(program_id); } - - uint64_t program_id_min() const { return program_id(); } - void set_program_id_min(uint64_t program_id) { set_program_id(program_id); } - - uint64_t program_id_max() const { return le_dword(program_id_max_); } - void set_program_id_max(uint64_t program_id) { program_id_max_ = le_dword(program_id); } - - const sAciSection& fac() const { return fac_; } - sAciSection& fac() { return fac_; } - - const sAciSection& sac() const { return sac_; } - sAciSection& sac() { return sac_; } - - const sAciSection& kc() const { return kc_; } - sAciSection& kc() { return kc_; } + le_uint32_t offset; // aligned by 0x10 from the last one + le_uint32_t size; + } fac, sac, kc; }; #pragma pack(pop) } \ No newline at end of file diff --git a/lib/libnx/source/AciHeader.cpp b/lib/libnx/source/AciHeader.cpp index eeaa6aa..485f7ed 100644 --- a/lib/libnx/source/AciHeader.cpp +++ b/lib/libnx/source/AciHeader.cpp @@ -13,7 +13,11 @@ bool AciHeader::isEqual(const AciHeader & other) const { return (mHeaderOffset == other.mHeaderOffset) \ && (mType == other.mType) \ + && (mIsProduction == other.mIsProduction) \ + && (mIsUnqualifiedApproval == other.mIsUnqualifiedApproval) \ && (mAcidSize == other.mAcidSize) \ + && (mProgramIdMin == other.mProgramIdMin) \ + && (mProgramIdMax == other.mProgramIdMax) \ && (mProgramId == other.mProgramId) \ && (mFac == other.mFac) \ && (mSac == other.mSac) \ @@ -30,7 +34,11 @@ void AciHeader::copyFrom(const AciHeader & other) { mHeaderOffset = other.mHeaderOffset; mType = other.mType; + mIsProduction = other.mIsProduction; + mIsUnqualifiedApproval = other.mIsUnqualifiedApproval; mAcidSize = other.mAcidSize; + mProgramIdMin = other.mProgramIdMin; + mProgramIdMax = other.mProgramIdMax; mProgramId = other.mProgramId; mFac = other.mFac; mSac = other.mSac; @@ -87,10 +95,10 @@ void AciHeader::exportBinary() switch (mType) { case (TYPE_ACI0): - hdr->set_signature(aci::kAciStructSig.c_str()); + memcpy(hdr->signature, aci::kAciStructSig.c_str(), 4); break; case (TYPE_ACID): - hdr->set_signature(aci::kAciDescStructSig.c_str()); + memcpy(hdr->signature, aci::kAciDescStructSig.c_str(), 4); break; default: throw fnd::Exception(kModuleName, "Unexpected ACI type"); @@ -98,30 +106,32 @@ void AciHeader::exportBinary() // set offset/size calculateSectionOffsets(); - hdr->fac().set_offset(mFac.offset); - hdr->fac().set_size(mFac.size); - hdr->sac().set_offset(mSac.offset); - hdr->sac().set_size(mSac.size); - hdr->kc().set_offset(mKc.offset); - hdr->kc().set_size(mKc.size); + hdr->fac.offset = mFac.offset; + hdr->fac.size = mFac.size; + hdr->sac.offset = mSac.offset; + hdr->sac.size = mSac.size; + hdr->kc.offset = mKc.offset; + hdr->kc.size = mKc.size; uint32_t flags = 0; if (mIsProduction) - flags |= BIT(0); + flags |= _BIT(aci::FLAG_PRODUCTION); + if (mIsProduction) + flags |= _BIT(aci::FLAG_UNQUALIFIED_APPROVAL); - hdr->set_flags(flags); + hdr->flags = flags; if (mType == TYPE_ACI0) { // set program - hdr->set_program_id(mProgramId); + hdr->program_id_info.program_id = mProgramId; } else if (mType == TYPE_ACID) { mAcidSize = getAciSize(); - hdr->set_size(mAcidSize); - hdr->set_program_id_min(mProgramIdMin); - hdr->set_program_id_max(mProgramIdMax); + hdr->size = mAcidSize; + hdr->program_id_info.program_id_restrict.min = mProgramIdMin; + hdr->program_id_info.program_id_restrict.max = mProgramIdMax; } } @@ -139,11 +149,11 @@ void AciHeader::importBinary(const byte_t * bytes, size_t len) sAciHeader* hdr = (sAciHeader*)mBinaryBlob.getBytes(); - if (memcmp(hdr->signature(), aci::kAciStructSig.c_str(), 4) == 0) + if (std::string(hdr->signature, 4) == aci::kAciStructSig) { mType = TYPE_ACI0; } - else if (memcmp(hdr->signature(), aci::kAciDescStructSig.c_str(), 4) == 0) + else if (std::string(hdr->signature, 4) == aci::kAciDescStructSig) { mType = TYPE_ACID; } @@ -155,8 +165,9 @@ void AciHeader::importBinary(const byte_t * bytes, size_t len) if (mType == TYPE_ACI0) { - mProgramId = hdr->program_id(); + mProgramId = hdr->program_id_info.program_id.get(); mIsProduction = false; + mIsUnqualifiedApproval = false; mAcidSize = 0; mProgramIdMin = 0; mProgramIdMax = 0; @@ -164,21 +175,22 @@ void AciHeader::importBinary(const byte_t * bytes, size_t len) else if (mType == TYPE_ACID) { mProgramId = 0; - mIsProduction = (hdr->flags() & BIT(0)) == BIT(0); - mAcidSize = hdr->size(); - mProgramIdMin = hdr->program_id_min(); - mProgramIdMax = hdr->program_id_max(); + mIsProduction = _HAS_BIT(hdr->flags.get(), aci::FLAG_PRODUCTION); + mIsUnqualifiedApproval = _HAS_BIT(hdr->flags.get(), aci::FLAG_UNQUALIFIED_APPROVAL); + mAcidSize = hdr->size.get(); + mProgramIdMin = hdr->program_id_info.program_id_restrict.min.get(); + mProgramIdMax = hdr->program_id_info.program_id_restrict.max.get(); } // the header offset is the MIN(sac.offset, fac.offset, kc.offset) - sizeof(sHeader) - mHeaderOffset = MAX(MIN(hdr->sac().offset(), MIN(hdr->fac().offset(), hdr->kc().offset())), align(sizeof(sAciHeader), aci::kAciAlignSize)) - align(sizeof(sAciHeader), aci::kAciAlignSize); + mHeaderOffset = MAX(MIN(hdr->sac.offset.get(), MIN(hdr->fac.offset.get(), hdr->kc.offset.get())), align(sizeof(sAciHeader), aci::kAciAlignSize)) - align(sizeof(sAciHeader), aci::kAciAlignSize); - mFac.offset = hdr->fac().offset() - mHeaderOffset; - mFac.size = hdr->fac().size(); - mSac.offset = hdr->sac().offset() - mHeaderOffset; - mSac.size = hdr->sac().size(); - mKc.offset = hdr->kc().offset() - mHeaderOffset; - mKc.size = hdr->kc().size(); + mFac.offset = hdr->fac.offset.get() - mHeaderOffset; + mFac.size = hdr->fac.size.get(); + mSac.offset = hdr->sac.offset.get() - mHeaderOffset; + mSac.size = hdr->sac.size.get(); + mKc.offset = hdr->kc.offset.get() - mHeaderOffset; + mKc.size = hdr->kc.size.get(); } void nx::AciHeader::clear() @@ -191,6 +203,7 @@ void nx::AciHeader::clear() mProgramIdMax = 0; mAcidSize = 0; mIsProduction = false; + mIsUnqualifiedApproval = false; mFac.offset = 0; mFac.size = 0; mSac.offset = 0; @@ -261,6 +274,16 @@ void nx::AciHeader::setIsProduction(bool isProduction) mIsProduction = isProduction; } +bool nx::AciHeader::isUnqualifiedApproval() const +{ + return mIsUnqualifiedApproval; +} + +void nx::AciHeader::setIsUnqualifiedApproval(bool isUnqualifiedApproval) +{ + mIsUnqualifiedApproval = isUnqualifiedApproval; +} + uint64_t AciHeader::getProgramId() const { return mProgramId; diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp index a1a4e2f..26cc318 100644 --- a/programs/nstool/source/NpdmProcess.cpp +++ b/programs/nstool/source/NpdmProcess.cpp @@ -465,7 +465,9 @@ void NpdmProcess::displayAciHdr(const nx::AciHeader& aci) { printf(" ACID Size: %" PRIx64 "\n", aci.getAcidSize()); - printf(" Target: %s\n", kAcidTarget[aci.isProduction()].c_str()); + printf(" Flags: \n"); + printf(" Production: %s\n", aci.isProduction() ? "TRUE" : "FALSE"); + printf(" UnqualifiedApproval: %s\n", aci.isUnqualifiedApproval() ? "TRUE" : "FALSE"); printf(" ProgramID Restriction\n"); printf(" Min: %016" PRIx64 "\n", aci.getProgramIdMin()); printf(" Max: %016" PRIx64 "\n", aci.getProgramIdMax());