mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Normalize goto tag names + support for gamecard key area.
Big thanks to SciresM.
This commit is contained in:
parent
8baa5800a1
commit
73861bc52f
17 changed files with 758 additions and 462 deletions
|
@ -66,14 +66,14 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
if (!out->indirect_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the BKTR Indirect Storage Block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read indirect storage block data. */
|
||||
if (!ncaReadFsSection(update_nca_fs_ctx, out->indirect_block, patch_info->indirect_size, patch_info->indirect_offset))
|
||||
{
|
||||
LOGFILE("Failed to read BKTR Indirect Storage Block data!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate space for an extra (fake) AesCtrEx storage entry, to simplify our logic. */
|
||||
|
@ -81,20 +81,20 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
if (!out->aes_ctr_ex_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the BKTR AesCtrEx Storage Block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read AesCtrEx storage block data. */
|
||||
if (!ncaReadFsSection(update_nca_fs_ctx, out->aes_ctr_ex_block, patch_info->aes_ctr_ex_size, patch_info->aes_ctr_ex_offset))
|
||||
{
|
||||
LOGFILE("Failed to read BKTR AesCtrEx Storage Block data!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->aes_ctr_ex_block->physical_size != patch_info->aes_ctr_ex_offset)
|
||||
{
|
||||
LOGFILE("Invalid BKTR AesCtrEx Storage Block size!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* This simplifies logic greatly... */
|
||||
|
@ -144,13 +144,13 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
if (!bktrPhysicalSectionRead(out, &(out->patch_romfs_ctx.header), sizeof(RomFileSystemHeader), out->patch_romfs_ctx.offset))
|
||||
{
|
||||
LOGFILE("Failed to read update NCA RomFS header!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->patch_romfs_ctx.header.cur_format.header_size != ROMFS_HEADER_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid update NCA RomFS header size!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read directory entries table. */
|
||||
|
@ -160,20 +160,20 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
if (!dir_table_offset || !out->patch_romfs_ctx.dir_table_size)
|
||||
{
|
||||
LOGFILE("Invalid update NCA RomFS directory entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
out->patch_romfs_ctx.dir_table = malloc(out->patch_romfs_ctx.dir_table_size);
|
||||
if (!out->patch_romfs_ctx.dir_table)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the update NCA RomFS directory entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!bktrPhysicalSectionRead(out, out->patch_romfs_ctx.dir_table, out->patch_romfs_ctx.dir_table_size, out->patch_romfs_ctx.offset + dir_table_offset))
|
||||
{
|
||||
LOGFILE("Failed to read update NCA RomFS directory entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read file entries table. */
|
||||
|
@ -183,20 +183,20 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
if (!file_table_offset || !out->patch_romfs_ctx.file_table_size)
|
||||
{
|
||||
LOGFILE("Invalid update NCA RomFS file entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
out->patch_romfs_ctx.file_table = malloc(out->patch_romfs_ctx.file_table_size);
|
||||
if (!out->patch_romfs_ctx.file_table)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the update NCA RomFS file entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!bktrPhysicalSectionRead(out, out->patch_romfs_ctx.file_table, out->patch_romfs_ctx.file_table_size, out->patch_romfs_ctx.offset + file_table_offset))
|
||||
{
|
||||
LOGFILE("Failed to read update NCA RomFS file entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get file data body offset. */
|
||||
|
@ -204,7 +204,7 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
|
||||
success = true;
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (!success) bktrFreeContext(out);
|
||||
|
||||
return success;
|
||||
|
|
|
@ -57,16 +57,16 @@ bool certRetrieveCertificateByName(Certificate *dst, const char *name)
|
|||
if (!dst || !name || !strlen(name))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!certOpenEsCertSaveFile()) goto exit;
|
||||
if (!certOpenEsCertSaveFile()) goto end;
|
||||
|
||||
ret = _certRetrieveCertificateByName(dst, name);
|
||||
|
||||
certCloseEsCertSaveFile();
|
||||
|
||||
exit:
|
||||
end:
|
||||
mutexUnlock(&g_esCertSaveMutex);
|
||||
|
||||
return ret;
|
||||
|
@ -82,16 +82,16 @@ bool certRetrieveCertificateChainBySignatureIssuer(CertificateChain *dst, const
|
|||
if (!dst || !issuer || !(issuer_len = strlen(issuer)) || issuer_len <= 5 || strcmp(issuer, "Root-") != 0)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!certOpenEsCertSaveFile()) goto exit;
|
||||
if (!certOpenEsCertSaveFile()) goto end;
|
||||
|
||||
ret = _certRetrieveCertificateChainBySignatureIssuer(dst, issuer);
|
||||
|
||||
certCloseEsCertSaveFile();
|
||||
|
||||
exit:
|
||||
end:
|
||||
mutexUnlock(&g_esCertSaveMutex);
|
||||
|
||||
return ret;
|
||||
|
@ -121,13 +121,13 @@ u8 *certGenerateRawCertificateChainBySignatureIssuer(const char *issuer, u64 *ou
|
|||
if (!raw_chain)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for raw \"%s\" certificate chain! (0x%lX).", issuer, raw_chain_size);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
certCopyCertificateChainDataToMemoryBuffer(raw_chain, &chain);
|
||||
*out_size = raw_chain_size;
|
||||
|
||||
out:
|
||||
end:
|
||||
certFreeCertificateChain(&chain);
|
||||
|
||||
return raw_chain;
|
||||
|
@ -171,13 +171,13 @@ u8 *certRetrieveRawCertificateChainFromGameCardByRightsId(const FsRightsId *id,
|
|||
if (!gamecardReadStorage(raw_chain, raw_chain_size, raw_chain_offset))
|
||||
{
|
||||
LOGFILE("Failed to read \"%s\" data from the inserted gamecard!", raw_chain_filename);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
*out_size = raw_chain_size;
|
||||
success = true;
|
||||
|
||||
out:
|
||||
end:
|
||||
if (!success && raw_chain)
|
||||
{
|
||||
free(raw_chain);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "mem.h"
|
||||
#include "gamecard.h"
|
||||
|
||||
#define GAMECARD_HFS0_MAGIC 0x48465330 /* "HFS0". */
|
||||
|
@ -27,8 +28,6 @@
|
|||
|
||||
#define GAMECARD_ACCESS_WAIT_TIME 3 /* Seconds. */
|
||||
|
||||
#define GAMECARD_UPDATE_TID (u64)0x0100000000000816
|
||||
|
||||
#define GAMECARD_ECC_BLOCK_SIZE 0x200
|
||||
#define GAMECARD_ECC_DATA_SIZE 0x24
|
||||
|
||||
|
@ -43,6 +42,15 @@
|
|||
|
||||
/* Type definitions. */
|
||||
|
||||
typedef struct {
|
||||
u32 memory_interface_mode;
|
||||
u32 asic_status;
|
||||
u8 card_id_area[0x48];
|
||||
u8 reserved[0x1B0];
|
||||
FsGameCardCertificate certificate;
|
||||
GameCardKeyArea key_area;
|
||||
} GameCardSecurityInformation;
|
||||
|
||||
typedef struct {
|
||||
u32 magic; ///< "HFS0".
|
||||
u32 entry_count;
|
||||
|
@ -98,6 +106,15 @@ static u64 g_gameCardCapacity = 0;
|
|||
static u8 *g_gameCardHfsRootHeader = NULL; /// GameCardHashFileSystemHeader + (entry_count * GameCardHashFileSystemEntry) + Name Table.
|
||||
static GameCardHashFileSystemPartitionInfo *g_gameCardHfsPartitions = NULL;
|
||||
|
||||
static MemoryLocation g_fsProgramMemory = {
|
||||
.program_id = FS_SYSMODULE_TID,
|
||||
.mask = 0,
|
||||
.data = NULL,
|
||||
.data_size = 0
|
||||
};
|
||||
|
||||
static GameCardSecurityInformation g_gameCardSecurityInfo = {0};
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
static bool gamecardCreateDetectionThread(void);
|
||||
|
@ -109,6 +126,8 @@ NX_INLINE bool gamecardIsInserted(void);
|
|||
static void gamecardLoadInfo(void);
|
||||
static void gamecardFreeInfo(void);
|
||||
|
||||
static bool gamecardReadSecurityInformation(void);
|
||||
|
||||
static bool gamecardGetHandle(void);
|
||||
NX_INLINE void gamecardCloseHandle(void);
|
||||
|
||||
|
@ -133,14 +152,14 @@ bool gamecardInitialize(void)
|
|||
Result rc = 0;
|
||||
|
||||
bool ret = g_gamecardInterfaceInit;
|
||||
if (ret) goto out;
|
||||
if (ret) goto end;
|
||||
|
||||
/* Allocate memory for the gamecard read buffer. */
|
||||
g_gameCardReadBuf = malloc(GAMECARD_READ_BUFFER_SIZE);
|
||||
if (!g_gameCardReadBuf)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the gamecard read buffer!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Open device operator. */
|
||||
|
@ -148,7 +167,7 @@ bool gamecardInitialize(void)
|
|||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsOpenDeviceOperator failed! (0x%08X).", rc);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
g_openDeviceOperator = true;
|
||||
|
@ -158,7 +177,7 @@ bool gamecardInitialize(void)
|
|||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsOpenGameCardDetectionEventNotifier failed! (0x%08X)", rc);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
g_openEventNotifier = true;
|
||||
|
@ -168,7 +187,7 @@ bool gamecardInitialize(void)
|
|||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsEventNotifierGetEventHandle failed! (0x%08X)", rc);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
g_loadKernelEvent = true;
|
||||
|
@ -180,11 +199,11 @@ bool gamecardInitialize(void)
|
|||
ueventCreate(&g_gameCardStatusChangeEvent, true);
|
||||
|
||||
/* Create gamecard detection thread. */
|
||||
if (!(g_gameCardDetectionThreadCreated = gamecardCreateDetectionThread())) goto out;
|
||||
if (!(g_gameCardDetectionThreadCreated = gamecardCreateDetectionThread())) goto end;
|
||||
|
||||
ret = g_gamecardInterfaceInit = true;
|
||||
|
||||
out:
|
||||
end:
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
|
@ -255,6 +274,15 @@ bool gamecardReadStorage(void *out, u64 read_size, u64 offset)
|
|||
return gamecardReadStorageArea(out, read_size, offset, true);
|
||||
}
|
||||
|
||||
bool gamecardGetKeyArea(GameCardKeyArea *out)
|
||||
{
|
||||
mutexLock(&g_gamecardMutex);
|
||||
bool ret = (g_gameCardInserted && g_gameCardInfoLoaded && out);
|
||||
if (ret) memcpy(out, &(g_gameCardSecurityInfo.key_area), sizeof(GameCardKeyArea));
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool gamecardGetHeader(GameCardHeader *out)
|
||||
{
|
||||
mutexLock(&g_gamecardMutex);
|
||||
|
@ -264,6 +292,23 @@ bool gamecardGetHeader(GameCardHeader *out)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool gamecardGetCertificate(FsGameCardCertificate *out)
|
||||
{
|
||||
Result rc = 0;
|
||||
bool ret = false;
|
||||
|
||||
mutexLock(&g_gamecardMutex);
|
||||
if (g_gameCardInserted && g_gameCardHandle.value && out)
|
||||
{
|
||||
rc = fsDeviceOperatorGetGameCardDeviceCertificate(&g_deviceOperator, &g_gameCardHandle, out);
|
||||
if (R_FAILED(rc)) LOGFILE("fsDeviceOperatorGetGameCardDeviceCertificate failed! (0x%08X)", rc);
|
||||
ret = R_SUCCEEDED(rc);
|
||||
}
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool gamecardGetTotalSize(u64 *out)
|
||||
{
|
||||
mutexLock(&g_gamecardMutex);
|
||||
|
@ -291,23 +336,6 @@ bool gamecardGetRomCapacity(u64 *out)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool gamecardGetCertificate(FsGameCardCertificate *out)
|
||||
{
|
||||
Result rc = 0;
|
||||
bool ret = false;
|
||||
|
||||
mutexLock(&g_gamecardMutex);
|
||||
if (g_gameCardInserted && g_gameCardHandle.value && out)
|
||||
{
|
||||
rc = fsDeviceOperatorGetGameCardDeviceCertificate(&g_deviceOperator, &g_gameCardHandle, out);
|
||||
if (R_FAILED(rc)) LOGFILE("fsDeviceOperatorGetGameCardDeviceCertificate failed! (0x%08X)", rc);
|
||||
ret = R_SUCCEEDED(rc);
|
||||
}
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool gamecardGetBundledFirmwareUpdateVersion(u32 *out)
|
||||
{
|
||||
Result rc = 0;
|
||||
|
@ -367,14 +395,14 @@ bool gamecardGetEntryInfoFromHashFileSystemPartitionByIndex(u8 hfs_partition_typ
|
|||
if (!fs_header)
|
||||
{
|
||||
LOGFILE("Failed to retrieve hash FS partition header!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
fs_entry = gamecardGetHashFileSystemEntryByIndex(fs_header, idx);
|
||||
if (!fs_entry)
|
||||
{
|
||||
LOGFILE("Failed to retrieve hash FS partition entry by index!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out_offset)
|
||||
|
@ -395,21 +423,21 @@ bool gamecardGetEntryInfoFromHashFileSystemPartitionByIndex(u8 hfs_partition_typ
|
|||
if (!entry_name || !strlen(entry_name))
|
||||
{
|
||||
LOGFILE("Invalid hash FS partition entry name!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
*out_name = strdup(entry_name);
|
||||
if (!*out_name)
|
||||
{
|
||||
LOGFILE("Failed to duplicate hash FS partition entry name!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = true;
|
||||
}
|
||||
|
||||
out:
|
||||
end:
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
|
@ -430,20 +458,20 @@ bool gamecardGetEntryInfoFromHashFileSystemPartitionByName(u8 hfs_partition_type
|
|||
if (!fs_header)
|
||||
{
|
||||
LOGFILE("Failed to retrieve hash FS partition header!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!gamecardGetHashFileSystemEntryIndexByName(fs_header, name, &fs_entry_idx))
|
||||
{
|
||||
LOGFILE("Failed to retrieve hash FS partition entry index by name!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
fs_entry = gamecardGetHashFileSystemEntryByIndex(fs_header, fs_entry_idx);
|
||||
if (!fs_entry)
|
||||
{
|
||||
LOGFILE("Failed to retrieve hash FS partition entry by index!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out_offset)
|
||||
|
@ -461,7 +489,7 @@ bool gamecardGetEntryInfoFromHashFileSystemPartitionByName(u8 hfs_partition_type
|
|||
ret = true;
|
||||
}
|
||||
|
||||
out:
|
||||
end:
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
|
@ -560,21 +588,21 @@ static void gamecardLoadInfo(void)
|
|||
if (!gamecardGetStorageAreasSizes())
|
||||
{
|
||||
LOGFILE("Failed to retrieve gamecard storage area sizes!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read gamecard header. */
|
||||
if (!gamecardReadStorageArea(&g_gameCardHeader, sizeof(GameCardHeader), 0, false))
|
||||
{
|
||||
LOGFILE("Failed to read gamecard header!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check magic word from gamecard header. */
|
||||
if (__builtin_bswap32(g_gameCardHeader.magic) != GAMECARD_HEAD_MAGIC)
|
||||
{
|
||||
LOGFILE("Invalid gamecard header magic word! (0x%08X)", __builtin_bswap32(g_gameCardHeader.magic));
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get gamecard capacity. */
|
||||
|
@ -582,7 +610,7 @@ static void gamecardLoadInfo(void)
|
|||
if (!g_gameCardCapacity)
|
||||
{
|
||||
LOGFILE("Invalid gamecard capacity value! (0x%02X).", g_gameCardHeader.rom_size);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (utilsGetCustomFirmwareType() == UtilsCustomFirmwareType_SXOS)
|
||||
|
@ -597,14 +625,14 @@ static void gamecardLoadInfo(void)
|
|||
if (!g_gameCardHfsRootHeader)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the root hash FS header!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read root hash FS header. */
|
||||
if (!gamecardReadStorageArea(g_gameCardHfsRootHeader, g_gameCardHeader.partition_fs_header_size, g_gameCardHeader.partition_fs_header_address, false))
|
||||
{
|
||||
LOGFILE("Failed to read root hash FS header from offset 0x%lX!", g_gameCardHeader.partition_fs_header_address);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
fs_header = (GameCardHashFileSystemHeader*)g_gameCardHfsRootHeader;
|
||||
|
@ -612,14 +640,14 @@ static void gamecardLoadInfo(void)
|
|||
if (__builtin_bswap32(fs_header->magic) != GAMECARD_HFS0_MAGIC)
|
||||
{
|
||||
LOGFILE("Invalid magic word in root hash FS header! (0x%08X).", __builtin_bswap32(fs_header->magic));
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!fs_header->entry_count || !fs_header->name_table_size || \
|
||||
(sizeof(GameCardHashFileSystemHeader) + (fs_header->entry_count * sizeof(GameCardHashFileSystemEntry)) + fs_header->name_table_size) > g_gameCardHeader.partition_fs_header_size)
|
||||
{
|
||||
LOGFILE("Invalid file count and/or name table size in root hash FS header!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate memory for the hash FS partitions info. */
|
||||
|
@ -627,7 +655,7 @@ static void gamecardLoadInfo(void)
|
|||
if (!g_gameCardHfsPartitions)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the hash FS partitions info!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read hash FS partitions. */
|
||||
|
@ -637,7 +665,7 @@ static void gamecardLoadInfo(void)
|
|||
if (!fs_entry || !fs_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid hash FS partition entry!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
g_gameCardHfsPartitions[i].offset = (g_gameCardHeader.partition_fs_header_address + g_gameCardHeader.partition_fs_header_size + fs_entry->offset);
|
||||
|
@ -648,19 +676,19 @@ static void gamecardLoadInfo(void)
|
|||
if (!gamecardReadStorageArea(&partition_header, sizeof(GameCardHashFileSystemHeader), g_gameCardHfsPartitions[i].offset, false))
|
||||
{
|
||||
LOGFILE("Failed to partially read hash FS partition #%u header from offset 0x%lX!", i, g_gameCardHfsPartitions[i].offset);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (__builtin_bswap32(partition_header.magic) != GAMECARD_HFS0_MAGIC)
|
||||
{
|
||||
LOGFILE("Invalid magic word in hash FS partition #%u header! (0x%08X).", i, __builtin_bswap32(partition_header.magic));
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!partition_header.name_table_size)
|
||||
{
|
||||
LOGFILE("Invalid name table size in hash FS partition #%u header!", i);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate the full header size for the current hash FS partition and round it to a GAMECARD_MEDIA_UNIT_SIZE bytes boundary. */
|
||||
|
@ -672,20 +700,30 @@ static void gamecardLoadInfo(void)
|
|||
if (!g_gameCardHfsPartitions[i].header)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the hash FS partition #%u header!", i);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Finally, read the full hash FS partition header. */
|
||||
if (!gamecardReadStorageArea(g_gameCardHfsPartitions[i].header, g_gameCardHfsPartitions[i].header_size, g_gameCardHfsPartitions[i].offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read full hash FS partition #%u header from offset 0x%lX!", i, g_gameCardHfsPartitions[i].offset);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read full FS program memory to retrieve the GameCardSecurityInformation data, which holds the gamecard key area. */
|
||||
/* This must be performed while the gamecard is in secure mode, which is already taken care of in the gamecardReadStorageArea() calls from the last iteration in the previous for() loop. */
|
||||
/* GameCardSecurityInformation data is returned by Lotus command "ChangeToSecureMode" (0xF), and kept in FS program memory only after the gamecard secure area has been both mounted and read from. */
|
||||
/* Under some circumstances, the gamecard key area is located *after* the GameCardSecurityInformation area (offset 0x600), instead of its common location at offset 0x400. */
|
||||
if (!gamecardReadSecurityInformation())
|
||||
{
|
||||
LOGFILE("Failed to read gamecard security information area from FS program memory!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
g_gameCardInfoLoaded = true;
|
||||
|
||||
out:
|
||||
end:
|
||||
if (!g_gameCardInfoLoaded) gamecardFreeInfo();
|
||||
}
|
||||
|
||||
|
@ -693,6 +731,8 @@ static void gamecardFreeInfo(void)
|
|||
{
|
||||
memset(&g_gameCardHeader, 0, sizeof(GameCardHeader));
|
||||
|
||||
memset(&g_gameCardSecurityInfo, 0, sizeof(GameCardSecurityInformation));
|
||||
|
||||
g_gameCardStorageNormalAreaSize = 0;
|
||||
g_gameCardStorageSecureAreaSize = 0;
|
||||
|
||||
|
@ -725,6 +765,49 @@ static void gamecardFreeInfo(void)
|
|||
g_gameCardInfoLoaded = false;
|
||||
}
|
||||
|
||||
static bool gamecardReadSecurityInformation(void)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
/* Retrieve full FS program memory dump. */
|
||||
if (!memRetrieveFullProgramMemory(&g_fsProgramMemory))
|
||||
{
|
||||
LOGFILE("Failed to retrieve full FS program memory dump!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Look for the gamecard header in the FS memory dump. */
|
||||
for(u64 offset = 0; offset < g_fsProgramMemory.data_size; offset++)
|
||||
{
|
||||
if (memcmp(&(g_gameCardHeader.magic), g_fsProgramMemory.data + offset, 0x90) != 0) continue;
|
||||
|
||||
/* Found the gamecard header. Let's read the GameCardSecurityInformation element. */
|
||||
offset += 0x100;
|
||||
memcpy(&g_gameCardSecurityInfo, g_fsProgramMemory.data + offset, sizeof(GameCardSecurityInformation));
|
||||
|
||||
/* Check the key_source / package_id value. */
|
||||
if (g_gameCardSecurityInfo.key_area.package_id == g_gameCardHeader.package_id)
|
||||
{
|
||||
/* Jackpot. */
|
||||
found = true;
|
||||
} else {
|
||||
/* Copy the sector right after the GameCardSecurityInformation element from the memory dump, since it may hold the gamecard key area. */
|
||||
offset += sizeof(GameCardSecurityInformation);
|
||||
memcpy(&(g_gameCardSecurityInfo.key_area), g_fsProgramMemory.data + offset, sizeof(GameCardKeyArea));
|
||||
found = (g_gameCardSecurityInfo.key_area.package_id == g_gameCardHeader.package_id);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) LOGFILE("Failed to locate gamecard key area!");
|
||||
|
||||
/* Free FS memory dump. */
|
||||
memFreeMemoryLocation(&g_fsProgramMemory);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool gamecardGetHandle(void)
|
||||
{
|
||||
if (!g_gameCardInserted)
|
||||
|
@ -818,7 +901,7 @@ static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset, bool l
|
|||
offset >= (g_gameCardStorageNormalAreaSize + g_gameCardStorageSecureAreaSize) || (offset + read_size) > (g_gameCardStorageNormalAreaSize + g_gameCardStorageSecureAreaSize))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
Result rc = 0;
|
||||
|
@ -831,7 +914,7 @@ static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset, bool l
|
|||
/* Calculate normal storage area size difference. */
|
||||
u64 diff_size = (g_gameCardStorageNormalAreaSize - offset);
|
||||
|
||||
if (!gamecardReadStorageArea(out_u8, diff_size, offset, false)) goto exit;
|
||||
if (!gamecardReadStorageArea(out_u8, diff_size, offset, false)) goto end;
|
||||
|
||||
/* Adjust variables to read right from the start of the secure storage area. */
|
||||
read_size -= diff_size;
|
||||
|
@ -845,7 +928,7 @@ static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset, bool l
|
|||
if (!gamecardOpenStorageArea(area))
|
||||
{
|
||||
LOGFILE("Failed to open %s storage area!", GAMECARD_STORAGE_AREA_NAME(area));
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate appropiate storage area offset and retrieve the right storage area pointer. */
|
||||
|
@ -858,7 +941,7 @@ static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset, bool l
|
|||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsStorageRead failed to read 0x%lX bytes at offset 0x%lX from %s storage area! (0x%08X) (aligned).", read_size, base_offset, GAMECARD_STORAGE_AREA_NAME(area), rc);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
@ -876,7 +959,7 @@ static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset, bool l
|
|||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsStorageRead failed to read 0x%lX bytes at offset 0x%lX from %s storage area! (0x%08X) (unaligned).", chunk_size, block_start_offset, GAMECARD_STORAGE_AREA_NAME(area), rc);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memcpy(out_u8, g_gameCardReadBuf + data_start_offset, out_chunk_size);
|
||||
|
@ -884,7 +967,7 @@ static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset, bool l
|
|||
success = (block_size > GAMECARD_READ_BUFFER_SIZE ? gamecardReadStorageArea(out_u8 + out_chunk_size, read_size - out_chunk_size, base_offset + out_chunk_size, false) : true);
|
||||
}
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (lock) mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return success;
|
||||
|
|
|
@ -30,10 +30,26 @@
|
|||
|
||||
#define GAMECARD_MEDIA_UNIT_SIZE 0x200
|
||||
|
||||
#define GAMECARD_UPDATE_TID (u64)0x0100000000000816
|
||||
|
||||
#define GAMECARD_HFS_PARTITION_NAME(x) ((x) == GameCardHashFileSystemPartitionType_Root ? "root" : ((x) == GameCardHashFileSystemPartitionType_Update ? "update" : \
|
||||
((x) == GameCardHashFileSystemPartitionType_Logo ? "logo" : ((x) == GameCardHashFileSystemPartitionType_Normal ? "normal" : \
|
||||
((x) == GameCardHashFileSystemPartitionType_Secure ? "secure" : "unknown")))))
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
u8 key_source[0x10];
|
||||
struct {
|
||||
u64 package_id; ///< Matches package_id from GameCardHeader.
|
||||
u64 padding; ///< Just zeroes.
|
||||
};
|
||||
};
|
||||
u8 encrypted_titlekey[0x10];
|
||||
u8 mac[0x10];
|
||||
u8 nonce[0xC];
|
||||
u8 reserved[0x1C4];
|
||||
} GameCardKeyArea;
|
||||
|
||||
typedef enum {
|
||||
GameCardKekIndex_Version0 = 0,
|
||||
GameCardKekIndex_VersionForDev = 1
|
||||
|
@ -153,11 +169,12 @@ bool gamecardReadStorage(void *out, u64 read_size, u64 offset);
|
|||
|
||||
/// Miscellaneous functions.
|
||||
|
||||
bool gamecardGetKeyArea(GameCardKeyArea *out);
|
||||
bool gamecardGetHeader(GameCardHeader *out);
|
||||
bool gamecardGetCertificate(FsGameCardCertificate *out);
|
||||
bool gamecardGetTotalSize(u64 *out);
|
||||
bool gamecardGetTrimmedSize(u64 *out);
|
||||
bool gamecardGetRomCapacity(u64 *out); ///< Not the same as gamecardGetTotalSize().
|
||||
bool gamecardGetCertificate(FsGameCardCertificate *out);
|
||||
bool gamecardGetBundledFirmwareUpdateVersion(u32 *out);
|
||||
|
||||
/// Retrieves the entry count from a hash FS partition.
|
||||
|
|
268
source/keys.c
268
source/keys.c
|
@ -22,51 +22,37 @@
|
|||
|
||||
#include "utils.h"
|
||||
#include "keys.h"
|
||||
#include "mem.h"
|
||||
#include "nca.h"
|
||||
|
||||
#define KEYS_FILE_PATH "sdmc:/switch/prod.keys" /* Location used by Lockpick_RCM. */
|
||||
|
||||
#define FS_SYSMODULE_TID (u64)0x0100000000000000
|
||||
#define BOOT_SYSMODULE_TID (u64)0x0100000000000005
|
||||
#define SPL_SYSMODULE_TID (u64)0x0100000000000028
|
||||
|
||||
#define SEGMENT_TEXT BIT(0)
|
||||
#define SEGMENT_RODATA BIT(1)
|
||||
#define SEGMENT_DATA BIT(2)
|
||||
|
||||
/* Type definitions. */
|
||||
|
||||
typedef struct {
|
||||
u64 program_id;
|
||||
u8 mask;
|
||||
u8 *data;
|
||||
u64 data_size;
|
||||
} keysMemoryLocation;
|
||||
|
||||
typedef struct {
|
||||
char name[64];
|
||||
u8 hash[SHA256_HASH_SIZE];
|
||||
u64 size;
|
||||
void *dst;
|
||||
} keysMemoryKey;
|
||||
} KeysMemoryKey;
|
||||
|
||||
typedef struct {
|
||||
keysMemoryLocation location;
|
||||
MemoryLocation location;
|
||||
u32 key_count;
|
||||
keysMemoryKey keys[];
|
||||
} keysMemoryInfo;
|
||||
KeysMemoryKey keys[];
|
||||
} KeysMemoryInfo;
|
||||
|
||||
typedef struct {
|
||||
///< Needed to decrypt the NCA header using AES-128-XTS.
|
||||
u8 header_kek_source[0x10]; ///< Seed for header kek. Retrieved from the .rodata section in the FS sysmodule.
|
||||
u8 header_key_source[0x20]; ///< Seed for NCA header key. Retrieved from the .data section in the FS sysmodule.
|
||||
u8 header_kek_source[0x10]; ///< Seed for header kek. Retrieved from the .rodata segment in the FS sysmodule.
|
||||
u8 header_key_source[0x20]; ///< Seed for NCA header key. Retrieved from the .data segment in the FS sysmodule.
|
||||
u8 header_kek[0x10]; ///< NCA header kek. Generated from header_kek_source.
|
||||
u8 header_key[0x20]; ///< NCA header key. Generated from header_kek and header_key_source.
|
||||
|
||||
///< Needed to derive the KAEK used to decrypt the NCA key area.
|
||||
u8 key_area_key_application_source[0x10]; ///< Seed for kaek 0. Retrieved from the .rodata section in the FS sysmodule.
|
||||
u8 key_area_key_ocean_source[0x10]; ///< Seed for kaek 1. Retrieved from the .rodata section in the FS sysmodule.
|
||||
u8 key_area_key_system_source[0x10]; ///< Seed for kaek 2. Retrieved from the .rodata section in the FS sysmodule.
|
||||
u8 key_area_key_application_source[0x10]; ///< Seed for kaek 0. Retrieved from the .rodata segment in the FS sysmodule.
|
||||
u8 key_area_key_ocean_source[0x10]; ///< Seed for kaek 1. Retrieved from the .rodata segment in the FS sysmodule.
|
||||
u8 key_area_key_system_source[0x10]; ///< Seed for kaek 2. Retrieved from the .rodata segment in the FS sysmodule.
|
||||
|
||||
///< Needed to decrypt the titlekey block from a ticket. Retrieved from the Lockpick_RCM keys file.
|
||||
u8 eticket_rsa_kek[0x10]; ///< eTicket RSA kek (generic).
|
||||
|
@ -83,10 +69,10 @@ static keysNcaKeyset g_ncaKeyset = {0};
|
|||
static bool g_ncaKeysetLoaded = false;
|
||||
static Mutex g_ncaKeysetMutex = 0;
|
||||
|
||||
static keysMemoryInfo g_fsRodataMemoryInfo = {
|
||||
static KeysMemoryInfo g_fsRodataMemoryInfo = {
|
||||
.location = {
|
||||
.program_id = FS_SYSMODULE_TID,
|
||||
.mask = SEGMENT_RODATA,
|
||||
.mask = MemoryProgramSegmentType_Rodata,
|
||||
.data = NULL,
|
||||
.data_size = 0
|
||||
},
|
||||
|
@ -123,10 +109,10 @@ static keysMemoryInfo g_fsRodataMemoryInfo = {
|
|||
}
|
||||
};
|
||||
|
||||
static keysMemoryInfo g_fsDataMemoryInfo = {
|
||||
static KeysMemoryInfo g_fsDataMemoryInfo = {
|
||||
.location = {
|
||||
.program_id = FS_SYSMODULE_TID,
|
||||
.mask = SEGMENT_DATA,
|
||||
.mask = MemoryProgramSegmentType_Data,
|
||||
.data = NULL,
|
||||
.data_size = 0
|
||||
},
|
||||
|
@ -144,10 +130,7 @@ static keysMemoryInfo g_fsDataMemoryInfo = {
|
|||
|
||||
/* Function prototypes. */
|
||||
|
||||
static bool keysRetrieveDebugHandleFromProcessByProgramId(Handle *out, u64 program_id);
|
||||
static bool keysRetrieveProcessMemory(keysMemoryLocation *location);
|
||||
static void keysFreeProcessMemory(keysMemoryLocation *location);
|
||||
static bool keysRetrieveKeysFromProcessMemory(keysMemoryInfo *info);
|
||||
static bool keysRetrieveKeysFromProgramMemory(KeysMemoryInfo *info);
|
||||
static bool keysDeriveNcaHeaderKey(void);
|
||||
static int keysGetKeyAndValueFromFile(FILE *f, char **key, char **value);
|
||||
static char keysConvertHexCharToBinary(char c);
|
||||
|
@ -159,7 +142,7 @@ bool keysLoadNcaKeyset(void)
|
|||
mutexLock(&g_ncaKeysetMutex);
|
||||
|
||||
bool ret = g_ncaKeysetLoaded;
|
||||
if (ret) goto exit;
|
||||
if (ret) goto end;
|
||||
|
||||
if (!(envIsSyscallHinted(0x60) && /* svcDebugActiveProcess. */
|
||||
envIsSyscallHinted(0x63) && /* svcGetDebugEvent. */
|
||||
|
@ -168,32 +151,32 @@ bool keysLoadNcaKeyset(void)
|
|||
envIsSyscallHinted(0x6A))) /* svcReadDebugProcessMemory. */
|
||||
{
|
||||
LOGFILE("Debug SVC permissions not available!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!keysRetrieveKeysFromProcessMemory(&g_fsRodataMemoryInfo))
|
||||
if (!keysRetrieveKeysFromProgramMemory(&g_fsRodataMemoryInfo))
|
||||
{
|
||||
LOGFILE("Unable to retrieve keys from FS .rodata section!");
|
||||
goto exit;
|
||||
LOGFILE("Unable to retrieve keys from FS .rodata segment!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!keysRetrieveKeysFromProcessMemory(&g_fsDataMemoryInfo))
|
||||
if (!keysRetrieveKeysFromProgramMemory(&g_fsDataMemoryInfo))
|
||||
{
|
||||
LOGFILE("Unable to retrieve keys from FS .data section!");
|
||||
goto exit;
|
||||
LOGFILE("Unable to retrieve keys from FS .data segment!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!keysDeriveNcaHeaderKey())
|
||||
{
|
||||
LOGFILE("Unable to derive NCA header key!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!keysReadKeysFromFile()) goto exit;
|
||||
if (!keysReadKeysFromFile()) goto end;
|
||||
|
||||
ret = g_ncaKeysetLoaded = true;
|
||||
|
||||
exit:
|
||||
end:
|
||||
mutexUnlock(&g_ncaKeysetMutex);
|
||||
|
||||
return ret;
|
||||
|
@ -264,190 +247,7 @@ const u8 *keysGetKeyAreaEncryptionKey(u8 key_generation, u8 kaek_index)
|
|||
return (const u8*)(g_ncaKeyset.key_area_keys[key_gen_val][kaek_index]);
|
||||
}
|
||||
|
||||
static bool keysRetrieveDebugHandleFromProcessByProgramId(Handle *out, u64 program_id)
|
||||
{
|
||||
if (!out || !program_id)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Result rc = 0;
|
||||
u64 d[8] = {0};
|
||||
Handle debug_handle = INVALID_HANDLE;
|
||||
|
||||
if (program_id > BOOT_SYSMODULE_TID && program_id != SPL_SYSMODULE_TID)
|
||||
{
|
||||
/* If not a kernel process, get PID from pm:dmnt. */
|
||||
u64 pid;
|
||||
|
||||
rc = pmdmntGetProcessId(&pid, program_id);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("pmdmntGetProcessId failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = svcDebugActiveProcess(&debug_handle, pid);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("svcDebugActiveProcess failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = svcGetDebugEvent((u8*)&d, debug_handle);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("svcGetDebugEvent failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* Otherwise, query svc for the process list. */
|
||||
u32 i, num_processes = 0;
|
||||
|
||||
u64 *pids = calloc(300, sizeof(u64));
|
||||
if (!pids)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for PID list!");
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = svcGetProcessList((s32*)&num_processes, pids, 300);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("svcGetProcessList failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
for(i = 0; i < (num_processes - 1); i++)
|
||||
{
|
||||
rc = svcDebugActiveProcess(&debug_handle, pids[i]);
|
||||
if (R_FAILED(rc)) continue;
|
||||
|
||||
rc = svcGetDebugEvent((u8*)&d, debug_handle);
|
||||
if (R_SUCCEEDED(rc) && d[2] == program_id) break;
|
||||
|
||||
svcCloseHandle(debug_handle);
|
||||
debug_handle = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
free(pids);
|
||||
|
||||
if (i == (num_processes - 1))
|
||||
{
|
||||
LOGFILE("Kernel process lookup failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*out = debug_handle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool keysRetrieveProcessMemory(keysMemoryLocation *location)
|
||||
{
|
||||
if (!location || !location->program_id || !location->mask)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Result rc = 0;
|
||||
Handle debug_handle = INVALID_HANDLE;
|
||||
|
||||
MemoryInfo mem_info = {0};
|
||||
|
||||
u32 page_info = 0;
|
||||
u64 addr = 0, last_text_addr = 0;
|
||||
u8 segment = 0;
|
||||
u8 *tmp = NULL;
|
||||
|
||||
bool success = true;
|
||||
|
||||
if (!keysRetrieveDebugHandleFromProcessByProgramId(&debug_handle, location->program_id))
|
||||
{
|
||||
LOGFILE("Unable to retrieve debug handle for program %016lX!", location->program_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Locate "real" .text segment as Atmosphere emuMMC has two. */
|
||||
for(;;)
|
||||
{
|
||||
rc = svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("svcQueryDebugProcessMemory failed! (0x%08X).", rc);
|
||||
success = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((mem_info.perm & Perm_X) && ((mem_info.type & 0xFF) >= MemType_CodeStatic) && ((mem_info.type & 0xFF) < MemType_Heap)) last_text_addr = mem_info.addr;
|
||||
|
||||
addr = (mem_info.addr + mem_info.size);
|
||||
if (!addr) break;
|
||||
}
|
||||
|
||||
addr = last_text_addr;
|
||||
|
||||
for(segment = 1; segment < BIT(3);)
|
||||
{
|
||||
rc = svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("svcQueryDebugProcessMemory failed! (0x%08X).", rc);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Code to allow for bitmasking segments. */
|
||||
if ((mem_info.perm & Perm_R) && ((mem_info.type & 0xFF) >= MemType_CodeStatic) && ((mem_info.type & 0xFF) < MemType_Heap) && ((segment <<= 1) >> 1 & location->mask) > 0)
|
||||
{
|
||||
/* If location->data == NULL, realloc will essentially act as a malloc. */
|
||||
tmp = realloc(location->data, location->data_size + mem_info.size);
|
||||
if (!tmp)
|
||||
{
|
||||
LOGFILE("Failed to resize key location data buffer to 0x%lX bytes.", location->data_size + mem_info.size);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
location->data = tmp;
|
||||
tmp = NULL;
|
||||
|
||||
rc = svcReadDebugProcessMemory(location->data + location->data_size, debug_handle, mem_info.addr, mem_info.size);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("svcReadDebugProcessMemory failed! (0x%08X).", rc);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
location->data_size += mem_info.size;
|
||||
}
|
||||
|
||||
addr = (mem_info.addr + mem_info.size);
|
||||
if (addr == 0) break;
|
||||
}
|
||||
|
||||
out:
|
||||
svcCloseHandle(debug_handle);
|
||||
|
||||
if (success && (!location->data || !location->data_size)) success = false;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void keysFreeProcessMemory(keysMemoryLocation *location)
|
||||
{
|
||||
if (location && location->data)
|
||||
{
|
||||
free(location->data);
|
||||
location->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool keysRetrieveKeysFromProcessMemory(keysMemoryInfo *info)
|
||||
static bool keysRetrieveKeysFromProgramMemory(KeysMemoryInfo *info)
|
||||
{
|
||||
if (!info || !info->key_count)
|
||||
{
|
||||
|
@ -459,11 +259,7 @@ static bool keysRetrieveKeysFromProcessMemory(keysMemoryInfo *info)
|
|||
u8 tmp_hash[SHA256_HASH_SIZE];
|
||||
bool success = false;
|
||||
|
||||
if (!keysRetrieveProcessMemory(&(info->location)))
|
||||
{
|
||||
LOGFILE("Unable to retrieve process memory from program %016lX!", info->location.program_id);
|
||||
return false;
|
||||
}
|
||||
if (!memRetrieveProgramMemorySegment(&(info->location))) return false;
|
||||
|
||||
for(u32 i = 0; i < info->key_count; i++)
|
||||
{
|
||||
|
@ -472,7 +268,7 @@ static bool keysRetrieveKeysFromProcessMemory(keysMemoryInfo *info)
|
|||
if (!info->keys[i].dst)
|
||||
{
|
||||
LOGFILE("Invalid destination pointer for key \"%s\" in program %016lX!", info->keys[i].name, info->location.program_id);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Hash every key length-sized byte chunk in the process memory buffer until a match is found. */
|
||||
|
@ -494,14 +290,14 @@ static bool keysRetrieveKeysFromProcessMemory(keysMemoryInfo *info)
|
|||
if (!found)
|
||||
{
|
||||
LOGFILE("Unable to locate key \"%s\" in process memory from program %016lX!", info->keys[i].name, info->location.program_id);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
out:
|
||||
keysFreeProcessMemory(&(info->location));
|
||||
end:
|
||||
memFreeMemoryLocation(&(info->location));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -333,6 +333,8 @@ int main(int argc, char *argv[])
|
|||
shared_data.data_written = 0;
|
||||
romfsGetTotalDataSize(&romfs_ctx, &(shared_data.total_size));
|
||||
|
||||
goto out2;
|
||||
|
||||
consolePrint("waiting for usb connection... ");
|
||||
|
||||
time_t start = time(NULL);
|
||||
|
@ -450,6 +452,26 @@ out2:
|
|||
consolePrint("press any button to exit\n");
|
||||
utilsWaitForButtonPress(KEY_NONE);
|
||||
|
||||
|
||||
|
||||
|
||||
if (gamecardIsReady())
|
||||
{
|
||||
GameCardKeyArea key_area = {0};
|
||||
if (gamecardGetKeyArea(&key_area))
|
||||
{
|
||||
FILE *kafd = fopen("sdmc:/gc_key_area.bin", "wb");
|
||||
if (kafd)
|
||||
{
|
||||
fwrite(&key_area, 1, sizeof(GameCardKeyArea), kafd);
|
||||
fclose(kafd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
lrExit();
|
||||
|
||||
if (serviceIsActive(&(ncm_storage.s))) ncmContentStorageClose(&ncm_storage);
|
||||
|
|
262
source/mem.c
Normal file
262
source/mem.c
Normal file
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* mem.c
|
||||
*
|
||||
* Copyright (c) 2019, shchmue.
|
||||
* Copyright (c) 2020, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* nxdumptool is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "mem.h"
|
||||
|
||||
#define MEMLOG(fmt, ...) LOGBUF(g_memLogBuf, sizeof(g_memLogBuf), fmt, ##__VA_ARGS__)
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
static char g_memLogBuf[512] = {0};
|
||||
static Mutex g_memMutex = 0;
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
static bool memRetrieveProgramMemory(MemoryLocation *location, bool is_segment);
|
||||
static bool memRetrieveDebugHandleFromProgramById(Handle *out, u64 program_id);
|
||||
|
||||
bool memRetrieveProgramMemorySegment(MemoryLocation *location)
|
||||
{
|
||||
if (!location || !location->program_id || !location->mask || location->mask >= BIT(3))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mutexLock(&g_memMutex);
|
||||
bool ret = memRetrieveProgramMemory(location, true);
|
||||
mutexUnlock(&g_memMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool memRetrieveFullProgramMemory(MemoryLocation *location)
|
||||
{
|
||||
if (!location || !location->program_id)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mutexLock(&g_memMutex);
|
||||
bool ret = memRetrieveProgramMemory(location, false);
|
||||
mutexUnlock(&g_memMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool memRetrieveProgramMemory(MemoryLocation *location, bool is_segment)
|
||||
{
|
||||
Result rc = 0;
|
||||
Handle debug_handle = INVALID_HANDLE;
|
||||
|
||||
MemoryInfo mem_info = {0};
|
||||
|
||||
u32 page_info = 0;
|
||||
u64 addr = 0, last_text_addr = 0;
|
||||
u8 segment = 1, mem_type = 0;
|
||||
u8 *tmp = NULL;
|
||||
|
||||
bool success = true;
|
||||
|
||||
*g_memLogBuf = '\0';
|
||||
|
||||
/* Clear output MemoryLocation element. */
|
||||
memFreeMemoryLocation(location);
|
||||
|
||||
/* LOGFILE() will be useless if the target program is the FS sysmodule. */
|
||||
/* This is because any FS I/O operation *will* lock up the console while FS itself is being debugged. */
|
||||
/* So we'll just temporarily log data to a char array using LOGBUF(), then write it all out after calling svcCloseHandle(). */
|
||||
/* However, we must prevent other threads from logging data as well in order to avoid a lock up, so we'll temporarily lock the logfile mutex. */
|
||||
utilsLogFileMutexControl(true);
|
||||
|
||||
/* Retrieve debug handle by program ID. */
|
||||
if (!memRetrieveDebugHandleFromProgramById(&debug_handle, location->program_id))
|
||||
{
|
||||
MEMLOG("Unable to retrieve debug handle for program %016lX!", location->program_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (is_segment && location->program_id == FS_SYSMODULE_TID)
|
||||
{
|
||||
/* If dealing with FS, locate the "real" .text segment, since Atmosphere emuMMC has two. */
|
||||
do {
|
||||
rc = svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
MEMLOG("svcQueryDebugProcessMemory failed for program %016lX! (0x%08X).", location->program_id, rc);
|
||||
success = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
mem_type = (u8)(mem_info.type & 0xFF);
|
||||
if ((mem_info.perm & Perm_X) && (mem_type == MemType_CodeStatic || mem_type == MemType_CodeMutable)) last_text_addr = mem_info.addr;
|
||||
|
||||
addr = (mem_info.addr + mem_info.size);
|
||||
} while(addr != 0);
|
||||
|
||||
addr = last_text_addr;
|
||||
}
|
||||
|
||||
do {
|
||||
rc = svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
MEMLOG("svcQueryDebugProcessMemory failed for program %016lX! (0x%08X).", location->program_id, rc);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
mem_type = (u8)(mem_info.type & 0xFF);
|
||||
|
||||
/* Code to allow for bitmasking segments. */
|
||||
if ((mem_info.perm & Perm_R) && ((!is_segment && mem_type != MemType_Unmapped && mem_type != MemType_Io && mem_type != MemType_ThreadLocal && mem_type != MemType_Reserved && !mem_info.attr) || \
|
||||
(is_segment && (mem_type == MemType_CodeStatic || mem_type == MemType_CodeMutable) && (((segment <<= 1) >> 1) & location->mask))))
|
||||
{
|
||||
/* If location->data == NULL, realloc() will essentially act as a malloc(). */
|
||||
tmp = realloc(location->data, location->data_size + mem_info.size);
|
||||
if (!tmp)
|
||||
{
|
||||
MEMLOG("Failed to resize segment data buffer to 0x%lX bytes for program %016lX!", location->data_size + mem_info.size, location->program_id);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
location->data = tmp;
|
||||
tmp = NULL;
|
||||
|
||||
rc = svcReadDebugProcessMemory(location->data + location->data_size, debug_handle, mem_info.addr, mem_info.size);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
MEMLOG("svcReadDebugProcessMemory failed for program %016lX! (0x%08X).", location->program_id, rc);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
location->data_size += mem_info.size;
|
||||
}
|
||||
|
||||
addr = (mem_info.addr + mem_info.size);
|
||||
} while(addr != 0 && segment < BIT(3));
|
||||
|
||||
end:
|
||||
/* Close debug handle. */
|
||||
if (debug_handle != INVALID_HANDLE) svcCloseHandle(debug_handle);
|
||||
|
||||
/* Unlock logfile mutex. */
|
||||
utilsLogFileMutexControl(false);
|
||||
|
||||
if (success && (!location->data || !location->data_size))
|
||||
{
|
||||
MEMLOG("total size: 0x%lX", location->data_size);
|
||||
MEMLOG("Unable to locate readable program %016lX memory pages that match the required criteria!", location->program_id);
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (!success) memFreeMemoryLocation(location);
|
||||
|
||||
/* Write log buffer data. This will do nothing if the log buffer length is zero. */
|
||||
utilsWriteLogBufferToLogFile(g_memLogBuf);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool memRetrieveDebugHandleFromProgramById(Handle *out, u64 program_id)
|
||||
{
|
||||
if (!out || !program_id)
|
||||
{
|
||||
MEMLOG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Result rc = 0;
|
||||
u64 pid = 0, d[8] = {0};
|
||||
Handle debug_handle = INVALID_HANDLE;
|
||||
|
||||
u32 i = 0, num_processes = 0;
|
||||
u64 *pids = NULL;
|
||||
|
||||
if (program_id > BOOT_SYSMODULE_TID && program_id != SPL_SYSMODULE_TID)
|
||||
{
|
||||
/* If not a kernel process, get PID from pm:dmnt. */
|
||||
rc = pmdmntGetProcessId(&pid, program_id);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
MEMLOG("pmdmntGetProcessId failed for program %016lX! (0x%08X).", program_id, rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Retrieve debug handle right away. */
|
||||
rc = svcDebugActiveProcess(&debug_handle, pid);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
MEMLOG("svcDebugActiveProcess failed for program %016lX! (0x%08X).", program_id, rc);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* Otherwise, query svc for the process list. */
|
||||
pids = calloc(300, sizeof(u64));
|
||||
if (!pids)
|
||||
{
|
||||
MEMLOG("Failed to allocate memory for PID list!");
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = svcGetProcessList((s32*)&num_processes, pids, 300);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
MEMLOG("svcGetProcessList failed! (0x%08X).", rc);
|
||||
free(pids);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Perform a lookup using the retrieved process list. */
|
||||
for(i = 0; i < num_processes; i++)
|
||||
{
|
||||
/* Retrieve debug handle for the current PID. */
|
||||
rc = svcDebugActiveProcess(&debug_handle, pids[i]);
|
||||
if (R_FAILED(rc)) continue;
|
||||
|
||||
/* Get debug event using the debug handle. */
|
||||
/* This will let us know the program ID from the current PID. */
|
||||
rc = svcGetDebugEvent((u8*)&d, debug_handle);
|
||||
if (R_SUCCEEDED(rc) && d[2] == program_id) break;
|
||||
|
||||
/* No match. Close debug handle and keep looking for our program. */
|
||||
svcCloseHandle(debug_handle);
|
||||
debug_handle = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
free(pids);
|
||||
|
||||
if (i == num_processes)
|
||||
{
|
||||
MEMLOG("Unable to find program %016lX in kernel process list! (0x%08X).", program_id, rc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set output debug handle. */
|
||||
*out = debug_handle;
|
||||
|
||||
return true;
|
||||
}
|
62
source/mem.h
Normal file
62
source/mem.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* mem.h
|
||||
*
|
||||
* Copyright (c) 2019, shchmue.
|
||||
* Copyright (c) 2020, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* nxdumptool is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __MEM_H__
|
||||
#define __MEM_H__
|
||||
|
||||
#define FS_SYSMODULE_TID (u64)0x0100000000000000
|
||||
#define BOOT_SYSMODULE_TID (u64)0x0100000000000005
|
||||
#define SPL_SYSMODULE_TID (u64)0x0100000000000028
|
||||
|
||||
typedef enum {
|
||||
MemoryProgramSegmentType_Text = BIT(0),
|
||||
MemoryProgramSegmentType_Rodata = BIT(1),
|
||||
MemoryProgramSegmentType_Data = BIT(2)
|
||||
} MemoryProgramSegmentType;
|
||||
|
||||
typedef struct {
|
||||
u64 program_id;
|
||||
u8 mask; ///< MemoryProgramSegmentType. Used with memRetrieveProgramMemorySegment(). Ignored in memRetrieveFullProgramMemory().
|
||||
u8 *data;
|
||||
u64 data_size;
|
||||
} MemoryLocation;
|
||||
|
||||
/// Retrieves memory segment (.text, .rodata, .data) data from a running program.
|
||||
/// These are memory pages with read permission (Perm_R) enabled and type MemType_CodeStatic or MemType_CodeMutable.
|
||||
bool memRetrieveProgramMemorySegment(MemoryLocation *location);
|
||||
|
||||
/// Retrieves full memory data from a running program.
|
||||
/// These are any type of memory pages with read permission (Perm_R) enabled.
|
||||
/// MemType_Unmapped, MemType_Io, MemType_ThreadLocal and MemType_Reserved memory pages are excluded, as well as memory pages with a populated MemoryAttribute value.
|
||||
bool memRetrieveFullProgramMemory(MemoryLocation *location);
|
||||
|
||||
/// Frees a populated MemoryLocation element.
|
||||
NX_INLINE void memFreeMemoryLocation(MemoryLocation *location)
|
||||
{
|
||||
if (!location) return;
|
||||
if (location->data) free(location->data);
|
||||
location->data = NULL;
|
||||
location->data_size = 0;
|
||||
}
|
||||
|
||||
#endif /* __MEM_H__ */
|
80
source/nca.c
80
source/nca.c
|
@ -432,7 +432,7 @@ bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *da
|
|||
(data_offset + data_size) > hash_target_layer_size || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate required offsets and sizes. */
|
||||
|
@ -455,14 +455,14 @@ bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *da
|
|||
if (!hash_data_layer)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes buffer for the full HierarchicalSha256 hash data layer!", hash_data_layer_size);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read full hash data layer. */
|
||||
if (!_ncaReadFsSection(ctx, hash_data_layer, hash_data_layer_size, hash_data_layer_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read full HierarchicalSha256 hash data layer!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate memory for the modified hash target layer block. */
|
||||
|
@ -470,14 +470,14 @@ bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *da
|
|||
if (!hash_target_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes buffer for the modified HierarchicalSha256 hash target layer block!", hash_target_size);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read hash target layer block. */
|
||||
if (!_ncaReadFsSection(ctx, hash_target_block, hash_target_size, hash_target_start_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read HierarchicalSha256 hash target layer block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Replace data. */
|
||||
|
@ -496,7 +496,7 @@ bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *da
|
|||
if (!out->hash_data_layer_patch.data)
|
||||
{
|
||||
LOGFILE("Failed to generate encrypted HierarchicalSha256 hash data layer block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Reencrypt hash target layer block. */
|
||||
|
@ -505,7 +505,7 @@ bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *da
|
|||
if (!out->hash_target_layer_patch.data)
|
||||
{
|
||||
LOGFILE("Failed to generate encrypted HierarchicalSha256 hash target layer block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Recalculate master hash from hash info block. */
|
||||
|
@ -519,7 +519,7 @@ bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *da
|
|||
|
||||
success = true;
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (hash_target_block) free(hash_target_block);
|
||||
|
||||
if (hash_data_layer) free(hash_data_layer);
|
||||
|
@ -549,7 +549,7 @@ bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void
|
|||
(data_offset + data_size) > ctx->header->hash_info.hierarchical_integrity.hash_target_layer_info.size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Process each IVFC layer. */
|
||||
|
@ -565,7 +565,7 @@ bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void
|
|||
if (!cur_layer_info->size || !cur_layer_info->block_size || (parent_layer_info && (!parent_layer_info->size || !parent_layer_info->block_size)))
|
||||
{
|
||||
LOGFILE("Invalid HierarchicalIntegrity parent/child layer!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate required offsets and sizes. */
|
||||
|
@ -604,7 +604,7 @@ bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void
|
|||
if (!hash_target_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes for the HierarchicalIntegrity hash target layer block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Adjust hash target layer end offset and size if needed to avoid read errors. */
|
||||
|
@ -618,7 +618,7 @@ bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void
|
|||
if (!_ncaReadFsSection(ctx, hash_target_block, hash_target_size, hash_target_start_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read HierarchicalIntegrity hash target layer block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Replace hash target layer block data. */
|
||||
|
@ -631,14 +631,14 @@ bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void
|
|||
if (!hash_data_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes for the HierarchicalIntegrity hash data layer block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read hash target layer block. */
|
||||
if (!_ncaReadFsSection(ctx, hash_data_block, hash_data_size, hash_data_layer_offset + hash_data_start_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read HierarchicalIntegrity hash data layer block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Recalculate hashes. */
|
||||
|
@ -656,7 +656,7 @@ bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void
|
|||
if (!cur_layer_patch->data)
|
||||
{
|
||||
LOGFILE("Failed to generate encrypted HierarchicalIntegrity hash target layer block!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Free hash target layer block. */
|
||||
|
@ -684,7 +684,7 @@ bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void
|
|||
|
||||
success = true;
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (hash_data_block) free(hash_data_block);
|
||||
|
||||
if (hash_target_block) free(hash_target_block);
|
||||
|
@ -936,7 +936,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
offset >= ctx->section_size || (offset + read_size) > ctx->section_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA FS section header parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
size_t crypt_res = 0;
|
||||
|
@ -952,7 +952,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
content_offset >= nca_ctx->content_size || (content_offset + read_size) > nca_ctx->content_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA header parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Optimization for reads from plaintext FS sections or reads that are aligned to the AES-CTR / AES-XTS sector size. */
|
||||
|
@ -964,14 +964,14 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
if (!ncaReadContentFile(nca_ctx, out, read_size, content_offset))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", read_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Return right away if we're dealing with a plaintext FS section. */
|
||||
if (ctx->encryption_type == NcaEncryptionType_None)
|
||||
{
|
||||
ret = true;
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Decrypt data. */
|
||||
|
@ -983,7 +983,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
if (crypt_res != read_size)
|
||||
{
|
||||
LOGFILE("Failed to AES-XTS decrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", read_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
if (ctx->encryption_type == NcaEncryptionType_AesCtr || ctx->encryption_type == NcaEncryptionType_AesCtrEx)
|
||||
|
@ -994,7 +994,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
}
|
||||
|
||||
ret = true;
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate offsets and block sizes. */
|
||||
|
@ -1010,7 +1010,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
if (!ncaReadContentFile(nca_ctx, g_ncaCryptoBuffer, chunk_size, block_start_offset))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes encrypted data block at offset 0x%lX from NCA \"%s\" FS section #%u! (unaligned).", chunk_size, block_start_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Decrypt data. */
|
||||
|
@ -1022,7 +1022,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
if (crypt_res != chunk_size)
|
||||
{
|
||||
LOGFILE("Failed to AES-XTS decrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (unaligned).", chunk_size, block_start_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
if (ctx->encryption_type == NcaEncryptionType_AesCtr || ctx->encryption_type == NcaEncryptionType_AesCtrEx)
|
||||
|
@ -1037,7 +1037,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
|
||||
ret = (block_size > NCA_CRYPTO_BUFFER_SIZE ? _ncaReadFsSection(ctx, (u8*)out + out_chunk_size, read_size - out_chunk_size, offset + out_chunk_size, false) : true);
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (lock) mutexUnlock(&g_ncaCryptoBufferMutex);
|
||||
|
||||
return ret;
|
||||
|
@ -1054,7 +1054,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
(offset + read_size) > ctx->section_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA FS section header parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
NcaContext *nca_ctx = (NcaContext*)ctx->nca_ctx;
|
||||
|
@ -1067,7 +1067,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
content_offset >= nca_ctx->content_size || (content_offset + read_size) > nca_ctx->content_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA header parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Optimization for reads that are aligned to the AES-CTR sector size. */
|
||||
|
@ -1077,7 +1077,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
if (!ncaReadContentFile(nca_ctx, out, read_size, content_offset))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", read_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Decrypt data */
|
||||
|
@ -1086,7 +1086,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
aes128CtrCrypt(&(ctx->ctr_ctx), out, out, read_size);
|
||||
|
||||
ret = true;
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate offsets and block sizes. */
|
||||
|
@ -1102,7 +1102,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
if (!ncaReadContentFile(nca_ctx, g_ncaCryptoBuffer, chunk_size, block_start_offset))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes encrypted data block at offset 0x%lX from NCA \"%s\" FS section #%u! (unaligned).", chunk_size, block_start_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Decrypt data. */
|
||||
|
@ -1115,7 +1115,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
|
||||
ret = (block_size > NCA_CRYPTO_BUFFER_SIZE ? _ncaReadAesCtrExStorageFromBktrSection(ctx, (u8*)out + out_chunk_size, read_size - out_chunk_size, offset + out_chunk_size, ctr_val, false) : true);
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (lock) mutexUnlock(&g_ncaCryptoBufferMutex);
|
||||
|
||||
return ret;
|
||||
|
@ -1133,7 +1133,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
data_offset >= ctx->section_size || (data_offset + data_size) > ctx->section_size || !out_block_size || !out_block_offset)
|
||||
{
|
||||
LOGFILE("Invalid NCA FS section header parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
size_t crypt_res = 0;
|
||||
|
@ -1149,7 +1149,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
content_offset >= nca_ctx->content_size || (content_offset + data_size) > nca_ctx->content_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA header parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Optimization for blocks from plaintext FS sections or blocks that are aligned to the AES-CTR / AES-XTS sector size. */
|
||||
|
@ -1162,7 +1162,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
if (!out)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes buffer! (aligned).", data_size);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Copy data. */
|
||||
|
@ -1177,7 +1177,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
if (crypt_res != data_size)
|
||||
{
|
||||
LOGFILE("Failed to AES-XTS encrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", data_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
if (ctx->encryption_type == NcaEncryptionType_AesCtr)
|
||||
|
@ -1191,7 +1191,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
*out_block_offset = content_offset;
|
||||
|
||||
success = true;
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate block offsets and size. */
|
||||
|
@ -1207,14 +1207,14 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
if (!out)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes buffer! (unaligned).", block_size);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read decrypted data using aligned offset and size. */
|
||||
if (!_ncaReadFsSection(ctx, out, block_size, block_start_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read decrypted NCA \"%s\" FS section #%u data block!", nca_ctx->content_id_str, ctx->section_num);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Replace plaintext data. */
|
||||
|
@ -1229,7 +1229,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
if (crypt_res != block_size)
|
||||
{
|
||||
LOGFILE("Failed to AES-XTS encrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", block_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
if (ctx->encryption_type == NcaEncryptionType_AesCtr)
|
||||
|
@ -1244,7 +1244,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
|
||||
success = true;
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (!success && out)
|
||||
{
|
||||
free(out);
|
||||
|
|
|
@ -102,7 +102,7 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
|||
if (!ncaReadFsSection(nca_fs_ctx, out->dir_table, out->dir_table_size, out->offset + dir_table_offset))
|
||||
{
|
||||
LOGFILE("Failed to read RomFS directory entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read file entries table. */
|
||||
|
@ -112,20 +112,20 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
|||
if (!out->file_table_size || file_table_offset >= out->size || (file_table_offset + out->file_table_size) > out->size)
|
||||
{
|
||||
LOGFILE("Invalid RomFS file entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
out->file_table = malloc(out->file_table_size);
|
||||
if (!out->file_table)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for RomFS file entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!ncaReadFsSection(nca_fs_ctx, out->file_table, out->file_table_size, out->offset + file_table_offset))
|
||||
{
|
||||
LOGFILE("Failed to read RomFS file entries table!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get file data body offset. */
|
||||
|
@ -133,12 +133,12 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
|||
if (out->body_offset >= out->size)
|
||||
{
|
||||
LOGFILE("Invalid RomFS file data body!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (!success) romfsFreeContext(out);
|
||||
|
||||
return success;
|
||||
|
@ -281,7 +281,7 @@ RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByPath(RomFileSystemContext *
|
|||
{
|
||||
LOGFILE("Failed to tokenize input path!");
|
||||
dir_entry = NULL;
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
while(pch)
|
||||
|
@ -295,7 +295,7 @@ RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByPath(RomFileSystemContext *
|
|||
pch = strtok(NULL, "/");
|
||||
}
|
||||
|
||||
out:
|
||||
end:
|
||||
if (path_dup) free(path_dup);
|
||||
|
||||
return dir_entry;
|
||||
|
@ -332,7 +332,7 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const
|
|||
if (!path_len || !(filename = strrchr(path_dup, '/')))
|
||||
{
|
||||
LOGFILE("Invalid input path!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Remove leading slash and adjust filename string pointer. */
|
||||
|
@ -343,13 +343,13 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const
|
|||
if (!(dir_entry = (*path_dup ? romfsGetDirectoryEntryByPath(ctx, path_dup) : romfsGetDirectoryEntryByOffset(ctx, 0))))
|
||||
{
|
||||
LOGFILE("Failed to retrieve directory entry!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Retrieve file entry. */
|
||||
if (!(file_entry = romfsGetChildFileEntryByName(ctx, dir_entry, filename))) LOGFILE("Failed to retrieve file entry by name!");
|
||||
|
||||
out:
|
||||
end:
|
||||
if (path_dup) free(path_dup);
|
||||
|
||||
return file_entry;
|
||||
|
@ -397,7 +397,7 @@ bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSyste
|
|||
if (!(tmp_dir_entries = realloc(dir_entries, (dir_entries_count + 1) * sizeof(RomFileSystemDirectoryEntry*))))
|
||||
{
|
||||
LOGFILE("Unable to reallocate directory entries buffer!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
dir_entries = tmp_dir_entries;
|
||||
|
@ -406,7 +406,7 @@ bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSyste
|
|||
if (!(dir_entries[dir_entries_count] = romfsGetDirectoryEntryByOffset(ctx, dir_offset)) || !dir_entries[dir_entries_count]->name_length)
|
||||
{
|
||||
LOGFILE("Failed to retrieve directory entry!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
path_len += (1 + dir_entries[dir_entries_count]->name_length);
|
||||
|
@ -416,7 +416,7 @@ bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSyste
|
|||
if (path_len >= out_path_size)
|
||||
{
|
||||
LOGFILE("Output path length exceeds output buffer size!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Generate output path. */
|
||||
|
@ -431,7 +431,7 @@ bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSyste
|
|||
|
||||
success = true;
|
||||
|
||||
out:
|
||||
end:
|
||||
if (dir_entries) free(dir_entries);
|
||||
|
||||
return success;
|
||||
|
|
|
@ -117,7 +117,7 @@ bool rsa2048GenerateSha256BasedCustomAcidSignature(void *dst, const void *src, s
|
|||
if (ret != 0)
|
||||
{
|
||||
LOGFILE("mbedtls_ctr_drbg_seed failed! (%d).", ret);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Parse private key. */
|
||||
|
@ -125,7 +125,7 @@ bool rsa2048GenerateSha256BasedCustomAcidSignature(void *dst, const void *src, s
|
|||
if (ret != 0)
|
||||
{
|
||||
LOGFILE("mbedtls_pk_parse_key failed! (%d).", ret);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Set RSA padding. */
|
||||
|
@ -136,14 +136,14 @@ bool rsa2048GenerateSha256BasedCustomAcidSignature(void *dst, const void *src, s
|
|||
if (ret != 0)
|
||||
{
|
||||
LOGFILE("mbedtls_pk_sign failed! (%d).", ret);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Copy signature to output buffer. */
|
||||
memcpy(dst, buf, RSA2048_SIG_SIZE);
|
||||
success = true;
|
||||
|
||||
out:
|
||||
end:
|
||||
mbedtls_pk_free(&pk);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
|
|
|
@ -144,7 +144,7 @@ static remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, rem
|
|||
if (!seg->entries)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for remap segment entry #%u!", entry_idx);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
seg->entries[seg->entry_count++] = &map_entries[entry_idx];
|
||||
|
@ -160,7 +160,7 @@ static remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, rem
|
|||
if (!ptr)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for remap segment entry #%u!", entry_idx);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memcpy(ptr, seg->entries, sizeof(remap_entry_ctx_t*) * seg->entry_count);
|
||||
|
@ -174,7 +174,7 @@ static remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, rem
|
|||
|
||||
success = true;
|
||||
|
||||
out:
|
||||
end:
|
||||
if (!success)
|
||||
{
|
||||
entry_idx = 0;
|
||||
|
@ -400,7 +400,7 @@ static bool save_ivfc_storage_init(hierarchical_integrity_verification_storage_c
|
|||
if (!ctx->level_validities)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for level validities!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for(u32 i = 1; i < ivfc->num_levels; i++)
|
||||
|
@ -417,7 +417,7 @@ static bool save_ivfc_storage_init(hierarchical_integrity_verification_storage_c
|
|||
if (!level_data->block_validities)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for block validities in IVFC level #%u!", i);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctx->level_validities[i - 1] = level_data->block_validities;
|
||||
|
@ -429,7 +429,7 @@ static bool save_ivfc_storage_init(hierarchical_integrity_verification_storage_c
|
|||
|
||||
success = true;
|
||||
|
||||
out:
|
||||
end:
|
||||
if (!success && ctx->level_validities)
|
||||
{
|
||||
free(ctx->level_validities);
|
||||
|
@ -909,21 +909,21 @@ u32 save_fs_list_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_
|
|||
if (!ctx || !key)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
u32 capacity = save_fs_list_get_capacity(ctx);
|
||||
if (!capacity)
|
||||
{
|
||||
LOGFILE("Failed to retrieve FS capacity!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
save_fs_list_entry_t entry;
|
||||
if (!save_fs_list_read_entry(ctx, ctx->used_list_head_index, &entry))
|
||||
{
|
||||
LOGFILE("Failed to read FS entry for initial index %u!", ctx->used_list_head_index);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
*prev_index = ctx->used_list_head_index;
|
||||
|
@ -951,7 +951,7 @@ u32 save_fs_list_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_
|
|||
|
||||
if (!index) LOGFILE("Unable to find FS index from key!");
|
||||
|
||||
out:
|
||||
end:
|
||||
*prev_index = 0xFFFFFFFF;
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
@ -1292,7 +1292,7 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (fr || br != 0x20)
|
||||
{
|
||||
LOGFILE("Failed to read data remap storage entry #%u! (%u).", i, fr);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctx->data_remap_storage.map_entries[i].physical_offset_end = (ctx->data_remap_storage.map_entries[i].physical_offset + ctx->data_remap_storage.map_entries[i].size);
|
||||
|
@ -1304,7 +1304,7 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!ctx->data_remap_storage.segments)
|
||||
{
|
||||
LOGFILE("Failed to retrieve data remap storage segments!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize duplex storage. */
|
||||
|
@ -1316,26 +1316,26 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!ctx->duplex_layers[1].data_a)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for data_a block in duplex layer #1!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_a, ctx->header.layout.duplex_l1_offset_a, ctx->header.layout.duplex_l1_size) != ctx->header.layout.duplex_l1_size)
|
||||
{
|
||||
LOGFILE("Failed to read data_a block from duplex layer #1 in data remap storage!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctx->duplex_layers[1].data_b = calloc(1, ctx->header.layout.duplex_l1_size);
|
||||
if (!ctx->duplex_layers[1].data_b)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for data_b block in duplex layer #1!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_b, ctx->header.layout.duplex_l1_offset_b, ctx->header.layout.duplex_l1_size) != ctx->header.layout.duplex_l1_size)
|
||||
{
|
||||
LOGFILE("Failed to read data_b block from duplex layer #1 in data remap storage!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memcpy(&ctx->duplex_layers[1].info, &ctx->header.duplex_header.layers[1], sizeof(duplex_info_t));
|
||||
|
@ -1344,26 +1344,26 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!ctx->duplex_layers[2].data_a)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for data_a block in duplex layer #2!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_a, ctx->header.layout.duplex_data_offset_a, ctx->header.layout.duplex_data_size) != ctx->header.layout.duplex_data_size)
|
||||
{
|
||||
LOGFILE("Failed to read data_a block from duplex layer #2 in data remap storage!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctx->duplex_layers[2].data_b = calloc(1, ctx->header.layout.duplex_data_size);
|
||||
if (!ctx->duplex_layers[2].data_b)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for data_b block in duplex layer #2!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_b, ctx->header.layout.duplex_data_offset_b, ctx->header.layout.duplex_data_size) != ctx->header.layout.duplex_data_size)
|
||||
{
|
||||
LOGFILE("Failed to read data_b block from duplex layer #2 in data remap storage!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memcpy(&ctx->duplex_layers[2].info, &ctx->header.duplex_header.layers[2], sizeof(duplex_info_t));
|
||||
|
@ -1374,7 +1374,7 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!save_duplex_storage_init(&ctx->duplex_storage.layers[0], &ctx->duplex_layers[1], bitmap, ctx->header.layout.duplex_master_size))
|
||||
{
|
||||
LOGFILE("Failed to initialize duplex storage layer #0!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctx->duplex_storage.layers[0]._length = ctx->header.layout.duplex_l1_size;
|
||||
|
@ -1383,20 +1383,20 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!bitmap)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for duplex storage layer #0 bitmap!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (save_duplex_storage_read(&ctx->duplex_storage.layers[0], bitmap, 0, ctx->duplex_storage.layers[0]._length) != ctx->duplex_storage.layers[0]._length)
|
||||
{
|
||||
LOGFILE("Failed to read duplex storage layer #0 bitmap!");
|
||||
free(bitmap);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!save_duplex_storage_init(&ctx->duplex_storage.layers[1], &ctx->duplex_layers[2], bitmap, ctx->duplex_storage.layers[0]._length))
|
||||
{
|
||||
LOGFILE("Failed to initialize duplex storage layer #1!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctx->duplex_storage.layers[1]._length = ctx->header.layout.duplex_data_size;
|
||||
|
@ -1413,14 +1413,14 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!ctx->meta_remap_storage.map_entries)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for meta remap storage entries!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
fr = f_lseek(ctx->file, ctx->header.layout.meta_map_entry_offset);
|
||||
if (fr || f_tell(ctx->file) != ctx->header.layout.meta_map_entry_offset)
|
||||
{
|
||||
LOGFILE("Failed to seek to meta map entry offset 0x%lX in savefile! (%u).", ctx->header.layout.meta_map_entry_offset, fr);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for(u32 i = 0; i < ctx->meta_remap_storage.header->map_entry_count; i++)
|
||||
|
@ -1429,7 +1429,7 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (fr || br != 0x20)
|
||||
{
|
||||
LOGFILE("Failed to read meta remap storage entry #%u! (%u).", i, fr);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctx->meta_remap_storage.map_entries[i].physical_offset_end = (ctx->meta_remap_storage.map_entries[i].physical_offset + ctx->meta_remap_storage.map_entries[i].size);
|
||||
|
@ -1440,7 +1440,7 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!ctx->meta_remap_storage.segments)
|
||||
{
|
||||
LOGFILE("Failed to retrieve meta remap storage segments!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize journal map. */
|
||||
|
@ -1448,13 +1448,13 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!ctx->journal_map_info.map_storage)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for journal map info!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (save_remap_read(&ctx->meta_remap_storage, ctx->journal_map_info.map_storage, ctx->header.layout.journal_map_table_offset, ctx->header.layout.journal_map_table_size) != ctx->header.layout.journal_map_table_size)
|
||||
{
|
||||
LOGFILE("Failed to read map storage from journal map info in meta remap storage!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize journal storage. */
|
||||
|
@ -1469,7 +1469,7 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!ctx->journal_storage.map.entries)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for journal map storage entries!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
u32 *pos = (u32*)ctx->journal_storage.map.map_storage;
|
||||
|
@ -1490,7 +1490,7 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!save_ivfc_storage_init(&ctx->core_data_ivfc_storage, ctx->header.layout.ivfc_master_hash_offset_a, &ctx->header.data_ivfc_header))
|
||||
{
|
||||
LOGFILE("Failed to initialize core IVFC storage!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize FAT storage. */
|
||||
|
@ -1500,13 +1500,13 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!ctx->fat_storage)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for FAT storage!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.layout.fat_offset, ctx->header.layout.fat_size) != ctx->header.layout.fat_size)
|
||||
{
|
||||
LOGFILE("Failed to read FAT storage from meta remap storage!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
for(u32 i = 0; i < 5; i++) ctx->fat_ivfc_storage.levels[i].save_ctx = ctx;
|
||||
|
@ -1514,20 +1514,20 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!save_ivfc_storage_init(&ctx->fat_ivfc_storage, ctx->header.layout.fat_ivfc_master_hash_a, &ctx->header.fat_ivfc_header))
|
||||
{
|
||||
LOGFILE("Failed to initialize FAT storage! (IVFC).");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctx->fat_storage = calloc(1, ctx->fat_ivfc_storage._length);
|
||||
if (!ctx->fat_storage)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for FAT storage! (IVFC).");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.fat_ivfc_header.level_headers[ctx->header.fat_ivfc_header.num_levels - 2].logical_offset, ctx->fat_ivfc_storage._length) != ctx->fat_ivfc_storage._length)
|
||||
{
|
||||
LOGFILE("Failed to read FAT storage from meta remap storage! (IVFC).");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1536,7 +1536,7 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (save_filesystem_verify(ctx) == VALIDITY_INVALID)
|
||||
{
|
||||
LOGFILE("Savefile FS verification failed!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1545,12 +1545,12 @@ bool save_process(save_ctx_t *ctx)
|
|||
if (!save_filesystem_init(&ctx->save_filesystem_core, ctx->fat_storage, &ctx->header.save_header, &ctx->header.fat_header))
|
||||
{
|
||||
LOGFILE("Failed to initialize savefile FS!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
out:
|
||||
end:
|
||||
if (!success) save_free_contexts(ctx);
|
||||
|
||||
return success;
|
||||
|
@ -1741,7 +1741,7 @@ save_ctx_t *save_open_savefile(const char *path, u32 action)
|
|||
if (fr != FR_OK)
|
||||
{
|
||||
LOGFILE("Failed to open \"%s\" savefile from BIS System partition! (%u).", path, fr);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
open_savefile = true;
|
||||
|
@ -1750,7 +1750,7 @@ save_ctx_t *save_open_savefile(const char *path, u32 action)
|
|||
if (!save_ctx)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for savefile \"%s\" context!", path);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
save_ctx->file = save_fd;
|
||||
|
@ -1759,7 +1759,7 @@ save_ctx_t *save_open_savefile(const char *path, u32 action)
|
|||
success = save_process(save_ctx);
|
||||
if (!success) LOGFILE("Failed to process savefile \"%s\"!", path);
|
||||
|
||||
out:
|
||||
end:
|
||||
if (!success)
|
||||
{
|
||||
if (save_ctx)
|
||||
|
|
|
@ -146,7 +146,7 @@ bool servicesCheckInitializedServiceByName(const char *name)
|
|||
|
||||
bool ret = false;
|
||||
|
||||
if (!name || !strlen(name)) goto exit;
|
||||
if (!name || !strlen(name)) goto end;
|
||||
|
||||
size_t name_len = strlen(name);
|
||||
|
||||
|
@ -159,7 +159,7 @@ bool servicesCheckInitializedServiceByName(const char *name)
|
|||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
end:
|
||||
mutexUnlock(&g_servicesMutex);
|
||||
|
||||
return ret;
|
||||
|
|
14
source/tik.c
14
source/tik.c
|
@ -240,20 +240,20 @@ static bool tikRetrieveTicketFromEsSaveDataByRightsId(Ticket *dst, const FsRight
|
|||
if (!save_get_fat_storage_from_file_entry_by_path(save_ctx, TIK_SAVEFILE_STORAGE_PATH, &fat_storage, &ticket_bin_size))
|
||||
{
|
||||
LOGFILE("Failed to locate \"%s\" in ES %s ticket system save!", TIK_SAVEFILE_STORAGE_PATH, titlekey_type == TikTitleKeyType_Common ? "common" : "personalized");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ticket_bin_size < SIGNED_TIK_MIN_SIZE || (ticket_bin_size % SIGNED_TIK_MAX_SIZE) != 0)
|
||||
{
|
||||
LOGFILE("Invalid size for \"%s\"! (0x%lX).", TIK_SAVEFILE_STORAGE_PATH, ticket_bin_size);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ticket_bin_buf = malloc(buf_size);
|
||||
if (!ticket_bin_buf)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes block for temporary read buffer!", buf_size);
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
while(total_br < ticket_bin_size)
|
||||
|
@ -265,7 +265,7 @@ static bool tikRetrieveTicketFromEsSaveDataByRightsId(Ticket *dst, const FsRight
|
|||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes chunk at offset 0x%lX from \"%s\" in ES %s ticket system save!", buf_size, total_br, TIK_SAVEFILE_STORAGE_PATH, \
|
||||
(titlekey_type == TikTitleKeyType_Common ? "common" : "personalized"));
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
total_br += br;
|
||||
|
@ -289,20 +289,20 @@ static bool tikRetrieveTicketFromEsSaveDataByRightsId(Ticket *dst, const FsRight
|
|||
if (!found_tik)
|
||||
{
|
||||
LOGFILE("Unable to find a matching ticket entry for the provided Rights ID!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!tikGetTicketTypeAndSize(ticket_bin_buf + i, SIGNED_TIK_MAX_SIZE, &(dst->type), &(dst->size)))
|
||||
{
|
||||
LOGFILE("Unable to determine ticket type and size!");
|
||||
goto out;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memcpy(dst->data, ticket_bin_buf + i, dst->size);
|
||||
|
||||
success = true;
|
||||
|
||||
out:
|
||||
end:
|
||||
if (ticket_bin_buf) free(ticket_bin_buf);
|
||||
|
||||
if (save_ctx) save_close_savefile(save_ctx);
|
||||
|
|
36
source/usb.c
36
source/usb.c
|
@ -149,14 +149,14 @@ bool usbInitialize(void)
|
|||
if (!usbAllocateTransferBuffer())
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for the USB transfer buffer!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize USB device interface. */
|
||||
if (!usbInitializeComms())
|
||||
{
|
||||
LOGFILE("Failed to initialize USB device interface!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Retrieve USB state change kernel event. */
|
||||
|
@ -164,7 +164,7 @@ bool usbInitialize(void)
|
|||
if (!g_usbStateChangeEvent)
|
||||
{
|
||||
LOGFILE("Failed to retrieve USB state change kernel event!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Create usermode exit event. */
|
||||
|
@ -175,11 +175,11 @@ bool usbInitialize(void)
|
|||
|
||||
/* Create USB detection thread. */
|
||||
atomic_store(&g_usbDetectionThreadCreated, usbCreateDetectionThread());
|
||||
if (!atomic_load(&g_usbDetectionThreadCreated)) goto exit;
|
||||
if (!atomic_load(&g_usbDetectionThreadCreated)) goto end;
|
||||
|
||||
ret = true;
|
||||
|
||||
exit:
|
||||
end:
|
||||
rwlockWriteUnlock(&g_usbDeviceLock);
|
||||
|
||||
return ret;
|
||||
|
@ -240,7 +240,7 @@ bool usbSendFileProperties(u64 file_size, const char *filename)
|
|||
!(filename_length = (u32)strlen(filename)) || filename_length >= FS_MAX_PATH)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
usbPrepareCommandHeader(UsbCommandType_SendFileProperties, (u32)sizeof(UsbCommandSendFileProperties));
|
||||
|
@ -263,7 +263,7 @@ bool usbSendFileProperties(u64 file_size, const char *filename)
|
|||
usbLogStatusDetail(status);
|
||||
}
|
||||
|
||||
exit:
|
||||
end:
|
||||
rwlockWriteUnlock(&(g_usbDeviceInterface.lock));
|
||||
rwlockWriteUnlock(&g_usbDeviceLock);
|
||||
|
||||
|
@ -283,7 +283,7 @@ bool usbSendFileData(void *data, u64 data_size)
|
|||
!data_size || data_size > USB_TRANSFER_BUFFER_SIZE || data_size > g_usbTransferRemainingSize)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Optimization for buffers that already are page aligned. */
|
||||
|
@ -298,7 +298,7 @@ bool usbSendFileData(void *data, u64 data_size)
|
|||
if (!usbWrite(buf, data_size))
|
||||
{
|
||||
LOGFILE("Failed to write 0x%lX bytes long file data chunk!", data_size);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
|
@ -311,7 +311,7 @@ bool usbSendFileData(void *data, u64 data_size)
|
|||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes long status block!", sizeof(UsbStatus));
|
||||
ret = false;
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
cmd_status = (UsbStatus*)g_usbTransferBuffer;
|
||||
|
@ -320,14 +320,14 @@ bool usbSendFileData(void *data, u64 data_size)
|
|||
{
|
||||
LOGFILE("Invalid status block magic word!");
|
||||
ret = false;
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = (cmd_status->status == UsbStatusType_Success);
|
||||
if (!ret) usbLogStatusDetail(cmd_status->status);
|
||||
}
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (!ret) g_usbTransferRemainingSize = 0;
|
||||
|
||||
rwlockWriteUnlock(&(g_usbDeviceInterface.lock));
|
||||
|
@ -550,13 +550,13 @@ static bool usbInitializeComms(void)
|
|||
Result rc = 0;
|
||||
|
||||
bool ret = (g_usbDeviceInterfaceInitialized && g_usbDeviceInterface.initialized);
|
||||
if (ret) goto exit;
|
||||
if (ret) goto end;
|
||||
|
||||
rc = usbDsInitialize();
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInitialize failed! (0x%08X).", rc);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (hosversionAtLeast(5,0,0))
|
||||
|
@ -673,7 +673,7 @@ static bool usbInitializeComms(void)
|
|||
if (R_FAILED(rc)) LOGFILE("usbDsSetVidPidBcd failed! (0x%08X).", rc);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc)) goto exit;
|
||||
if (R_FAILED(rc)) goto end;
|
||||
|
||||
/* Initialize USB device interface. */
|
||||
rwlockWriteLock(&(g_usbDeviceInterface.lock));
|
||||
|
@ -689,7 +689,7 @@ static bool usbInitializeComms(void)
|
|||
if (!dev_iface_init)
|
||||
{
|
||||
LOGFILE("Failed to initialize USB device interface!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (hosversionAtLeast(5,0,0))
|
||||
|
@ -698,13 +698,13 @@ static bool usbInitializeComms(void)
|
|||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsEnable failed! (0x%08X).", rc);
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = g_usbDeviceInterfaceInitialized = true;
|
||||
|
||||
exit:
|
||||
end:
|
||||
if (!ret) usbCloseComms();
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -66,52 +66,52 @@ bool utilsInitializeResources(void)
|
|||
mutexLock(&g_resourcesMutex);
|
||||
|
||||
bool ret = g_resourcesInitialized;
|
||||
if (ret) goto exit;
|
||||
if (ret) goto end;
|
||||
|
||||
/* Initialize needed services. */
|
||||
if (!servicesInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize needed services!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize USB interface. */
|
||||
if (!usbInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize USB interface!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Load NCA keyset. */
|
||||
if (!keysLoadNcaKeyset())
|
||||
{
|
||||
LOGFILE("Failed to load NCA keyset!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate NCA crypto buffer. */
|
||||
if (!ncaAllocateCryptoBuffer())
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for NCA crypto buffer!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize gamecard interface. */
|
||||
if (!gamecardInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize gamecard interface!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Retrieve SD card FsFileSystem element. */
|
||||
if (!(g_sdCardFileSystem = fsdevGetDeviceFileSystem("sdmc:")))
|
||||
{
|
||||
LOGFILE("fsdevGetDeviceFileSystem failed!");
|
||||
goto exit;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Mount eMMC BIS System partition. */
|
||||
if (!utilsMountEmmcBisSystemPartitionStorage()) goto exit;
|
||||
if (!utilsMountEmmcBisSystemPartitionStorage()) goto end;
|
||||
|
||||
/* Get applet type. */
|
||||
g_programAppletType = appletGetAppletType();
|
||||
|
@ -136,7 +136,7 @@ bool utilsInitializeResources(void)
|
|||
|
||||
ret = g_resourcesInitialized = true;
|
||||
|
||||
exit:
|
||||
end:
|
||||
mutexUnlock(&g_resourcesMutex);
|
||||
|
||||
return ret;
|
||||
|
@ -210,15 +210,17 @@ void utilsWaitForButtonPress(u64 flag)
|
|||
}
|
||||
}
|
||||
|
||||
void utilsWriteLogMessage(const char *func_name, const char *fmt, ...)
|
||||
void utilsWriteMessageToLogFile(const char *func_name, const char *fmt, ...)
|
||||
{
|
||||
if (!func_name || !strlen(func_name) || !fmt || !strlen(fmt)) return;
|
||||
|
||||
mutexLock(&g_logfileMutex);
|
||||
|
||||
va_list args;
|
||||
FILE *logfile = NULL;
|
||||
|
||||
logfile = fopen(LOGFILE_PATH, "a+");
|
||||
if (!logfile) goto out;
|
||||
if (!logfile) goto end;
|
||||
|
||||
time_t now = time(NULL);
|
||||
struct tm *ts = localtime(&now);
|
||||
|
@ -232,10 +234,58 @@ void utilsWriteLogMessage(const char *func_name, const char *fmt, ...)
|
|||
fprintf(logfile, "\r\n");
|
||||
fclose(logfile);
|
||||
|
||||
out:
|
||||
end:
|
||||
mutexUnlock(&g_logfileMutex);
|
||||
}
|
||||
|
||||
void utilsWriteMessageToLogBuffer(char *dst, size_t dst_size, const char *func_name, const char *fmt, ...)
|
||||
{
|
||||
if (!dst || !dst_size || !func_name || !strlen(func_name) || !fmt || !strlen(fmt)) return;
|
||||
|
||||
va_list args;
|
||||
time_t now = time(NULL);
|
||||
struct tm *ts = localtime(&now);
|
||||
|
||||
char msg[512] = {0};
|
||||
size_t msg_len = 0, dst_len = strlen(dst);
|
||||
|
||||
snprintf(msg, sizeof(msg), "%d-%02d-%02d %02d:%02d:%02d -> %s: ", ts->tm_year + 1900, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, func_name);
|
||||
msg_len = strlen(msg);
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg + msg_len, sizeof(msg) - msg_len, fmt, args);
|
||||
va_end(args);
|
||||
msg_len = strlen(msg);
|
||||
|
||||
if ((dst_size - dst_len) > (msg_len + 2)) snprintf(dst + dst_len, dst_size - dst_len, "%s\r\n", msg);
|
||||
}
|
||||
|
||||
void utilsWriteLogBufferToLogFile(const char *src)
|
||||
{
|
||||
if (!src || !strlen(src)) return;
|
||||
|
||||
mutexLock(&g_logfileMutex);
|
||||
|
||||
FILE *logfile = fopen(LOGFILE_PATH, "a+");
|
||||
if (!logfile) goto end;
|
||||
|
||||
fprintf(logfile, "%s", src);
|
||||
fclose(logfile);
|
||||
|
||||
end:
|
||||
mutexUnlock(&g_logfileMutex);
|
||||
}
|
||||
|
||||
void utilsLogFileMutexControl(bool lock)
|
||||
{
|
||||
if (lock)
|
||||
{
|
||||
mutexLock(&g_logfileMutex);
|
||||
} else {
|
||||
mutexUnlock(&g_logfileMutex);
|
||||
}
|
||||
}
|
||||
|
||||
void utilsReplaceIllegalCharacters(char *str, bool ascii_only)
|
||||
{
|
||||
size_t strsize = 0;
|
||||
|
|
|
@ -40,12 +40,13 @@
|
|||
#define APP_BASE_PATH "sdmc:/switch/nxdumptool/"
|
||||
#define LOGFILE_PATH APP_BASE_PATH "nxdumptool.log"
|
||||
|
||||
#define LOGFILE(fmt, ...) utilsWriteLogMessage(__func__, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define MEMBER_SIZE(type, member) sizeof(((type*)NULL)->member)
|
||||
|
||||
#define MAX_ELEMENTS(x) ((sizeof((x))) / (sizeof((x)[0])))
|
||||
|
||||
#define LOGFILE(fmt, ...) utilsWriteMessageToLogFile(__func__, fmt, ##__VA_ARGS__)
|
||||
#define LOGBUF(dst, dst_size, fmt, ...) utilsWriteMessageToLogBuffer(dst, dst_size, __func__, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define ALIGN_DOWN(x, y) ((x) & ~((y) - 1))
|
||||
#define ALIGN_UP(x, y) ((((y) - 1) + (x)) & ~((y) - 1))
|
||||
#define IS_ALIGNED(x, y) (((x) & ((y) - 1)) == 0)
|
||||
|
@ -83,7 +84,10 @@ void utilsCloseResources(void);
|
|||
u64 utilsReadInput(u8 input_type);
|
||||
void utilsWaitForButtonPress(u64 flag);
|
||||
|
||||
void utilsWriteLogMessage(const char *func_name, const char *fmt, ...);
|
||||
void utilsWriteMessageToLogFile(const char *func_name, const char *fmt, ...);
|
||||
void utilsWriteMessageToLogBuffer(char *dst, size_t dst_size, const char *func_name, const char *fmt, ...);
|
||||
void utilsWriteLogBufferToLogFile(const char *src);
|
||||
void utilsLogFileMutexControl(bool lock);
|
||||
|
||||
void utilsReplaceIllegalCharacters(char *str, bool ascii_only);
|
||||
|
||||
|
|
Loading…
Reference in a new issue