mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
nso: update read logic
Changes include: * mem: change all references to `Rodata` to `RoData`. * nso: change all references to `Rodata` to `RoData`. * nso: update `NsoModStart` struct. * nso: rename `NsoModuleInfo` struct to `NsoModulePath`. * nso: add `NsoRoDataStart` struct. * nso: update logic in both nsoIsNnSdkVersionWithinSegment() and nsoGetNnSdkVersion() functions to work entirely with memory-based offsets. * nso: rename nsoGetModuleInfoName() to nsoGetModulePath(). * nso: update logic in nsoInitializeContext() to always validate and use the NsoNnSdkVersion block offset from the NsoModStart block.
This commit is contained in:
parent
414780ada8
commit
00497b5181
3 changed files with 90 additions and 68 deletions
|
@ -32,9 +32,9 @@ extern "C" {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MemoryProgramSegmentType_None = 0,
|
MemoryProgramSegmentType_None = 0,
|
||||||
MemoryProgramSegmentType_Text = BIT(0),
|
MemoryProgramSegmentType_Text = BIT(0),
|
||||||
MemoryProgramSegmentType_Rodata = BIT(1),
|
MemoryProgramSegmentType_RoData = BIT(1),
|
||||||
MemoryProgramSegmentType_Data = BIT(2),
|
MemoryProgramSegmentType_Data = BIT(2),
|
||||||
MemoryProgramSegmentType_All = (MemoryProgramSegmentType_Data | MemoryProgramSegmentType_Rodata | MemoryProgramSegmentType_Text),
|
MemoryProgramSegmentType_All = (MemoryProgramSegmentType_Data | MemoryProgramSegmentType_RoData | MemoryProgramSegmentType_Text),
|
||||||
MemoryProgramSegmentType_Limit = (MemoryProgramSegmentType_All + 1) ///< Placed here for convenience.
|
MemoryProgramSegmentType_Limit = (MemoryProgramSegmentType_All + 1) ///< Placed here for convenience.
|
||||||
} MemoryProgramSegmentType;
|
} MemoryProgramSegmentType;
|
||||||
|
|
||||||
|
|
|
@ -89,17 +89,20 @@ typedef struct {
|
||||||
NXDT_ASSERT(NsoHeader, 0x100);
|
NXDT_ASSERT(NsoHeader, 0x100);
|
||||||
|
|
||||||
/// Placed at the very start of the decompressed .text segment.
|
/// Placed at the very start of the decompressed .text segment.
|
||||||
|
/// All offsets are relative to the start of this header, but they only apply to uncompressed + contiguous NSO segments.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 version; ///< Usually set to 0 or a branch instruction (0x14000002). Set to 1 or 0x14000003 if a NsoNnSdkVersion block is available.
|
u32 version; ///< Usually set to 0 or a branch instruction (0x14000002). Set to 1 or 0x14000003 if a NsoNnSdkVersion block is available.
|
||||||
s32 mod_offset; ///< NsoModHeader block offset (relative to the start of this header). Almost always set to 0x8 (the size of this struct).
|
s32 mod_offset; ///< NsoModHeader block offset. Almost always set to 0x8 (the size of this struct), but it could also reference another segment (e.g. .rodata).
|
||||||
|
s32 nnsdk_version_offset; ///< NsoNnSdkVersion block offset. Only valid if version is set to 1 or 0x14000003.
|
||||||
|
u8 reserved[0x4];
|
||||||
} NsoModStart;
|
} NsoModStart;
|
||||||
|
|
||||||
NXDT_ASSERT(NsoModStart, 0x8);
|
NXDT_ASSERT(NsoModStart, 0x10);
|
||||||
|
|
||||||
/// This is essentially a replacement for the PT_DYNAMIC program header available in ELF binaries.
|
/// This is essentially a replacement for the PT_DYNAMIC program header available in ELF binaries.
|
||||||
/// All offsets are signed 32-bit values relative to the start of this header.
|
/// All offsets are signed 32-bit values relative to the start of this header.
|
||||||
/// This is usually placed at the start of the decompressed .text segment, right after a NsoModStart block.
|
/// This is usually placed at the start of the decompressed .text segment, right after a NsoModStart block.
|
||||||
/// However, in some NSOs, it can instead be placed at the start of the decompressed .rodata segment, right after its NsoModuleInfo block.
|
/// However, in some NSOs, it can instead be placed at the start of the decompressed .rodata segment, right after its NsoRoDataStart block.
|
||||||
/// In these cases, the 'mod_offset' value from the NsoModStart block will point to an offset within the .rodata segment.
|
/// In these cases, the 'mod_offset' value from the NsoModStart block will point to an offset within the .rodata segment.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 magic; ///< "MOD0".
|
u32 magic; ///< "MOD0".
|
||||||
|
@ -123,14 +126,24 @@ typedef struct {
|
||||||
|
|
||||||
NXDT_ASSERT(NsoNnSdkVersion, 0xC);
|
NXDT_ASSERT(NsoNnSdkVersion, 0xC);
|
||||||
|
|
||||||
/// Placed at the start of the decompressed .rodata segment + 0x4.
|
/// If 'zero' is 0 and 'path_length' is greater than 0, 'path' will hold the module path.
|
||||||
/// If the 'name_length' element is greater than 0, 'name' will hold the module name.
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 name_length;
|
u32 zero; ///< Always 0.
|
||||||
char name[];
|
u32 path_length;
|
||||||
} NsoModuleInfo;
|
char path[];
|
||||||
|
} NsoModulePath;
|
||||||
|
|
||||||
NXDT_ASSERT(NsoModuleInfo, 0x4);
|
NXDT_ASSERT(NsoModulePath, 0x8);
|
||||||
|
|
||||||
|
/// Placed at the very start of the decompressed .rodata segment.
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
u64 data_segment_offset; ///< Deprecated.
|
||||||
|
NsoModulePath module_path;
|
||||||
|
};
|
||||||
|
} NsoRoDataStart;
|
||||||
|
|
||||||
|
NXDT_ASSERT(NsoRoDataStart, 0x8);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where this NSO is stored.
|
PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where this NSO is stored.
|
||||||
|
@ -139,7 +152,7 @@ typedef struct {
|
||||||
NsoHeader nso_header; ///< NSO header.
|
NsoHeader nso_header; ///< NSO header.
|
||||||
char *module_name; ///< Pointer to a dynamically allocated buffer that holds the NSO module name, if available. Otherwise, this is set to NULL.
|
char *module_name; ///< Pointer to a dynamically allocated buffer that holds the NSO module name, if available. Otherwise, this is set to NULL.
|
||||||
NsoNnSdkVersion *nnsdk_version; ///< Pointer to a dynamically allocated buffer that holds the nnSdk version info, if available. Otherwise, this is set to NULL.
|
NsoNnSdkVersion *nnsdk_version; ///< Pointer to a dynamically allocated buffer that holds the nnSdk version info, if available. Otherwise, this is set to NULL.
|
||||||
char *module_info_name; ///< Pointer to a dynamically allocated buffer that holds the .rodata module info module name, if available. Otherwise, this is set to NULL.
|
char *module_path; ///< Pointer to a dynamically allocated buffer that holds the .rodata module path, if available. Otherwise, this is set to NULL.
|
||||||
char *rodata_api_info_section; ///< Pointer to a dynamically allocated buffer that holds the .rodata API info section data, if available. Otherwise, this is set to NULL.
|
char *rodata_api_info_section; ///< Pointer to a dynamically allocated buffer that holds the .rodata API info section data, if available. Otherwise, this is set to NULL.
|
||||||
///< Middleware and GuidelineApi entries are retrieved from this section.
|
///< Middleware and GuidelineApi entries are retrieved from this section.
|
||||||
u64 rodata_api_info_section_size; ///< .rodata API info section size, if available. Otherwise, this is set to 0. Kept here for convenience - this is part of 'nso_header'.
|
u64 rodata_api_info_section_size; ///< .rodata API info section size, if available. Otherwise, this is set to 0. Kept here for convenience - this is part of 'nso_header'.
|
||||||
|
@ -159,7 +172,7 @@ NX_INLINE void nsoFreeContext(NsoContext *nso_ctx)
|
||||||
if (!nso_ctx) return;
|
if (!nso_ctx) return;
|
||||||
if (nso_ctx->module_name) free(nso_ctx->module_name);
|
if (nso_ctx->module_name) free(nso_ctx->module_name);
|
||||||
if (nso_ctx->nnsdk_version) free(nso_ctx->nnsdk_version);
|
if (nso_ctx->nnsdk_version) free(nso_ctx->nnsdk_version);
|
||||||
if (nso_ctx->module_info_name) free(nso_ctx->module_info_name);
|
if (nso_ctx->module_path) free(nso_ctx->module_path);
|
||||||
if (nso_ctx->rodata_api_info_section) free(nso_ctx->rodata_api_info_section);
|
if (nso_ctx->rodata_api_info_section) free(nso_ctx->rodata_api_info_section);
|
||||||
if (nso_ctx->rodata_dynstr_section) free(nso_ctx->rodata_dynstr_section);
|
if (nso_ctx->rodata_dynstr_section) free(nso_ctx->rodata_dynstr_section);
|
||||||
if (nso_ctx->rodata_dynsym_section) free(nso_ctx->rodata_dynsym_section);
|
if (nso_ctx->rodata_dynsym_section) free(nso_ctx->rodata_dynsym_section);
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NsoSegmentType_Text = 0,
|
NsoSegmentType_Text = 0,
|
||||||
NsoSegmentType_Rodata = 1,
|
NsoSegmentType_RoData = 1,
|
||||||
NsoSegmentType_Data = 2,
|
NsoSegmentType_Data = 2,
|
||||||
NsoSegmentType_Count = 3 ///< Total values supported by this enum.
|
NsoSegmentType_Count = 3 ///< Total values supported by this enum.
|
||||||
} NsoSegmentType;
|
} NsoSegmentType;
|
||||||
|
@ -43,7 +43,7 @@ typedef struct {
|
||||||
#if LOG_LEVEL < LOG_LEVEL_NONE
|
#if LOG_LEVEL < LOG_LEVEL_NONE
|
||||||
static const char *g_nsoSegmentTypeNames[NsoSegmentType_Count] = {
|
static const char *g_nsoSegmentTypeNames[NsoSegmentType_Count] = {
|
||||||
[NsoSegmentType_Text] = ".text",
|
[NsoSegmentType_Text] = ".text",
|
||||||
[NsoSegmentType_Rodata] = ".rodata",
|
[NsoSegmentType_RoData] = ".rodata",
|
||||||
[NsoSegmentType_Data] = ".data",
|
[NsoSegmentType_Data] = ".data",
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,17 +55,18 @@ static bool nsoGetModuleName(NsoContext *nso_ctx);
|
||||||
static bool nsoGetSegment(NsoContext *nso_ctx, NsoSegment *out, u8 type);
|
static bool nsoGetSegment(NsoContext *nso_ctx, NsoSegment *out, u8 type);
|
||||||
NX_INLINE void nsoFreeSegment(NsoSegment *segment);
|
NX_INLINE void nsoFreeSegment(NsoSegment *segment);
|
||||||
|
|
||||||
NX_INLINE bool nsoIsNnSdkVersionWithinSegment(const NsoModStart *mod_start, const NsoSegment *segment);
|
NX_INLINE bool nsoIsNnSdkVersionWithinSegment(const NsoModStart *mod_start, const NsoSegment *segment, u32 nnsdk_version_memory_offset);
|
||||||
static bool nsoGetNnSdkVersion(NsoContext *nso_ctx, const NsoModStart *mod_start, const NsoSegment *segment);
|
static bool nsoGetNnSdkVersion(NsoContext *nso_ctx, const NsoModStart *mod_start, const NsoSegment *segment, u32 nnsdk_version_memory_offset);
|
||||||
|
|
||||||
static bool nsoGetModuleInfoName(NsoContext *nso_ctx, const NsoSegment *segment);
|
static bool nsoGetModulePath(NsoContext *nso_ctx, const NsoSegment *segment);
|
||||||
|
|
||||||
static bool nsoGetSectionFromRodataSegment(NsoContext *nso_ctx, const NsoSectionInfo *section_info, const NsoSegment *segment, u8 **out_ptr);
|
static bool nsoGetSectionFromRoDataSegment(NsoContext *nso_ctx, const NsoSectionInfo *section_info, const NsoSegment *segment, u8 **out_ptr);
|
||||||
|
|
||||||
bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx, PartitionFileSystemEntry *pfs_entry)
|
bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx, PartitionFileSystemEntry *pfs_entry)
|
||||||
{
|
{
|
||||||
NsoModStart mod_start = {0};
|
NsoModStart mod_start = {0};
|
||||||
NsoSegment segment = {0};
|
NsoSegment segment = {0};
|
||||||
|
u32 nnsdk_version_memory_offset = 0;
|
||||||
bool success = false, dump_nso_header = false, read_nnsdk_version = false;
|
bool success = false, dump_nso_header = false, read_nnsdk_version = false;
|
||||||
|
|
||||||
if (!out || !pfs_ctx || !ncaStorageIsValidContext(&(pfs_ctx->storage_ctx)) || !pfs_ctx->nca_fs_ctx->nca_ctx || \
|
if (!out || !pfs_ctx || !ncaStorageIsValidContext(&(pfs_ctx->storage_ctx)) || !pfs_ctx->nca_fs_ctx->nca_ctx || \
|
||||||
|
@ -124,7 +125,7 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx,
|
||||||
|
|
||||||
#define NSO_GET_RODATA_SECTION(name) \
|
#define NSO_GET_RODATA_SECTION(name) \
|
||||||
do { \
|
do { \
|
||||||
if (!nsoGetSectionFromRodataSegment(out, &(out->nso_header.name##_section_info), &segment, (u8**)&(out->rodata_##name##_section))) goto end; \
|
if (!nsoGetSectionFromRoDataSegment(out, &(out->nso_header.name##_section_info), &segment, (u8**)&(out->rodata_##name##_section))) goto end; \
|
||||||
out->rodata_##name##_section_size = out->nso_header.name##_section_info.size; \
|
out->rodata_##name##_section_size = out->nso_header.name##_section_info.size; \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -154,32 +155,37 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx,
|
||||||
/* Get NsoModStart block. */
|
/* Get NsoModStart block. */
|
||||||
memcpy(&mod_start, segment.data, sizeof(NsoModStart));
|
memcpy(&mod_start, segment.data, sizeof(NsoModStart));
|
||||||
|
|
||||||
/* Check if a nnSdk version struct exists within this NRO. */
|
/* Check if a NsoNnSdkVersion block exists within this NRO. */
|
||||||
read_nnsdk_version = ((mod_start.version & 1) != 0);
|
read_nnsdk_version = ((mod_start.version & 1) != 0 && mod_start.nnsdk_version_offset >= (s32)sizeof(NsoModStart));
|
||||||
|
if (read_nnsdk_version)
|
||||||
|
{
|
||||||
|
/* Calculate memory offset for the NsoNnSdkVersion block. */
|
||||||
|
nnsdk_version_memory_offset = (segment.info.memory_offset + (u32)mod_start.nnsdk_version_offset);
|
||||||
|
|
||||||
/* Check if the nnSdk version struct is located within the .text segment. */
|
/* Check if the NsoNnSdkVersion block is located within the .text segment. */
|
||||||
/* If so, we'll retrieve it immediately. */
|
/* If so, we'll retrieve it immediately. */
|
||||||
if (read_nnsdk_version && nsoIsNnSdkVersionWithinSegment(&mod_start, &segment) && !nsoGetNnSdkVersion(out, &mod_start, &segment)) goto end;
|
if (nsoIsNnSdkVersionWithinSegment(&mod_start, &segment, nnsdk_version_memory_offset) && !nsoGetNnSdkVersion(out, &mod_start, &segment, nnsdk_version_memory_offset)) goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get .rodata segment. */
|
/* Get .rodata segment. */
|
||||||
if (!nsoGetSegment(out, &segment, NsoSegmentType_Rodata)) goto end;
|
if (!nsoGetSegment(out, &segment, NsoSegmentType_RoData)) goto end;
|
||||||
|
|
||||||
/* Check if we didn't read the nnSdk version struct from the .text segment. */
|
/* Check if we didn't read the NsoNnSdkVersion block from the .text segment. */
|
||||||
if (read_nnsdk_version && !out->nnsdk_version)
|
if (read_nnsdk_version && !out->nnsdk_version)
|
||||||
{
|
{
|
||||||
/* Check if the nnSdk version struct is located within the .rodata segment. */
|
/* Check if the NsoNnSdkVersion block is located within the .rodata segment. */
|
||||||
if (!nsoIsNnSdkVersionWithinSegment(&mod_start, &segment))
|
if (!nsoIsNnSdkVersionWithinSegment(&mod_start, &segment, nnsdk_version_memory_offset))
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("nnSdk version struct not located within .text or .rodata segments in NSO \"%s\".", out->nso_filename);
|
LOG_MSG_ERROR("nnSdk version struct not located within .text or .rodata segments in NSO \"%s\".", out->nso_filename);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve nnSdk version struct data from the .rodata segment. */
|
/* Retrieve NsoNnSdkVersion block from the .rodata segment. */
|
||||||
if (!nsoGetNnSdkVersion(out, &mod_start, &segment)) goto end;
|
if (!nsoGetNnSdkVersion(out, &mod_start, &segment, nnsdk_version_memory_offset)) goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get module info name from the .rodata segment. */
|
/* Get module path from the .rodata segment. */
|
||||||
if (!nsoGetModuleInfoName(out, &segment)) goto end;
|
if (!nsoGetModulePath(out, &segment)) goto end;
|
||||||
|
|
||||||
/* Get sections from the .rodata segment. */
|
/* Get sections from the .rodata segment. */
|
||||||
NSO_GET_RODATA_SECTION(api_info);
|
NSO_GET_RODATA_SECTION(api_info);
|
||||||
|
@ -238,22 +244,22 @@ static bool nsoGetSegment(NsoContext *nso_ctx, NsoSegment *out, u8 type)
|
||||||
const char *segment_name = g_nsoSegmentTypeNames[type];
|
const char *segment_name = g_nsoSegmentTypeNames[type];
|
||||||
|
|
||||||
const NsoSegmentInfo *segment_info = (type == NsoSegmentType_Text ? &(nso_ctx->nso_header.text_segment_info) : \
|
const NsoSegmentInfo *segment_info = (type == NsoSegmentType_Text ? &(nso_ctx->nso_header.text_segment_info) : \
|
||||||
(type == NsoSegmentType_Rodata ? &(nso_ctx->nso_header.rodata_segment_info) : &(nso_ctx->nso_header.data_segment_info)));
|
(type == NsoSegmentType_RoData ? &(nso_ctx->nso_header.rodata_segment_info) : &(nso_ctx->nso_header.data_segment_info)));
|
||||||
|
|
||||||
u32 segment_file_size = (type == NsoSegmentType_Text ? nso_ctx->nso_header.text_file_size : \
|
u32 segment_file_size = (type == NsoSegmentType_Text ? nso_ctx->nso_header.text_file_size : \
|
||||||
(type == NsoSegmentType_Rodata ? nso_ctx->nso_header.rodata_file_size : nso_ctx->nso_header.data_file_size));
|
(type == NsoSegmentType_RoData ? nso_ctx->nso_header.rodata_file_size : nso_ctx->nso_header.data_file_size));
|
||||||
|
|
||||||
const u8 *segment_hash = (type == NsoSegmentType_Text ? nso_ctx->nso_header.text_segment_hash : \
|
const u8 *segment_hash = (type == NsoSegmentType_Text ? nso_ctx->nso_header.text_segment_hash : \
|
||||||
(type == NsoSegmentType_Rodata ? nso_ctx->nso_header.rodata_segment_hash : nso_ctx->nso_header.data_segment_hash));
|
(type == NsoSegmentType_RoData ? nso_ctx->nso_header.rodata_segment_hash : nso_ctx->nso_header.data_segment_hash));
|
||||||
|
|
||||||
int lz4_res = 0;
|
int lz4_res = 0;
|
||||||
bool compressed = (nso_ctx->nso_header.flags & BIT(type)), verify = (nso_ctx->nso_header.flags & BIT(type + 3));
|
bool compressed = (nso_ctx->nso_header.flags & BIT(type)), verify = (nso_ctx->nso_header.flags & BIT(type + 3));
|
||||||
|
|
||||||
u8 *buf = NULL;
|
u8 *buf = NULL;
|
||||||
u64 buf_size = (compressed ? LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(segment_info->size) : segment_info->size);
|
u32 buf_size = (compressed ? LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(segment_info->size) : segment_info->size);
|
||||||
|
|
||||||
u8 *read_ptr = NULL;
|
u8 *read_ptr = NULL;
|
||||||
u64 read_size = (compressed ? segment_file_size : segment_info->size);
|
u32 read_size = (compressed ? segment_file_size : segment_info->size);
|
||||||
|
|
||||||
u8 hash[SHA256_HASH_SIZE] = {0};
|
u8 hash[SHA256_HASH_SIZE] = {0};
|
||||||
|
|
||||||
|
@ -265,7 +271,7 @@ static bool nsoGetSegment(NsoContext *nso_ctx, NsoSegment *out, u8 type)
|
||||||
/* Allocate memory for the segment buffer. */
|
/* Allocate memory for the segment buffer. */
|
||||||
if (!(buf = calloc(buf_size, sizeof(u8))))
|
if (!(buf = calloc(buf_size, sizeof(u8))))
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Failed to allocate 0x%lX bytes for the %s segment in NSO \"%s\"!", buf_size, segment_name, nso_ctx->nso_filename);
|
LOG_MSG_ERROR("Failed to allocate 0x%X bytes for the %s segment in NSO \"%s\"!", buf_size, segment_name, nso_ctx->nso_filename);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,13 +323,13 @@ NX_INLINE void nsoFreeSegment(NsoSegment *segment)
|
||||||
memset(segment, 0, sizeof(NsoSegment));
|
memset(segment, 0, sizeof(NsoSegment));
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE bool nsoIsNnSdkVersionWithinSegment(const NsoModStart *mod_start, const NsoSegment *segment)
|
NX_INLINE bool nsoIsNnSdkVersionWithinSegment(const NsoModStart *mod_start, const NsoSegment *segment, u32 nnsdk_version_memory_offset)
|
||||||
{
|
{
|
||||||
return (mod_start && segment && mod_start->mod_offset >= (s32)segment->info.memory_offset && \
|
return (mod_start && segment && nnsdk_version_memory_offset >= segment->info.memory_offset && \
|
||||||
(mod_start->mod_offset + (s32)sizeof(NsoModHeader) + (s32)sizeof(NsoNnSdkVersion)) <= (s32)(segment->info.memory_offset + segment->info.size));
|
(nnsdk_version_memory_offset + sizeof(NsoNnSdkVersion)) <= (segment->info.memory_offset + segment->info.size));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nsoGetNnSdkVersion(NsoContext *nso_ctx, const NsoModStart *mod_start, const NsoSegment *segment)
|
static bool nsoGetNnSdkVersion(NsoContext *nso_ctx, const NsoModStart *mod_start, const NsoSegment *segment, u32 nnsdk_version_memory_offset)
|
||||||
{
|
{
|
||||||
if (!nso_ctx || !mod_start || !segment || !segment->data)
|
if (!nso_ctx || !mod_start || !segment || !segment->data)
|
||||||
{
|
{
|
||||||
|
@ -331,19 +337,18 @@ static bool nsoGetNnSdkVersion(NsoContext *nso_ctx, const NsoModStart *mod_start
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return immediately if the nnSdk struct has already been retrieved. */
|
/* Return immediately if the NsoNnSdkVersion block has already been retrieved. */
|
||||||
if (nso_ctx->nnsdk_version) return 0;
|
if (nso_ctx->nnsdk_version) return true;
|
||||||
|
|
||||||
/* Calculate virtual offset for the nnSdk version struct and check if it is within range. */
|
/* Make sure we're targetting the right NSO segment. */
|
||||||
u32 nnsdk_ver_virt_offset = (u32)(mod_start->mod_offset + (s32)sizeof(NsoModHeader));
|
if (!nsoIsNnSdkVersionWithinSegment(mod_start, segment, nnsdk_version_memory_offset))
|
||||||
if (mod_start->mod_offset < (s32)segment->info.memory_offset || (nnsdk_ver_virt_offset + sizeof(NsoNnSdkVersion)) > (segment->info.memory_offset + segment->info.size))
|
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("nnSdk version struct isn't located within %s segment in NSO \"%s\"! ([0x%X, 0x%X] not within [0x%X, 0x%X]).", segment->name, nso_ctx->nso_filename, \
|
LOG_MSG_ERROR("nnSdk version struct isn't located within %s segment in NSO \"%s\"! ([0x%X, 0x%X] not within [0x%X, 0x%X]).", segment->name, nso_ctx->nso_filename, \
|
||||||
mod_start->mod_offset, nnsdk_ver_virt_offset + (u32)sizeof(NsoNnSdkVersion), segment->info.memory_offset, segment->info.memory_offset + segment->info.size);
|
nnsdk_version_memory_offset, nnsdk_version_memory_offset + (u32)sizeof(NsoNnSdkVersion), segment->info.memory_offset, segment->info.memory_offset + segment->info.size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory for the nnSdk version struct. */
|
/* Allocate memory for the NsoNnSdkVersion block. */
|
||||||
nso_ctx->nnsdk_version = malloc(sizeof(NsoNnSdkVersion));
|
nso_ctx->nnsdk_version = malloc(sizeof(NsoNnSdkVersion));
|
||||||
if (!nso_ctx->nnsdk_version)
|
if (!nso_ctx->nnsdk_version)
|
||||||
{
|
{
|
||||||
|
@ -351,45 +356,49 @@ static bool nsoGetNnSdkVersion(NsoContext *nso_ctx, const NsoModStart *mod_start
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate segment-relative offset for the nnSdk version struct and copy its data. */
|
/* Calculate segment-relative offset for the NsoNnSdkVersion block and copy its data. */
|
||||||
u32 nnsdk_ver_phys_offset = (nnsdk_ver_virt_offset - segment->info.memory_offset);
|
u32 nnsdk_version_segment_offset = (nnsdk_version_memory_offset - segment->info.memory_offset);
|
||||||
memcpy(nso_ctx->nnsdk_version, segment->data + nnsdk_ver_phys_offset, sizeof(NsoNnSdkVersion));
|
memcpy(nso_ctx->nnsdk_version, segment->data + nnsdk_version_segment_offset, sizeof(NsoNnSdkVersion));
|
||||||
|
|
||||||
LOG_MSG_DEBUG("nnSdk version (NSO \"%s\", %s segment, virtual offset 0x%X, physical offset 0x%X): %u.%u.%u.", nso_ctx->nso_filename, segment->name, \
|
LOG_MSG_DEBUG("nnSdk version (NSO \"%s\", %s segment, virtual offset 0x%X, physical offset 0x%X): %u.%u.%u.", nso_ctx->nso_filename, segment->name, \
|
||||||
nnsdk_ver_virt_offset, nnsdk_ver_phys_offset, nso_ctx->nnsdk_version->major, nso_ctx->nnsdk_version->minor, nso_ctx->nnsdk_version->micro);
|
nnsdk_version_memory_offset, nnsdk_version_segment_offset, nso_ctx->nnsdk_version->major, nso_ctx->nnsdk_version->minor, nso_ctx->nnsdk_version->micro);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nsoGetModuleInfoName(NsoContext *nso_ctx, const NsoSegment *segment)
|
static bool nsoGetModulePath(NsoContext *nso_ctx, const NsoSegment *segment)
|
||||||
{
|
{
|
||||||
if (!nso_ctx || !segment || segment->type != NsoSegmentType_Rodata || !segment->data)
|
if (!nso_ctx || !segment || segment->type != NsoSegmentType_RoData || !segment->data)
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Invalid parameters!");
|
LOG_MSG_ERROR("Invalid parameters!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NsoModuleInfo *module_info = (const NsoModuleInfo*)(segment->data + 0x4);
|
/* Get data from the start of the .rodata segment. */
|
||||||
if (!module_info->name_length || !module_info->name[0]) return true;
|
const NsoRoDataStart *rodata_start = (const NsoRoDataStart*)segment->data;
|
||||||
|
|
||||||
/* Allocate memory for the module info name. */
|
/* Perform sanity checks. */
|
||||||
nso_ctx->module_info_name = calloc(module_info->name_length + 1, sizeof(char));
|
if ((nso_ctx->nso_header.text_segment_info.memory_offset + rodata_start->data_segment_offset) == nso_ctx->nso_header.data_segment_info.memory_offset || \
|
||||||
if (!nso_ctx->module_info_name)
|
rodata_start->module_path.zero != 0 || !rodata_start->module_path.path_length || !rodata_start->module_path.path[0]) return true;
|
||||||
|
|
||||||
|
/* Allocate memory for the module path string. */
|
||||||
|
nso_ctx->module_path = calloc(rodata_start->module_path.path_length + 1, sizeof(char));
|
||||||
|
if (!nso_ctx->module_path)
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Failed to allocate memory for NSO \"%s\" module info name!", nso_ctx->nso_filename);
|
LOG_MSG_ERROR("Failed to allocate memory for NSO \"%s\" module path!", nso_ctx->nso_filename);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy module info name. */
|
/* Copy module path string. */
|
||||||
sprintf(nso_ctx->module_info_name, "%.*s", (int)module_info->name_length, module_info->name);
|
sprintf(nso_ctx->module_path, "%.*s", (int)rodata_start->module_path.path_length, rodata_start->module_path.path);
|
||||||
LOG_MSG_DEBUG("Module info name (NSO \"%s\"): \"%s\".", nso_ctx->nso_filename, nso_ctx->module_info_name);
|
LOG_MSG_DEBUG("Module path (NSO \"%s\"): \"%s\".", nso_ctx->nso_filename, nso_ctx->module_path);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nsoGetSectionFromRodataSegment(NsoContext *nso_ctx, const NsoSectionInfo *section_info, const NsoSegment *segment, u8 **out_ptr)
|
static bool nsoGetSectionFromRoDataSegment(NsoContext *nso_ctx, const NsoSectionInfo *section_info, const NsoSegment *segment, u8 **out_ptr)
|
||||||
{
|
{
|
||||||
if (!nso_ctx || !section_info || !segment || segment->type != NsoSegmentType_Rodata || !segment->data || !out_ptr)
|
if (!nso_ctx || !section_info || !segment || segment->type != NsoSegmentType_RoData || !segment->data || !out_ptr)
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Invalid parameters!");
|
LOG_MSG_ERROR("Invalid parameters!");
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue