Merge pull request #22 from jakcron/userset-refactor

Userset refactor
This commit is contained in:
Jack 2018-06-18 01:13:01 +08:00 committed by GitHub
commit d8800615af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 116 additions and 27 deletions

View file

@ -17,6 +17,8 @@
#include <nx/nca.h>
#include <nx/npdm.h>
#include <nx/romfs.h>
#include <nx/cnmt.h>
#include <nx/nacp.h>
#include <nx/nso.h>
#include <nx/nro.h>
#include <nx/aset.h>
@ -49,8 +51,8 @@ void UserSettings::showHelp()
printf(" nstool [--listfs] [--update <dir> --normal <dir> --secure <dir>] <.xci file>\n");
printf(" --listfs Print file system in embedded partitions\n");
printf(" --update Extract \"update\" partition to directory\n");
printf(" --normal Extract \"normal\" partition to directory\n");
printf(" --logo Extract \"logo\" partition to directory\n");
printf(" --normal Extract \"normal\" partition to directory\n");
printf(" --secure Extract \"secure\" partition to directory\n");
printf("\n PFS0/HFS0 (PartitionFs), RomFs, NSP (Ninendo Submission Package)\n");
printf(" nstool [--listfs] [--fsdir <dir>] <file>\n");
@ -128,6 +130,11 @@ const sOptional<std::string>& UserSettings::getXciUpdatePath() const
return mXciUpdatePath;
}
const sOptional<std::string>& UserSettings::getXciLogoPath() const
{
return mXciLogoPath;
}
const sOptional<std::string>& UserSettings::getXciNormalPath() const
{
return mXciNormalPath;
@ -138,11 +145,6 @@ const sOptional<std::string>& UserSettings::getXciSecurePath() const
return mXciSecurePath;
}
const sOptional<std::string>& UserSettings::getXciLogoPath() const
{
return mXciLogoPath;
}
const sOptional<std::string>& UserSettings::getFsPath() const
{
return mFsPath;
@ -688,7 +690,7 @@ FileType UserSettings::getFileTypeFromString(const std::string& type_str)
FileType UserSettings::determineFileTypeFromFile(const std::string& path)
{
static const size_t kMaxReadSize = 0x1000;
static const size_t kMaxReadSize = 0x4000;
FileType file_type = FILE_INVALID;
fnd::SimpleFile file;
fnd::MemoryBlob scratch;
@ -702,16 +704,7 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path)
// close file
file.close();
//fnd::SimpleTextOutput::hxdStyleDump(scratch.getBytes(), scratch.getSize());
// prepare decrypted NCA data
byte_t nca_raw[nx::nca::kHeaderSize];
nx::sNcaHeader* nca_header = (nx::sNcaHeader*)(nca_raw + nx::NcaUtils::sectorToOffset(1));
if (scratch.getSize() >= nx::nca::kHeaderSize)
{
nx::NcaUtils::decryptNcaHeader(scratch.getBytes(), nca_raw, mKeyset.nca.header_key);
}
// _QUICK_CAST resolves to a pointer of type 'st' located at scratch.getBytes() + 'oft'
#define _QUICK_CAST(st, oft) ((st*)(scratch.getBytes() + (oft)))
@ -729,15 +722,18 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path)
// test romfs
else if (_ASSERT_SIZE(sizeof(nx::sRomfsHeader)) && _QUICK_CAST(nx::sRomfsHeader, 0)->header_size.get() == sizeof(nx::sRomfsHeader) && _QUICK_CAST(nx::sRomfsHeader, 0)->sections[1].offset.get() == (_QUICK_CAST(nx::sRomfsHeader, 0)->sections[0].offset.get() + _QUICK_CAST(nx::sRomfsHeader, 0)->sections[0].size.get()))
file_type = FILE_ROMFS;
// test nca2
else if (_ASSERT_SIZE(nx::nca::kHeaderSize) && nca_header->signature.get() == nx::nca::kNca2Sig)
file_type = FILE_NCA;
// test nca3
else if (_ASSERT_SIZE(nx::nca::kHeaderSize) && nca_header->signature.get() == nx::nca::kNca3Sig)
file_type = FILE_NCA;
// test npdm
else if (_ASSERT_SIZE(sizeof(nx::sNpdmHeader)) && _QUICK_CAST(nx::sNpdmHeader, 0)->signature.get() == nx::npdm::kNpdmStructSig)
file_type = FILE_NPDM;
// test nca
else if (determineValidNcaFromSample(scratch))
file_type = FILE_NCA;
// test cnmt
else if (determineValidCnmtFromSample(scratch))
file_type = FILE_CNMT;
// test nacp
else if (determineValidNacpFromSample(scratch))
file_type = FILE_NACP;
// test nso
else if (_ASSERT_SIZE(sizeof(nx::sNsoHeader)) && _QUICK_CAST(nx::sNsoHeader, 0)->signature.get() == nx::nso::kNsoSig)
file_type = FILE_NSO;
@ -757,6 +753,95 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path)
return file_type;
}
bool UserSettings::determineValidNcaFromSample(const fnd::MemoryBlob& sample) const
{
// prepare decrypted NCA data
byte_t nca_raw[nx::nca::kHeaderSize];
nx::sNcaHeader* nca_header = (nx::sNcaHeader*)(nca_raw + nx::NcaUtils::sectorToOffset(1));
if (sample.getSize() < nx::nca::kHeaderSize)
return false;
nx::NcaUtils::decryptNcaHeader(sample.getBytes(), nca_raw, mKeyset.nca.header_key);
if (nca_header->signature.get() != nx::nca::kNca2Sig && nca_header->signature.get() != nx::nca::kNca3Sig)
return false;
return true;
}
bool UserSettings::determineValidCnmtFromSample(const fnd::MemoryBlob& sample) const
{
if (sample.getSize() < sizeof(nx::sContentMetaHeader))
return false;
const nx::sContentMetaHeader* data = (const nx::sContentMetaHeader*)sample.getBytes();
size_t minimum_size = sizeof(nx::sContentMetaHeader) + data->exhdr_size.get() + data->content_count.get() * sizeof(nx::sContentInfo) + data->content_meta_count.get() * sizeof(nx::sContentMetaInfo) + nx::cnmt::kDigestLen;
if (sample.getSize() < minimum_size)
return false;
if (data->type == nx::cnmt::METATYPE_APPLICATION)
{
const nx::sApplicationMetaExtendedHeader* meta = (const nx::sApplicationMetaExtendedHeader*)(sample.getBytes() + sizeof(nx::sContentMetaHeader));
if ((meta->patch_id.get() & data->id.get()) != data->id.get())
return false;
}
else if (data->type == nx::cnmt::METATYPE_PATCH)
{
const nx::sPatchMetaExtendedHeader* meta = (const nx::sPatchMetaExtendedHeader*)(sample.getBytes() + sizeof(nx::sContentMetaHeader));
if ((meta->application_id.get() & data->id.get()) != meta->application_id.get())
return false;
minimum_size += meta->extended_data_size.get();
}
else if (data->type == nx::cnmt::METATYPE_ADD_ON_CONTENT)
{
const nx::sAddOnContentMetaExtendedHeader* meta = (const nx::sAddOnContentMetaExtendedHeader*)(sample.getBytes() + sizeof(nx::sContentMetaHeader));
if ((meta->application_id.get() & data->id.get()) != meta->application_id.get())
return false;
}
else if (data->type == nx::cnmt::METATYPE_DELTA)
{
const nx::sDeltaMetaExtendedHeader* meta = (const nx::sDeltaMetaExtendedHeader*)(sample.getBytes() + sizeof(nx::sContentMetaHeader));
if ((meta->application_id.get() & data->id.get()) != meta->application_id.get())
return false;
minimum_size += meta->extended_data_size.get();
}
if (sample.getSize() != minimum_size)
return false;
return true;
}
bool UserSettings::determineValidNacpFromSample(const fnd::MemoryBlob& sample) const
{
if (sample.getSize() != sizeof(nx::sApplicationControlProperty))
return false;
const nx::sApplicationControlProperty* data = (const nx::sApplicationControlProperty*)sample.getBytes();
if (data->logo_type > nx::nacp::LOGO_Nintendo)
return false;
if (data->display_version[0] == 0)
return false;
if (data->user_account_save_data_size.get() == 0 && data->user_account_save_data_journal_size.get() != 0)
return false;
if (data->user_account_save_data_journal_size.get() == 0 && data->user_account_save_data_size.get() != 0)
return false;
if (data->supported_language_flag.get() == 0)
return false;
return true;
}
nx::npdm::InstructionType UserSettings::getInstructionTypeFromString(const std::string & type_str)
{
std::string str = type_str;

View file

@ -1,6 +1,7 @@
#pragma once
#include <string>
#include <fnd/types.h>
#include <fnd/MemoryBlob.h>
#include <nx/npdm.h>
#include "nstool.h"
@ -27,9 +28,9 @@ public:
// specialised paths
const sOptional<std::string>& getXciUpdatePath() const;
const sOptional<std::string>& getXciLogoPath() const;
const sOptional<std::string>& getXciNormalPath() const;
const sOptional<std::string>& getXciSecurePath() const;
const sOptional<std::string>& getXciLogoPath() const;
const sOptional<std::string>& getFsPath() const;
const sOptional<std::string>& getNcaPart0Path() const;
const sOptional<std::string>& getNcaPart1Path() const;
@ -53,9 +54,9 @@ private:
sOptional<bool> minimal_output;
sOptional<bool> list_fs;
sOptional<std::string> update_path;
sOptional<std::string> logo_path;
sOptional<std::string> normal_path;
sOptional<std::string> secure_path;
sOptional<std::string> logo_path;
sOptional<std::string> fs_path;
sOptional<std::string> nca_titlekey;
sOptional<std::string> nca_bodykey;
@ -78,9 +79,9 @@ private:
bool mListFs;
sOptional<std::string> mXciUpdatePath;
sOptional<std::string> mXciLogoPath;
sOptional<std::string> mXciNormalPath;
sOptional<std::string> mXciSecurePath;
sOptional<std::string> mXciLogoPath;
sOptional<std::string> mFsPath;
sOptional<std::string> mNcaPart0Path;
@ -101,5 +102,8 @@ private:
void decodeHexStringToBytes(const std::string& name, const std::string& str, byte_t* out, size_t out_len);
FileType getFileTypeFromString(const std::string& type_str);
FileType determineFileTypeFromFile(const std::string& path);
bool determineValidNcaFromSample(const fnd::MemoryBlob& sample) const;
bool determineValidCnmtFromSample(const fnd::MemoryBlob& sample) const;
bool determineValidNacpFromSample(const fnd::MemoryBlob& sample) const;
nx::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str);
};

View file

@ -30,12 +30,12 @@ int main(int argc, char** argv)
if (user_set.getXciUpdatePath().isSet)
xci.setPartitionForExtract(nx::xci::kUpdatePartitionStr, user_set.getXciUpdatePath().var);
if (user_set.getXciLogoPath().isSet)
xci.setPartitionForExtract(nx::xci::kLogoPartitionStr, user_set.getXciLogoPath().var);
if (user_set.getXciNormalPath().isSet)
xci.setPartitionForExtract(nx::xci::kNormalPartitionStr, user_set.getXciNormalPath().var);
if (user_set.getXciSecurePath().isSet)
xci.setPartitionForExtract(nx::xci::kSecurePartitionStr, user_set.getXciSecurePath().var);
if (user_set.getXciLogoPath().isSet)
xci.setPartitionForExtract(nx::xci::kLogoPartitionStr, user_set.getXciLogoPath().var);
xci.setListFs(user_set.isListFs());
xci.process();