diff --git a/modules/title/iospatcher.py b/modules/title/iospatcher.py new file mode 100644 index 0000000..63712aa --- /dev/null +++ b/modules/title/iospatcher.py @@ -0,0 +1,66 @@ +# "modules/title/iospatcher.py" from WiiPy by NinjaCheetah +# https://github.com/NinjaCheetah/WiiPy + +import pathlib +import libWiiPy + + +def handle_iospatch(args): + input_path = pathlib.Path(args.input) + if not input_path.exists(): + raise FileNotFoundError(input_path) + + title = libWiiPy.title.Title() + title.load_wad(open(input_path, "rb").read()) + + tid = title.tmd.title_id + if tid[:8] != "00000001" or tid[8:] == "00000001" or tid[8:] == "00000002": + raise ValueError("This WAD does not appear to contain an IOS! Patching cannot continue.") + + patches_applied = False + + if args.version is not None: + title.set_title_version(args.version) + patches_applied = True + + if args.slot is not None: + slot = args.slot + if 3 <= slot <= 255: + tid = title.tmd.title_id[:-2] + f"{slot:02X}" + title.set_title_id(tid) + patches_applied = True + + ios_patcher = libWiiPy.title.IOSPatcher() + ios_patcher.load(title) + + if args.all is True: + ios_patcher.patch_all() + patches_applied = True + else: + if args.fakesigning is True: + ios_patcher.patch_fakesigning() + patches_applied = True + if args.es_identify is True: + ios_patcher.patch_es_identify() + patches_applied = True + if args.nand_access is True: + ios_patcher.patch_nand_access() + patches_applied = True + if args.version_patch is True: + ios_patcher.patch_version_patch() + patches_applied = True + + if not patches_applied: + raise ValueError("No patches were selected! Please select patches to apply.") + + if args.output is not None: + output_path = pathlib.Path(args.output) + output_file = open(output_path, "wb") + output_file.write(ios_patcher.title.dump_wad()) + output_file.close() + else: + output_file = open(input_path, "wb") + output_file.write(ios_patcher.title.dump_wad()) + output_file.close() + + print("IOS successfully patched!") diff --git a/wiipy.py b/wiipy.py index dc8e497..2e7cc96 100644 --- a/wiipy.py +++ b/wiipy.py @@ -8,6 +8,7 @@ from modules.archive.ash import * from modules.archive.u8 import * from modules.title.emunand import * from modules.title.fakesign import * +from modules.title.iospatcher import * from modules.title.nus import * from modules.title.wad import * @@ -34,8 +35,8 @@ if __name__ == "__main__": help="number of bits in each distance tree leaf (default: 11)", default=11) # Argument parser for the EmuNAND subcommand. - emunand_parser = subparsers.add_parser("emunand", help="handle Wii EmuNAND directories", - description="handle Wii EmuNAND directories") + emunand_parser = subparsers.add_parser("emunand", help="manage Wii EmuNAND directories", + description="manage Wii EmuNAND directories") emunand_subparsers = emunand_parser.add_subparsers(title="emunand", dest="emunand", required=True) # Title EmuNAND subcommand. emunand_title_parser = emunand_subparsers.add_parser("title", help="manage titles on an EmuNAND", @@ -56,6 +57,22 @@ if __name__ == "__main__": fakesign_parser.add_argument("input", metavar="IN", type=str, help="input file") fakesign_parser.add_argument("output", metavar="OUT", type=str, help="output file") + # Argument parser for the iospatch command. + iospatch_parser = subparsers.add_parser("iospatch", help="patch IOS WADs to re-enable exploits", + description="patch IOS WADs to re-enable exploits; by default, this will" + "overwrite the input file in place unless you use -o/--output") + iospatch_parser.set_defaults(func=handle_iospatch) + iospatch_parser.add_argument("input", metavar="IN", type=str, help="input file") + iospatch_parser.add_argument("-o", "--output", metavar="OUT", type=str, help="output file (optional)") + iospatch_parser.add_argument("-fs", "--fakesigning", action="store_true", help="patch in fakesigning support") + iospatch_parser.add_argument("-ei", "--es-identify", action="store_true", help="patch in ES_Identify access") + iospatch_parser.add_argument("-na", "--nand-access", action="store_true", help="patch in /dev/flash access") + iospatch_parser.add_argument("-vp", "--version-patch", action="store_true", help="patch in the version patch?") + iospatch_parser.add_argument("-v", "--version", metavar="VERSION", type=int, help="set the IOS version") + iospatch_parser.add_argument("-s", "--slot", metavar="SLOT", type=int, + help="set the slot that this IOS will install to") + iospatch_parser.add_argument("-a", "--all", action="store_true", help="apply all patches (overrides other options)") + # Argument parser for the NUS subcommand. nus_parser = subparsers.add_parser("nus", help="download data from the NUS", description="download from the NUS")