Skip to content

Instantly share code, notes, and snippets.

@Reisyukaku
Last active May 11, 2023 16:38
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Reisyukaku/dba796a54d2c92e2c356153a418ca034 to your computer and use it in GitHub Desktop.
Save Reisyukaku/dba796a54d2c92e2c356153a418ca034 to your computer and use it in GitHub Desktop.
Write Save
/*
* 1. Boot game
* 2. Wait a second or so (for the game tid to register but before the code mounts the savedata)
* 3. Home button
* 4. Run this script
* 5. ???
* 6. PROFIT
*/
var tid = '0000000000000000'; //Change Title ID here
utils.log("stage1, hijack fsppr and set perms");
sc.getFSPPR();
sc.ipcMsg(1).sendPid().data(0).sendTo('fsp-srv').assertOk();
var pid = sc.read4(sc.ipcBufAddr, 0xC >> 2);
utils.log('Got process PID: '+pid.toString(16));
var buf1_sz = 0x1C;
var buf2_sz = 0x2C;
var buf = sc.malloc(buf1_sz + buf2_sz);
var buf2 = utils.add2(buf, buf1_sz);
//buffer init
sc.write4(1, buf, 0x0>>2);
sc.write8([0xFFFFFFFF, 0xFFFFFFFF], buf, 0x4 >> 2); //This is the permissions value.
sc.write4(buf1_sz, buf, 0xC >> 2);
sc.write4(buf1_sz, buf, 0x14 >> 2);
sc.write4(1, buf2, 0x0 >> 2);
sc.write8([0xFFFFFFFF, 0xFFFFFFFF], buf2, 0x4 >> 2); //This is the permissions value -- actual perms = buf2_val & buf1_val
sc.write4(0xFFFFFFFF, buf2, 0x14 >> 2);
sc.write4(0xFFFFFFFF, buf2, 0x18 >> 2);
sc.write4(0xFFFFFFFF, buf2, 0x24 >> 2);
sc.write4(0xFFFFFFFF, buf2, 0x28 >> 2);
sc.ipcMsg(256).data(0).sendTo('fsp-pr').assertOk().show();
sc.ipcMsg(1).data(pid).sendTo('fsp-pr').assertOk().show();
sc.ipcMsg(0).data(2, [pid,0], utils.parseAddr(tid), buf1_sz, buf2_sz, pid, pid, 0, 0, 0, 0, 0).aDescriptor(buf, buf1_sz).aDescriptor(buf2, buf2_sz).sendTo('fsp-pr').assertOk().show();
sc.free(buf);
sc.free(buf2);
utils.log("stage2, open save data");
utils.log("GetLastUserProfile");
res = sc.ipcMsg(4).sendTo('acc:u1').assertOk();
var userID = res.data;
utils.log('MountSaveData');
res = sc.ipcMsg(51).datau64(1, utils.parseAddr(tid), [userID[0], userID[1]], [userID[2], userID[3]], [0,0], 1, 0, 0, 0).sendTo('fsp-srv').assertOk();
copyFiles = function(saveDir, sdDir){
var entryCount = utils.trunc32(sdDir.GetEntryCount().assertOk());
if (entryCount > 0) {
var entryBuf = new Uint32Array(0x310 * entryCount);
sdDir.GetEntries(entryBuf, entryCount).assertOk();
for (i = 0; i < entryCount; i++) {
var fn = utils.u8a2nullstr(new Uint8Array(entryBuf.buffer, 0x310 * i, 0x300));
var eType = entryBuf[(0x310 * i + 0x304) >> 2];
if (eType === 1) {
//files
utils.log('[Writing file] ' + sdDir.path + fn + ' -> ' + saveDir.path + fn);
var fp = saveDir.fs.OpenFile(saveDir.path + fn).assertOk();
var fp_sd = sdDir.fs.OpenFile(sdDir.path + fn).assertOk();
try {
var size = fp_sd.GetSize().assertOk();
var buf = fp_sd.Read(size).assertOk();
fp.Write(0, buf, size).assertOk();
utils.log('Wrote ' + size + ' bytes');
} finally {
fp.Close();
fp_sd.Close();
}
} else {
//folders
utils.log('[Opening folder] '+fn);
var f = saveDir.fs.OpenDir(saveDir.path + fn + '/').assertOk();
var f_sd = sdDir.fs.OpenDir(sdDir.path + fn + '/').assertOk();
try {
copyFiles(f, f_sd);
} finally {
f.Close();
f_sd.Close();
}
}
}
}
};
sc.withHandle(res.movedHandles[0], (ifile) => {
utils.log("Mounting SD card");
try {
var sd_mnt = sc.ipcMsg(18).sendTo('fsp-srv').assertOk();
} catch(e) {
throw new Error("Failed to open SD card. Is it inserted?");
}
sd_mnt.withHandles((r, m, c) => {
var fs = new sc.IFileSystem(sc, ifile);
var fs_sd = new sc.IFileSystem(sc, m[0]);
var dir = fs.OpenDir('/').assertOk();
var dir_sd = fs_sd.OpenDir('/Saves/'+tid+'/').assertOk();
try{
copyFiles(dir, dir_sd);
} finally {
dir.Close();
dir_sd.Close();
}
utils.log('Closing file systems');
fs.Commit();
fs.Close();
fs_sd.Close();
});
});
@RyuSeisuke1992
Copy link

I always get this mistake:
ERROR: [15, 'sc.getFSPPR is not a function. (In \ 'sc.getFSPPR()\', \ 'sc.getFSPPR\' is undefined)' ]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment