diff --git a/bootloader/hos/pkg2.c b/bootloader/hos/pkg2.c index 3783b8d..4e514ee 100644 --- a/bootloader/hos/pkg2.c +++ b/bootloader/hos/pkg2.c @@ -19,6 +19,8 @@ #include #include "pkg2.h" +#include "pkg2_ini_kippatch.h" + #include "../config/config.h" #include "../libs/fatfs/ff.h" #include "../utils/aarch64_util.h" @@ -30,7 +32,7 @@ #include "../gfx/gfx.h" extern hekate_config h_cfg; - +extern void *sd_file_read(const char *path, u32 *fsize); #ifdef KIP1_PATCH_DEBUG #include "../utils/util.h" @@ -334,88 +336,41 @@ static kip1_patch_t _fs_emummc[] = { 0, 0, NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_100[] = -{ - { KPS(KIP_TEXT) | 0x194A0, 4, "\xBA\x09\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0x3A79C, 4, "\xE0\x06\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patchset_t _fs_patches_100[] = { - { "nosigchk", _fs_nosigchk_100 }, { "nogc", NULL }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_200[] = -{ - { KPS(KIP_TEXT) | 0x15DF4, 4, "\xBC\x0A\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0x3F720, 4, "\x00\x06\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patchset_t _fs_patches_200[] = { - { "nosigchk", _fs_nosigchk_200 }, { "nogc", NULL }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_210[] = -{ - { KPS(KIP_TEXT) | 0x15F64, 4, "\xDF\x0A\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0x3FAF8, 4, "\x00\x06\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patchset_t _fs_patches_210[] = { - { "nosigchk", _fs_nosigchk_210 }, { "nogc", NULL }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_300[] = -{ - { KPS(KIP_TEXT) | 0x18E24, 4, "\x52\x0C\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0x49EC8, 4, "\x40\x04\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patchset_t _fs_patches_300[] = { - { "nosigchk", _fs_nosigchk_300 }, { "nogc", NULL }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_30x[] = -{ - { KPS(KIP_TEXT) | 0x18E90, 4, "\x52\x0C\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0x49F34, 4, "\xE0\x03\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patchset_t _fs_patches_30x[] = { - { "nosigchk", _fs_nosigchk_30x }, { "nogc", NULL }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_4xx[] = -{ - { KPS(KIP_TEXT) | 0x1C4FC, 4, "\x3C\x2F\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0x57934, 4, "\xE0\x02\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patch_t _fs_nogc_40x[] = { { KPS(KIP_TEXT) | 0xA3458, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" }, @@ -425,7 +380,6 @@ static kip1_patch_t _fs_nogc_40x[] = static kip1_patchset_t _fs_patches_40x[] = { - { "nosigchk", _fs_nosigchk_4xx }, { "nogc", _fs_nogc_40x }, { "emummc", _fs_emummc }, { NULL, NULL } @@ -440,19 +394,11 @@ static kip1_patch_t _fs_nogc_410[] = static kip1_patchset_t _fs_patches_410[] = { - { "nosigchk", _fs_nosigchk_4xx }, { "nogc", _fs_nogc_410 }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_50x[] = -{ - { KPS(KIP_TEXT) | 0x22DDC, 4, "\x7D\x3E\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0x7D490, 4, "\x40\x03\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patch_t _fs_nogc_50x[] = { { KPS(KIP_TEXT) | 0xCF3C4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, @@ -462,19 +408,11 @@ static kip1_patch_t _fs_nogc_50x[] = static kip1_patchset_t _fs_patches_50x[] = { - { "nosigchk", _fs_nosigchk_50x }, { "nogc", _fs_nogc_50x }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_510[] = -{ - { KPS(KIP_TEXT) | 0x22E0C, 4, "\x85\x3E\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0x7D860, 4, "\x40\x03\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patch_t _fs_nogc_510[] = { { KPS(KIP_TEXT) | 0xCF794, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, @@ -484,26 +422,11 @@ static kip1_patch_t _fs_nogc_510[] = static kip1_patchset_t _fs_patches_510[] = { - { "nosigchk", _fs_nosigchk_510 }, { "nogc", _fs_nogc_510 }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_600[] = -{ - { KPS(KIP_TEXT) | 0x712A8, 4, "\x8E\x3E\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0xEB08C, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patch_t _fs_nosigchk_600_exfat[] = -{ - { KPS(KIP_TEXT) | 0x7C9A8, 4, "\x8E\x3E\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0xF678C, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patch_t _fs_nogc_600[] = { { KPS(KIP_TEXT) | 0x12CC20, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, @@ -520,7 +443,6 @@ static kip1_patch_t _fs_nogc_600_exfat[] = static kip1_patchset_t _fs_patches_600[] = { - { "nosigchk", _fs_nosigchk_600 }, { "nogc", _fs_nogc_600 }, { "emummc", _fs_emummc }, { NULL, NULL } @@ -528,26 +450,11 @@ static kip1_patchset_t _fs_patches_600[] = static kip1_patchset_t _fs_patches_600_exfat[] = { - { "nosigchk", _fs_nosigchk_600_exfat }, { "nogc", _fs_nogc_600_exfat }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_700[] = -{ - { KPS(KIP_TEXT) | 0x74A2C, 4, "\x31\x43\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0xF25E4, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patch_t _fs_nosigchk_700_exfat[] = -{ - { KPS(KIP_TEXT) | 0x7FFDC, 4, "\x31\x43\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0xFDB94, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patch_t _fs_nogc_700[] = { { KPS(KIP_TEXT) | 0x134160, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, @@ -564,7 +471,6 @@ static kip1_patch_t _fs_nogc_700_exfat[] = static kip1_patchset_t _fs_patches_700[] = { - { "nosigchk", _fs_nosigchk_700 }, { "nogc", _fs_nogc_700 }, { "emummc", _fs_emummc }, { NULL, NULL } @@ -572,26 +478,11 @@ static kip1_patchset_t _fs_patches_700[] = static kip1_patchset_t _fs_patches_700_exfat[] = { - { "nosigchk", _fs_nosigchk_700_exfat }, { "nogc", _fs_nogc_700_exfat }, { "emummc", _fs_emummc }, { NULL, NULL } }; -static kip1_patch_t _fs_nosigchk_800[] = -{ - { KPS(KIP_TEXT) | 0x7630C, 4, "\x51\x44\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0xF49A4, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patch_t _fs_nosigchk_800_exfat[] = -{ - { KPS(KIP_TEXT) | 0x818BC, 4, "\x51\x44\x00\x94", "\xE0\x03\x1F\x2A" }, - { KPS(KIP_TEXT) | 0xFFF54, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" }, - { 0, 0, NULL, NULL } -}; - static kip1_patch_t _fs_nogc_800[] = { { KPS(KIP_TEXT) | 0x136800, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, @@ -608,7 +499,6 @@ static kip1_patch_t _fs_nogc_800_exfat[] = static kip1_patchset_t _fs_patches_800[] = { - { "nosigchk", _fs_nosigchk_800 }, { "nogc", _fs_nogc_800 }, { "emummc", _fs_emummc }, { NULL, NULL } @@ -616,7 +506,6 @@ static kip1_patchset_t _fs_patches_800[] = static kip1_patchset_t _fs_patches_800_exfat[] = { - { "nosigchk", _fs_nosigchk_800_exfat }, { "nogc", _fs_nogc_800_exfat }, { "emummc", _fs_emummc }, { NULL, NULL } @@ -655,6 +544,82 @@ static kip1_id_t _kip_ids[] = { "FS", "\xB4\xCA\xE1\xF2\x49\x65\xD9\x2E", _fs_patches_800_exfat } // FS 8.1.0 exfat }; +static void parse_external_kip_patches() +{ + u32 curr_kip_idx = 0; + LIST_INIT(ini_kip_sections); + if (ini_patch_parse(&ini_kip_sections, "bootloader/patches.ini")) + { + // Parse patchsets and glue them together. + LIST_FOREACH_ENTRY(ini_kip_sec_t, ini_psec, &ini_kip_sections, link) + { + kip1_id_t* curr_kip = &_kip_ids[curr_kip_idx]; + + if (!strcmp(curr_kip->name, ini_psec->name) && !memcmp(curr_kip->hash, ini_psec->hash, 8)) + { + kip1_patchset_t *patchsets = (kip1_patchset_t *)calloc(sizeof(kip1_patchset_t), 8); + + u32 curr_patchset_idx; + for(curr_patchset_idx = 0; curr_kip->patchset[curr_patchset_idx].name != NULL; curr_patchset_idx++) + { + patchsets[curr_patchset_idx].name = curr_kip->patchset[curr_patchset_idx].name; + patchsets[curr_patchset_idx].patches = curr_kip->patchset[curr_patchset_idx].patches; + } + + curr_kip->patchset = patchsets; + bool first_ext_patch = true; + u32 curr_patch_idx = 0; + + // Parse patches and glue them together to a patchset. + kip1_patch_t *patches = calloc(sizeof(kip1_patch_t), 16); + LIST_FOREACH_ENTRY(ini_patchset_t, pt, &ini_psec->pts, link) + { + if (first_ext_patch) + { + first_ext_patch = false; + patchsets[curr_patchset_idx].name = malloc(strlen(pt->name) + 1); + strcpy(patchsets[curr_patchset_idx].name, pt->name); + patchsets[curr_patchset_idx].patches = patches; + } + else + { + if (strcmp(pt->name, patchsets[curr_patchset_idx].name)) + { + curr_patchset_idx++; + curr_patch_idx = 0; + patches = calloc(sizeof(kip1_patch_t), 16); + + patchsets[curr_patchset_idx].name = malloc(strlen(pt->name) + 1); + strcpy(patchsets[curr_patchset_idx].name, pt->name); + patchsets[curr_patchset_idx].patches = patches; + } + } + + if (pt->length) + { + patches[curr_patch_idx].offset = pt->offset; + patches[curr_patch_idx].length = pt->length; + + patches[curr_patch_idx].srcData = malloc(pt->length); + patches[curr_patch_idx].dstData = malloc(pt->length); + memcpy(patches[curr_patch_idx].srcData, pt->srcData, pt->length); + memcpy(patches[curr_patch_idx].dstData, pt->dstData, pt->length); + } + + curr_patch_idx++; + } + curr_patchset_idx++; + patchsets[curr_patchset_idx].name = NULL; + patchsets[curr_patchset_idx].patches = NULL; + } + + curr_kip_idx++; + if (!(curr_kip_idx < (sizeof(_kip_ids) / sizeof(_kip_ids[0])))) + break; + } + } +} + const pkg2_kernel_id_t *pkg2_identify(u8 *hash) { for (u32 i = 0; i < (sizeof(_pkg2_kernel_ids) / sizeof(pkg2_kernel_id_t)); i++) @@ -872,11 +837,19 @@ static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info return 1; } +static bool ext_patches_parsed = false; + const char* pkg2_patch_kips(link_t *info, char* patchNames) { if (patchNames == NULL || patchNames[0] == 0) return NULL; + if (!ext_patches_parsed) + { + parse_external_kip_patches(); + ext_patches_parsed = true; + } + static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32) * 8; char* patches[MAX_NUM_PATCHES_REQUESTED]; diff --git a/bootloader/hos/pkg2.h b/bootloader/hos/pkg2.h index fe98d2d..cf0bdc8 100644 --- a/bootloader/hos/pkg2.h +++ b/bootloader/hos/pkg2.h @@ -122,13 +122,13 @@ typedef struct _kip1_patch_t { u32 offset; // section+offset of patch to apply. u32 length; // In bytes, 0 means last patch. - const char* srcData; // That must match. - const char* dstData; // That it gets replaced by. + char* srcData; // That must match. + char* dstData; // That it gets replaced by. } kip1_patch_t; typedef struct _kip1_patchset_t { - const char* name; // NULL means end. + char* name; // NULL means end. kip1_patch_t* patches; // NULL means not necessary. } kip1_patchset_t; diff --git a/bootloader/hos/pkg2_ini_kippatch.c b/bootloader/hos/pkg2_ini_kippatch.c new file mode 100644 index 0000000..b71b06a --- /dev/null +++ b/bootloader/hos/pkg2_ini_kippatch.c @@ -0,0 +1,165 @@ +#include +#include + +#include "pkg2_ini_kippatch.h" +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" + +#define KPS(x) ((u32)(x) << 29) + +static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len) +{ + char ch = *ptr; + u32 ascii_len = byte_len * 2; + if (!result) + result = malloc(byte_len); + u8 *dst = result; + + while (ch == ' ' || ch == '\t') + ch = *(++ptr); + + bool shift = true; + while (ascii_len) + { + u8 tmp = 0; + if (ch >= '0' && ch <= '9') + tmp = (ch - '0'); + else if (ch >= 'A' && ch <= 'F') + tmp = (ch - 'A' + 10); + else if (ch >= 'a' && ch <= 'f') + tmp = (ch - 'a' + 10); + + if (shift) + *dst = (tmp << 4) & 0xF0; + else + { + *dst |= (tmp & 0x0F); + dst++; + } + + ascii_len--; + ch = *(++ptr); + shift = !shift; + } + + return result; +} + +static char *_strdup(char *str) +{ + if (!str) + return NULL; + if (str[0] == ' ' && (strlen(str) > 1)) + str++; + char *res = (char *)malloc(strlen(str) + 1); + strcpy(res, str); + if (res[strlen(res) - 1] == ' ' && (strlen(res) > 1)) + res[strlen(res) - 1] = 0; + + return res; +} + +static u32 _find_patch_section_name(char *lbuf, u32 lblen, char schar) +{ + u32 i; + for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++) + ; + lbuf[i] = 0; + + return i; +} + +static ini_kip_sec_t *_ini_create_kip_section(link_t *dst, ini_kip_sec_t *ksec, char *name) +{ + if (ksec) + { + list_append(dst, &ksec->link); + ksec = NULL; + } + + ksec = (ini_kip_sec_t *)malloc(sizeof(ini_kip_sec_t)); + u32 i = _find_patch_section_name(name, strlen(name), ':') + 1; + ksec->name = _strdup(name); + + // Get hash section. + _htoa(ksec->hash, &name[i], 8); + + return ksec; +} + +int ini_patch_parse(link_t *dst, char *ini_path) +{ + u32 lblen; + char lbuf[512]; + FIL fp; + ini_kip_sec_t *ksec = NULL; + + // Open ini. + if (f_open(&fp, ini_path, FA_READ) != FR_OK) + return 0; + + do + { + // Fetch one line. + lbuf[0] = 0; + f_gets(lbuf, 512, &fp); + lblen = strlen(lbuf); + + // Remove trailing newline. + if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r') + lbuf[lblen - 1] = 0; + + if (lblen > 2 && lbuf[0] == '[') // Create new section. + { + _find_patch_section_name(lbuf, lblen, ']'); + + ksec = _ini_create_kip_section(dst, ksec, &lbuf[1]); + list_init(&ksec->pts); + } + else if (ksec && lbuf[0] == '.') //Extract key/value. + { + u32 tmp = 0; + u32 i = _find_patch_section_name(lbuf, lblen, '='); + + ini_patchset_t *pt = (ini_patchset_t *)malloc(sizeof(ini_patchset_t)); + + pt->name = _strdup(&lbuf[1]); + + u8 kip_sidx = lbuf[i + 1] - '0'; + + if (kip_sidx < 6) + { + pt->offset = KPS(kip_sidx); + tmp = _find_patch_section_name(&lbuf[i + 3], lblen, ':'); + pt->offset |= strtol(&lbuf[i + 3], NULL, 16); + + i += tmp + 4; + + tmp = _find_patch_section_name(&lbuf[i], lblen, ':'); + pt->length = strtol(&lbuf[i], NULL, 16); + + i += tmp + 1; + + tmp = _find_patch_section_name(&lbuf[i], lblen, ','); + pt->srcData = _htoa(NULL, &lbuf[i], pt->length); + i += tmp + 1; + pt->dstData = _htoa(NULL, &lbuf[i], pt->length); + } + else + { + pt->offset = 0; + pt->length = 0; + pt->srcData = NULL; + pt->dstData = NULL; + } + list_append(&ksec->pts, &pt->link); + } + } while (!f_eof(&fp)); + + f_close(&fp); + + if (ksec) + list_append(dst, &ksec->link); + + return 1; +} diff --git a/bootloader/hos/pkg2_ini_kippatch.h b/bootloader/hos/pkg2_ini_kippatch.h new file mode 100644 index 0000000..f459c3c --- /dev/null +++ b/bootloader/hos/pkg2_ini_kippatch.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _INIPATCH_H_ +#define _INIPATCH_H_ + +#include "../utils/types.h" +#include "../utils/list.h" + +typedef struct _ini_patchset_t +{ + char *name; + u32 offset; // section + offset of patch to apply. + u32 length; // In bytes, 0 means last patch. + u8 *srcData; // That must match. + u8 *dstData; // Gets replaced with. + link_t link; +} ini_patchset_t; + +typedef struct _ini_kip_sec_t +{ + char *name; + u8 hash[8]; + link_t pts; + link_t link; +} ini_kip_sec_t; + +int ini_patch_parse(link_t *dst, char *ini_path); + +#endif diff --git a/res/patches.ini b/res/patches.ini new file mode 100644 index 0000000..97ed3a2 --- /dev/null +++ b/res/patches.ini @@ -0,0 +1,147 @@ +# UTF-8 +# A KIP section is [kip1_name:sha256_hex_8bytes] +# A patchset is .patch_name=kip_section_dec:offset_hex_0x:length_hex_0x:src_data_hex,dst_data_hex +# _dec: 1 char decimal | _hex_0x: max u32 prefixed with 0x | _hex: hex array. +# Kip1 section decimals: TEXT: 0, RODATA: 1, DATA: 2. +# +# Care when editing this, otherwise it will fail to be parsed. + +#FS Patches for 1.0.0 +[FS:de9fdda4085dd5fe] +.nosigchk=0:0x194A0:0x4:BA090094,E0031F2A +.nosigchk=0:0x3A79C:0x4:E0060036,1F2003D5 + +#FS Patches for 1.0.0 exfat +[FS:fc3e80991dca1796] +.nosigchk=0:0x194A0:0x4:BA090094,E0031F2A +.nosigchk=0:0x3A79C:0x4:E0060036,1F2003D5 + +#FS Patches for 2.0.0 +[FS:cd7bbe18d6130b28] +.nosigchk=0:0x15DF4:0x4:BC0A0094,E0031F2A +.nosigchk=0:0x3F720:0x4:00060036,1F2003D5 + +#FS Patches for 2.0.0 exfat +[FS:e76692dfaa0420e9] +.nosigchk=0:0x15DF4:0x4:BC0A0094,E0031F2A +.nosigchk=0:0x3F720:0x4:00060036,1F2003D5 + +#FS Patches for 2.1.0 +[FS:0d7005627b07767c] +.nosigchk=0:0x15F64:0x4:DF0A0094,E0031F2A +.nosigchk=0:0x3FAF8:0x4:00060036,1F2003D5 + +#FS Patches for 2.1.0 exfat +[FS:dbd85fcacc193da8] +.nosigchk=0:0x15F64:0x4:DF0A0094,E0031F2A +.nosigchk=0:0x3FAF8:0x4:00060036,1F2003D5 + +#FS Patches for 3.0.0 +[FS:a86da5e87ef1097b] +.nosigchk=0:0x18E24:0x4:520C0094,E0031F2A +.nosigchk=0:0x49EC8:0x4:40040036,1F2003D5 + +#FS Patches for 3.0.0 exfat +[FS:981c57e7f02f70f7] +.nosigchk=0:0x18E24:0x4:520C0094,E0031F2A +.nosigchk=0:0x49EC8:0x4:40040036,1F2003D5 + +#FS Patches for 3.0.1 +[FS:57397c063f10b631] +.nosigchk=0:0x18E90:0x4:520C0094,E0031F2A +.nosigchk=0:0x49F34:0x4:E0030036,1F2003D5 + +#FS Patches for 3.0.1 exfat +[FS:073099d7c6ad7d89] +.nosigchk=0:0x18E90:0x4:520C0094,E0031F2A +.nosigchk=0:0x49F34:0x4:E0030036,1F2003D5 + +#FS Patches for 4.0.0 +[FS:06e90719595a010c] +.nosigchk=0:0x1C4FC:0x4:3C2F0094,E0031F2A +.nosigchk=0:0x57934:0x4:E0020036,1F2003D5 + +#FS Patches for 4.0.0 exfat +[FS:549b0f8d6f72c4e9] +.nosigchk=0:0x1C4FC:0x4:3C2F0094,E0031F2A +.nosigchk=0:0x57934:0x4:E0020036,1F2003D5 + +#FS Patches for 4.1.0 +[FS:8096af7c6a35aa82] +.nosigchk=0:0x1C4FC:0x4:3C2F0094,E0031F2A +.nosigchk=0:0x57934:0x4:E0020036,1F2003D5 + +#FS Patches for 4.1.0 exfat +[FS:02d5abaafd20c8b0] +.nosigchk=0:0x1C4FC:0x4:3C2F0094,E0031F2A +.nosigchk=0:0x57934:0x4:E0020036,1F2003D5 + +#FS Patches for 5.0.0 +[FS:a6f27ad9ac7c73ad] +.nosigchk=0:0x22DDC:0x4:7D3E0094,E0031F2A +.nosigchk=0:0x7D490:0x4:40030036,1F2003D5 + +#FS Patches for 5.0.0 exfat +[FS:ce3ecba2f2f062f5] +.nosigchk=0:0x22DDC:0x4:7D3E0094,E0031F2A +.nosigchk=0:0x7D490:0x4:40030036,1F2003D5 + +#FS Patches for 5.1.0 +[FS:76f87402c9387c0f] +.nosigchk=0:0x22E0C:0x4:853E0094,E0031F2A +.nosigchk=0:0x7D860:0x4:40030036,1F2003D5 + +#FS Patches for 5.1.0 exfat +[FS:10b2d81605488599] +.nosigchk=0:0x22E0C:0x4:853E0094,E0031F2A +.nosigchk=0:0x7D860:0x4:40030036,1F2003D5 + +#FS Patches for 6.0.0 - 4 +[FS:1b82cb221867cb52] +.nosigchk=0:0x712A8:0x4:8E3E0094,E0031F2A +.nosigchk=0:0xEB08C:0x4:C0030036,1F2003D5 + +#FS Patches for 6.0.0 - 4 exfat +[FS:966add3d20b62713] +.nosigchk=0:0x7C9A8:0x4:8E3E0094,E0031F2A +.nosigchk=0:0xF678C:0x4:C0030036,1F2003D5 + +#FS Patches for 6.0.0 - 5 +[FS:3a574d436186191d] +.nosigchk=0:0x712A8:0x4:8E3E0094,E0031F2A +.nosigchk=0:0xEB08C:0x4:C0030036,1F2003D5 + +#FS Patches for 6.0.0 - 5 exfat +[FS:330553f6b5fb55c4] +.nosigchk=0:0x7C9A8:0x4:8E3E0094,E0031F2A +.nosigchk=0:0xF678C:0x4:C0030036,1F2003D5 + +#FS Patches for 7.0.0 +[FS:2ADBE97E9B5F4177] +.nosigchk=0:0x74A2C:0x4:31430094,E0031F2A +.nosigchk=0:0xF25E4:0x4:C0030036,1F2003D5 + +#FS Patches for 7.0.0 exfat +[FS:2CCE659CEC536A8E] +.nosigchk=0:0x7FFDC:0x4:31430094,E0031F2A +.nosigchk=0:0xFDB94:0x4:C0030036,1F2003D5 + +#FS Patches for 8.0.0 +[FS:B2F5176B3548364D] +.nosigchk=0:0x7630C:0x4:51440094,E0031F2A +.nosigchk=0:0xF49A4:0x4:C0030036,1F2003D5 + +#FS Patches for 8.0.0 exfat +[FS:DBD941C0C53C52CC] +.nosigchk=0:0x818BC:0x4:51440094,E0031F2A +.nosigchk=0:0xFFF54:0x4:C0030036,1F2003D5 + +#FS Patches for 8.1.0 +[FS:6B09B67B29C02024] +.nosigchk=0:0x7630C:0x4:51440094,E0031F2A +.nosigchk=0:0xF49A4:0x4:C0030036,1F2003D5 + +#FS Patches for 8.1.0 exfat +[FS:B4CAE1F24965D92E] +.nosigchk=0:0x818BC:0x4:51440094,E0031F2A +.nosigchk=0:0xFFF54:0x4:C0030036,1F2003D5