mirror of
https://github.com/NinjaCheetah/WiiPy.git
synced 2025-04-26 13:21:01 -04:00
Joined all WAD re-encryption commands into "wad convert"
This commit is contained in:
parent
a4c06cae36
commit
530afd4189
@ -55,9 +55,11 @@ def build_cios(args):
|
|||||||
base_version = int(target_base.get("version"))
|
base_version = int(target_base.get("version"))
|
||||||
if title.tmd.title_version != base_version:
|
if title.tmd.title_version != base_version:
|
||||||
raise ValueError("The provided base IOS does not match the required version for this base!")
|
raise ValueError("The provided base IOS does not match the required version for this base!")
|
||||||
|
print(f"Building cIOS \"{args.cios_ver}\" from base IOS{target_base.get('ios')} v{base_version}...")
|
||||||
|
|
||||||
# We're ready to begin building the cIOS now. Find all the <content> tags that have <patch> tags, and then apply
|
# We're ready to begin building the cIOS now. Find all the <content> tags that have <patch> tags, and then apply
|
||||||
# the patches listed in them to the content.
|
# the patches listed in them to the content.
|
||||||
|
print("Patching existing modules...")
|
||||||
for content in target_base.findall("content"):
|
for content in target_base.findall("content"):
|
||||||
patches = content.findall("patch")
|
patches = content.findall("patch")
|
||||||
if patches:
|
if patches:
|
||||||
@ -90,6 +92,7 @@ def build_cios(args):
|
|||||||
title.set_content(dec_content, content_index, content_type=libWiiPy.title.ContentType.NORMAL)
|
title.set_content(dec_content, content_index, content_type=libWiiPy.title.ContentType.NORMAL)
|
||||||
|
|
||||||
# Next phase of cIOS building is to add the required extra modules.
|
# Next phase of cIOS building is to add the required extra modules.
|
||||||
|
print("Adding required additional modules...")
|
||||||
for content in target_base.findall("content"):
|
for content in target_base.findall("content"):
|
||||||
target_module = content.get("module")
|
target_module = content.get("module")
|
||||||
if target_module is not None:
|
if target_module is not None:
|
||||||
@ -122,6 +125,7 @@ def build_cios(args):
|
|||||||
title.set_title_version(args.version)
|
title.set_title_version(args.version)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError(f"The provided version \"{args.version}\" is not valid!")
|
raise ValueError(f"The provided version \"{args.version}\" is not valid!")
|
||||||
|
print(f"Set cIOS slot to \"{slot}\" and cIOS version to \"{args.version}\"!")
|
||||||
|
|
||||||
# If this is a vWii cIOS, then we need to re-encrypt it with the Wii Common key so that it's installable from
|
# If this is a vWii cIOS, then we need to re-encrypt it with the Wii Common key so that it's installable from
|
||||||
# within Wii mode.
|
# within Wii mode.
|
||||||
@ -134,8 +138,6 @@ def build_cios(args):
|
|||||||
title.fakesign()
|
title.fakesign()
|
||||||
|
|
||||||
# Write the new cIOS to the specified output path.
|
# Write the new cIOS to the specified output path.
|
||||||
out_file = open(output_path, "wb")
|
output_path.write_bytes(title.dump_wad())
|
||||||
out_file.write(title.dump_wad())
|
|
||||||
out_file.close()
|
|
||||||
|
|
||||||
print("success")
|
print(f"Successfully built cIOS \"{args.cios_ver}\"!")
|
||||||
|
@ -88,7 +88,10 @@ def _print_ticket_info(ticket: libWiiPy.title.Ticket):
|
|||||||
print(f" Certificate Info: {ticket.signature_issuer} (Unknown)")
|
print(f" Certificate Info: {ticket.signature_issuer} (Unknown)")
|
||||||
match ticket.common_key_index:
|
match ticket.common_key_index:
|
||||||
case 0:
|
case 0:
|
||||||
key = "Common"
|
if ticket.is_dev:
|
||||||
|
key = "Common (Development)"
|
||||||
|
else:
|
||||||
|
key = "Common (Retail)"
|
||||||
case 1:
|
case 1:
|
||||||
key = "Korean"
|
key = "Korean"
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -68,6 +68,75 @@ def handle_wad_add(args):
|
|||||||
print(f"Successfully added new content with Content ID \"{target_cid:08X}\" and type \"{target_type.name}\"!")
|
print(f"Successfully added new content with Content ID \"{target_cid:08X}\" and type \"{target_type.name}\"!")
|
||||||
|
|
||||||
|
|
||||||
|
def handle_wad_convert(args):
|
||||||
|
input_path = pathlib.Path(args.input)
|
||||||
|
if args.dev:
|
||||||
|
target = "development"
|
||||||
|
elif args.retail:
|
||||||
|
target = "retail"
|
||||||
|
elif args.vwii:
|
||||||
|
target = "vWii"
|
||||||
|
else:
|
||||||
|
raise ValueError("No valid target was provided!")
|
||||||
|
|
||||||
|
if args.output is None:
|
||||||
|
match target:
|
||||||
|
case "development":
|
||||||
|
output_path = pathlib.Path(input_path.stem + "_dev" + input_path.suffix)
|
||||||
|
case "retail":
|
||||||
|
output_path = pathlib.Path(input_path.stem + "_retail" + input_path.suffix)
|
||||||
|
case "vWii":
|
||||||
|
output_path = pathlib.Path(input_path.stem + "_vWii" + input_path.suffix)
|
||||||
|
case _:
|
||||||
|
raise ValueError("No valid target was provided!")
|
||||||
|
else:
|
||||||
|
output_path = pathlib.Path(args.output)
|
||||||
|
|
||||||
|
if not input_path.exists():
|
||||||
|
raise FileNotFoundError(input_path)
|
||||||
|
|
||||||
|
title = libWiiPy.title.Title()
|
||||||
|
title.load_wad(input_path.read_bytes())
|
||||||
|
# First, verify that this WAD isn't already the type we're trying to convert to.
|
||||||
|
if title.ticket.is_dev and target == "development":
|
||||||
|
raise ValueError("This is already a development WAD!")
|
||||||
|
elif not title.ticket.is_dev and not title.tmd.vwii and target == "retail":
|
||||||
|
raise ValueError("This is already a retail WAD!")
|
||||||
|
elif not title.ticket.is_dev and title.tmd.vwii and target == "vWii":
|
||||||
|
raise ValueError("This is already a vWii WAD!")
|
||||||
|
# Get the current type to display later.
|
||||||
|
if title.ticket.is_dev:
|
||||||
|
source = "development"
|
||||||
|
elif title.tmd.vwii:
|
||||||
|
source = "vWii"
|
||||||
|
else:
|
||||||
|
source = "retail"
|
||||||
|
# Extract the Title Key so it can be re-encrypted with the correct key later.
|
||||||
|
title_key = title.ticket.get_title_key()
|
||||||
|
title_key_new = None
|
||||||
|
if target == "development":
|
||||||
|
# Set the development signature info.
|
||||||
|
title.ticket.signature_issuer = "Root-CA00000002-XS00000006" + title.ticket.signature_issuer[26:]
|
||||||
|
title.tmd.signature_issuer = "Root-CA00000002-CP00000007" + title.tmd.signature_issuer[26:]
|
||||||
|
# Re-encrypt the title key with the dev key, and set that in the Ticket.
|
||||||
|
title_key_new = libWiiPy.title.encrypt_title_key(title_key, 0, title.ticket.title_id, True)
|
||||||
|
title.ticket.common_key_index = 0
|
||||||
|
else:
|
||||||
|
# Set the retail signature info.
|
||||||
|
title.ticket.signature_issuer = "Root-CA00000001-XS00000003" + title.ticket.signature_issuer[26:]
|
||||||
|
title.tmd.signature_issuer = "Root-CA00000001-CP00000004" + title.tmd.signature_issuer[26:]
|
||||||
|
if target == "retail":
|
||||||
|
title_key_new = libWiiPy.title.encrypt_title_key(title_key, 0, title.ticket.title_id, False)
|
||||||
|
title.ticket.common_key_index = 0
|
||||||
|
elif target == "vWii":
|
||||||
|
title_key_new = libWiiPy.title.encrypt_title_key(title_key, 2, title.ticket.title_id, False)
|
||||||
|
title.ticket.common_key_index = 2
|
||||||
|
title.ticket.title_key_enc = title_key_new
|
||||||
|
title.fakesign()
|
||||||
|
output_path.write_bytes(title.dump_wad())
|
||||||
|
print(f"Successfully converted {source} WAD to {target} WAD \"{output_path.name}\"!")
|
||||||
|
|
||||||
|
|
||||||
def handle_wad_pack(args):
|
def handle_wad_pack(args):
|
||||||
input_path = pathlib.Path(args.input)
|
input_path = pathlib.Path(args.input)
|
||||||
output_path = pathlib.Path(args.output)
|
output_path = pathlib.Path(args.output)
|
||||||
@ -299,77 +368,3 @@ def handle_wad_unpack(args):
|
|||||||
output_path.joinpath(content_file_name).write_bytes(title.get_content_by_index(content_file, skip_hash))
|
output_path.joinpath(content_file_name).write_bytes(title.get_content_by_index(content_file, skip_hash))
|
||||||
|
|
||||||
print("WAD file unpacked!")
|
print("WAD file unpacked!")
|
||||||
|
|
||||||
|
|
||||||
def handle_wad_d2r(args):
|
|
||||||
input_path = pathlib.Path(args.input)
|
|
||||||
output_path = pathlib.Path(input_path.stem + "_retail" + input_path.suffix)
|
|
||||||
|
|
||||||
if not input_path.exists():
|
|
||||||
raise FileNotFoundError(input_path)
|
|
||||||
|
|
||||||
title = libWiiPy.title.Title()
|
|
||||||
title.load_wad(input_path.read_bytes())
|
|
||||||
# First, verify that this IS actually a dev WAD.
|
|
||||||
if not title.ticket.is_dev:
|
|
||||||
raise ValueError("This is not a development WAD!")
|
|
||||||
# Now, extract the Title Key, change the certs in the TMD/tik, and set the new retail-encrypted Title Key. The certs
|
|
||||||
# need to be changed so that this WAD can be identified as retail later. The WAD will also be fakesigned, since
|
|
||||||
# making this change invalidates the signature, so there's no downside.
|
|
||||||
title_key = title.ticket.get_title_key()
|
|
||||||
title.ticket.signature_issuer = "Root-CA00000001-XS00000003" + title.ticket.signature_issuer[26:]
|
|
||||||
title_key_retail = libWiiPy.title.encrypt_title_key(title_key, 0, title.ticket.title_id, False)
|
|
||||||
title.ticket.title_key_enc = title_key_retail
|
|
||||||
title.tmd.signature_issuer = "Root-CA00000001-CP00000004" + title.tmd.signature_issuer[26:]
|
|
||||||
title.fakesign()
|
|
||||||
output_path.write_bytes(title.dump_wad())
|
|
||||||
print(f"Successfully converted development WAD to retail WAD \"{output_path.name}\"!")
|
|
||||||
|
|
||||||
|
|
||||||
def handle_wad_r2d(args):
|
|
||||||
input_path = pathlib.Path(args.input)
|
|
||||||
output_path = pathlib.Path(input_path.stem + "_dev" + input_path.suffix)
|
|
||||||
|
|
||||||
if not input_path.exists():
|
|
||||||
raise FileNotFoundError(input_path)
|
|
||||||
|
|
||||||
title = libWiiPy.title.Title()
|
|
||||||
title.load_wad(input_path.read_bytes())
|
|
||||||
# First, verify that this IS actually a retail WAD.
|
|
||||||
if title.ticket.is_dev:
|
|
||||||
raise ValueError("This is not a retail WAD!")
|
|
||||||
# Now, extract the Title Key, change the certs in the TMD/tik, and set the new dev-encrypted Title Key. The certs
|
|
||||||
# need to be changed so that this WAD can be identified as dev later. The WAD will also be fakesigned, since making
|
|
||||||
# this change invalidates the signature, so there's no downside.
|
|
||||||
title_key = title.ticket.get_title_key()
|
|
||||||
title.ticket.signature_issuer = "Root-CA00000002-XS00000006" + title.ticket.signature_issuer[26:]
|
|
||||||
title_key_dev = libWiiPy.title.encrypt_title_key(title_key, 0, title.ticket.title_id, True)
|
|
||||||
title.ticket.title_key_enc = title_key_dev
|
|
||||||
title.tmd.signature_issuer = "Root-CA00000002-CP00000007" + title.tmd.signature_issuer[26:]
|
|
||||||
title.fakesign()
|
|
||||||
output_path.write_bytes(title.dump_wad())
|
|
||||||
print(f"Successfully converted retail WAD to development WAD \"{output_path.name}\"!")
|
|
||||||
|
|
||||||
|
|
||||||
def handle_wad_v2w(args):
|
|
||||||
input_path = pathlib.Path(args.input)
|
|
||||||
output_path = pathlib.Path(input_path.stem + "_Wii" + input_path.suffix)
|
|
||||||
|
|
||||||
if not input_path.exists():
|
|
||||||
raise FileNotFoundError(input_path)
|
|
||||||
|
|
||||||
title = libWiiPy.title.Title()
|
|
||||||
title.load_wad(input_path.read_bytes())
|
|
||||||
# First, verify that this IS actually a vWii WAD.
|
|
||||||
if title.ticket.common_key_index != 2:
|
|
||||||
raise ValueError("This is not a vWii WAD!")
|
|
||||||
# Now, extract the Title Key, change the required flags in the TMD/tik, and set the new common key encrypted
|
|
||||||
# Title Key. The WAD will also be fakesigned, since making this change invalidates the signature, so there's no
|
|
||||||
# downside.
|
|
||||||
title_key_dec = title.ticket.get_title_key()
|
|
||||||
title_key_common = libWiiPy.title.encrypt_title_key(title_key_dec, 0, title.tmd.title_id)
|
|
||||||
title.ticket.title_key_enc = title_key_common
|
|
||||||
title.ticket.common_key_index = 0
|
|
||||||
title.fakesign()
|
|
||||||
output_path.write_bytes(title.dump_wad())
|
|
||||||
print(f"Successfully re-encrypted vWii WAD to regular WAD \"{output_path.name}\"!")
|
|
||||||
|
39
wiipy.py
39
wiipy.py
@ -224,12 +224,26 @@ if __name__ == "__main__":
|
|||||||
"(optional, will default to \"Normal\" if not specified)")
|
"(optional, will default to \"Normal\" if not specified)")
|
||||||
wad_add_parser.add_argument("-o", "--output", metavar="OUT", type=str,
|
wad_add_parser.add_argument("-o", "--output", metavar="OUT", type=str,
|
||||||
help="file to output the updated WAD to (optional)")
|
help="file to output the updated WAD to (optional)")
|
||||||
# dev2retail WAD subcommand.
|
# Convert WAD subcommand.
|
||||||
wad_d2r_parser = wad_subparsers.add_parser("dev2retail", help="re-encrypt a dev WAD for retail consoles",
|
wad_convert_parser = wad_subparsers.add_parser("convert", help="re-encrypt a WAD file with a different key",
|
||||||
description="re-encrypt a dev WAD for retail consoles, and update"
|
description="re-encrypt a WAD file with a different key, making it "
|
||||||
"the certs to match; this also fakesigns the WAD")
|
"possible to use the WAD in a different environment; "
|
||||||
wad_d2r_parser.set_defaults(func=handle_wad_d2r)
|
"this fakesigns the WAD by default")
|
||||||
wad_d2r_parser.add_argument("input", metavar="IN", type=str, help="dev WAD file to re-encrypt")
|
wad_convert_parser.set_defaults(func=handle_wad_convert)
|
||||||
|
wad_convert_parser.add_argument("input", metavar="IN", type=str, help="WAD file to re-encrypt")
|
||||||
|
wad_convert_targets_lbl = wad_convert_parser.add_argument_group(title="target keys")
|
||||||
|
wad_convert_targets = wad_convert_targets_lbl.add_mutually_exclusive_group(required=True)
|
||||||
|
wad_convert_targets.add_argument("-d", "--dev", action="store_true",
|
||||||
|
help="re-encrypt the WAD with the development common key, allowing it to be "
|
||||||
|
"installed on development consoles")
|
||||||
|
wad_convert_targets.add_argument("-r", "--retail", action="store_true",
|
||||||
|
help="re-encrypt the WAD with the retail common key, allowing it to be installed "
|
||||||
|
"on retail consoles or inside of Dolphin")
|
||||||
|
wad_convert_targets.add_argument("-v", "--vwii", action="store_true",
|
||||||
|
help="re-encrypt the WAD with the vWii key, allowing it to theoretically be "
|
||||||
|
"installed from Wii U mode if a Wii U mode WAD installer is created")
|
||||||
|
wad_convert_parser.add_argument("-o", "--output", metavar="OUT", type=str,
|
||||||
|
help="file to output the new WAD to (optional, defaults to '<old_name>_<key>.wad')")
|
||||||
# Pack WAD subcommand.
|
# Pack WAD subcommand.
|
||||||
wad_pack_parser = wad_subparsers.add_parser("pack", help="pack a directory to a WAD file",
|
wad_pack_parser = wad_subparsers.add_parser("pack", help="pack a directory to a WAD file",
|
||||||
description="pack a directory to a WAD file")
|
description="pack a directory to a WAD file")
|
||||||
@ -252,12 +266,6 @@ if __name__ == "__main__":
|
|||||||
help="Content ID of the content to remove")
|
help="Content ID of the content to remove")
|
||||||
wad_remove_parser.add_argument("-o", "--output", metavar="OUT", type=str,
|
wad_remove_parser.add_argument("-o", "--output", metavar="OUT", type=str,
|
||||||
help="file to output the updated WAD to (optional)")
|
help="file to output the updated WAD to (optional)")
|
||||||
# retail2dev WAD subcommand.
|
|
||||||
wad_r2d_parser = wad_subparsers.add_parser("retail2dev", help="re-encrypt a retail WAD for development consoles",
|
|
||||||
description="re-encrypt a retail WAD for development consoles, and "
|
|
||||||
"update the certs to match; this also fakesigns the WAD")
|
|
||||||
wad_r2d_parser.set_defaults(func=handle_wad_r2d)
|
|
||||||
wad_r2d_parser.add_argument("input", metavar="IN", type=str, help="retail WAD file to re-encrypt")
|
|
||||||
# Set WAD subcommand.
|
# Set WAD subcommand.
|
||||||
wad_set_parser = wad_subparsers.add_parser("set", help="set content in a WAD file",
|
wad_set_parser = wad_subparsers.add_parser("set", help="set content in a WAD file",
|
||||||
description="replace existing content in a WAD file with new decrypted "
|
description="replace existing content in a WAD file with new decrypted "
|
||||||
@ -284,13 +292,6 @@ if __name__ == "__main__":
|
|||||||
wad_unpack_parser.add_argument("output", metavar="OUT", type=str, help="output directory")
|
wad_unpack_parser.add_argument("output", metavar="OUT", type=str, help="output directory")
|
||||||
wad_unpack_parser.add_argument("-s", "--skip-hash", help="skips validating the hashes of decrypted "
|
wad_unpack_parser.add_argument("-s", "--skip-hash", help="skips validating the hashes of decrypted "
|
||||||
"content", action="store_true")
|
"content", action="store_true")
|
||||||
# vwii2wii WAD subcommand.
|
|
||||||
wad_v2w_parser = wad_subparsers.add_parser("vwii2wii", help="re-encrypt a vWii WAD with the common key",
|
|
||||||
description="re-encrypt a vWii WAD with the common key, allowing it to "
|
|
||||||
"be installed in Dolphin and from within Wii mode on Wii U; "
|
|
||||||
"this also fakesigns the WAD")
|
|
||||||
wad_v2w_parser.set_defaults(func=handle_wad_v2w)
|
|
||||||
wad_v2w_parser.add_argument("input", metavar="IN", type=str, help="vWii WAD file to re-encrypt")
|
|
||||||
|
|
||||||
|
|
||||||
# Parse all the args, and call the appropriate function with all of those args if a valid subcommand was passed.
|
# Parse all the args, and call the appropriate function with all of those args if a valid subcommand was passed.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user