[libctr] Add initial code for CTR library.

This commit is contained in:
jakcron 2018-09-22 22:41:12 +08:00
parent 44e054fb6a
commit 91eede10d2
24 changed files with 2309 additions and 2 deletions

View file

@ -32,6 +32,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libhac", "lib\libhac\libhac
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libhac-hb", "lib\libhac-hb\libhac-hb.vcxproj", "{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libhac-hb", "lib\libhac-hb\libhac-hb.vcxproj", "{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}"
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 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|x64.Build.0 = Release|x64
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x86.ActiveCfg = Release|Win32 {738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x86.ActiveCfg = Release|Win32
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x86.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -117,6 +137,8 @@ Global
{7BE99936-0D40-410D-944B-4513C2EFF8DC} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C} {7BE99936-0D40-410D-944B-4513C2EFF8DC} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
{91BA9E79-8242-4F7D-B997-0DFEC95EA22B} = {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} {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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {07DCCACC-D10D-47C9-85AE-FB9C54DB7D62} SolutionGuid = {07DCCACC-D10D-47C9-85AE-FB9C54DB7D62}

View 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];
};
}
}

View 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;
};
}
}

View 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;
};
}
}

View 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;
};
}
}

View 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)
}
}

View 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]))

View 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)
}
}

View 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
View 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>

View 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>

View 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
View 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
View 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?

View 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];
}

View 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;
}

View 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;
}

View 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;
}

View file

@ -3,8 +3,8 @@ LIB_DIR = $(PROJECT_DIR)/lib
PROGRAM_DIR = $(PROJECT_DIR)/programs PROGRAM_DIR = $(PROJECT_DIR)/programs
BIN_DIR = $(PROJECT_DIR)/bin BIN_DIR = $(PROJECT_DIR)/bin
LIBS = libpolarssl liblz4 libfnd libes libpki libhac libhac-hb LIBS = libpolarssl liblz4 libfnd libes libpki libctr libhac libhac-hb
PROGS = nstool PROGS = nstool ctr-test
main: build main: build

View 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>

View 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>

View 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>

View 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)

View 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;
}