|
|
@@ -14,11 +14,48 @@ |
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
*/
|
|
|
|
|
|
#include "hwinit/gfx.h"
|
|
|
#include "hwinit/list.h"
|
|
|
#include "hwinit.h"
|
|
|
#include "error.h"
|
|
|
#include "fs.h"
|
|
|
#include "package.h"
|
|
|
#include "kippatches/fs.inc"
|
|
|
|
|
|
u8 *ReadPackage1(sdmmc_storage_t *storage) {
|
|
|
u8 *pk11 = malloc(0x40000);
|
|
|
sdmmc_storage_read(storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pk11);
|
|
|
return pk11;
|
|
|
}
|
|
|
|
|
|
u8 *ReadPackage2(sdmmc_storage_t *storage) {
|
|
|
// Read GPT partition.
|
|
|
LIST_INIT(gpt);
|
|
|
sdmmc_storage_set_mmc_partition(storage, 0);
|
|
|
print("Parsing GPT...\n");
|
|
|
nx_emmc_gpt_parse(&gpt, storage);
|
|
|
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
|
|
nx_emmc_gpt_free(&gpt);
|
|
|
if (!pkg2_part) {
|
|
|
error("Failed to read GPT!\n");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
// Read Package2.
|
|
|
u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
|
|
print("Reading Package2 size...\n");
|
|
|
nx_emmc_part_read(storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp);
|
|
|
u32 *hdr = (u32 *)(tmp + 0x100);
|
|
|
u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3];
|
|
|
free(tmp);
|
|
|
u8 *pkg2 = malloc(ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE));
|
|
|
print("Reading Package2...\n");
|
|
|
u32 ret = nx_emmc_part_read(storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE) / NX_EMMC_BLOCKSIZE, pkg2);
|
|
|
sdmmc_storage_end(storage);
|
|
|
if (!ret) {
|
|
|
error("Failed to read Package2!\n");
|
|
|
return 0;
|
|
|
}
|
|
|
return pkg2;
|
|
|
}
|
|
|
|
|
|
pkg2_hdr_t *unpackFirmwarePackage(u8 *data) {
|
|
|
print("Unpacking firmware...\n");
|
|
|
@@ -189,4 +226,99 @@ void loadKip(link_t *info, char *path) { |
|
|
ki->kip1 = ckip;
|
|
|
ki->size = calcKipSize(ckip);
|
|
|
list_append(info, &ki->link);
|
|
|
}
|
|
|
|
|
|
// TODO: get full hashes somewhere and not just the first 16 bytes
|
|
|
// every second one is the exfat version
|
|
|
kippatchset_t kip_patches[] = {
|
|
|
{ "FS", "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe\x68\xdc\xb2\x0b\x41\x09\x5b\xb4", fs_kip_patches_100 },
|
|
|
{ "FS", "\xfc\x3e\x80\x99\x1d\xca\x17\x96\x4a\x12\x1f\x04\xb6\x1b\x17\x5e", fs_kip_patches_100 },
|
|
|
{ "FS", "\xcd\x7b\xbe\x18\xd6\x13\x0b\x28\xf6\x2f\x19\xfa\x79\x45\x53\x5b", fs_kip_patches_200 },
|
|
|
{ "FS", "\xe7\x66\x92\xdf\xaa\x04\x20\xe9\xfd\xd6\x8e\x43\x63\x16\x18\x18", fs_kip_patches_200 },
|
|
|
{ "FS", "\x0d\x70\x05\x62\x7b\x07\x76\x7c\x0b\x96\x3f\x9a\xff\xdd\xe5\x66", fs_kip_patches_210 },
|
|
|
{ "FS", "\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8\x30\x51\xc6\x64\xe6\x45\x2d\x32", fs_kip_patches_210 },
|
|
|
{ "FS", "\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b\x23\xda\xb5\xb4\xdb\xba\xef\xe7", fs_kip_patches_300 },
|
|
|
{ "FS", "\x98\x1c\x57\xe7\xf0\x2f\x70\xf7\xbc\xde\x75\x31\x81\xd9\x01\xa6", fs_kip_patches_300 },
|
|
|
{ "FS", "\x57\x39\x7c\x06\x3f\x10\xb6\x31\x3f\x4d\x83\x76\x53\xcc\xc3\x71", fs_kip_patches_301 },
|
|
|
{ "FS", "\x07\x30\x99\xd7\xc6\xad\x7d\x89\x83\xbc\x7a\xdd\x93\x2b\xe3\xd1", fs_kip_patches_301 },
|
|
|
{ "FS", "\x06\xe9\x07\x19\x59\x5a\x01\x0c\x62\x46\xff\x70\x94\x6f\x10\xfb", fs_kip_patches_401 },
|
|
|
{ "FS", "\x54\x9b\x0f\x8d\x6f\x72\xc4\xe9\xf3\xfd\x1f\x19\xea\xce\x4a\x5a", fs_kip_patches_401 },
|
|
|
{ "FS", "\x80\x96\xaf\x7c\x6a\x35\xaa\x82\x71\xf3\x91\x69\x95\x41\x3b\x0b", fs_kip_patches_410 },
|
|
|
{ "FS", "\x02\xd5\xab\xaa\xfd\x20\xc8\xb0\x63\x3a\xa0\xdb\xae\xe0\x37\x7e", fs_kip_patches_410 },
|
|
|
{ "FS", "\xa6\xf2\x7a\xd9\xac\x7c\x73\xad\x41\x9b\x63\xb2\x3e\x78\x5a\x0c", fs_kip_patches_500 },
|
|
|
{ "FS", "\xce\x3e\xcb\xa2\xf2\xf0\x62\xf5\x75\xf8\xf3\x60\x84\x2b\x32\xb4", fs_kip_patches_500 },
|
|
|
{ "FS", "\x76\xf8\x74\x02\xc9\x38\x7c\x0f\x0a\x2f\xab\x1b\x45\xce\xbb\x93", fs_kip_patches_510 },
|
|
|
{ "FS", "\x10\xb2\xd8\x16\x05\x48\x85\x99\xdf\x22\x42\xcb\x6b\xac\x2d\xf1", fs_kip_patches_510 },
|
|
|
{ "FS", "\x1b\x82\xcb\x22\x18\x67\xcb\x52\xc4\x4a\x86\x9e\xa9\x1a\x1a\xdd", fs_kip_patches_600 },
|
|
|
{ "FS", "\x96\x6a\xdd\x3d\x20\xb6\x27\x13\x2c\x5a\x8d\xa4\x9a\xc9\xd8\xdd", fs_kip_patches_600_exfat },
|
|
|
{ NULL, NULL, NULL },
|
|
|
};
|
|
|
|
|
|
int kippatch_apply(u8 *kipdata, u64 kipdata_len, kippatch_t *patch) {
|
|
|
if (!patch || !patch->diffs) return -1;
|
|
|
|
|
|
for (kipdiff_t *diff = patch->diffs; diff->len; ++diff) {
|
|
|
if (!diff->len || diff->offset + diff->len > kipdata_len)
|
|
|
return 1 + (int)(diff - patch->diffs);
|
|
|
u8 *start = kipdata + diff->offset;
|
|
|
if (memcmp(start, diff->orig_bytes, diff->len))
|
|
|
continue;
|
|
|
// TODO: maybe start copying after every diff has been verified?
|
|
|
memcpy(start, diff->patch_bytes, diff->len);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
int nca_patch(u8 * kipdata, u64 kipdata_len) {
|
|
|
char pattern[8] = {0xE5, 0x07, 0x00, 0x32, 0xE0, 0x03, 0x16, 0xAA};
|
|
|
char buf[0x10];
|
|
|
memcpy(buf, kipdata+0x1C450, 0x10);
|
|
|
u32 * addr = memsearch(kipdata, kipdata_len, pattern, sizeof(pattern));
|
|
|
int ret=0;
|
|
|
int max_dist = 0x10;
|
|
|
for(int i=0; i<max_dist; i++) {
|
|
|
u32 op = addr[i];
|
|
|
if((op & 0xFC000000)==0x94000000) { //is a BL op
|
|
|
addr[i] = NOP;
|
|
|
ret=1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
int kippatch_apply_set(u8 *kipdata, u64 kipdata_len, kippatchset_t *patchset) {
|
|
|
char *patchFilter[] = { "nosigchk", "nocmac", "nogc", NULL };
|
|
|
|
|
|
if (!fopen("/ReiNX/nogc", "rb")) {
|
|
|
patchFilter[2] = NULL;
|
|
|
fclose();
|
|
|
}
|
|
|
|
|
|
for (kippatch_t *p = patchset->patches; p && p->name; ++p) {
|
|
|
int found = 0;
|
|
|
for (char **filtname = patchFilter; filtname && *filtname; ++filtname) {
|
|
|
if (!strcmp(p->name, *filtname)) {
|
|
|
found = 1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (patchFilter && !found) continue;
|
|
|
|
|
|
int r = kippatch_apply(kipdata, kipdata_len, p);
|
|
|
if (r) return r;
|
|
|
}
|
|
|
if(!strncmp("FS", patchset->kip_name, 2))
|
|
|
nca_patch(kipdata, kipdata_len);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
kippatchset_t *kippatch_find_set(u8 *kiphash, kippatchset_t *patchsets) {
|
|
|
for (kippatchset_t *ps = patchsets; ps && ps->kip_name; ++ps) {
|
|
|
if (!memcmp(kiphash, ps->kip_hash, 0x10)) return ps;
|
|
|
}
|
|
|
return NULL;
|
|
|
}
|