Skip to content

Instantly share code, notes, and snippets.

@AcK77 AcK77/dumpGamecard.js Secret
Created Mar 21, 2018

Embed
What would you like to do?
/*
Provide with the courtesy of the mob.
Ac_K.
*/
CrashFspPr = function(callback) {
if (sc.closed_pr !== undefined) return;
sc.enableTurbo();
var i = 0;
while (true) {
sc.ipcMsg(2).setType(5).sendTo('pm:shell');
var fsppr_result = sc.getService('fsp-pr');
if(fsppr_result.isOk) {
fsppr_handle = fsppr_result.getValue();
break;
}
i++;
}
utils.log('Got fsp-pr handle after ' + i + ' iterations: 0x' + fsppr_handle.toString(16));
sc.svcCloseHandle(fsppr_handle).assertOk();
sc.closed_pr = true;
if(sc.pr_handle) {
sc.svcCloseHandle(sc.pr_handle);
sc.pr_handle = undefined;
}
sc.enableTurbo();
callback();
};
HookFspLdrHandle = function(callback){
var fspldr_handle = sc.getService('fsp-ldr');
if (fspldr_handle.isOk)
{
var i = 0;
while (true) {
sc.ipcMsg(2).setType(5).sendTo('ldr:dmnt');
fspldr_handle = sc.getService('fsp-ldr');
if (fspldr_handle.isOk) break;
i++;
}
utils.log('Got fsp-ldr handle after ' + i + ' iterations: 0x' + fspldr_handle.toString(16));
fspldr_handle = fspldr_handle.assertOk();
}
callback(fspldr_handle);
};
HookFspSrvPerms = function(callback) { //by SciresM
sc.getService('fsp-pr', (fsppr_hd) => {
var pid = sc.getService('fsp-srv', (tmp_hnd) => {
utils.log('Got fsp-srv');
sc.ipcMsg(1).sendPid().data(0).sendTo(tmp_hnd).assertOk();
return 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);
/* Change to mount a particular title's romfs */
var tid = '0000000000000000';
sc.ipcMsg(256).data(0).sendTo(fsppr_hd).assertOk().show();
sc.ipcMsg(1).data(pid).sendTo(fsppr_hd).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(fsppr_hd).assertOk().show();
sc.free(buf);
sc.free(buf2);
callback();
});
};
FspSrvInit = function(callback) {
sc.getService('fsp-srv', (fspsrv_Handle) => {
sc.ipcMsg(1).sendPid().datau64(0).sendTo(fspsrv_Handle).assertOk();
utils.log("Initialized fsp-srv");
callback(fspsrv_Handle);
});
};
function buf2hex(buffer) { // buffer is an ArrayBuffer
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).reverse().join('');
}
GetGameCardTitleId = function(callback) {
sc.getService('ncm', (ncm_Handle) => {
sc.ipcMsg(11).data(2).sendTo(ncm_Handle).assertOk(); //OpenIContentMetaDatabase
var IContentMetaDatabase = sc.ipcMsg(5).data(2).sendTo(ncm_Handle).assertOk(); //GetIContentMetaDatabase
sc.withHandle(IContentMetaDatabase.movedHandles[0], (IContentMetaDatabase_Handle) => {
var TitleId = new ArrayBuffer(0x8);
sc.ipcMsg(7).data(0).bDescriptor(TitleId, 24, 0).sendTo(IContentMetaDatabase_Handle).assertOk(); //ListApplicationa
callback(buf2hex(TitleId));
});
});
};
MoundSdCard = function(fspsrv_handle, callback) { //by SciresM
var SD_IFileSystem;
try {
SD_IFileSystem = sc.ipcMsg(18).sendTo(fspsrv_handle).assertOk();
}
catch(e) {
throw new Error("Failed to open SD card. Is it inserted?");
}
utils.log("SdCard Mounted");
SD_IFileSystem.withHandles((r, m, c) => {
callback(m[0]);
});
};
IFileSystemCreateFile = function(ifs_hnd, path, size) { //by SciresM
if (size == undefined) {
size = 0x100;
}
var pbuf = utils.str2ab(path);
var res = sc.ipcMsg(0).data([0, 0], utils.trunc32(size)).xDescriptor(pbuf, pbuf.byteLength, 0).sendTo(ifs_hnd);
utils.log('Create '+path+' (size ' + size.toString(16) + ')');
res.show();
// ignore failure, it probably just means the file already existed
//res.assertOk();
};
IFileSystemWriteBufferToFile = function(f_hnd, offset, buf, sz) { //by SciresM
sc.ipcMsg(1).aDescriptor(buf, sz, 1).data([0,0], utils.pad64(offset), utils.trunc32(sz)).sendTo(f_hnd).show().assertOk();
};
IFileSystemOpenFilepenDirectory = function(ifs_hnd, path) { //by SciresM
var pbuf = utils.str2ab(path);
return sc.ipcMsg(9).datau32(3).xDescriptor(pbuf, pbuf.byteLength, 0).sendTo(ifs_hnd).asResult().map((r) => r.movedHandles[0]).getValue();
};
IFileSystemOpenFile = function(ifs_hnd, path) { //by SciresM
var pbuf = utils.str2ab(path);
utils.log('Open ' + path);
return sc.ipcMsg(8).datau32(3).xDescriptor(pbuf, pbuf.byteLength, 0).sendTo(ifs_hnd).show().asResult().map((r) => r.movedHandles[0]).getValue();
};
IFileSystemOpenReadFile = function(ifs_hnd, path) { //by SciresM
var pbuf = utils.str2ab(path);
utils.log('Open '+path+': ');
return sc.ipcMsg(8).datau32(1).xDescriptor(pbuf, pbuf.byteLength, 0).sendTo(ifs_hnd).show().asResult().map((r) => r.movedHandles[0]).getValue();
};
IFileSystemCreateDirectory = function(ifs_hnd, path) {
var pbuf = utils.str2ab(path);
var res = sc.ipcMsg(2).xDescriptor(pbuf, pbuf.byteLength, 0).sendTo(ifs_hnd);
utils.log('Create '+path+' directory');
res.show();
};
IDirectoryGetEntryCount = function (iDir_hnd) {
return sc.ipcMsg(1).sendTo(iDir_hnd).asResult().map((r) => [r.dataBuffer[0], r.dataBuffer[1]]);
};
IDirectoryGetEntries = function (iDir_hnd, buf, numEntries) {
if(buf.byteLength < 0x310 * numEntries) {
throw new Error("buffer too small");
}
return sc.ipcMsg(0).data(0).bDescriptor(buf, 0x310 * numEntries, 0).sendTo(iDir_hnd).asResult();
};
IFileGetSize = function (iFile_hnd) {
return sc.ipcMsg(4).sendTo(iFile_hnd).assertOk().data;
};
IFileRead = function (iFile_hnd, offset, buf_sz, outbuf) {
return sc.ipcMsg(0).datau64(0, offset, buf_sz).bDescriptor(outbuf, buf_sz, 1).sendTo(iFile_hnd).assertOk();
};
DumpIFileSystem = function(IFileSystem, sdcard_Handle, Partition_path) {
var IDirectory = IFileSystemOpenFilepenDirectory(IFileSystem, '/');
sc.withHandle(IDirectory, () => {
utils.log('Got IDirectory handle: 0x'+ IDirectory.toString(16));
var entryCount = utils.trunc32(IDirectoryGetEntryCount(IDirectory).assertOk());
if (entryCount > 0) {
var entryBuf = new Uint32Array(0x310 * entryCount);
IDirectoryGetEntries(IDirectory, entryBuf, entryCount).assertOk();
for (i = 0; i < entryCount; i++) {
var IFilePath = '/' + utils.u8a2nullstr(new Uint8Array(entryBuf.buffer, 0x310 * i, 0x300));
var eType = entryBuf[(0x310 * i + 0x304) >> 2];
if (eType === 1) {
var IFile = IFileSystemOpenReadFile(IFileSystem, IFilePath);
sc.withHandle(IFile, () => {
var IFileSize = IFileGetSize(IFile);
utils.log('Size: ' + IFileSize + 'bytes - ' + IFilePath);
//SciresM Code.
utils.log('size: '+utils.paddr(IFileSize));
var two_gigs = 0x80000000 >>> 0;
var outbuf = new ArrayBuffer(0x1000000);
var buf_sz = 0x1000000;
var out_path = Partition_path + IFilePath;
if ((IFileSize[1] > 0 || IFileSize[0] > two_gigs)) {
out_path = Partition_path + IFilePath + '.0';
IFileSystemCreateFile(sdcard_Handle, out_path, two_gigs);
} else {
IFileSystemCreateFile(sdcard_Handle, out_path, IFileSize);
}
var f_hnd = IFileSystemOpenFile(sdcard_Handle, out_path);
var offset = [0, 0];
var ofs_in_file = 0;
var file_num = 0;
while (offset[0] < IFileSize[0] || offset[1] < IFileSize[1]) {
if (offset[1] == IFileSize[1] && IFileSize[0] < offset[0] + buf_sz) {
buf_sz = IFileSize[0] - offset[0];
utils.log('Final block!');
}
IFileRead(IFile, offset, buf_sz, outbuf);
IFileSystemWriteBufferToFile(f_hnd, ofs_in_file, outbuf, buf_sz);
offset = utils.add2(offset, buf_sz);
utils.log('Dumped: '+utils.paddr(offset)+'/'+utils.paddr(IFileSize));
// Multi-part files.
ofs_in_file += buf_sz;
if (ofs_in_file >= two_gigs) {
sc.ipcMsg(2).sendTo(f_hnd).assertOk(); // flush
sc.svcCloseHandle(f_hnd);
file_num++;
var new_path = Partition_path + IFilePath + '.' + file_num;
if (IFileSize[1] > offset[1] || IFileSize[0] > two_gigs + offset[0]) {
IFileSystemCreateFile(sdcard_Handle, new_path, two_gigs);
} else {
IFileSystemCreateFile(sdcard_Handle, new_path, IFileSize[0] - offset[0]);
}
f_hnd = IFileSystemOpenFile(sdcard_Handle, new_path);
ofs_in_file = 0;
}
}
sc.ipcMsg(2).sendTo(f_hnd).assertOk();
sc.svcCloseHandle(f_hnd).assertOk();
});
}
}
}
});
};
//Partition 0 - Update | 1 - Normal | 2 - Secure
MountAndDumpGameCard = function(fspsrv_Handle, sdcard_Handle, TitleId) {
var Partition_ID = 2;
var Partition_Path = '/' + TitleId + '/' + Partition_ID;
IFileSystemCreateDirectory(sdcard_Handle, Partition_Path);
var OpenDeviceOperator = sc.ipcMsg(400).sendTo(fspsrv_Handle).assertOk(); //OpenDeviceOperator
sc.withHandle(OpenDeviceOperator.movedHandles[0], (OpenDeviceOperator_handle) => {
utils.log('Got OpenDeviceOperator handle: 0x'+ OpenDeviceOperator_handle.toString(16));
var GetGameCardHandle = sc.ipcMsg(202).sendTo(OpenDeviceOperator_handle).assertOk(); //GetGameCardHandle
GetGameCardHandle = GetGameCardHandle.data[0];
var IFileSystem = sc.ipcMsg(31).datau32(GetGameCardHandle, Partition_ID).sendTo(fspsrv_Handle).show(); //OpenGameCardFileSystem
sc.withHandle(IFileSystem.movedHandles[0], (IFileSystem_handle) => {
utils.log('Gamecard Mounted! Got handle: 0x'+ IFileSystem_handle.toString(16));
DumpIFileSystem(IFileSystem_handle, sdcard_Handle, Partition_Path);
});
});
};
CrashFspPr(function() {
HookFspSrvPerms(function() {
FspSrvInit(function(fspsrv_Handle) {
MoundSdCard(fspsrv_Handle, function(sdcard_Handle) {
GetGameCardTitleId(function(TitleId) {
utils.log("GameCardTitleId: " + TitleId);
IFileSystemCreateDirectory(sdcard_Handle, '/' + TitleId);
MountAndDumpGameCard(fspsrv_Handle, sdcard_Handle, TitleId);
});
});
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.