1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-10-29 23:11:45 +00:00

bis_storage: add menu option.

Makes it possible to browse eMMC partitions and dump data from them.

Since we're manually parsing FAT partitions, reading files protected by the FS sysmodule at runtime is possible.
This commit is contained in:
Pablo Curiel 2024-10-28 15:44:31 +01:00
parent 596928a3c6
commit 4589614183
4 changed files with 138 additions and 50 deletions

View file

@ -37,8 +37,8 @@ Currently planned changes for this branch include:
* Control.nacp patching while dumping NSPs (lets you patch screenshot, video, user account and HDCP restrictions). :white_check_mark: * Control.nacp patching while dumping NSPs (lets you patch screenshot, video, user account and HDCP restrictions). :white_check_mark:
* Partition FS / Hash FS / RomFS browser using custom devoptab wrappers. :white_check_mark: * Partition FS / Hash FS / RomFS browser using custom devoptab wrappers. :white_check_mark:
* Full system update dumps with checksum and signature verification. :white_check_mark: * Full system update dumps with checksum and signature verification. :white_check_mark:
* `FsStorage` + `FatFs` based eMMC browser using a custom devoptab wrapper (allows copying files protected by the FS sysmodule at runtime). :white_check_mark:
* Batch NSP dumps. :x: * Batch NSP dumps. :x:
* `FsFileSystem` + `FatFs` based eMMC browser using a custom devoptab wrapper (allows copying files protected by the FS sysmodule at runtime). :x:
* New UI using a [customized borealis fork](https://github.com/DarkMatterCore/borealis/tree/nxdumptool-legacy). :warning: * New UI using a [customized borealis fork](https://github.com/DarkMatterCore/borealis/tree/nxdumptool-legacy). :warning:
Legend: Legend:

View file

@ -30,6 +30,7 @@
#include <core/usb.h> #include <core/usb.h>
#include <core/devoptab/nxdt_devoptab.h> #include <core/devoptab/nxdt_devoptab.h>
#include <core/system_update.h> #include <core/system_update.h>
#include <core/bis_storage.h>
#define BLOCK_SIZE USB_TRANSFER_BUFFER_SIZE #define BLOCK_SIZE USB_TRANSFER_BUFFER_SIZE
#define WAIT_TIME_LIMIT 30 #define WAIT_TIME_LIMIT 30
@ -85,7 +86,8 @@ typedef enum {
MenuId_NcaFsSectionsSubMenu = 14, MenuId_NcaFsSectionsSubMenu = 14,
MenuId_SystemTitles = 15, MenuId_SystemTitles = 15,
MenuId_SystemUpdate = 16, MenuId_SystemUpdate = 16,
MenuId_Count = 17 MenuId_BrowseEmmc = 17,
MenuId_Count = 18
} MenuId; } MenuId;
typedef struct typedef struct
@ -233,8 +235,11 @@ static bool browseNintendoContentArchiveFsSection(void *userdata);
static bool saveSystemUpdateDump(void *userdata); static bool saveSystemUpdateDump(void *userdata);
static bool browseEmmcPartition(void *userdata);
static bool fsBrowser(const char *mount_name, const char *base_out_path); static bool fsBrowser(const char *mount_name, const char *base_out_path);
static bool fsBrowserGetDirEntries(const char *dir_path, FsBrowserEntry **out_entries, u32 *out_entry_count); static bool fsBrowserGetDirEntries(const char *dir_path, FsBrowserEntry **out_entries, u32 *out_entry_count);
static int fsBrowserDirEntrySortFunction(const void *a, const void *b);
static bool fsBrowserDumpFile(const char *dir_path, const FsBrowserEntry *entry, const char *base_out_path); static bool fsBrowserDumpFile(const char *dir_path, const FsBrowserEntry *entry, const char *base_out_path);
static bool fsBrowserDumpHighlightedEntries(const char *dir_path, const FsBrowserEntry *entries, u32 entries_count, const char *base_out_path); static bool fsBrowserDumpHighlightedEntries(const char *dir_path, const FsBrowserEntry *entries, u32 entries_count, const char *base_out_path);
@ -989,12 +994,42 @@ static MenuElement *g_dumpSystemUpdateMenuElements[] = {
NULL NULL
}; };
static Menu g_dumpSystemUpdateMenu = { static u8 g_emmcProdinfofPartition = FsBisPartitionId_CalibrationFile;
.id = MenuId_SystemUpdate, static u8 g_emmcSafePartition = FsBisPartitionId_SafeMode;
.parent = NULL, static u8 g_emmcUserPartition = FsBisPartitionId_User;
.selected = 0, static u8 g_emmcSystemPartition = FsBisPartitionId_System;
.scroll = 0,
.elements = g_dumpSystemUpdateMenuElements static MenuElement *g_emmcBrowseMenuElements[] = {
&(MenuElement){
.str = "browse prodinfof emmc partition",
.child_menu = NULL,
.task_func = &browseEmmcPartition,
.element_options = NULL,
.userdata = &g_emmcProdinfofPartition
},
&(MenuElement){
.str = "browse safe emmc partition",
.child_menu = NULL,
.task_func = &browseEmmcPartition,
.element_options = NULL,
.userdata = &g_emmcSafePartition
},
&(MenuElement){
.str = "browse user emmc partition",
.child_menu = NULL,
.task_func = &browseEmmcPartition,
.element_options = NULL,
.userdata = &g_emmcUserPartition
},
&(MenuElement){
.str = "browse system mmc partition",
.child_menu = NULL,
.task_func = &browseEmmcPartition,
.element_options = NULL,
.userdata = &g_emmcSystemPartition
},
&g_storageMenuElement,
NULL
}; };
static MenuElement *g_rootMenuElements[] = { static MenuElement *g_rootMenuElements[] = {
@ -1027,7 +1062,26 @@ static MenuElement *g_rootMenuElements[] = {
}, },
&(MenuElement){ &(MenuElement){
.str = "dump system update", .str = "dump system update",
.child_menu = &g_dumpSystemUpdateMenu, .child_menu = &(Menu){
.id = MenuId_SystemUpdate,
.parent = NULL,
.selected = 0,
.scroll = 0,
.elements = g_dumpSystemUpdateMenuElements
},
.task_func = NULL,
.element_options = NULL,
.userdata = NULL
},
&(MenuElement){
.str = "browse emmc partitions",
.child_menu = &(Menu){
.id = MenuId_BrowseEmmc,
.parent = NULL,
.selected = 0,
.scroll = 0,
.elements = g_emmcBrowseMenuElements
},
.task_func = NULL, .task_func = NULL,
.element_options = NULL, .element_options = NULL,
.userdata = NULL .userdata = NULL
@ -1382,7 +1436,7 @@ int main(int argc, char *argv[])
break; break;
} }
if ((cur_menu->id == MenuId_NcaFsSectionsSubMenu && cur_menu->selected == 1) || cur_menu->id == MenuId_BrowseHFS) if ((cur_menu->id == MenuId_NcaFsSectionsSubMenu && cur_menu->selected == 1) || cur_menu->id == MenuId_BrowseHFS || cur_menu->id == MenuId_BrowseEmmc)
{ {
show_button_prompt = false; show_button_prompt = false;
@ -3668,6 +3722,49 @@ end:
return success; return success;
} }
static bool browseEmmcPartition(void *userdata)
{
u8 bis_partition_id = (userdata ? *((u8*)userdata) : 0);
const char *mount_name = NULL;
char *base_out_path = NULL;
bool success = false;
if (bis_partition_id < FsBisPartitionId_CalibrationFile || bis_partition_id > FsBisPartitionId_System)
{
consolePrint("invalid bis partition id! (%u)\n", bis_partition_id);
goto end;
}
/* Mount BIS partition. */
if (!bisStorageMountPartition(bis_partition_id, &mount_name))
{
consolePrint("failed to mount bis partition %u!\n", bis_partition_id);
goto end;
}
/* Generate output base path. */
base_out_path = generateOutputGameCardFileName(utilsGetAtmosphereEmummcStatus() ? "emuMMC" : "sysMMC", mount_name, false);
if (!base_out_path) goto end;
/* Display file browser. */
success = fsBrowser(mount_name, base_out_path);
end:
/* Free data. */
if (base_out_path) free(base_out_path);
if (mount_name) bisStorageUnmountPartition(bis_partition_id);
if (!success && g_appletStatus)
{
consolePrint("press any button to continue\n");
utilsWaitForButtonPress(0);
}
return success;
}
static bool fsBrowser(const char *mount_name, const char *base_out_path) static bool fsBrowser(const char *mount_name, const char *base_out_path)
{ {
char dir_path[FS_MAX_PATH] = {0}; char dir_path[FS_MAX_PATH] = {0};
@ -3701,8 +3798,13 @@ static bool fsBrowser(const char *mount_name, const char *base_out_path)
consolePrint("press + to exit\n"); consolePrint("press + to exit\n");
consolePrint("______________________________\n\n"); consolePrint("______________________________\n\n");
consolePrint("entry: %u / %u\n", selected + 1, entries_count); if (entries_count)
consolePrint("highlighted: %u / %u\n", highlighted, entries_count); {
consolePrint("entry: %u / %u\n", selected + 1, entries_count);
consolePrint("highlighted: %u / %u\n", highlighted, entries_count);
consolePrint("selected: %s\n", entries[selected].dt.d_name);
}
consolePrint("current path: %s\n", dir_path); consolePrint("current path: %s\n", dir_path);
consolePrint("______________________________\n\n"); consolePrint("______________________________\n\n");
@ -3957,6 +4059,9 @@ static bool fsBrowserGetDirEntries(const char *dir_path, FsBrowserEntry **out_en
goto end; goto end;
} }
/* Sort entries. */
if (count > 1) qsort(entries, count, sizeof(FsBrowserEntry), &fsBrowserDirEntrySortFunction);
/* Update output pointers. */ /* Update output pointers. */
*out_entries = entries; *out_entries = entries;
*out_entry_count = count; *out_entry_count = count;
@ -3972,6 +4077,23 @@ end:
return success; return success;
} }
static int fsBrowserDirEntrySortFunction(const void *a, const void *b)
{
const FsBrowserEntry *entry_1 = (const FsBrowserEntry*)a;
const FsBrowserEntry *entry_2 = (const FsBrowserEntry*)b;
if (entry_1->dt.d_type < entry_2->dt.d_type)
{
return -1;
} else
if (entry_1->dt.d_type > entry_2->dt.d_type)
{
return 1;
}
return strcasecmp(entry_1->dt.d_name, entry_2->dt.d_name);
}
static bool fsBrowserDumpFile(const char *dir_path, const FsBrowserEntry *entry, const char *base_out_path) static bool fsBrowserDumpFile(const char *dir_path, const FsBrowserEntry *entry, const char *base_out_path)
{ {
u64 free_space = 0; u64 free_space = 0;

View file

@ -43,10 +43,10 @@ static BisStorageFatFsContext *g_bisStorageContexts[FF_VOLUMES] = {0};
/// Required by FatFs. /// Required by FatFs.
const char *VolumeStr[FF_VOLUMES] = { const char *VolumeStr[FF_VOLUMES] = {
"prodinfof", "PRODINFOF",
"safe", "SAFE",
"user", "USER",
"system", "SYSTEM",
}; };
/* Function prototypes. */ /* Function prototypes. */

View file

@ -1738,40 +1738,6 @@ save_ctx_t *save_open_savefile(const char *path, u32 action)
goto end; goto end;
} }
/* Code to dump the requested file in its entirety. Useful to retrieve protected system savefiles without exiting HOS. */
/*char sd_path[FS_MAX_PATH] = {0};
snprintf(sd_path, MAX_ELEMENTS(sd_path), DEVOPTAB_SDMC_DEVICE "/%s", strrchr(path, '/') + 1);
utilsCreateDirectoryTree(sd_path, false);
u64 blksize = 0x100000;
u8 *buf = malloc(blksize);
FILE *sd_fp = fopen(sd_path, "wb");
if (buf && sd_fp)
{
fseek(save_fp, 0, SEEK_END);
u64 size = ftell(save_fp);
rewind(save_fp);
for(u64 offset = 0; offset < size; offset += blksize)
{
if ((size - offset) < blksize) blksize = (size - offset);
if (fread(buf, 1, blksize, save_fp) != blksize) break;
fwrite(buf, 1, blksize, sd_fp);
}
rewind(save_fp);
}
if (sd_fp)
{
fclose(sd_fp);
utilsCommitSdCardFileSystemChanges();
}
if (buf) free(buf);*/
save_ctx = calloc(1, sizeof(save_ctx_t)); save_ctx = calloc(1, sizeof(save_ctx_t));
if (!save_ctx) if (!save_ctx)
{ {