1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-22 18:26:39 +00:00

Wipe more legacy code that has already been rewritten.

This commit is contained in:
Pablo Curiel 2020-10-12 12:17:29 -04:00
parent 84f651eae8
commit 4ab8f44003
5 changed files with 1 additions and 820 deletions

View file

@ -87,7 +87,7 @@ int main(int argc, char *argv[])
while(true)
{
consoleClear();
printf("select an user application to generate a cnmt xml for.\npress b to exit.\n\n");
printf("select an user application to generate xmls for.\npress b to exit.\n\n");
printf("title: %u / %u\n", selected_idx + 1, app_count);
printf("selected title: %016lX - %s\n\n", app_metadata[selected_idx]->title_id, app_metadata[selected_idx]->lang_entry.name);

View file

@ -931,332 +931,3 @@ bool patchCnmtNca(u8 *ncaBuf, u64 ncaBufSize, cnmt_xml_program_info *xml_program
return true;
}
bool generateProgramInfoXml(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, bool useCustomAcidRsaPubKey, char **outBuf, u64 *outBufSize)
{
if (!ncmStorage || !ncaId || !dec_nca_header || !decrypted_nca_keys || !outBuf || !outBufSize)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to generate \"programinfo.xml\"!", __func__);
return false;
}
if (dec_nca_header->fs_headers[0].partition_type != NCA_FS_HEADER_PARTITION_PFS0 || dec_nca_header->fs_headers[0].fs_type != NCA_FS_HEADER_FSTYPE_PFS0)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: Program NCA section #0 doesn't hold a PFS0 partition!", __func__);
return false;
}
if (!dec_nca_header->fs_headers[0].pfs0_superblock.pfs0_size)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid size for PFS0 partition in Program NCA section #0!", __func__);
return false;
}
if (dec_nca_header->fs_headers[0].crypt_type != NCA_FS_HEADER_CRYPT_CTR)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid AES crypt type for Program NCA section #0! (0x%02X)", __func__, dec_nca_header->fs_headers[0].crypt_type);
return false;
}
u32 i;
bool proceed = true, success = false;
u64 section_offset;
u64 nca_pfs0_offset;
pfs0_header nca_pfs0_header;
pfs0_file_entry *nca_pfs0_entries = NULL;
char *nca_pfs0_str_table = NULL;
u64 nca_pfs0_str_table_offset;
u64 nca_pfs0_data_offset;
Aes128CtrContext aes_ctx;
char *programInfoXml = NULL;
char tmp[NAME_BUF_LEN] = {'\0'};
u32 npdmEntry = 0;
npdm_t npdm_header;
u8 *npdm_acid_section = NULL;
u64 npdm_acid_section_b64_size = 0;
char *npdm_acid_section_b64 = NULL;
u32 acid_flags = 0;
section_offset = ((u64)dec_nca_header->section_entries[0].media_start_offset * (u64)MEDIA_UNIT_SIZE);
nca_pfs0_offset = (section_offset + dec_nca_header->fs_headers[0].pfs0_superblock.pfs0_offset);
if (!section_offset || section_offset < NCA_FULL_HEADER_LENGTH || !nca_pfs0_offset)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid offsets for Program NCA section #0!", __func__);
return false;
}
// Generate initial CTR
unsigned char ctr[0x10];
u64 ofs = (section_offset >> 4);
for(i = 0; i < 0x8; i++)
{
ctr[i] = dec_nca_header->fs_headers[0].section_ctr[0x08 - i - 1];
ctr[0x10 - i - 1] = (unsigned char)(ofs & 0xFF);
ofs >>= 8;
}
u8 ctr_key[NCA_KEY_AREA_KEY_SIZE];
memcpy(ctr_key, decrypted_nca_keys + (NCA_KEY_AREA_KEY_SIZE * 2), NCA_KEY_AREA_KEY_SIZE);
aes128CtrContextCreate(&aes_ctx, ctr_key, ctr);
if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, nca_pfs0_offset, &nca_pfs0_header, sizeof(pfs0_header), false))
{
breaks++;
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read Program NCA section #0 PFS0 partition header!", __func__);
return false;
}
if (__builtin_bswap32(nca_pfs0_header.magic) != PFS0_MAGIC)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid magic word for Program NCA section #0 PFS0 partition! Wrong KAEK? (0x%08X)\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__, __builtin_bswap32(nca_pfs0_header.magic));
return false;
}
if (!nca_pfs0_header.file_cnt || !nca_pfs0_header.str_table_size)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: Program NCA section #0 PFS0 partition is empty! Wrong KAEK?\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__);
return false;
}
nca_pfs0_entries = calloc(nca_pfs0_header.file_cnt, sizeof(pfs0_file_entry));
if (!nca_pfs0_entries)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for Program NCA section #0 PFS0 partition entries!", __func__);
return false;
}
if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, nca_pfs0_offset + sizeof(pfs0_header), nca_pfs0_entries, (u64)nca_pfs0_header.file_cnt * sizeof(pfs0_file_entry), false))
{
breaks++;
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read Program NCA section #0 PFS0 partition entries!", __func__);
goto out;
}
nca_pfs0_str_table_offset = (nca_pfs0_offset + sizeof(pfs0_header) + ((u64)nca_pfs0_header.file_cnt * sizeof(pfs0_file_entry)));
nca_pfs0_str_table = calloc((u64)nca_pfs0_header.str_table_size, sizeof(char));
if (!nca_pfs0_str_table)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for Program NCA section #0 PFS0 string table!", __func__);
goto out;
}
if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, nca_pfs0_str_table_offset, nca_pfs0_str_table, (u64)nca_pfs0_header.str_table_size, false))
{
breaks++;
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read Program NCA section #0 PFS0 string table!", __func__);
goto out;
}
nca_pfs0_data_offset = (nca_pfs0_str_table_offset + (u64)nca_pfs0_header.str_table_size);
// Allocate memory for the programinfo.xml contents, making sure there's enough space
programInfoXml = calloc(NSP_XML_BUFFER_SIZE, sizeof(char));
if (!programInfoXml)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for the \"programinfo.xml\" contents!", __func__);
goto out;
}
sprintf(programInfoXml, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" \
"<ProgramInfo>\n" \
" <SdkVersion>%u_%u_%u</SdkVersion>\n", dec_nca_header->sdk_major, dec_nca_header->sdk_minor, dec_nca_header->sdk_micro);
// Retrieve the main.npdm contents
bool found_npdm = false;
for(i = 0; i < nca_pfs0_header.file_cnt; i++)
{
char *curFilename = (nca_pfs0_str_table + nca_pfs0_entries[i].filename_offset);
if (strlen(curFilename) == 9 && !strncasecmp(curFilename, "main.npdm", 9) && nca_pfs0_entries[i].file_size > 0)
{
found_npdm = true;
npdmEntry = i;
break;
}
}
if (!found_npdm)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for the \"programinfo.xml\" contents!", __func__);
goto out;
}
// Read the META header from the NPDM
if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, nca_pfs0_data_offset + nca_pfs0_entries[npdmEntry].file_offset, &npdm_header, sizeof(npdm_t), false))
{
breaks++;
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read NPDM entry header from Program NCA section #0 PFS0!", __func__);
goto out;
}
if (__builtin_bswap32(npdm_header.magic) != META_MAGIC)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid NPDM META magic word! Wrong KAEK? (0x%08X)\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__, __builtin_bswap32(npdm_header.magic));
goto out;
}
// Allocate memory for the ACID section
npdm_acid_section = malloc(npdm_header.acid_size);
if (!npdm_acid_section)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for the Program NCA NPDM ACID section contents!", __func__);
goto out;
}
if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, nca_pfs0_data_offset + nca_pfs0_entries[npdmEntry].file_offset + (u64)npdm_header.acid_offset, npdm_acid_section, (u64)npdm_header.acid_size, false))
{
breaks++;
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read ACID section from Program NCA NPDM!", __func__);
goto out;
}
// If we're dealing with a gamecard title, replace the ACID public key with the patched one
if (useCustomAcidRsaPubKey) memcpy(npdm_acid_section + (u64)NPDM_SIGNATURE_SIZE, rsa_get_public_key(), (u64)NPDM_SIGNATURE_SIZE);
sprintf(tmp, " <BuildTarget>%u</BuildTarget>\n", ((npdm_header.mmu_flags & 0x01) ? 64 : 32));
strcat(programInfoXml, tmp);
// Default this one to Release
strcat(programInfoXml, " <BuildType>Release</BuildType>\n");
// Retrieve the Base64 conversion length for the whole ACID section
mbedtls_base64_encode(NULL, 0, &npdm_acid_section_b64_size, npdm_acid_section, (u64)npdm_header.acid_size);
if (npdm_acid_section_b64_size <= (u64)npdm_header.acid_size)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid Base64 conversion length for the ACID section from Program NCA NPDM!", __func__);
goto out;
}
npdm_acid_section_b64 = calloc(npdm_acid_section_b64_size + 1, sizeof(char));
if (!npdm_acid_section_b64)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for the Base64 converted ACID section from Program NCA NPDM!", __func__);
goto out;
}
// Perform the Base64 conversion
if (mbedtls_base64_encode((unsigned char*)npdm_acid_section_b64, npdm_acid_section_b64_size + 1, &npdm_acid_section_b64_size, npdm_acid_section, (u64)npdm_header.acid_size) != 0)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: Base64 conversion failed for the ACID section from Program NCA NPDM!", __func__);
goto out;
}
strcat(programInfoXml, " <Desc>");
strcat(programInfoXml, npdm_acid_section_b64);
strcat(programInfoXml, "</Desc>\n");
// TO-DO: Add more ACID flags?
acid_flags = *((u32*)(&(npdm_acid_section[0x20C])));
strcat(programInfoXml, " <DescFlags>\n");
sprintf(tmp, " <Production>%s</Production>\n", ((acid_flags & 0x01) ? "true" : "false"));
strcat(programInfoXml, tmp);
sprintf(tmp, " <UnqualifiedApproval>%s</UnqualifiedApproval>\n", ((acid_flags & 0x02) ? "true" : "false"));
strcat(programInfoXml, tmp);
strcat(programInfoXml, " </DescFlags>\n");
// Middleware list
strcat(programInfoXml, " <MiddlewareList>\n");
for(i = 0; i < nca_pfs0_header.file_cnt; i++)
{
nso_header_t nsoHeader;
char *curFilename = (nca_pfs0_str_table + nca_pfs0_entries[i].filename_offset);
u64 curFileOffset = (nca_pfs0_data_offset + nca_pfs0_entries[i].file_offset);
if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, curFileOffset, &nsoHeader, sizeof(nso_header_t), false))
{
breaks++;
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read 0x%016lX bytes from \"%s\" in Program NCA section #0 PFS0 partition!", __func__, sizeof(nso_header_t), curFilename);
proceed = false;
break;
}
// Check if we're dealing with a NSO
if (__builtin_bswap32(nsoHeader.magic) != NSO_MAGIC) continue;
// Retrieve middleware list from this NSO
if (!retrieveMiddlewareListFromNso(ncmStorage, ncaId, &aes_ctx, curFilename, curFileOffset, &nsoHeader, programInfoXml))
{
proceed = false;
break;
}
}
if (!proceed) goto out;
strcat(programInfoXml, " </MiddlewareList>\n");
// Leave these fields empty (for now)
strcat(programInfoXml, " <DebugApiList />\n");
strcat(programInfoXml, " <PrivateApiList />\n");
// Symbols list from main NSO
strcat(programInfoXml, " <UnresolvedApiList>\n");
for(i = 0; i < nca_pfs0_header.file_cnt; i++)
{
nso_header_t nsoHeader;
char *curFilename = (nca_pfs0_str_table + nca_pfs0_entries[i].filename_offset);
u64 curFileOffset = (nca_pfs0_data_offset + nca_pfs0_entries[i].file_offset);
if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, curFileOffset, &nsoHeader, sizeof(nso_header_t), false))
{
breaks++;
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read 0x%016lX bytes from \"%s\" in Program NCA section #0 PFS0 partition!", __func__, sizeof(nso_header_t), curFilename);
proceed = false;
break;
}
// Check if we're dealing with the main NSO
if (strlen(curFilename) != 4 || strncmp(curFilename, "main", 4) != 0 || __builtin_bswap32(nsoHeader.magic) != NSO_MAGIC) continue;
// Retrieve symbols list from main NSO
if (!retrieveSymbolsListFromNso(ncmStorage, ncaId, &aes_ctx, curFilename, curFileOffset, &nsoHeader, programInfoXml)) proceed = false;
break;
}
if (!proceed) goto out;
strcat(programInfoXml, " </UnresolvedApiList>\n");
// Leave this field empty (for now)
strcat(programInfoXml, " <FsAccessControlData />\n");
strcat(programInfoXml, "</ProgramInfo>");
*outBuf = programInfoXml;
*outBufSize = strlen(programInfoXml);
success = true;
out:
if (npdm_acid_section_b64) free(npdm_acid_section_b64);
if (npdm_acid_section) free(npdm_acid_section);
if (!success && programInfoXml) free(programInfoXml);
if (nca_pfs0_str_table) free(nca_pfs0_str_table);
if (nca_pfs0_entries) free(nca_pfs0_entries);
return success;
}

View file

@ -365,6 +365,4 @@ bool retrieveCnmtNcaData(NcmStorageId curStorageId, u8 *ncaBuf, cnmt_xml_program
bool patchCnmtNca(u8 *ncaBuf, u64 ncaBufSize, cnmt_xml_program_info *xml_program_info, cnmt_xml_content_info *xml_content_info, nca_cnmt_mod_data *cnmt_mod);
bool generateProgramInfoXml(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, bool useCustomAcidRsaPubKey, char **outBuf, u64 *outBufSize);
#endif

View file

@ -1,430 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "nso.h"
#include "lz4.h"
#include "util.h"
#include "ui.h"
/* Extern variables */
extern int breaks;
extern int font_height;
/* Statically allocated variables */
static u8 *nsoBinaryData = NULL;
static u64 nsoBinaryDataSize = 0;
static u64 nsoBinaryTextSectionOffset = 0;
static u64 nsoBinaryTextSectionSize = 0;
static u64 nsoBinaryRodataSectionOffset = 0;
static u64 nsoBinaryRodataSectionSize = 0;
static u64 nsoBinaryDataSectionOffset = 0;
static u64 nsoBinaryDataSectionSize = 0;
void freeNsoBinaryData()
{
if (nsoBinaryData)
{
free(nsoBinaryData);
nsoBinaryData = NULL;
}
nsoBinaryDataSize = 0;
nsoBinaryTextSectionOffset = 0;
nsoBinaryTextSectionSize = 0;
nsoBinaryRodataSectionOffset = 0;
nsoBinaryRodataSectionSize = 0;
nsoBinaryDataSectionOffset = 0;
nsoBinaryDataSectionSize = 0;
}
bool loadNsoBinaryData(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, Aes128CtrContext *aes_ctx, u64 nso_base_offset, nso_header_t *nsoHeader)
{
if (!ncmStorage || !ncaId || !aes_ctx || !nso_base_offset || !nsoHeader)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to load .text, .rodata and .data sections from NSO in Program NCA!", __func__);
return false;
}
u8 i;
u8 *nsoTextSection = NULL;
u64 nsoTextSectionSize = 0;
u8 *nsoRodataSection = NULL;
u64 nsoRodataSectionSize = 0;
u8 *nsoDataSection = NULL;
u64 nsoDataSectionSize = 0;
u8 *curCompressedSection;
u64 curCompressedSectionSize;
u64 curCompressedSectionOffset;
u8 curSectionFlag;
u8 *curDecompressedSection;
u64 curDecompressedSectionSize;
bool success = true;
freeNsoBinaryData();
for(i = 0; i < 3; i++)
{
curCompressedSection = NULL;
curCompressedSectionSize = (i == 0 ? (u64)nsoHeader->text_compressed_size : (i == 1 ? (u64)nsoHeader->rodata_compressed_size : (u64)nsoHeader->data_compressed_size));
curCompressedSectionOffset = (nso_base_offset + (i == 0 ? (u64)nsoHeader->text_segment_header.file_offset : (i == 1 ? (u64)nsoHeader->rodata_segment_header.file_offset : (u64)nsoHeader->data_segment_header.file_offset)));
curSectionFlag = (1 << i);
curDecompressedSection = NULL;
curDecompressedSectionSize = (i == 0 ? (u64)nsoHeader->text_segment_header.decompressed_size : (i == 1 ? (u64)nsoHeader->rodata_segment_header.decompressed_size : (u64)nsoHeader->data_segment_header.decompressed_size));
// Load section
curCompressedSection = malloc(curCompressedSectionSize);
if (!curCompressedSection)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for the compressed %s section from NSO in Program NCA!", __func__, (i == 0 ? ".text" : (i == 1 ? ".rodata" : ".data")));
success = false;
break;
}
if (!processNcaCtrSectionBlock(ncmStorage, ncaId, aes_ctx, curCompressedSectionOffset, curCompressedSection, curCompressedSectionSize, false))
{
breaks++;
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read 0x%016lX bytes %s section from NSO in Program NCA!", __func__, curCompressedSectionSize, (i == 0 ? ".text" : (i == 1 ? ".rodata" : ".data")));
free(curCompressedSection);
success = false;
break;
}
if (nsoHeader->flags & curSectionFlag)
{
if (curDecompressedSectionSize <= curCompressedSectionSize)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid decompressed size for %s section from NSO in Program NCA!", __func__, (i == 0 ? ".text" : (i == 1 ? ".rodata" : ".data")));
free(curCompressedSection);
success = false;
break;
}
// Uncompress section
curDecompressedSection = malloc(curDecompressedSectionSize);
if (!curDecompressedSection)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for the decompressed %s section from NSO in Program NCA!", __func__, (i == 0 ? ".text" : (i == 1 ? ".rodata" : ".data")));
free(curCompressedSection);
success = false;
break;
}
if (LZ4_decompress_safe((const char*)curCompressedSection, (char*)curDecompressedSection, (int)curCompressedSectionSize, (int)curDecompressedSectionSize) != (int)curDecompressedSectionSize)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to decompress %s section from NSO in Program NCA!", __func__, (i == 0 ? ".text" : (i == 1 ? ".rodata" : ".data")));
free(curDecompressedSection);
free(curCompressedSection);
success = false;
break;
}
free(curCompressedSection);
switch(i)
{
case 0:
nsoTextSection = curDecompressedSection;
nsoTextSectionSize = curDecompressedSectionSize;
break;
case 1:
nsoRodataSection = curDecompressedSection;
nsoRodataSectionSize = curDecompressedSectionSize;
break;
case 2:
nsoDataSection = curDecompressedSection;
nsoDataSectionSize = curDecompressedSectionSize;
break;
default:
break;
}
} else {
switch(i)
{
case 0:
nsoTextSection = curCompressedSection;
nsoTextSectionSize = curCompressedSectionSize;
break;
case 1:
nsoRodataSection = curCompressedSection;
nsoRodataSectionSize = curCompressedSectionSize;
break;
case 2:
nsoDataSection = curCompressedSection;
nsoDataSectionSize = curCompressedSectionSize;
break;
default:
break;
}
}
}
curCompressedSection = curDecompressedSection = NULL;
if (success)
{
// Calculate full binary size
u64 finalTextSectionSize = nsoTextSectionSize;
u64 finalRodataSectionSize = nsoRodataSectionSize;
nsoBinaryDataSize = nsoTextSectionSize;
if ((u64)nsoHeader->rodata_segment_header.memory_offset > nsoBinaryDataSize)
{
nsoBinaryDataSize += ((u64)nsoHeader->rodata_segment_header.memory_offset - nsoBinaryDataSize);
} else
if ((u64)nsoHeader->rodata_segment_header.memory_offset < nsoBinaryDataSize)
{
finalTextSectionSize -= (nsoBinaryDataSize - (u64)nsoHeader->rodata_segment_header.memory_offset);
nsoBinaryDataSize -= (nsoBinaryDataSize - (u64)nsoHeader->rodata_segment_header.memory_offset);
}
nsoBinaryDataSize += nsoRodataSectionSize;
if ((u64)nsoHeader->data_segment_header.memory_offset > nsoBinaryDataSize)
{
nsoBinaryDataSize += ((u64)nsoHeader->data_segment_header.memory_offset - nsoBinaryDataSize);
} else
if ((u64)nsoHeader->data_segment_header.memory_offset < nsoBinaryDataSize)
{
finalRodataSectionSize -= (nsoBinaryDataSize - (u64)nsoHeader->data_segment_header.memory_offset);
nsoBinaryDataSize -= (nsoBinaryDataSize - (u64)nsoHeader->data_segment_header.memory_offset);
}
nsoBinaryDataSize += nsoDataSectionSize;
nsoBinaryData = calloc(nsoBinaryDataSize, sizeof(u8));
if (nsoBinaryData)
{
memcpy(nsoBinaryData, nsoTextSection, finalTextSectionSize);
memcpy(nsoBinaryData + (u64)nsoHeader->rodata_segment_header.memory_offset, nsoRodataSection, finalRodataSectionSize);
memcpy(nsoBinaryData + (u64)nsoHeader->data_segment_header.memory_offset, nsoDataSection, nsoDataSectionSize);
nsoBinaryTextSectionOffset = 0;
nsoBinaryTextSectionSize = finalTextSectionSize;
nsoBinaryRodataSectionOffset = (u64)nsoHeader->rodata_segment_header.memory_offset;
nsoBinaryRodataSectionSize = finalRodataSectionSize;
nsoBinaryDataSectionOffset = (u64)nsoHeader->data_segment_header.memory_offset;
nsoBinaryDataSectionSize = nsoDataSectionSize;
} else {
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate %lu bytes for full decompressed NSO in Program NCA!", __func__, nsoBinaryDataSize);
nsoBinaryDataSize = 0;
success = false;
}
}
if (nsoTextSection) free(nsoTextSection);
if (nsoRodataSection) free(nsoRodataSection);
if (nsoDataSection) free(nsoDataSection);
return success;
}
bool retrieveMiddlewareListFromNso(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, Aes128CtrContext *aes_ctx, const char *nso_filename, u64 nso_base_offset, nso_header_t *nsoHeader, char *programInfoXml)
{
if (!ncmStorage || !ncaId || !aes_ctx || !nso_filename || !strlen(nso_filename) || !nso_base_offset || !nsoHeader || !programInfoXml)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to retrieve middleware list from NSO in Program NCA!", __func__);
return false;
}
u64 i;
char tmp[NAME_BUF_LEN] = {'\0'};
if (!loadNsoBinaryData(ncmStorage, ncaId, aes_ctx, nso_base_offset, nsoHeader)) return false;
for(i = 0; i < nsoBinaryRodataSectionSize; i++)
{
char *curStr = ((char*)nsoBinaryData + nsoBinaryRodataSectionOffset + i);
if (strncmp(curStr, "SDK MW+", 7) != 0) continue;
// Found a match
char *mwDev = (curStr + 7);
char *mwName = (strchr(mwDev, '+') + 1);
// Filter nnSdk entries
if (!strncasecmp(mwName, "NintendoSdk_nnSdk", 17))
{
i += strlen(curStr);
continue;
}
sprintf(tmp, " <Middleware>\n" \
" <ModuleName>%s</ModuleName>\n" \
" <VenderName>%.*s</VenderName>\n" \
" <NsoName>%s</NsoName>\n" \
" </Middleware>\n", \
mwName, \
(int)(mwName - mwDev - 1), mwDev, \
nso_filename);
strcat(programInfoXml, tmp);
// Update counter
i += strlen(curStr);
}
freeNsoBinaryData();
return true;
}
bool retrieveSymbolsListFromNso(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, Aes128CtrContext *aes_ctx, const char *nso_filename, u64 nso_base_offset, nso_header_t *nsoHeader, char *programInfoXml)
{
if (!ncmStorage || !ncaId || !aes_ctx || !nso_filename || !strlen(nso_filename) || !nso_base_offset || !nsoHeader || !programInfoXml)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to retrieve symbols list from NSO in Program NCA!", __func__);
return false;
}
u64 i;
bool success = false;
char tmp[NAME_BUF_LEN] = {'\0'};
u32 mod_magic_offset;
u32 mod_magic;
s32 dynamic_section_offset;
bool armv7;
u64 dynamic_block_size;
u64 dynamic_block_cnt;
bool found_strtab = false;
u64 symbol_str_table_offset = 0;
bool found_symtab = false;
u64 symbol_table_offset = 0;
bool found_strsz = false;
u64 symbol_str_table_size = 0;
char *symbol_str_table = NULL;
u64 cur_symbol_table_offset = 0;
if (!loadNsoBinaryData(ncmStorage, ncaId, aes_ctx, nso_base_offset, nsoHeader)) return false;
mod_magic_offset = *((u32*)(&(nsoBinaryData[0x04])));
mod_magic = *((u32*)(&(nsoBinaryData[mod_magic_offset])));
dynamic_section_offset = ((s32)mod_magic_offset + *((s32*)(&(nsoBinaryData[mod_magic_offset + 0x04]))));
if (__builtin_bswap32(mod_magic) != MOD_MAGIC)
{
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid MOD0 magic word in decompressed NSO from Program NCA! (0x%08X)", __func__, __builtin_bswap32(mod_magic));
goto out;
}
armv7 = (*((u64*)(&(nsoBinaryData[dynamic_section_offset]))) > (u64)0xFFFFFFFF || *((u64*)(&(nsoBinaryData[dynamic_section_offset + 0x10]))) > (u64)0xFFFFFFFF);
// Read dynamic section
dynamic_block_size = (armv7 ? 0x08 : 0x10);
dynamic_block_cnt = ((nsoBinaryDataSize - dynamic_section_offset) / dynamic_block_size);
for(i = 0; i < dynamic_block_cnt; i++)
{
if ((nsoBinaryDataSize - dynamic_section_offset - (i * dynamic_block_size)) < dynamic_block_size) break;
u64 tag = (armv7 ? (u64)(*((u32*)(&(nsoBinaryData[dynamic_section_offset + (i * dynamic_block_size)])))) : *((u64*)(&(nsoBinaryData[dynamic_section_offset + (i * dynamic_block_size)]))));
u64 val = (armv7 ? (u64)(*((u32*)(&(nsoBinaryData[dynamic_section_offset + (i * dynamic_block_size) + 0x04])))) : *((u64*)(&(nsoBinaryData[dynamic_section_offset + (i * dynamic_block_size) + 0x08]))));
if (!tag) break;
if (tag == DT_STRTAB && !found_strtab)
{
// Retrieve symbol string table offset
symbol_str_table_offset = val;
found_strtab = true;
}
if (tag == DT_SYMTAB && !found_symtab)
{
// Retrieve symbol table offset
symbol_table_offset = val;
found_symtab = true;
}
if (tag == DT_STRSZ && !found_strsz)
{
// Retrieve symbol string table size
symbol_str_table_size = val;
found_strsz = true;
}
if (found_strtab && found_symtab && found_strsz) break;
}
if (!found_strtab || !found_symtab || !found_strsz)
{
// Nothing to do here if we can't find what we need
success = true;
goto out;
}
// Point to the symbol string table
symbol_str_table = ((char*)nsoBinaryData + symbol_str_table_offset);
// Retrieve symbol list
cur_symbol_table_offset = symbol_table_offset;
while(true)
{
if (symbol_table_offset < symbol_str_table_offset && cur_symbol_table_offset >= symbol_str_table_offset) break;
u32 st_name = *((u32*)(&(nsoBinaryData[cur_symbol_table_offset])));
u8 st_info = (armv7 ? nsoBinaryData[cur_symbol_table_offset + 0x0C] : nsoBinaryData[cur_symbol_table_offset + 0x04]);
//u8 st_other = (armv7 ? nsoBinaryData[cur_symbol_table_offset + 0x0D] : nsoBinaryData[cur_symbol_table_offset + 0x05]);
u16 st_shndx = (armv7 ? *((u16*)(&(nsoBinaryData[cur_symbol_table_offset + 0x0E]))) : *((u16*)(&(nsoBinaryData[cur_symbol_table_offset + 0x06]))));
u64 st_value = (armv7 ? (u64)(*((u32*)(&(nsoBinaryData[cur_symbol_table_offset + 0x04])))) : *((u64*)(&(nsoBinaryData[cur_symbol_table_offset + 0x08]))));
//u64 st_size = (armv7 ? (u64)(*((u32*)(&(nsoBinaryData[cur_symbol_table_offset + 0x08])))) : *((u64*)(&(nsoBinaryData[cur_symbol_table_offset + 0x10]))));
//u8 st_vis = (st_other & 0x03);
u8 st_type = (st_info & 0x0F);
//u8 st_bind = (st_info >> 0x04);
if (st_name >= symbol_str_table_size) break;
cur_symbol_table_offset += (armv7 ? 0x10 : 0x18);
// TO-DO: Add more filters?
if (!st_shndx && !st_value && st_type != ST_OBJECT)
{
sprintf(tmp, " <UnresolvedApi>\n" \
" <ApiName>%s</ApiName>\n" \
" <NsoName>%s</NsoName>\n" \
" </UnresolvedApi>\n", \
symbol_str_table + st_name, \
nso_filename);
strcat(programInfoXml, tmp);
}
}
success = true;
out:
freeNsoBinaryData();
return success;
}

View file

@ -1,58 +0,0 @@
#pragma once
#ifndef __NSO_H__
#define __NSO_H__
#include <switch.h>
#define NSO_MAGIC (u32)0x4E534F30 // "NSO0"
#define MOD_MAGIC (u32)0x4D4F4430 // "MOD0"
#define DT_STRTAB 0x05
#define DT_SYMTAB 0x06
#define DT_STRSZ 0x0A
#define ST_OBJECT 0x01
typedef struct {
u32 file_offset;
u32 memory_offset;
u32 decompressed_size;
} PACKED segment_header_t;
typedef struct {
u32 region_offset;
u32 region_size;
} PACKED rodata_extent_t;
typedef struct {
u32 magic;
u32 version;
u32 reserved1;
u32 flags;
segment_header_t text_segment_header;
u32 module_offset;
segment_header_t rodata_segment_header;
u32 module_file_size;
segment_header_t data_segment_header;
u32 bss_size;
u8 elf_note_build_id[0x20];
u32 text_compressed_size;
u32 rodata_compressed_size;
u32 data_compressed_size;
u8 reserved2[0x1C];
rodata_extent_t rodata_api_info;
rodata_extent_t rodata_dynstr;
rodata_extent_t rodata_dynsym;
u8 text_decompressed_hash[0x20];
u8 rodata_decompressed_hash[0x20];
u8 data_decompressed_hash[0x20];
} PACKED nso_header_t;
// Retrieves the middleware list from a NSO stored in a partition from a NCA file
bool retrieveMiddlewareListFromNso(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, Aes128CtrContext *aes_ctx, const char *nso_filename, u64 nso_base_offset, nso_header_t *nsoHeader, char *programInfoXml);
// Retrieves the symbols list from a NSO stored in a partition from a NCA file
bool retrieveSymbolsListFromNso(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, Aes128CtrContext *aes_ctx, const char *nso_filename, u64 nso_base_offset, nso_header_t *nsoHeader, char *programInfoXml);
#endif