diff --git a/docs/README.md b/docs/README.md index 5dcee7e..b2f99ca 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,4 +6,5 @@ Contents: It does not attempt to handle things such as client certificates or user passwords. - [`patch_overwrite_ios.md`](patch_overwrite_ios.md): An explanation over why and how IOS is patched for operation of the Wii Shop Channel. - [`patch_custom_ca_ios.md`](patch_custom_ca_ios.md): The logistics of inserting our custom CA into IOS as well for EC usage. - - [`patch_base_domain.md`](patch_base_domain.md): Information about what URLs are present within the main DOL and information about patching them. \ No newline at end of file + - [`patch_base_domain.md`](patch_base_domain.md): Information about what URLs are present within the main DOL and information about patching them. + - [`patch_ec_title_check.md`](patch_ec_title_check.md): Information about title checks run by EC, and why they were negated. \ No newline at end of file diff --git a/docs/patch_ec_title_check.md b/docs/patch_ec_title_check.md new file mode 100644 index 0000000..8c6bb4f --- /dev/null +++ b/docs/patch_ec_title_check.md @@ -0,0 +1,25 @@ +# Patch: Negate EC Title Check + +## Motivation +A check on the title type is present, preventing installation of `00010008` (hidden) titles. We would like to do so. + +## Explanation +Via symbols within the main ARC, we are able to see function names. + +Prior to downloading a title in three scenarios - normal downloading, gifting, or purchasing - EC runs a function called `ec::allowDownloadByApp`. + +Within this, four conditions are checked: + - Is the channel a downloadable title/NAND title? (`00010001`) + - Is the channel a game channel? This checks two types: + - `00010000`, typically used for discs + - `00010004`. + - Is the channel a "service title"? (`00010100`) + - Name taken from `ec::isServiceTitle`. + +If any of these are true, installation of the title is permitted. +Otherwise, installation is forbidden. + +## Execution +This behavior is not ideal. `ec::allowDownloadByApp` is patched to immediately return `1`, or true. + +In the future, `ec::isManagedTitle` and `ec::isManagedTicket` may wish to be patched as well due to similar reasons. \ No newline at end of file diff --git a/modify_dol.go b/modify_dol.go index ca691dd..40e0f34 100644 --- a/modify_dol.go +++ b/modify_dol.go @@ -93,4 +93,5 @@ func applyDefaultPatches() { applyPatchSet("Overwrite IOS Syscall for ES", OverwriteIOSPatch) applyPatchSet("Load Custom CA within IOS", LoadCustomCA()) applyPatchSet("Change Base Domain", PatchBaseDomain()) + applyPatchSet("Negate EC Title Check", NegateECTitle) } diff --git a/patch_ec_title_check.go b/patch_ec_title_check.go new file mode 100644 index 0000000..892a430 --- /dev/null +++ b/patch_ec_title_check.go @@ -0,0 +1,20 @@ +package main + +var NegateECTitle = PatchSet{ + Patch{ + Name: "Allow all titles", + AtOffset: 619648, + + // Generic function prolog + Before: Instructions{ + STWU(R1, R1, 0xffe0), + MFSPR(), + }.toBytes(), + + // Immediately return true + After: Instructions{ + LI(R3, 1), + BLR(), + }.toBytes(), + }, +} diff --git a/patch_overwrite.go b/patch_overwrite.go index 4206de5..a11cf73 100644 --- a/patch_overwrite.go +++ b/patch_overwrite.go @@ -110,8 +110,7 @@ var OverwriteIOSPatch = PatchSet{ // We inject in the epilog of the function. Before: Instructions{ LWZ(R0, 0x14, R1), - // mtspr LR, r0 - Instruction{0x7C, 0x08, 0x03, 0xA6}, + MTSPR(), ADDI(R1, R1, 0x10), BLR(), padding, @@ -120,8 +119,7 @@ var OverwriteIOSPatch = PatchSet{ LWZ(R0, 0x14, R1), // bl overwriteIOSMemory @ 0x80014428 Instruction{0x4B, 0xDB, 0xB1, 0x01}, - // mtspr LR, r0 - Instruction{0x7C, 0x08, 0x03, 0xA6}, + MTSPR(), ADDI(R1, R1, 0x10), BLR(), }.toBytes(), diff --git a/powerpc.go b/powerpc.go index d520060..3838677 100644 --- a/powerpc.go +++ b/powerpc.go @@ -85,3 +85,20 @@ func NOP() Instruction { func CMPWI(rA Register, value uint16) Instruction { return EncodeInstrDForm(11, 0, rA, value) } + +// MTSPR is a hack, hardcoding LR, r0. +// TODO(spotlightishere): actually encode this +func MTSPR() Instruction { + return [4]byte{0x7c, 0x08, 0x03, 0xa6} +} + +// MFSPR is a hack, hardcoding r0, LR. +// TODO(spotlightishere): actually encode this +func MFSPR() Instruction { + return [4]byte{0x7c, 0x08, 0x02, 0xa6} +} + +// STWU represents the stwu PowerPC instruction. +func STWU(rS Register, rA Register, offset uint16) Instruction { + return EncodeInstrDForm(37, rS, rA, offset) +}