1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-26 04:02:11 +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:
Pablo Curiel 2024-08-08 12:27:54 +02:00
parent 414780ada8
commit 00497b5181
3 changed files with 90 additions and 68 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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;