Skip to content

Commit

Permalink
bis_storage: add menu option.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
DarkMatterCore committed Oct 28, 2024
1 parent 596928a commit 4589614
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 50 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
* 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:
* `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:
* `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:

Legend:
Expand Down
144 changes: 133 additions & 11 deletions code_templates/nxdt_rw_poc.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <core/usb.h>
#include <core/devoptab/nxdt_devoptab.h>
#include <core/system_update.h>
#include <core/bis_storage.h>

#define BLOCK_SIZE USB_TRANSFER_BUFFER_SIZE
#define WAIT_TIME_LIMIT 30
Expand Down Expand Up @@ -85,7 +86,8 @@ typedef enum {
MenuId_NcaFsSectionsSubMenu = 14,
MenuId_SystemTitles = 15,
MenuId_SystemUpdate = 16,
MenuId_Count = 17
MenuId_BrowseEmmc = 17,
MenuId_Count = 18
} MenuId;

typedef struct
Expand Down Expand Up @@ -233,8 +235,11 @@ static bool browseNintendoContentArchiveFsSection(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 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 fsBrowserDumpHighlightedEntries(const char *dir_path, const FsBrowserEntry *entries, u32 entries_count, const char *base_out_path);

Expand Down Expand Up @@ -989,12 +994,42 @@ static MenuElement *g_dumpSystemUpdateMenuElements[] = {
NULL
};

static Menu g_dumpSystemUpdateMenu = {
.id = MenuId_SystemUpdate,
.parent = NULL,
.selected = 0,
.scroll = 0,
.elements = g_dumpSystemUpdateMenuElements
static u8 g_emmcProdinfofPartition = FsBisPartitionId_CalibrationFile;
static u8 g_emmcSafePartition = FsBisPartitionId_SafeMode;
static u8 g_emmcUserPartition = FsBisPartitionId_User;
static u8 g_emmcSystemPartition = FsBisPartitionId_System;

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[] = {
Expand Down Expand Up @@ -1027,7 +1062,26 @@ static MenuElement *g_rootMenuElements[] = {
},
&(MenuElement){
.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,
.element_options = NULL,
.userdata = NULL
Expand Down Expand Up @@ -1382,7 +1436,7 @@ int main(int argc, char *argv[])
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;

Expand Down Expand Up @@ -3668,6 +3722,49 @@ static bool saveSystemUpdateDump(void *userdata)
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)
{
char dir_path[FS_MAX_PATH] = {0};
Expand Down Expand Up @@ -3701,8 +3798,13 @@ static bool fsBrowser(const char *mount_name, const char *base_out_path)
consolePrint("press + to exit\n");
consolePrint("______________________________\n\n");

consolePrint("entry: %u / %u\n", selected + 1, entries_count);
consolePrint("highlighted: %u / %u\n", highlighted, entries_count);
if (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("______________________________\n\n");

Expand Down Expand Up @@ -3957,6 +4059,9 @@ static bool fsBrowserGetDirEntries(const char *dir_path, FsBrowserEntry **out_en
goto end;
}

/* Sort entries. */
if (count > 1) qsort(entries, count, sizeof(FsBrowserEntry), &fsBrowserDirEntrySortFunction);

/* Update output pointers. */
*out_entries = entries;
*out_entry_count = count;
Expand All @@ -3972,6 +4077,23 @@ static bool fsBrowserGetDirEntries(const char *dir_path, FsBrowserEntry **out_en
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)
{
u64 free_space = 0;
Expand Down
8 changes: 4 additions & 4 deletions source/core/bis_storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ static BisStorageFatFsContext *g_bisStorageContexts[FF_VOLUMES] = {0};

/// Required by FatFs.
const char *VolumeStr[FF_VOLUMES] = {
"prodinfof",
"safe",
"user",
"system",
"PRODINFOF",
"SAFE",
"USER",
"SYSTEM",
};

/* Function prototypes. */
Expand Down
34 changes: 0 additions & 34 deletions source/core/save.c
Original file line number Diff line number Diff line change
Expand Up @@ -1738,40 +1738,6 @@ save_ctx_t *save_open_savefile(const char *path, u32 action)
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));
if (!save_ctx)
{
Expand Down

0 comments on commit 4589614

Please sign in to comment.