mirror of
https://github.com/jakcron/nstool.git
synced 2024-12-22 18:55:29 +00:00
[libctr] Add initial code for CTR library.
This commit is contained in:
parent
44e054fb6a
commit
91eede10d2
22
NNTools.sln
22
NNTools.sln
|
@ -32,6 +32,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libhac", "lib\libhac\libhac
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libhac-hb", "lib\libhac-hb\libhac-hb.vcxproj", "{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libctr", "lib\libctr\libctr.vcxproj", "{96900163-D5A3-42AA-A387-D7D5DAD0A11E}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctr-test", "programs\ctr-test\ctr-test.vcxproj", "{93C2F450-6682-41F8-9E19-35363BA15EF6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -104,6 +108,22 @@ Global
|
|||
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x64.Build.0 = Release|x64
|
||||
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x86.ActiveCfg = Release|Win32
|
||||
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x86.Build.0 = Release|Win32
|
||||
{96900163-D5A3-42AA-A387-D7D5DAD0A11E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{96900163-D5A3-42AA-A387-D7D5DAD0A11E}.Debug|x64.Build.0 = Debug|x64
|
||||
{96900163-D5A3-42AA-A387-D7D5DAD0A11E}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{96900163-D5A3-42AA-A387-D7D5DAD0A11E}.Debug|x86.Build.0 = Debug|Win32
|
||||
{96900163-D5A3-42AA-A387-D7D5DAD0A11E}.Release|x64.ActiveCfg = Release|x64
|
||||
{96900163-D5A3-42AA-A387-D7D5DAD0A11E}.Release|x64.Build.0 = Release|x64
|
||||
{96900163-D5A3-42AA-A387-D7D5DAD0A11E}.Release|x86.ActiveCfg = Release|Win32
|
||||
{96900163-D5A3-42AA-A387-D7D5DAD0A11E}.Release|x86.Build.0 = Release|Win32
|
||||
{93C2F450-6682-41F8-9E19-35363BA15EF6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{93C2F450-6682-41F8-9E19-35363BA15EF6}.Debug|x64.Build.0 = Debug|x64
|
||||
{93C2F450-6682-41F8-9E19-35363BA15EF6}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{93C2F450-6682-41F8-9E19-35363BA15EF6}.Debug|x86.Build.0 = Debug|Win32
|
||||
{93C2F450-6682-41F8-9E19-35363BA15EF6}.Release|x64.ActiveCfg = Release|x64
|
||||
{93C2F450-6682-41F8-9E19-35363BA15EF6}.Release|x64.Build.0 = Release|x64
|
||||
{93C2F450-6682-41F8-9E19-35363BA15EF6}.Release|x86.ActiveCfg = Release|Win32
|
||||
{93C2F450-6682-41F8-9E19-35363BA15EF6}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -117,6 +137,8 @@ Global
|
|||
{7BE99936-0D40-410D-944B-4513C2EFF8DC} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
|
||||
{91BA9E79-8242-4F7D-B997-0DFEC95EA22B} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
|
||||
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
|
||||
{96900163-D5A3-42AA-A387-D7D5DAD0A11E} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
|
||||
{93C2F450-6682-41F8-9E19-35363BA15EF6} = {E0863FCC-8E72-490D-BE1B-458F12CA8298}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {07DCCACC-D10D-47C9-85AE-FB9C54DB7D62}
|
||||
|
|
78
lib/libctr/include/nn/ctr/CodeBinaryHeader.h
Normal file
78
lib/libctr/include/nn/ctr/CodeBinaryHeader.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
CodeBinaryHeader.h
|
||||
(c) 2018 Jakcron
|
||||
|
||||
This is a header to prepend to raw EXEFS .code binaries that provide enough data to be equivalent to an ELF.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include <fnd/ISerialisable.h>
|
||||
#include <fnd/List.h>
|
||||
#include <nn/ctr/code.h>
|
||||
#include <nn/ctr/CodeSegment.h>
|
||||
|
||||
|
||||
namespace nn
|
||||
{
|
||||
namespace ctr
|
||||
{
|
||||
class CodeBinaryHeader : public fnd::ISerialisable
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CodeBinaryHeader();
|
||||
CodeBinaryHeader(const CodeBinaryHeader& other);
|
||||
|
||||
void operator=(const CodeBinaryHeader& other);
|
||||
bool operator==(const CodeBinaryHeader& other) const;
|
||||
bool operator!=(const CodeBinaryHeader& other) const;
|
||||
|
||||
// export/import binary
|
||||
void toBytes();
|
||||
void fromBytes(const byte_t* data, size_t len);
|
||||
const fnd::Vec<byte_t>& getBytes() const;
|
||||
|
||||
// variables
|
||||
void clear();
|
||||
|
||||
// mutators
|
||||
void setCodeBinOffset(uint32_t offset);
|
||||
uint32_t getCodeBinOffset() const;
|
||||
|
||||
void setCodeBinSize(uint32_t size);
|
||||
uint32_t getCodeBinSize() const;
|
||||
|
||||
void setStackSize(uint32_t size);
|
||||
uint32_t getStackSize() const;
|
||||
|
||||
void setBssSize(uint32_t size);
|
||||
uint32_t getBssSize() const;
|
||||
|
||||
void setTextSegment(const ctr::CodeSegment& segment);
|
||||
const ctr::CodeSegment& getTextSegment() const;
|
||||
|
||||
void setRODataSegment(const ctr::CodeSegment& segment);
|
||||
const ctr::CodeSegment& getRODataSegment() const;
|
||||
|
||||
void setDataSegment(const ctr::CodeSegment& segment);
|
||||
const ctr::CodeSegment& getDataSegment() const;
|
||||
|
||||
private:
|
||||
const std::string kModuleName = "CODE_BINARY_HEADER";
|
||||
|
||||
|
||||
// serialised data
|
||||
fnd::Vec<byte_t> mRawBinary;
|
||||
|
||||
// members
|
||||
uint32_t mCodeBinOffset;
|
||||
uint32_t mCodeBinSize;
|
||||
uint32_t mStackSize;
|
||||
uint32_t mBssSize;
|
||||
CodeSegment mSegmentList[code::kCodeSegmentNum];
|
||||
|
||||
};
|
||||
}
|
||||
}
|
37
lib/libctr/include/nn/ctr/CodeSegment.h
Normal file
37
lib/libctr/include/nn/ctr/CodeSegment.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
CodeSegment.h
|
||||
(c) 2018 Jakcron
|
||||
*/
|
||||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
|
||||
namespace nn
|
||||
{
|
||||
namespace ctr
|
||||
{
|
||||
class CodeSegment
|
||||
{
|
||||
public:
|
||||
CodeSegment();
|
||||
CodeSegment(const CodeSegment& other);
|
||||
CodeSegment(uint32_t address, uint32_t size, uint32_t page_num);
|
||||
|
||||
void operator=(const CodeSegment& other);
|
||||
bool operator==(const CodeSegment& other) const;
|
||||
bool operator!=(const CodeSegment& other) const;
|
||||
|
||||
void setAddress(uint32_t address);
|
||||
uint32_t getAddress() const;
|
||||
|
||||
void setSize(uint32_t size);
|
||||
uint32_t getSize() const;
|
||||
|
||||
void setPageNum(uint32_t num);
|
||||
uint32_t getPageNum() const;
|
||||
private:
|
||||
uint32_t mAddress;
|
||||
uint32_t mSize;
|
||||
uint32_t mPageNum;
|
||||
};
|
||||
}
|
||||
}
|
210
lib/libctr/include/nn/ctr/NcchHeader.h
Normal file
210
lib/libctr/include/nn/ctr/NcchHeader.h
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
NcchHeader.h
|
||||
(c) 2018 Jakcron
|
||||
|
||||
This is a 0x100 byte header used to map/hash sections in CXI/CFA files, is preceeded by a RSA-2048 signature over
|
||||
these 0x100 bytes in such files. It is also used in CCI files in the CardInfo structure
|
||||
|
||||
#Implementation Details
|
||||
- sizes/offsets are in blocks (usually 512 bytes)
|
||||
- all offsets in the raw structure are from the start of the file, not the start of the header.
|
||||
*/
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/sha.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <fnd/List.h>
|
||||
#include <fnd/ISerialisable.h>
|
||||
#include <nn/ctr/ProgramId.h>
|
||||
#include <nn/ctr/ncch.h>
|
||||
|
||||
namespace nn
|
||||
{
|
||||
namespace ctr
|
||||
{
|
||||
class NcchHeader : public fnd::ISerialisable
|
||||
{
|
||||
public:
|
||||
class Layout
|
||||
{
|
||||
public:
|
||||
Layout() :
|
||||
mOffset(0),
|
||||
mSize(0),
|
||||
mHashedSize(0),
|
||||
mHash()
|
||||
{}
|
||||
|
||||
void operator=(const Layout& other)
|
||||
{
|
||||
mOffset = other.mOffset;
|
||||
mSize = other.mSize;
|
||||
mHashedSize = other.mHashedSize;
|
||||
mHash = other.mHash;
|
||||
}
|
||||
|
||||
bool operator==(const Layout& other) const
|
||||
{
|
||||
return (mOffset == other.mOffset) \
|
||||
&& (mSize == other.mSize) \
|
||||
&& (mHashedSize == other.mHashedSize) \
|
||||
&& (mHash == other.mHash);
|
||||
}
|
||||
|
||||
bool operator!=(const Layout& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void setOffset(size_t offset)
|
||||
{
|
||||
mOffset = offset;
|
||||
}
|
||||
|
||||
size_t getOffset() const
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
void setSize(size_t size)
|
||||
{
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
size_t getSize() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
void setHashedSize(size_t hashed_size)
|
||||
{
|
||||
mHashedSize = hashed_size;
|
||||
}
|
||||
|
||||
size_t getHashedSize() const
|
||||
{
|
||||
return mHashedSize;
|
||||
}
|
||||
|
||||
void setHash(const fnd::sha::sSha256Hash& hash)
|
||||
{
|
||||
mHash = hash;
|
||||
}
|
||||
|
||||
const fnd::sha::sSha256Hash& getHash() const
|
||||
{
|
||||
return mHash;
|
||||
}
|
||||
private:
|
||||
size_t mOffset;
|
||||
size_t mSize;
|
||||
size_t mHashedSize;
|
||||
fnd::sha::sSha256Hash mHash;
|
||||
};
|
||||
|
||||
// constructors
|
||||
NcchHeader();
|
||||
NcchHeader(const NcchHeader& other);
|
||||
|
||||
void operator=(const NcchHeader& other);
|
||||
bool operator==(const NcchHeader& other) const;
|
||||
bool operator!=(const NcchHeader& other) const;
|
||||
|
||||
// export/import binary
|
||||
void toBytes();
|
||||
void fromBytes(const byte_t* data, size_t len);
|
||||
const fnd::Vec<byte_t>& getBytes() const;
|
||||
|
||||
// variables
|
||||
void clear();
|
||||
|
||||
// data layout mutators
|
||||
void setNcchBinarySize(size_t size);
|
||||
size_t getNcchBinarySize() const;
|
||||
|
||||
void setExtendedHeaderLayout(const Layout layout);
|
||||
const Layout& getExtendedHeaderLayout() const;
|
||||
|
||||
void setPlainRegionLayout(const Layout layout);
|
||||
const Layout& getPlainRegionLayout() const;
|
||||
|
||||
void setLogoLayout(const Layout layout);
|
||||
const Layout& getLogoLayout() const;
|
||||
|
||||
void setExefsLayout(const Layout layout);
|
||||
const Layout& getExefsLayout() const;
|
||||
|
||||
void setRomfsLayout(const Layout layout);
|
||||
const Layout& getRomfsLayout() const;
|
||||
|
||||
// property mutators
|
||||
void setNcchType(ncch::NcchType type);
|
||||
ncch::NcchType getNcchType() const;
|
||||
|
||||
void setNewCryptoFlag(ncch::NewCryptoFlag flag);
|
||||
ncch::NewCryptoFlag getNewCryptoFlag() const;
|
||||
|
||||
void setPlatform(ncch::Platform platform);
|
||||
ncch::Platform getPlatform() const;
|
||||
|
||||
void setFormType(ncch::FormType type);
|
||||
ncch::FormType getFormType() const;
|
||||
|
||||
void setContentType(ncch::ContentType type);
|
||||
ncch::ContentType getContentType() const;
|
||||
|
||||
void setBlockSize(ncch::BlockSizeFlag flag);
|
||||
ncch::BlockSizeFlag getBlockSize() const;
|
||||
|
||||
void setOtherFlagList(const fnd::List<ncch::OtherFlag>& list);
|
||||
const fnd::List<ncch::OtherFlag>& getOtherFlagList() const;
|
||||
|
||||
void setCompanyCode(const std::string& company_code);
|
||||
const std::string& getCompanyCode() const;
|
||||
|
||||
void setTitleId(const ctr::ProgramId& id);
|
||||
const ctr::ProgramId& getTitleId() const;
|
||||
|
||||
void setProgramId(const ctr::ProgramId& id);
|
||||
const ctr::ProgramId& getProgramId() const;
|
||||
|
||||
void setProductCode(const std::string& product_code);
|
||||
const std::string& getProductCode() const;
|
||||
|
||||
void setSeedChecksum(uint32_t checksum);
|
||||
uint32_t getSeedChecksum() const;
|
||||
|
||||
private:
|
||||
const std::string kModuleName = "NCCH_HEADER";
|
||||
|
||||
// serialised data
|
||||
fnd::Vec<byte_t> mRawBinary;
|
||||
|
||||
// members
|
||||
size_t mNcchBinarySize;
|
||||
Layout mExHeaderLayout;
|
||||
Layout mPlainRegionLayout;
|
||||
Layout mLogoLayout;
|
||||
Layout mExefsLayout;
|
||||
Layout mRomfsLayout;
|
||||
|
||||
std::string mCompanyCode;
|
||||
std::string mProductCode;
|
||||
|
||||
uint32_t mSeedChecksum;
|
||||
|
||||
ncch::NcchType mNcchType;
|
||||
ProgramId mTitleId;
|
||||
ProgramId mProgramId;
|
||||
|
||||
ncch::NewCryptoFlag mNewCryptoFlag;
|
||||
ncch::Platform mPlatform;
|
||||
ncch::FormType mFormType;
|
||||
ncch::ContentType mContentType;
|
||||
ncch::BlockSizeFlag mBlockSize;
|
||||
fnd::List<ncch::OtherFlag> mOtherFlagList;
|
||||
};
|
||||
}
|
||||
}
|
48
lib/libctr/include/nn/ctr/ProgramId.h
Normal file
48
lib/libctr/include/nn/ctr/ProgramId.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
ProgramId.h
|
||||
(c) 2018 Jakcron
|
||||
|
||||
This is a wrapper class for the 64bit unique id assigned to programs
|
||||
*/
|
||||
#pragma once
|
||||
#include <nn/ctr/prog_id.h>
|
||||
|
||||
namespace nn
|
||||
{
|
||||
namespace ctr
|
||||
{
|
||||
class ProgramId
|
||||
{
|
||||
public:
|
||||
ProgramId();
|
||||
ProgramId(const ProgramId &other);
|
||||
ProgramId(uint64_t prog_id);
|
||||
ProgramId(uint16_t device_group, uint16_t category, uint32_t unique_id, uint8_t variation);
|
||||
|
||||
void operator=(const ProgramId& other);
|
||||
bool operator==(const ProgramId& other) const;
|
||||
bool operator!=(const ProgramId& other) const;
|
||||
|
||||
// mutators
|
||||
void setInnerValue(uint64_t id);
|
||||
uint64_t getInnerValue() const;
|
||||
|
||||
void setDeviceGroup(uint16_t device_group);
|
||||
uint16_t getDeviceGroup() const;
|
||||
|
||||
void setCategory(uint16_t category);
|
||||
uint16_t getCategory() const;
|
||||
|
||||
void setUniqueId(uint32_t uid);
|
||||
uint32_t getUniqueId() const;
|
||||
|
||||
void setVariation(uint8_t variation);
|
||||
uint8_t getVariation() const;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
uint64_t mProgramId;
|
||||
};
|
||||
}
|
||||
}
|
44
lib/libctr/include/nn/ctr/code.h
Normal file
44
lib/libctr/include/nn/ctr/code.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/rsa.h>
|
||||
#include <nn/ctr/macro.h>
|
||||
|
||||
namespace nn
|
||||
{
|
||||
namespace ctr
|
||||
{
|
||||
namespace code
|
||||
{
|
||||
static const uint32_t kStructMagic = _MAKE_STRUCT_MAGIC_U32("CODE");
|
||||
static const uint32_t kCtrFormatIdent = _MAKE_STRUCT_MAGIC_U32("CTR0");
|
||||
static const size_t kCodeSegmentNum = 3;
|
||||
|
||||
enum CodeSegmentIndex
|
||||
{
|
||||
TEXT_SEGMENT,
|
||||
RODATA_SEGMENT,
|
||||
DATA_SEGMENT,
|
||||
};
|
||||
}
|
||||
#pragma pack(push,1)
|
||||
struct sCodeBinaryHeader
|
||||
{
|
||||
le_uint32_t st_magic;
|
||||
le_uint32_t format_ident;
|
||||
le_uint32_t flags;
|
||||
byte_t reserved_00[4];
|
||||
le_uint32_t code_bin_offset;
|
||||
le_uint32_t code_bin_size;
|
||||
le_uint32_t stack_size;
|
||||
le_uint32_t bss_size;
|
||||
struct sCodeSegment
|
||||
{
|
||||
le_uint32_t v_addr;
|
||||
le_uint32_t size;
|
||||
le_uint32_t page_num;
|
||||
le_uint32_t padding;
|
||||
} segments[code::kCodeSegmentNum];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
}
|
||||
}
|
5
lib/libctr/include/nn/ctr/macro.h
Normal file
5
lib/libctr/include/nn/ctr/macro.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
#define _MAKE_STRUCT_MAGIC_U32(x) ((uint32_t)(x[3]) << 24 | (uint32_t)(x[2]) << 16 | (uint32_t)(x[1]) << 8 | (uint32_t)(x[0]))
|
||||
#define _MAKE_STRUCT_MAGIC_U64(x) ((uint64_t)(x[7]) << 56 | (uint64_t)(x[6]) << 48 | (uint64_t)(x[5]) << 40 | (uint64_t)(x[4]) << 32 | (uint64_t)(x[3]) << 24 | (uint64_t)(x[2]) << 16 | (uint64_t)(x[1]) << 8 | (uint64_t)(x[0]))
|
127
lib/libctr/include/nn/ctr/ncch.h
Normal file
127
lib/libctr/include/nn/ctr/ncch.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/sha.h>
|
||||
#include <fnd/rsa.h>
|
||||
#include <nn/ctr/macro.h>
|
||||
|
||||
namespace nn
|
||||
{
|
||||
namespace ctr
|
||||
{
|
||||
namespace ncch
|
||||
{
|
||||
static const uint32_t kNcchStructMagic = _MAKE_STRUCT_MAGIC_U32("NCCH");
|
||||
static const size_t kCompanyCodeLen = 2;
|
||||
static const size_t kProductCodeLen = 0x10;
|
||||
static const byte_t kFormTypeBitWidth = 2;
|
||||
static const byte_t kContentTypeBitWidth = 6;
|
||||
|
||||
enum NcchType
|
||||
{
|
||||
TYPE_CFA = 0,
|
||||
TYPE_CXI = 2
|
||||
};
|
||||
|
||||
enum NewCryptoFlag
|
||||
{
|
||||
CRYPTO_DEFAULT = 0x00,
|
||||
CRYPTO_25 = 0x01,
|
||||
CRYPTO_18 = 0x0A,
|
||||
CRYPTO_1B = 0x0B
|
||||
};
|
||||
|
||||
enum Platform
|
||||
{
|
||||
PLATFORM_UNDEFINED,
|
||||
PLATFORM_CTR,
|
||||
PLATFORM_SNAKE,
|
||||
};
|
||||
|
||||
enum FormType
|
||||
{
|
||||
UNASSIGNED,
|
||||
SIMPLE_CONTENT,
|
||||
EXECUTABLE_WITHOUT_ROMFS,
|
||||
EXECUTABLE
|
||||
};
|
||||
|
||||
enum ContentType
|
||||
{
|
||||
APPLICATION,
|
||||
SYSTEM_UPDATE,
|
||||
MANUAL,
|
||||
CHILD,
|
||||
TRIAL,
|
||||
EXTENDED_SYSTEM_UPDATE
|
||||
};
|
||||
|
||||
enum BlockSizeFlag
|
||||
{
|
||||
BLOCK_SIZE_512
|
||||
};
|
||||
|
||||
enum OtherFlag
|
||||
{
|
||||
FIXED_AES_KEY = 0,
|
||||
NO_MOUNT_ROMFS = 1,
|
||||
NO_AES = 2,
|
||||
SEED_KEY = 5,
|
||||
MANUAL_DISCLOSURE = 6,
|
||||
};
|
||||
|
||||
enum FlagIndex
|
||||
{
|
||||
CRYPTO_FLAG_INDEX = 3,
|
||||
PLATFORM_INDEX = 4,
|
||||
CONTENT_TYPE_INDEX = 5,
|
||||
BLOCK_SIZE_INDEX = 6,
|
||||
OTHER_FLAG_INDEX = 7
|
||||
};
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct sLayout
|
||||
{
|
||||
le_uint32_t block_offset;
|
||||
le_uint32_t block_num;
|
||||
};
|
||||
|
||||
struct sLayoutHashed : public sLayout
|
||||
{
|
||||
le_uint32_t block_num_hash_protected;
|
||||
};
|
||||
|
||||
struct sNcchHeader
|
||||
{
|
||||
le_uint32_t st_magic;
|
||||
le_uint32_t size;
|
||||
le_uint64_t title_id;
|
||||
char company_code[ncch::kCompanyCodeLen];
|
||||
le_uint16_t ncch_type;
|
||||
le_uint32_t seed_checksum;
|
||||
le_uint64_t program_id;
|
||||
byte_t reserved1[0x10];
|
||||
fnd::sha::sSha256Hash logo_hash;
|
||||
char product_code[ncch::kProductCodeLen];
|
||||
fnd::sha::sSha256Hash exheader_hash;
|
||||
le_uint32_t exheader_size;
|
||||
byte_t reserved2[0x4];
|
||||
byte_t flags[8];
|
||||
sLayout plain_region;
|
||||
sLayout logo;
|
||||
sLayoutHashed exefs;
|
||||
byte_t reserved3[4];
|
||||
sLayoutHashed romfs;
|
||||
byte_t reserved4[4];
|
||||
fnd::sha::sSha256Hash exefs_hash;
|
||||
fnd::sha::sSha256Hash romfs_hash;
|
||||
};
|
||||
|
||||
struct sNcchHeaderBlock
|
||||
{
|
||||
byte_t rsa_signature[fnd::rsa::kRsa2048Size];
|
||||
sNcchHeader header;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
}
|
||||
}
|
87
lib/libctr/include/nn/ctr/prog_id.h
Normal file
87
lib/libctr/include/nn/ctr/prog_id.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
|
||||
namespace nn
|
||||
{
|
||||
namespace ctr
|
||||
{
|
||||
namespace prog_id
|
||||
{
|
||||
static const uint64_t kDeviceGroupMask = 0xffff000000000000;
|
||||
static const uint64_t kDeviceGroupShift = 48;
|
||||
static const uint64_t kCategoryMask = 0x0000ffff00000000;
|
||||
static const uint64_t kCategoryShift = 32;
|
||||
static const uint64_t kUniqueIdMask = 0x00000000ffffff00;
|
||||
static const uint64_t kUniqueIdShift = 8;
|
||||
static const uint64_t kVariationMask = 0x00000000000000ff;
|
||||
static const uint64_t kVariationShift = 0;
|
||||
|
||||
enum DeviceGroup
|
||||
{
|
||||
DEVICE_TWL = 0x0003,
|
||||
DEVICE_CTR = 0x0004,
|
||||
DEVICE_CAFE = 0x0005,
|
||||
};
|
||||
|
||||
enum CategoryFlags
|
||||
{
|
||||
CATEGORY_FLAG_NORMAL = 0,
|
||||
CATEGORY_FLAG_DLP_CHILD = _BIT(0),
|
||||
CATEGORY_FLAG_DEMO = _BIT(1),
|
||||
CATEGORY_FLAG_CONTENTS = _BIT(0) | _BIT(1),
|
||||
CATEGORY_FLAG_ADD_ON_CONTENTS = _BIT(2),
|
||||
CATEGORY_FLAG_PATCH = _BIT(1) | _BIT(2),
|
||||
CATEGORY_FLAG_NOT_EXECUTABLE = _BIT(3),
|
||||
CATEGORY_FLAG_SYSTEM = _BIT(4),
|
||||
CATEGORY_FLAG_REQUIRE_BATCH_UPDATE = _BIT(5),
|
||||
CATEGORY_FLAG_NOT_REQUIRE_USER_APPROVAL = _BIT(6),
|
||||
CATEGORY_FLAG_NOT_REQUIRE_RIGHT_FOR_MOUNT = _BIT(7),
|
||||
CATEGORY_FLAG_CAN_SKIP_CONVERT_JUMP_ID = _BIT(8),
|
||||
CATEGORY_FLAG_TWL_LEGACY = _BIT(15),
|
||||
};
|
||||
|
||||
enum CategoryType
|
||||
{
|
||||
CATEGORY_APPLICATION = (CATEGORY_FLAG_NORMAL),
|
||||
CATEGORY_DLP_CHILD = (CATEGORY_FLAG_DLP_CHILD),
|
||||
CATEGORY_DEMO = (CATEGORY_FLAG_DEMO),
|
||||
CATEGORY_CONTENTS = (CATEGORY_FLAG_CONTENTS),
|
||||
CATEGORY_PATCH = (CATEGORY_FLAG_PATCH |
|
||||
CATEGORY_FLAG_NOT_EXECUTABLE),
|
||||
CATEGORY_ADD_ON_CONTENTS = (CATEGORY_FLAG_ADD_ON_CONTENTS |
|
||||
CATEGORY_FLAG_NOT_EXECUTABLE |
|
||||
CATEGORY_FLAG_NOT_REQUIRE_RIGHT_FOR_MOUNT),
|
||||
CATEGORY_FIRMWARE = (CATEGORY_FLAG_SYSTEM |
|
||||
CATEGORY_FLAG_NOT_EXECUTABLE |
|
||||
CATEGORY_FLAG_REQUIRE_BATCH_UPDATE |
|
||||
CATEGORY_FLAG_CAN_SKIP_CONVERT_JUMP_ID),
|
||||
CATEGORY_MODULE = (CATEGORY_FLAG_SYSTEM |
|
||||
CATEGORY_FLAG_REQUIRE_BATCH_UPDATE |
|
||||
CATEGORY_FLAG_CAN_SKIP_CONVERT_JUMP_ID),
|
||||
CATEGORY_APPLET = (CATEGORY_FLAG_SYSTEM |
|
||||
CATEGORY_FLAG_REQUIRE_BATCH_UPDATE),
|
||||
CATEGORY_SYSTEM_APPLICATION = (CATEGORY_FLAG_SYSTEM),
|
||||
CATEGORY_SYSTEM_CONTENT = (CATEGORY_FLAG_SYSTEM |
|
||||
CATEGORY_FLAG_CONTENTS |
|
||||
CATEGORY_FLAG_NOT_EXECUTABLE),
|
||||
CATEGORY_SHARED_CONTENT = (CATEGORY_FLAG_SYSTEM |
|
||||
CATEGORY_FLAG_CONTENTS |
|
||||
CATEGORY_FLAG_NOT_EXECUTABLE |
|
||||
CATEGORY_FLAG_NOT_REQUIRE_RIGHT_FOR_MOUNT),
|
||||
CATEGORY_AUTO_UPDATE_CONTENT = (CATEGORY_FLAG_SYSTEM |
|
||||
CATEGORY_FLAG_CONTENTS |
|
||||
CATEGORY_FLAG_NOT_EXECUTABLE |
|
||||
CATEGORY_FLAG_NOT_REQUIRE_RIGHT_FOR_MOUNT |
|
||||
CATEGORY_FLAG_NOT_REQUIRE_USER_APPROVAL),
|
||||
};
|
||||
|
||||
enum DeviceMask
|
||||
{
|
||||
ID_MASK = _BIT(28) - 1,
|
||||
ID_MASK_CTR = 0, // 3DS
|
||||
ID_MASK_CAFE = _BIT(28), // WiiU
|
||||
ID_MASK_SNAKE = _BIT(29) // n3DS
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
150
lib/libctr/libctr.vcxproj
Normal file
150
lib/libctr/libctr.vcxproj
Normal file
|
@ -0,0 +1,150 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{96900163-D5A3-42AA-A387-D7D5DAD0A11E}</ProjectGuid>
|
||||
<RootNamespace>libctr</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\libfnd\include;..\libctr\include;..\libes\include;..\libpki\include;</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\libfnd\include;..\libctr\include;..\libes\include;..\libpki\include;</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\libfnd\include;..\libctr\include;..\libes\include;..\libpki\include;</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\libfnd\include;..\libctr\include;..\libes\include;..\libpki\include;</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\CodeBinaryHeader.cpp" />
|
||||
<ClCompile Include="source\CodeSegment.cpp" />
|
||||
<ClCompile Include="source\NcchHeader.cpp" />
|
||||
<ClCompile Include="source\ProgramId.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="makefile" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="notes.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\nn\ctr\code.h" />
|
||||
<ClInclude Include="include\nn\ctr\CodeBinaryHeader.h" />
|
||||
<ClInclude Include="include\nn\ctr\CodeSegment.h" />
|
||||
<ClInclude Include="include\nn\ctr\macro.h" />
|
||||
<ClInclude Include="include\nn\ctr\ncch.h" />
|
||||
<ClInclude Include="include\nn\ctr\NcchHeader.h" />
|
||||
<ClInclude Include="include\nn\ctr\ProgramId.h" />
|
||||
<ClInclude Include="include\nn\ctr\prog_id.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
63
lib/libctr/libctr.vcxproj.filters
Normal file
63
lib/libctr/libctr.vcxproj.filters
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\CodeBinaryHeader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\CodeSegment.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\NcchHeader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\ProgramId.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="makefile" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="notes.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\nn\ctr\CodeBinaryHeader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\nn\ctr\CodeSegment.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\nn\ctr\NcchHeader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\nn\ctr\ProgramId.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\nn\ctr\code.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\nn\ctr\macro.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\nn\ctr\prog_id.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\nn\ctr\ncch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
4
lib/libctr/libctr.vcxproj.user
Normal file
4
lib/libctr/libctr.vcxproj.user
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
47
lib/libctr/makefile
Normal file
47
lib/libctr/makefile
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Sources
|
||||
SRC_DIR = source
|
||||
OBJS = $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c)))
|
||||
|
||||
# External dependencies
|
||||
DEPENDS = fnd crypto
|
||||
LIB_DIR = ..
|
||||
INCS = -I"include" $(foreach dep,$(DEPENDS), -I"$(LIB_DIR)/lib$(dep)/include")
|
||||
|
||||
|
||||
# Compiler Settings
|
||||
CXXFLAGS = -std=c++11 $(INCS) -D__STDC_FORMAT_MACROS -Wall -Wno-unused-but-set-variable -Wno-unused-value
|
||||
CFLAGS = -std=c11 $(INCS) -Wall -Wno-unused-but-set-variable -Wno-unused-value
|
||||
ARFLAGS = cr -o
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows Only Flags/Libs
|
||||
CC = x86_64-w64-mingw32-gcc
|
||||
CXX = x86_64-w64-mingw32-g++
|
||||
CFLAGS +=
|
||||
CXXFLAGS +=
|
||||
else
|
||||
UNAME = $(shell uname -s)
|
||||
ifeq ($(UNAME), Darwin)
|
||||
# MacOS Only Flags/Libs
|
||||
CFLAGS +=
|
||||
CXXFLAGS +=
|
||||
ARFLAGS = rc
|
||||
else
|
||||
# *nix Only Flags/Libs
|
||||
CFLAGS +=
|
||||
CXXFLAGS +=
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
# Output
|
||||
OUTPUT = $(shell basename $(CURDIR)).a
|
||||
|
||||
main: build
|
||||
|
||||
rebuild: clean build
|
||||
|
||||
build: $(OBJS)
|
||||
ar $(ARFLAGS) $(OUTPUT) $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -rf $(OUTPUT) $(OBJS)
|
28
lib/libctr/notes.txt
Normal file
28
lib/libctr/notes.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
Proposed classes
|
||||
NcchHeader
|
||||
NcsdHeader
|
||||
CiaHeader
|
||||
CiaFooter
|
||||
ExtendedHeader
|
||||
|
||||
ncch:
|
||||
NcchHeader
|
||||
ExtendedHeader
|
||||
SystemControlInfo
|
||||
Arm11SystemCaps
|
||||
Arm11KernelCaps
|
||||
Arm9Caps
|
||||
ExefsHeader
|
||||
IvfcHeader
|
||||
RomfsHeader
|
||||
RomfsNodes**
|
||||
|
||||
ncsd:
|
||||
NcsdHeader
|
||||
CardInfoHeader
|
||||
|
||||
cia:
|
||||
CiaHeader
|
||||
CiaFooter
|
||||
es::Ticket?
|
||||
es::Tmd?
|
201
lib/libctr/source/CodeBinaryHeader.cpp
Normal file
201
lib/libctr/source/CodeBinaryHeader.cpp
Normal file
|
@ -0,0 +1,201 @@
|
|||
#include <nn/ctr/CodeBinaryHeader.h>
|
||||
#include <cstring>
|
||||
|
||||
nn::ctr::CodeBinaryHeader::CodeBinaryHeader() :
|
||||
mRawBinary(),
|
||||
mCodeBinSize(0),
|
||||
mStackSize(0),
|
||||
mBssSize(0),
|
||||
mSegmentList()
|
||||
{
|
||||
}
|
||||
|
||||
nn::ctr::CodeBinaryHeader::CodeBinaryHeader(const CodeBinaryHeader& other) :
|
||||
CodeBinaryHeader()
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::operator=(const CodeBinaryHeader& other)
|
||||
{
|
||||
clear();
|
||||
mCodeBinOffset = other.mCodeBinOffset;
|
||||
mCodeBinSize = other.mCodeBinSize;
|
||||
mStackSize = other.mStackSize;
|
||||
mBssSize = other.mBssSize;
|
||||
mSegmentList[code::TEXT_SEGMENT] = other.mSegmentList[code::TEXT_SEGMENT];
|
||||
mSegmentList[code::RODATA_SEGMENT] = other.mSegmentList[code::RODATA_SEGMENT];
|
||||
mSegmentList[code::DATA_SEGMENT] = other.mSegmentList[code::DATA_SEGMENT];
|
||||
}
|
||||
|
||||
bool nn::ctr::CodeBinaryHeader::operator==(const CodeBinaryHeader& other) const
|
||||
{
|
||||
return (mCodeBinOffset == other.mCodeBinOffset) \
|
||||
&& (mCodeBinSize == other.mCodeBinSize) \
|
||||
&& (mStackSize == other.mStackSize) \
|
||||
&& (mBssSize == other.mBssSize) \
|
||||
&& (mSegmentList[code::TEXT_SEGMENT] == other.mSegmentList[code::TEXT_SEGMENT]) \
|
||||
&& (mSegmentList[code::RODATA_SEGMENT] == other.mSegmentList[code::RODATA_SEGMENT]) \
|
||||
&& (mSegmentList[code::DATA_SEGMENT] == other.mSegmentList[code::DATA_SEGMENT]);
|
||||
}
|
||||
|
||||
bool nn::ctr::CodeBinaryHeader::operator!=(const CodeBinaryHeader& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::toBytes()
|
||||
{
|
||||
// allocate memory for header
|
||||
mRawBinary.clear();
|
||||
mRawBinary.alloc(sizeof(sCodeBinaryHeader));
|
||||
|
||||
// get ptr to header struct
|
||||
sCodeBinaryHeader* hdr = (sCodeBinaryHeader*)mRawBinary.data();
|
||||
|
||||
// write variables
|
||||
hdr->st_magic = code::kStructMagic;
|
||||
hdr->code_bin_size = le_word(mCodeBinSize);
|
||||
hdr->stack_size = le_word(mStackSize);
|
||||
hdr->bss_size = le_word(mBssSize);
|
||||
for (size_t i = 0; i < code::kCodeSegmentNum; i++)
|
||||
{
|
||||
hdr->segments[i].v_addr = le_word(mSegmentList[i].getAddress());
|
||||
hdr->segments[i].size = le_word(mSegmentList[i].getSize());
|
||||
hdr->segments[i].page_num = le_word(mSegmentList[i].getPageNum());
|
||||
}
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::fromBytes(const byte_t* data, size_t len)
|
||||
{
|
||||
// check size
|
||||
if (len < sizeof(sCodeBinaryHeader))
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "CODE header corrupt (binary is too small)");
|
||||
}
|
||||
|
||||
// clear variables
|
||||
clear();
|
||||
|
||||
// save a copy of the header
|
||||
sCodeBinaryHeader hdr;
|
||||
memcpy((void*)&hdr, data, sizeof(sCodeBinaryHeader));
|
||||
|
||||
// check magic
|
||||
if (hdr.st_magic.get() != code::kStructMagic)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "CODE header corrupt (unrecognised header signature)");
|
||||
}
|
||||
|
||||
if (hdr.format_ident.get() != code::kCtrFormatIdent)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "CODE header corrupt (unsupported format version)");
|
||||
}
|
||||
|
||||
// allocate memory for header
|
||||
mRawBinary.alloc(sizeof(sCodeBinaryHeader));
|
||||
memcpy(mRawBinary.data(), data, mRawBinary.size());
|
||||
|
||||
// save variables
|
||||
mCodeBinOffset = hdr.code_bin_offset.get();
|
||||
mCodeBinSize = hdr.code_bin_size.get();
|
||||
mStackSize = hdr.stack_size.get();
|
||||
mBssSize = hdr.bss_size.get();
|
||||
for (size_t i = 0; i < code::kCodeSegmentNum; i++)
|
||||
{
|
||||
mSegmentList[i].setAddress(hdr.segments[i].v_addr.get());
|
||||
mSegmentList[i].setSize(hdr.segments[i].size.get());
|
||||
mSegmentList[i].setPageNum(hdr.segments[i].page_num.get());
|
||||
}
|
||||
}
|
||||
|
||||
const fnd::Vec<byte_t>& nn::ctr::CodeBinaryHeader::getBytes() const
|
||||
{
|
||||
return mRawBinary;
|
||||
}
|
||||
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::clear()
|
||||
{
|
||||
mRawBinary.clear();
|
||||
mCodeBinOffset = 0;
|
||||
mCodeBinSize = 0;
|
||||
mStackSize = 0;
|
||||
mBssSize = 0;
|
||||
for (size_t i = 0; i < code::kCodeSegmentNum; i++)
|
||||
{
|
||||
mSegmentList[i].setAddress(0);
|
||||
mSegmentList[i].setSize(0);
|
||||
mSegmentList[i].setPageNum(0);
|
||||
}
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::setCodeBinOffset(uint32_t offset)
|
||||
{
|
||||
mCodeBinOffset = offset;
|
||||
}
|
||||
|
||||
uint32_t nn::ctr::CodeBinaryHeader::getCodeBinOffset() const
|
||||
{
|
||||
return mCodeBinOffset;
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::setCodeBinSize(uint32_t size)
|
||||
{
|
||||
mCodeBinSize = size;
|
||||
}
|
||||
|
||||
uint32_t nn::ctr::CodeBinaryHeader::getCodeBinSize() const
|
||||
{
|
||||
return mCodeBinSize;
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::setStackSize(uint32_t size)
|
||||
{
|
||||
mStackSize = size;
|
||||
}
|
||||
|
||||
uint32_t nn::ctr::CodeBinaryHeader::getStackSize() const
|
||||
{
|
||||
return mStackSize;
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::setBssSize(uint32_t size)
|
||||
{
|
||||
mBssSize = size;
|
||||
}
|
||||
|
||||
uint32_t nn::ctr::CodeBinaryHeader::getBssSize() const
|
||||
{
|
||||
return mBssSize;
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::setTextSegment(const nn::ctr::CodeSegment & segment)
|
||||
{
|
||||
mSegmentList[code::TEXT_SEGMENT] = segment;
|
||||
}
|
||||
|
||||
const nn::ctr::CodeSegment & nn::ctr::CodeBinaryHeader::getTextSegment() const
|
||||
{
|
||||
return mSegmentList[code::TEXT_SEGMENT];
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::setRODataSegment(const nn::ctr::CodeSegment & segment)
|
||||
{
|
||||
mSegmentList[code::RODATA_SEGMENT] = segment;
|
||||
}
|
||||
|
||||
const nn::ctr::CodeSegment & nn::ctr::CodeBinaryHeader::getRODataSegment() const
|
||||
{
|
||||
return mSegmentList[code::RODATA_SEGMENT];
|
||||
}
|
||||
|
||||
void nn::ctr::CodeBinaryHeader::setDataSegment(const nn::ctr::CodeSegment & segment)
|
||||
{
|
||||
mSegmentList[code::DATA_SEGMENT] = segment;
|
||||
}
|
||||
|
||||
const nn::ctr::CodeSegment & nn::ctr::CodeBinaryHeader::getDataSegment() const
|
||||
{
|
||||
return mSegmentList[code::DATA_SEGMENT];
|
||||
}
|
70
lib/libctr/source/CodeSegment.cpp
Normal file
70
lib/libctr/source/CodeSegment.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include <nn/ctr/CodeSegment.h>
|
||||
|
||||
nn::ctr::CodeSegment::CodeSegment() :
|
||||
mAddress(0),
|
||||
mSize(0),
|
||||
mPageNum(0)
|
||||
{
|
||||
}
|
||||
|
||||
nn::ctr::CodeSegment::CodeSegment(const CodeSegment& other) :
|
||||
mAddress(other.mAddress),
|
||||
mSize(other.mSize),
|
||||
mPageNum(other.mPageNum)
|
||||
{}
|
||||
|
||||
|
||||
nn::ctr::CodeSegment::CodeSegment(uint32_t address, uint32_t size, uint32_t page_num) :
|
||||
mAddress(address),
|
||||
mSize(size),
|
||||
mPageNum(page_num)
|
||||
{}
|
||||
|
||||
void nn::ctr::CodeSegment::operator=(const CodeSegment& other)
|
||||
{
|
||||
mAddress = other.mAddress;
|
||||
mSize = other.mSize;
|
||||
mPageNum = other.mPageNum;
|
||||
}
|
||||
|
||||
bool nn::ctr::CodeSegment::operator==(const CodeSegment& other) const
|
||||
{
|
||||
return (mAddress == other.mAddress) \
|
||||
&& (mSize == other.mSize) \
|
||||
&& (mPageNum == other.mPageNum);
|
||||
}
|
||||
|
||||
bool nn::ctr::CodeSegment::operator!=(const CodeSegment& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void nn::ctr::CodeSegment::setAddress(uint32_t address)
|
||||
{
|
||||
mAddress = address;
|
||||
}
|
||||
|
||||
uint32_t nn::ctr::CodeSegment::getAddress() const
|
||||
{
|
||||
return mAddress;
|
||||
}
|
||||
|
||||
void nn::ctr::CodeSegment::setSize(uint32_t size)
|
||||
{
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
uint32_t nn::ctr::CodeSegment::getSize() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
void nn::ctr::CodeSegment::setPageNum(uint32_t num)
|
||||
{
|
||||
mPageNum = num;
|
||||
}
|
||||
|
||||
uint32_t nn::ctr::CodeSegment::getPageNum() const
|
||||
{
|
||||
return mPageNum;
|
||||
}
|
473
lib/libctr/source/NcchHeader.cpp
Normal file
473
lib/libctr/source/NcchHeader.cpp
Normal file
|
@ -0,0 +1,473 @@
|
|||
#include <nn/ctr/NcchHeader.h>
|
||||
|
||||
nn::ctr::NcchHeader::NcchHeader() :
|
||||
mRawBinary(),
|
||||
mNcchBinarySize(),
|
||||
mExHeaderLayout(),
|
||||
mPlainRegionLayout(),
|
||||
mLogoLayout(),
|
||||
mExefsLayout(),
|
||||
mRomfsLayout(),
|
||||
mCompanyCode(),
|
||||
mProductCode(),
|
||||
mSeedChecksum(),
|
||||
mNcchType(),
|
||||
mTitleId(),
|
||||
mProgramId(),
|
||||
mNewCryptoFlag(),
|
||||
mPlatform(),
|
||||
mFormType(),
|
||||
mContentType(),
|
||||
mBlockSize(),
|
||||
mOtherFlagList()
|
||||
{
|
||||
}
|
||||
|
||||
nn::ctr::NcchHeader::NcchHeader(const NcchHeader& other) :
|
||||
NcchHeader()
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::operator=(const NcchHeader& other)
|
||||
{
|
||||
clear();
|
||||
mRawBinary = other.mRawBinary;
|
||||
mNcchBinarySize = other.mNcchBinarySize;
|
||||
mExHeaderLayout = other.mExHeaderLayout;
|
||||
mPlainRegionLayout = other.mPlainRegionLayout;
|
||||
mLogoLayout = other.mLogoLayout;
|
||||
mExefsLayout = other.mExefsLayout;
|
||||
mRomfsLayout = other.mRomfsLayout;
|
||||
mCompanyCode = other.mCompanyCode;
|
||||
mProductCode = other.mProductCode;
|
||||
mSeedChecksum = other.mSeedChecksum;
|
||||
mNcchType = other.mNcchType;
|
||||
mTitleId = other.mTitleId;
|
||||
mProgramId = other.mProgramId;
|
||||
mNewCryptoFlag = other.mNewCryptoFlag;
|
||||
mPlatform = other.mPlatform;
|
||||
mFormType = other.mFormType;
|
||||
mContentType = other.mContentType;
|
||||
mBlockSize = other.mBlockSize;
|
||||
mOtherFlagList = other.mOtherFlagList;
|
||||
}
|
||||
|
||||
bool nn::ctr::NcchHeader::operator==(const NcchHeader& other) const
|
||||
{
|
||||
return (mRawBinary == other.mRawBinary) \
|
||||
&& (mNcchBinarySize == other.mNcchBinarySize) \
|
||||
&& (mExHeaderLayout == other.mExHeaderLayout) \
|
||||
&& (mPlainRegionLayout == other.mPlainRegionLayout) \
|
||||
&& (mLogoLayout == other.mLogoLayout) \
|
||||
&& (mExefsLayout == other.mExefsLayout) \
|
||||
&& (mRomfsLayout == other.mRomfsLayout) \
|
||||
&& (mCompanyCode == other.mCompanyCode) \
|
||||
&& (mProductCode == other.mProductCode) \
|
||||
&& (mSeedChecksum == other.mSeedChecksum) \
|
||||
&& (mNcchType == other.mNcchType) \
|
||||
&& (mTitleId == other.mTitleId) \
|
||||
&& (mProgramId == other.mProgramId) \
|
||||
&& (mNewCryptoFlag == other.mNewCryptoFlag) \
|
||||
&& (mPlatform == other.mPlatform) \
|
||||
&& (mFormType == other.mFormType) \
|
||||
&& (mContentType == other.mContentType) \
|
||||
&& (mBlockSize == other.mBlockSize) \
|
||||
&& (mOtherFlagList == other.mOtherFlagList);
|
||||
}
|
||||
|
||||
bool nn::ctr::NcchHeader::operator!=(const NcchHeader& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::toBytes()
|
||||
{
|
||||
mRawBinary.alloc(sizeof(sNcchHeader));
|
||||
nn::ctr::sNcchHeader* hdr = (nn::ctr::sNcchHeader*)mRawBinary.data();
|
||||
|
||||
// set header identifers
|
||||
hdr->st_magic = ncch::kNcchStructMagic;
|
||||
hdr->ncch_type = mNcchType;
|
||||
|
||||
// variable to store flag before commiting to header
|
||||
byte_t otherflag = 0;
|
||||
byte_t contentflag = 0;
|
||||
for (size_t i = 0; i < mOtherFlagList.size(); i++)
|
||||
{
|
||||
_SET_BIT(otherflag, mOtherFlagList[i]);
|
||||
}
|
||||
contentflag |= (mContentType & _BITMASK(ncch::kContentTypeBitWidth)) << ncch::kFormTypeBitWidth;
|
||||
contentflag |= (mFormType & _BITMASK(ncch::kFormTypeBitWidth));
|
||||
|
||||
// set flags
|
||||
hdr->flags[ncch::CRYPTO_FLAG_INDEX] = mNewCryptoFlag;
|
||||
hdr->flags[ncch::PLATFORM_INDEX] = mPlatform;
|
||||
hdr->flags[ncch::CONTENT_TYPE_INDEX] = contentflag;
|
||||
hdr->flags[ncch::BLOCK_SIZE_INDEX] = mBlockSize;
|
||||
hdr->flags[ncch::OTHER_FLAG_INDEX] = otherflag;
|
||||
|
||||
// set strings
|
||||
strncpy(hdr->product_code, mProductCode.c_str(), ncch::kProductCodeLen);
|
||||
strncpy(hdr->company_code, mCompanyCode.c_str(), ncch::kCompanyCodeLen);
|
||||
|
||||
// misc
|
||||
hdr->title_id = mTitleId.getInnerValue();
|
||||
hdr->program_id = mProgramId.getInnerValue();
|
||||
hdr->seed_checksum = mSeedChecksum;
|
||||
|
||||
// exheader
|
||||
hdr->exheader_size = mExHeaderLayout.getSize();
|
||||
hdr->exheader_hash = mExHeaderLayout.getHash();
|
||||
|
||||
// block size
|
||||
size_t block_size = 0;
|
||||
if (mBlockSize == ncch::BLOCK_SIZE_512)
|
||||
block_size = 512;
|
||||
else
|
||||
throw fnd::Exception(kModuleName, "Illegal block size flag");
|
||||
|
||||
// plain region
|
||||
if (mPlainRegionLayout.getOffset() % block_size || mPlainRegionLayout.getSize() % block_size)
|
||||
throw fnd::Exception(kModuleName, "Plain region geometry not aligned to block size");
|
||||
hdr->plain_region.block_offset = mPlainRegionLayout.getOffset() / block_size;
|
||||
hdr->plain_region.block_num = mPlainRegionLayout.getSize() / block_size;
|
||||
|
||||
// logo
|
||||
if (mLogoLayout.getOffset() % block_size || mLogoLayout.getSize() % block_size)
|
||||
throw fnd::Exception(kModuleName, "Logo geometry not aligned to block size");
|
||||
hdr->logo.block_offset = mLogoLayout.getOffset() / block_size;
|
||||
hdr->logo.block_num = mLogoLayout.getSize() / block_size;
|
||||
hdr->logo_hash = mLogoLayout.getHash();
|
||||
|
||||
// exefs
|
||||
if (mExefsLayout.getOffset() % block_size || mExefsLayout.getSize() % block_size || mExefsLayout.getHashedSize() % block_size)
|
||||
throw fnd::Exception(kModuleName, "ExeFs geometry not aligned to block size");
|
||||
hdr->exefs.block_offset = mExefsLayout.getOffset() / block_size;
|
||||
hdr->exefs.block_num = mExefsLayout.getSize() / block_size;
|
||||
hdr->exefs.block_num_hash_protected = mExefsLayout.getHashedSize() / block_size;
|
||||
hdr->exefs_hash = mExefsLayout.getHash();
|
||||
|
||||
// romfs
|
||||
if (mRomfsLayout.getOffset() % block_size || mRomfsLayout.getSize() % block_size || mRomfsLayout.getHashedSize() % block_size)
|
||||
throw fnd::Exception(kModuleName, "RomFs geometry not aligned to block size");
|
||||
hdr->romfs.block_offset = mRomfsLayout.getOffset() / block_size;
|
||||
hdr->romfs.block_num = mRomfsLayout.getSize() / block_size;
|
||||
hdr->romfs.block_num_hash_protected = mRomfsLayout.getHashedSize() / block_size;
|
||||
hdr->romfs_hash = mRomfsLayout.getHash();
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::fromBytes(const byte_t* data, size_t len)
|
||||
{
|
||||
// check input data size
|
||||
if (len < sizeof(sNcchHeader))
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "NCCH header size is too small");
|
||||
}
|
||||
|
||||
// clear internal members
|
||||
clear();
|
||||
|
||||
// allocate internal local binary copy
|
||||
mRawBinary.alloc(sizeof(sNcchHeader));
|
||||
memcpy(mRawBinary.data(), data, mRawBinary.size());
|
||||
|
||||
// get ptr
|
||||
const nn::ctr::sNcchHeader* hdr = (const nn::ctr::sNcchHeader*)mRawBinary.data();
|
||||
|
||||
// check NCCH signature
|
||||
if (hdr->st_magic.get() != ncch::kNcchStructMagic)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "NCCH header corrupt (unrecognised header signature)");
|
||||
}
|
||||
|
||||
// check NCCH type
|
||||
if (hdr->ncch_type.get() != ncch::TYPE_CFA && hdr->ncch_type.get() != ncch::TYPE_CXI)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "NCCH header corrupt (unsupported NCCH type)");
|
||||
}
|
||||
|
||||
// save flags
|
||||
mNewCryptoFlag = (ncch::NewCryptoFlag)hdr->flags[ncch::CRYPTO_FLAG_INDEX];
|
||||
mPlatform = (ncch::Platform)hdr->flags[ncch::PLATFORM_INDEX];
|
||||
mBlockSize = (ncch::BlockSizeFlag)hdr->flags[ncch::BLOCK_SIZE_INDEX];
|
||||
mContentType = (ncch::ContentType)((hdr->flags[ncch::CONTENT_TYPE_INDEX] >> ncch::kFormTypeBitWidth) & (byte_t)_BITMASK(ncch::kContentTypeBitWidth));
|
||||
mFormType = (ncch::FormType)(hdr->flags[ncch::CONTENT_TYPE_INDEX] & (byte_t)_BITMASK(ncch::kFormTypeBitWidth));
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (_HAS_BIT(hdr->flags[ncch::OTHER_FLAG_INDEX], i))
|
||||
mOtherFlagList.addElement((ncch::OtherFlag)i);
|
||||
}
|
||||
|
||||
// save strings
|
||||
if (hdr->company_code[0] != '\0')
|
||||
mCompanyCode = std::string(hdr->company_code, _MIN(strlen(hdr->company_code), ncch::kCompanyCodeLen));
|
||||
if (hdr->product_code[0] != '\0')
|
||||
mCompanyCode = std::string(hdr->product_code, _MIN(strlen(hdr->product_code), ncch::kProductCodeLen));
|
||||
|
||||
// save misc
|
||||
mTitleId = ProgramId(hdr->title_id.get());
|
||||
mProgramId = ProgramId(hdr->program_id.get());
|
||||
mSeedChecksum = hdr->seed_checksum.get();
|
||||
|
||||
|
||||
// block size
|
||||
size_t block_size = 0;
|
||||
if (mBlockSize == ncch::BLOCK_SIZE_512)
|
||||
block_size = 512;
|
||||
else
|
||||
throw fnd::Exception(kModuleName, "NCCH header corrupt (illegal block size flag)");
|
||||
|
||||
// save layouts
|
||||
mNcchBinarySize = (size_t)hdr->size.get() * block_size;
|
||||
|
||||
// exheader
|
||||
if (hdr->exheader_size.get() != 0)
|
||||
{
|
||||
mExHeaderLayout.setSize(hdr->exheader_size.get());
|
||||
mExHeaderLayout.setHash(hdr->exheader_hash);
|
||||
}
|
||||
|
||||
// plain region
|
||||
if (hdr->plain_region.block_num.get() != 0)
|
||||
{
|
||||
mPlainRegionLayout.setOffset((size_t)hdr->plain_region.block_offset.get() * block_size);
|
||||
mPlainRegionLayout.setSize((size_t)hdr->plain_region.block_num.get() * block_size);
|
||||
}
|
||||
|
||||
// logo region
|
||||
if (hdr->logo.block_num.get() != 0)
|
||||
{
|
||||
mLogoLayout.setOffset((size_t)hdr->logo.block_offset.get() * block_size);
|
||||
mLogoLayout.setSize((size_t)hdr->logo.block_num.get() * block_size);
|
||||
mLogoLayout.setHash(hdr->logo_hash);
|
||||
}
|
||||
|
||||
|
||||
// exefs region
|
||||
if (hdr->exefs.block_num.get() != 0)
|
||||
{
|
||||
mExefsLayout.setOffset((size_t)hdr->exefs.block_offset.get() * block_size);
|
||||
mExefsLayout.setSize((size_t)hdr->exefs.block_num.get() * block_size);
|
||||
mExefsLayout.setHashedSize((size_t)hdr->exefs.block_num_hash_protected.get() * block_size);
|
||||
mExefsLayout.setHash(hdr->exefs_hash);
|
||||
}
|
||||
|
||||
// romfs region
|
||||
if (hdr->romfs.block_num.get() != 0)
|
||||
{
|
||||
mRomfsLayout.setOffset((size_t)hdr->romfs.block_offset.get() * block_size);
|
||||
mRomfsLayout.setSize((size_t)hdr->romfs.block_num.get() * block_size);
|
||||
mRomfsLayout.setHashedSize((size_t)hdr->romfs.block_num_hash_protected.get() * block_size);
|
||||
mRomfsLayout.setHash(hdr->romfs_hash);
|
||||
}
|
||||
}
|
||||
|
||||
const fnd::Vec<byte_t>& nn::ctr::NcchHeader::getBytes() const
|
||||
{
|
||||
return mRawBinary;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::clear()
|
||||
{
|
||||
mRawBinary.clear();
|
||||
mNcchBinarySize = 0;
|
||||
mExHeaderLayout = Layout();
|
||||
mPlainRegionLayout = Layout();
|
||||
mLogoLayout = Layout();
|
||||
mExefsLayout = Layout();
|
||||
mRomfsLayout = Layout();
|
||||
mCompanyCode = std::string();
|
||||
mProductCode = std::string();
|
||||
mSeedChecksum = 0;
|
||||
mNcchType = ncch::NcchType::TYPE_CFA;
|
||||
mTitleId = ProgramId();
|
||||
mProgramId = ProgramId();
|
||||
mNewCryptoFlag = ncch::NewCryptoFlag::CRYPTO_DEFAULT;
|
||||
mPlatform = ncch::Platform::PLATFORM_CTR;
|
||||
mFormType = ncch::FormType::UNASSIGNED;
|
||||
mContentType = ncch::ContentType::APPLICATION;
|
||||
mBlockSize = ncch::BlockSizeFlag::BLOCK_SIZE_512;
|
||||
mOtherFlagList.clear();
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setNcchBinarySize(size_t size)
|
||||
{
|
||||
mNcchBinarySize = size;
|
||||
}
|
||||
|
||||
size_t nn::ctr::NcchHeader::getNcchBinarySize() const
|
||||
{
|
||||
return mNcchBinarySize;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setExtendedHeaderLayout(const Layout layout)
|
||||
{
|
||||
mExHeaderLayout = layout;
|
||||
}
|
||||
|
||||
const nn::ctr::NcchHeader::Layout& nn::ctr::NcchHeader::getExtendedHeaderLayout() const
|
||||
{
|
||||
return mExHeaderLayout;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setPlainRegionLayout(const Layout layout)
|
||||
{
|
||||
mPlainRegionLayout = layout;
|
||||
}
|
||||
|
||||
const nn::ctr::NcchHeader::Layout& nn::ctr::NcchHeader::getPlainRegionLayout() const
|
||||
{
|
||||
return mPlainRegionLayout;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setLogoLayout(const Layout layout)
|
||||
{
|
||||
mLogoLayout = layout;
|
||||
}
|
||||
|
||||
const nn::ctr::NcchHeader::Layout& nn::ctr::NcchHeader::getLogoLayout() const
|
||||
{
|
||||
return mLogoLayout;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setExefsLayout(const Layout layout)
|
||||
{
|
||||
mExefsLayout = layout;
|
||||
}
|
||||
|
||||
const nn::ctr::NcchHeader::Layout& nn::ctr::NcchHeader::getExefsLayout() const
|
||||
{
|
||||
return mExefsLayout;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setRomfsLayout(const Layout layout)
|
||||
{
|
||||
mRomfsLayout = layout;
|
||||
}
|
||||
|
||||
const nn::ctr::NcchHeader::Layout& nn::ctr::NcchHeader::getRomfsLayout() const
|
||||
{
|
||||
return mRomfsLayout;
|
||||
}
|
||||
|
||||
// property mutators
|
||||
void nn::ctr::NcchHeader::setNcchType(ncch::NcchType type)
|
||||
{
|
||||
mNcchType = type;
|
||||
}
|
||||
|
||||
nn::ctr::ncch::NcchType nn::ctr::NcchHeader::getNcchType() const
|
||||
{
|
||||
return mNcchType;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setNewCryptoFlag(ncch::NewCryptoFlag flag)
|
||||
{
|
||||
mNewCryptoFlag = flag;
|
||||
}
|
||||
|
||||
nn::ctr::ncch::NewCryptoFlag nn::ctr::NcchHeader::getNewCryptoFlag() const
|
||||
{
|
||||
return mNewCryptoFlag;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setPlatform(ncch::Platform platform)
|
||||
{
|
||||
mPlatform = platform;
|
||||
}
|
||||
|
||||
nn::ctr::ncch::Platform nn::ctr::NcchHeader::getPlatform() const
|
||||
{
|
||||
return mPlatform;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setFormType(ncch::FormType type)
|
||||
{
|
||||
mFormType = type;
|
||||
}
|
||||
|
||||
nn::ctr::ncch::FormType nn::ctr::NcchHeader::getFormType() const
|
||||
{
|
||||
return mFormType;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setContentType(ncch::ContentType type)
|
||||
{
|
||||
mContentType = type;
|
||||
}
|
||||
|
||||
nn::ctr::ncch::ContentType nn::ctr::NcchHeader::getContentType() const
|
||||
{
|
||||
return mContentType;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setBlockSize(ncch::BlockSizeFlag size)
|
||||
{
|
||||
mBlockSize = size;
|
||||
}
|
||||
|
||||
nn::ctr::ncch::BlockSizeFlag nn::ctr::NcchHeader::getBlockSize() const
|
||||
{
|
||||
return mBlockSize;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setOtherFlagList(const fnd::List<ncch::OtherFlag>& list)
|
||||
{
|
||||
mOtherFlagList = list;
|
||||
}
|
||||
|
||||
const fnd::List<nn::ctr::ncch::OtherFlag>& nn::ctr::NcchHeader::getOtherFlagList() const
|
||||
{
|
||||
return mOtherFlagList;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setCompanyCode(const std::string& company_code)
|
||||
{
|
||||
mCompanyCode = company_code;
|
||||
}
|
||||
|
||||
const std::string& nn::ctr::NcchHeader::getCompanyCode() const
|
||||
{
|
||||
return mCompanyCode;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setTitleId(const ctr::ProgramId& id)
|
||||
{
|
||||
mTitleId = id;
|
||||
}
|
||||
|
||||
const nn::ctr::ProgramId& nn::ctr::NcchHeader::getTitleId() const
|
||||
{
|
||||
return mTitleId;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setProgramId(const ctr::ProgramId& id)
|
||||
{
|
||||
mProgramId = id;
|
||||
}
|
||||
|
||||
const nn::ctr::ProgramId& nn::ctr::NcchHeader::getProgramId() const
|
||||
{
|
||||
return mProgramId;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setProductCode(const std::string& product_code)
|
||||
{
|
||||
mProductCode = product_code;
|
||||
}
|
||||
|
||||
const std::string& nn::ctr::NcchHeader::getProductCode() const
|
||||
{
|
||||
return mProductCode;
|
||||
}
|
||||
|
||||
void nn::ctr::NcchHeader::setSeedChecksum(uint32_t checksum)
|
||||
{
|
||||
mSeedChecksum = checksum;
|
||||
}
|
||||
|
||||
uint32_t nn::ctr::NcchHeader::getSeedChecksum() const
|
||||
{
|
||||
return mSeedChecksum;
|
||||
}
|
91
lib/libctr/source/ProgramId.cpp
Normal file
91
lib/libctr/source/ProgramId.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
#include <nn/ctr/ProgramId.h>
|
||||
|
||||
nn::ctr::ProgramId::ProgramId() :
|
||||
mProgramId(0)
|
||||
{}
|
||||
|
||||
nn::ctr::ProgramId::ProgramId(const ProgramId & other) :
|
||||
mProgramId(other.getInnerValue())
|
||||
{}
|
||||
|
||||
nn::ctr::ProgramId::ProgramId(uint64_t prog_id) :
|
||||
mProgramId(prog_id)
|
||||
{}
|
||||
|
||||
nn::ctr::ProgramId::ProgramId(uint16_t device_group, uint16_t category, uint32_t unique_id, uint8_t variation) :
|
||||
mProgramId(0)
|
||||
{
|
||||
setDeviceGroup(device_group);
|
||||
setCategory(category);
|
||||
setUniqueId(unique_id);
|
||||
setVariation(variation);
|
||||
}
|
||||
|
||||
void nn::ctr::ProgramId::operator=(const ProgramId& other)
|
||||
{
|
||||
mProgramId = other.mProgramId;
|
||||
}
|
||||
|
||||
bool nn::ctr::ProgramId::operator==(const ProgramId& other) const
|
||||
{
|
||||
return mProgramId == other.mProgramId;
|
||||
}
|
||||
|
||||
bool nn::ctr::ProgramId::operator!=(const ProgramId& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void nn::ctr::ProgramId::setInnerValue(uint64_t id)
|
||||
{
|
||||
mProgramId = id;
|
||||
}
|
||||
|
||||
uint64_t nn::ctr::ProgramId::getInnerValue() const
|
||||
{
|
||||
return mProgramId;
|
||||
}
|
||||
|
||||
void nn::ctr::ProgramId::setDeviceGroup(uint16_t device_group)
|
||||
{
|
||||
mProgramId &= ~prog_id::kDeviceGroupMask;
|
||||
mProgramId |= ((uint64_t)device_group) << prog_id::kDeviceGroupShift;
|
||||
}
|
||||
|
||||
uint16_t nn::ctr::ProgramId::getDeviceGroup() const
|
||||
{
|
||||
return (mProgramId & prog_id::kDeviceGroupMask) >> prog_id::kDeviceGroupShift;
|
||||
}
|
||||
|
||||
void nn::ctr::ProgramId::setCategory(uint16_t category)
|
||||
{
|
||||
mProgramId &= ~prog_id::kCategoryMask;
|
||||
mProgramId |= ((uint64_t)category) << prog_id::kCategoryShift;
|
||||
}
|
||||
|
||||
uint16_t nn::ctr::ProgramId::getCategory() const
|
||||
{
|
||||
return (mProgramId & prog_id::kCategoryMask) >> prog_id::kCategoryShift;
|
||||
}
|
||||
|
||||
void nn::ctr::ProgramId::setUniqueId(uint32_t uid)
|
||||
{
|
||||
mProgramId &= ~prog_id::kUniqueIdMask;
|
||||
mProgramId |= ((uint64_t)uid) << prog_id::kUniqueIdShift;
|
||||
}
|
||||
|
||||
uint32_t nn::ctr::ProgramId::getUniqueId() const
|
||||
{
|
||||
return (mProgramId & prog_id::kUniqueIdMask) >> prog_id::kUniqueIdShift;
|
||||
}
|
||||
|
||||
void nn::ctr::ProgramId::setVariation(uint8_t variation)
|
||||
{
|
||||
mProgramId &= ~prog_id::kVariationMask;
|
||||
mProgramId |= (uint64_t)variation;
|
||||
}
|
||||
|
||||
uint8_t nn::ctr::ProgramId::getVariation() const
|
||||
{
|
||||
return mProgramId & prog_id::kVariationMask;
|
||||
}
|
4
makefile
4
makefile
|
@ -3,8 +3,8 @@ LIB_DIR = $(PROJECT_DIR)/lib
|
|||
PROGRAM_DIR = $(PROJECT_DIR)/programs
|
||||
BIN_DIR = $(PROJECT_DIR)/bin
|
||||
|
||||
LIBS = libpolarssl liblz4 libfnd libes libpki libhac libhac-hb
|
||||
PROGS = nstool
|
||||
LIBS = libpolarssl liblz4 libfnd libes libpki libctr libhac libhac-hb
|
||||
PROGS = nstool ctr-test
|
||||
|
||||
main: build
|
||||
|
||||
|
|
147
programs/ctr-test/ctr-test.vcxproj
Normal file
147
programs/ctr-test/ctr-test.vcxproj
Normal file
|
@ -0,0 +1,147 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{93C2F450-6682-41F8-9E19-35363BA15EF6}</ProjectGuid>
|
||||
<RootNamespace>ctrtest</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\lib\libpki\include;..\..\lib\libes\include;..\..\lib\libfnd\include;..\..\lib\libctr\include;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\lib\libpki\include;..\..\lib\libes\include;..\..\lib\libfnd\include;..\..\lib\libctr\include;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\lib\libpki\include;..\..\lib\libes\include;..\..\lib\libfnd\include;..\..\lib\libctr\include;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\lib\libpki\include;..\..\lib\libes\include;..\..\lib\libfnd\include;..\..\lib\libctr\include;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\lib\libctr\libctr.vcxproj">
|
||||
<Project>{96900163-d5a3-42aa-a387-d7d5dad0a11e}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\lib\libes\libes.vcxproj">
|
||||
<Project>{7be99936-0d40-410d-944b-4513c2eff8dc}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\lib\libfnd\libfnd.vcxproj">
|
||||
<Project>{4d27edb9-5110-44fe-8ce2-d46c5ad3c55b}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\lib\libpki\libpki.vcxproj">
|
||||
<Project>{b9113734-6e84-44ff-8cf7-58199aa815c5}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\lib\libpolarssl\libpolarssl.vcxproj">
|
||||
<Project>{394efc16-bd3a-4538-b33d-7ba1edb8dac1}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="makefile" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
25
programs/ctr-test/ctr-test.vcxproj.filters
Normal file
25
programs/ctr-test/ctr-test.vcxproj.filters
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="makefile" />
|
||||
</ItemGroup>
|
||||
</Project>
|
4
programs/ctr-test/ctr-test.vcxproj.user
Normal file
4
programs/ctr-test/ctr-test.vcxproj.user
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
39
programs/ctr-test/makefile
Normal file
39
programs/ctr-test/makefile
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Sources
|
||||
SRC_DIR = source
|
||||
OBJS = $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c)))
|
||||
|
||||
# External dependencies
|
||||
DEPENDS = polarssl lz4 fnd ctr
|
||||
LIB_DIR = ../../lib
|
||||
LIBS = $(foreach dep,$(DEPENDS), -L"$(LIB_DIR)/lib$(dep)" -l$(dep))
|
||||
INCS = $(foreach dep,$(DEPENDS), -I"$(LIB_DIR)/lib$(dep)/include")
|
||||
|
||||
BIN_DIR = bin
|
||||
OUTPUT = $(BIN_DIR)/$(shell basename $(CURDIR))
|
||||
|
||||
# Compiler Settings
|
||||
CXXFLAGS = -std=c++11 $(INCS) -D__STDC_FORMAT_MACROS -Wall -Wno-unused-but-set-variable -Wno-unused-value
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows Only Flags/Libs
|
||||
CC = x86_64-w64-mingw32-gcc
|
||||
CXX = x86_64-w64-mingw32-g++
|
||||
CFLAGS +=
|
||||
CXXFLAGS +=
|
||||
LIBS += -static
|
||||
else
|
||||
# *nix Only Flags/Libs
|
||||
CFLAGS +=
|
||||
CXXFLAGS +=
|
||||
LIBS +=
|
||||
endif
|
||||
|
||||
all: build
|
||||
|
||||
rebuild: clean build
|
||||
|
||||
build: $(OBJS)
|
||||
mkdir -p $(BIN_DIR)
|
||||
$(CXX) $(OBJS) $(LIBS) -o $(OUTPUT)
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJS) $(OUTPUT) $(BIN_DIR)
|
307
programs/ctr-test/source/main.cpp
Normal file
307
programs/ctr-test/source/main.cpp
Normal file
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
(c) 2018 Jakcron
|
||||
*/
|
||||
#include <cstdio>
|
||||
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <nn/ctr/CodeBinaryHeader.h>
|
||||
#include <nn/ctr/NcchHeader.h>
|
||||
|
||||
void dump_code_header(const nn::ctr::CodeBinaryHeader& codeHdr)
|
||||
{
|
||||
printf("Code Bin Size: 0x%08x\n", codeHdr.getCodeBinSize());
|
||||
printf("Stack Size: 0x%08x\n", codeHdr.getStackSize());
|
||||
printf("BSS Size: 0x%08x\n", codeHdr.getBssSize());
|
||||
printf("Text Segment:\n");
|
||||
printf(" Addr: 0x%08x\n", codeHdr.getTextSegment().getAddress());
|
||||
printf(" Size: 0x%08x\n", codeHdr.getTextSegment().getSize());
|
||||
printf(" PageNum: 0x%08x\n", codeHdr.getTextSegment().getPageNum());
|
||||
printf("RO Data Segment:\n");
|
||||
printf(" Addr: 0x%08x\n", codeHdr.getRODataSegment().getAddress());
|
||||
printf(" Size: 0x%08x\n", codeHdr.getRODataSegment().getSize());
|
||||
printf(" PageNum: 0x%08x\n", codeHdr.getRODataSegment().getPageNum());
|
||||
printf("RW Data Segment:\n");
|
||||
printf(" Addr: 0x%08x\n", codeHdr.getDataSegment().getAddress());
|
||||
printf(" Size: 0x%08x\n", codeHdr.getDataSegment().getSize());
|
||||
printf(" PageNum: 0x%08x\n", codeHdr.getDataSegment().getPageNum());
|
||||
}
|
||||
|
||||
const char* dump_ncch_header_ncch_type(uint16_t type)
|
||||
{
|
||||
const char* ret_string = nullptr;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case (nn::ctr::ncch::TYPE_CFA):
|
||||
ret_string = "CTR File Archive (CFA)";
|
||||
break;
|
||||
case (nn::ctr::ncch::TYPE_CXI):
|
||||
ret_string = "CTR Excutable Image (CXI)";
|
||||
break;
|
||||
default:
|
||||
ret_string = "Unknown";
|
||||
}
|
||||
|
||||
return ret_string;
|
||||
}
|
||||
|
||||
const char* dump_ncch_header_crypto_flag(uint8_t type)
|
||||
{
|
||||
const char* ret_string = nullptr;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case (nn::ctr::ncch::CRYPTO_DEFAULT):
|
||||
ret_string = "[CTR|SNAKE] 0x2C";
|
||||
break;
|
||||
case (nn::ctr::ncch::CRYPTO_25):
|
||||
ret_string = "[CTR|SNAKE] 0x2C/0x25";
|
||||
break;
|
||||
case (nn::ctr::ncch::CRYPTO_18):
|
||||
ret_string = "[SNAKE] 0x2C/0x18";
|
||||
break;
|
||||
case (nn::ctr::ncch::CRYPTO_1B):
|
||||
ret_string = "[SNAKE] 0x2C/0x1B";
|
||||
break;
|
||||
default:
|
||||
ret_string = "Unknown";
|
||||
}
|
||||
|
||||
return ret_string;
|
||||
}
|
||||
|
||||
const char* dump_ncch_header_platform_type(uint8_t type)
|
||||
{
|
||||
const char* ret_string = nullptr;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case (nn::ctr::ncch::PLATFORM_CTR):
|
||||
ret_string = "CTR";
|
||||
break;
|
||||
case (nn::ctr::ncch::PLATFORM_SNAKE):
|
||||
ret_string = "SNAKE";
|
||||
break;
|
||||
default:
|
||||
ret_string = "Unknown";
|
||||
}
|
||||
|
||||
return ret_string;
|
||||
}
|
||||
|
||||
const char* dump_ncch_header_form_type(uint8_t type)
|
||||
{
|
||||
const char* ret_string = nullptr;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case (nn::ctr::ncch::SIMPLE_CONTENT):
|
||||
ret_string = "Simple Content";
|
||||
break;
|
||||
case (nn::ctr::ncch::EXECUTABLE_WITHOUT_ROMFS):
|
||||
ret_string = "Executable Without RomFS";
|
||||
break;
|
||||
case (nn::ctr::ncch::EXECUTABLE):
|
||||
ret_string = "Executable";
|
||||
break;
|
||||
default:
|
||||
ret_string = "Unknown";
|
||||
}
|
||||
|
||||
return ret_string;
|
||||
}
|
||||
|
||||
const char* dump_ncch_header_content_type(uint8_t type)
|
||||
{
|
||||
const char* ret_string = nullptr;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case (nn::ctr::ncch::APPLICATION):
|
||||
ret_string = "Application";
|
||||
break;
|
||||
case (nn::ctr::ncch::SYSTEM_UPDATE):
|
||||
ret_string = "System Update";
|
||||
break;
|
||||
case (nn::ctr::ncch::MANUAL):
|
||||
ret_string = "Manual";
|
||||
break;
|
||||
case (nn::ctr::ncch::CHILD):
|
||||
ret_string = "Child";
|
||||
break;
|
||||
case (nn::ctr::ncch::TRIAL):
|
||||
ret_string = "Trial";
|
||||
break;
|
||||
case (nn::ctr::ncch::EXTENDED_SYSTEM_UPDATE):
|
||||
ret_string = "Extended System Update";
|
||||
break;
|
||||
default:
|
||||
ret_string = "Unknown";
|
||||
}
|
||||
|
||||
return ret_string;
|
||||
}
|
||||
|
||||
const char* dump_ncch_header_other_flag_bit(uint8_t bit)
|
||||
{
|
||||
const char* ret_string = nullptr;
|
||||
|
||||
switch (_BIT(bit))
|
||||
{
|
||||
case (nn::ctr::ncch::FIXED_AES_KEY):
|
||||
ret_string = "FIXED_AES_KEY";
|
||||
break;
|
||||
case (nn::ctr::ncch::NO_MOUNT_ROMFS):
|
||||
ret_string = "NO_MOUNT_ROMFS";
|
||||
break;
|
||||
case (nn::ctr::ncch::NO_AES):
|
||||
ret_string = "NO_AES";
|
||||
break;
|
||||
case (nn::ctr::ncch::SEED_KEY):
|
||||
ret_string = "SEED_KEY";
|
||||
break;
|
||||
case (nn::ctr::ncch::MANUAL_DISCLOSURE):
|
||||
ret_string = "MANUAL_DISCLOSURE";
|
||||
break;
|
||||
default:
|
||||
ret_string = nullptr;
|
||||
}
|
||||
|
||||
return ret_string;
|
||||
}
|
||||
|
||||
void dump_ncch_header(const nn::ctr::NcchHeader& ncchHdr)
|
||||
{
|
||||
printf("NcchSize: 0x%08x\n", ncchHdr.getNcchBinarySize());
|
||||
printf("TitleID: %04x-%04x-%06x-%02x\n", ncchHdr.getTitleId().getDeviceGroup(), ncchHdr.getTitleId().getCategory(), ncchHdr.getTitleId().getUniqueId(), ncchHdr.getTitleId().getVariation());
|
||||
printf("CompanyCode: %s\n", ncchHdr.getCompanyCode().c_str());
|
||||
printf("NcchType: %04x (%s)\n", ncchHdr.getNcchType(), dump_ncch_header_ncch_type(ncchHdr.getNcchType()));
|
||||
printf("SeedChecksum: %08x\n", ncchHdr.getSeedChecksum());
|
||||
printf("ProgramID: %04x-%04x-%06x-%02x\n", ncchHdr.getProgramId().getDeviceGroup(), ncchHdr.getProgramId().getCategory(), ncchHdr.getProgramId().getUniqueId(), ncchHdr.getProgramId().getVariation());
|
||||
printf("Product Code: %s\n", ncchHdr.getProductCode().c_str());
|
||||
printf("Flags:\n");
|
||||
printf(" NewCryptoFlag: %02x (%s)\n", ncchHdr.getNewCryptoFlag(), dump_ncch_header_crypto_flag(ncchHdr.getNewCryptoFlag()));
|
||||
printf(" Platform: %02x (%s)\n", ncchHdr.getPlatform(), dump_ncch_header_platform_type(ncchHdr.getPlatform()));
|
||||
printf(" FormType: %02x (%s)\n", ncchHdr.getFormType(), dump_ncch_header_form_type(ncchHdr.getFormType()));
|
||||
printf(" ContentType: %02x (%s)\n", ncchHdr.getContentType(), dump_ncch_header_content_type(ncchHdr.getContentType()));
|
||||
printf(" BlockSize: %02x\n", ncchHdr.getBlockSize());
|
||||
|
||||
if (ncchHdr.getOtherFlagList().size() > 0)
|
||||
printf(" OtherFlag:\n");
|
||||
for (size_t i = 0; i < ncchHdr.getOtherFlagList().size(); i++)
|
||||
{
|
||||
nn::ctr::ncch::OtherFlag flag = ncchHdr.getOtherFlagList()[i];
|
||||
if (dump_ncch_header_other_flag_bit(flag) != nullptr)
|
||||
{
|
||||
printf(" %s\n", dump_ncch_header_other_flag_bit(flag));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" [bit%d]", flag);
|
||||
}
|
||||
}
|
||||
printf("Exheader:\n");
|
||||
printf(" Size: 0x%08x\n", ncchHdr.getExtendedHeaderLayout().getSize());
|
||||
printf(" Hash: ");
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
printf("%02x", ncchHdr.getExtendedHeaderLayout().getHash().bytes[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("PlainRegion:\n");
|
||||
printf(" Offset: 0x%08x\n", ncchHdr.getPlainRegionLayout().getOffset());
|
||||
printf(" Size: 0x%08x\n", ncchHdr.getPlainRegionLayout().getSize());
|
||||
printf("Logo:\n");
|
||||
printf(" Offset: 0x%08x\n", ncchHdr.getLogoLayout().getOffset());
|
||||
printf(" Size: 0x%08x\n", ncchHdr.getLogoLayout().getSize());
|
||||
printf(" Hash: ");
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
printf("%02x", ncchHdr.getLogoLayout().getHash().bytes[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("Exefs:\n");
|
||||
printf(" Offset: 0x%08x\n", ncchHdr.getExefsLayout().getOffset());
|
||||
printf(" Size: 0x%08x\n", ncchHdr.getExefsLayout().getSize());
|
||||
printf(" ProtSize: 0x%08x\n", ncchHdr.getExefsLayout().getHashedSize());
|
||||
printf(" Hash: ");
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
printf("%02x", ncchHdr.getExefsLayout().getHash().bytes[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("Romfs:\n");
|
||||
printf(" Offset: 0x%08x\n", ncchHdr.getRomfsLayout().getOffset());
|
||||
printf(" Size: 0x%08x\n", ncchHdr.getRomfsLayout().getSize());
|
||||
printf(" ProtSize: 0x%08x\n", ncchHdr.getRomfsLayout().getHashedSize());
|
||||
printf(" Hash: ");
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
printf("%02x", ncchHdr.getRomfsLayout().getHash().bytes[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
fnd::SimpleFile fileObj;
|
||||
fnd::Vec<byte_t> fileData;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("usage: %s <file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// read file
|
||||
try
|
||||
{
|
||||
fileObj.open(argv[1], fnd::SimpleFile::Read);
|
||||
fileData.alloc(_MAX(fileObj.size(), 0x1000));
|
||||
fileObj.read(fileData.data(), fileData.size());
|
||||
}
|
||||
catch (const fnd::Exception &e)
|
||||
{
|
||||
printf("[ERROR] %s\n", e.error());
|
||||
return 2;
|
||||
}
|
||||
|
||||
// attempt to read file
|
||||
try
|
||||
{
|
||||
nn::ctr::CodeBinaryHeader hdr, test;
|
||||
hdr.fromBytes(fileData.data(), fileData.size());
|
||||
printf("[NOTICE] .code file detected\n");
|
||||
dump_code_header(hdr);
|
||||
|
||||
hdr.toBytes();
|
||||
test.fromBytes(hdr.getBytes().data(), hdr.getBytes().size());
|
||||
printf("Testing re-serialisation\n");
|
||||
dump_code_header(test);
|
||||
}
|
||||
catch (const fnd::Exception &e)
|
||||
{
|
||||
printf("[NOTICE] not a .code file (%s)\n", e.what());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
nn::ctr::NcchHeader hdr, test;
|
||||
hdr.fromBytes(fileData.data() + 0x100, fileData.size() >= 0x200 ? 0x100 : 0);
|
||||
printf("[NOTICE] NCCH file detected\n");
|
||||
dump_ncch_header(hdr);
|
||||
|
||||
hdr.toBytes();
|
||||
test.fromBytes(hdr.getBytes().data(), hdr.getBytes().size());
|
||||
printf("Testing re-serialisation\n");
|
||||
dump_ncch_header(test);
|
||||
}
|
||||
catch (const fnd::Exception &e)
|
||||
{
|
||||
printf("[NOTICE] not a NCCH file (%s)\n", e.what());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue