diff --git a/patch_overwrite.go b/patch_overwrite.go index a11cf73..8d71401 100644 --- a/patch_overwrite.go +++ b/patch_overwrite.go @@ -4,30 +4,53 @@ package main // See docs/patch_overwrite_ios.md for more information. var OverwriteIOSPatch = PatchSet{ Patch{ - Name: "Clear extraneous textinput::EventObserver functions", - AtOffset: 20336, + Name: "Clear extraneous functions", + AtOffset: 20272, Before: Instructions{ + // Function: textinput::EventObserver::onOutOfLength + LIS(R3, 0x802f), + ADDI(R3, R3, 0x7ac4), + CRXOR(), + // b printf + Instruction{0x48, 0x2a, 0x8b, 0x78}, + + // Function: textinput::EventObserver::onCancel + LIS(R3, 0x802f), + ADDI(R3, R3, 0x7ab8), + CRXOR(), + // b printf + Instruction{0x48, 0x2a, 0x8b, 0x68}, + + // Function: textinput::EventObserver::onOK + // subi r3, r3, 0x7fe0 + Instruction{0x38, 0x6d, 0x80, 0x20}, + CRXOR(), + // b printf + Instruction{0x48, 0x2a, 0x8b, 0x5c}, + + padding, + + // Function: textinput::EventObserver::onSE + BLR(), + padding, padding, padding, // Function: textinput::EventObserver::onEvent BLR(), - padding, - padding, - padding, + padding, padding, padding, // Function: textinput::EventObserver::onCommand BLR(), - padding, - padding, - padding, + padding, padding, padding, // Function: textinput::EventObserver::onInput BLR(), - padding, - padding, - padding, + padding, padding, padding, }.toBytes(), // We wish to clear extraneous blrs so that our custom overwriteIOSMemory - // function does not somehow conflict. We only preserve onSE. - After: emptyBytes(48), + // function does not somehow conflict. + // We only preserve onSE, which is this immediate BLR. + After: append(Instructions{ + BLR(), + }.toBytes(), emptyBytes(108)...), }, Patch{ Name: "Repair textinput::EventObserver vtable", @@ -38,13 +61,19 @@ var OverwriteIOSPatch = PatchSet{ 0x80, 0x01, 0x44, 0x40, // onEvent 0x80, 0x01, 0x44, 0x30, // onCommand 0x80, 0x01, 0x44, 0x20, // onInput + 0x80, 0x01, 0x44, 0x10, // onOK + 0x80, 0x01, 0x44, 0x00, // onCancel + 0x80, 0x01, 0x43, 0xf0, // onOutOfLength }, After: []byte{ // These are all pointers to our so-called doNothing. - 0x80, 0x01, 0x44, 0x20, - 0x80, 0x01, 0x44, 0x20, - 0x80, 0x01, 0x44, 0x20, - 0x80, 0x01, 0x44, 0x20, + 0x80, 0x01, 0x43, 0xf0, + 0x80, 0x01, 0x43, 0xf0, + 0x80, 0x01, 0x43, 0xf0, + 0x80, 0x01, 0x43, 0xf0, + 0x80, 0x01, 0x43, 0xf0, + 0x80, 0x01, 0x43, 0xf0, + 0x80, 0x01, 0x43, 0xf0, }, }, Patch{ @@ -52,55 +81,154 @@ var OverwriteIOSPatch = PatchSet{ AtOffset: 3097888, Before: []byte{ - 0x80, 0x01, 0x44, 0x50, // onSE - 0x80, 0x01, 0x84, 0xE0, // ipl::keyboard::EventObserver::onCommand - not patched - 0x80, 0x01, 0x44, 0x30, // onCommand + 0x80, 0x01, 0x44, 0x50, // textinput::EventObserver::onSE + 0x80, 0x01, 0x84, 0xE0, // onCommand - not patched + 0x80, 0x01, 0x44, 0x30, // textinput::EventObserver::onCommand + 0x80, 0x01, 0x85, 0x20, // onSE - not patching + 0x80, 0x01, 0x87, 0x40, // onOK - not patching + 0x80, 0x01, 0x87, 0x60, // onCancel - not patching + 0x80, 0x01, 0x43, 0xF0, // textinput::EventObserver::onOutOfLength }, After: []byte{ - 0x80, 0x01, 0x44, 0x20, // doNothing - 0x80, 0x01, 0x84, 0xE0, // ipl::keyboard::EventObserver::onCommand - not patched - 0x80, 0x01, 0x44, 0x20, // doNothing + 0x80, 0x01, 0x43, 0xf0, // textinput::EventObserver::doNothing + 0x80, 0x01, 0x84, 0xE0, // onCommand - not patched + 0x80, 0x01, 0x43, 0xf0, // textinput::EventObserver::doNothing + 0x80, 0x01, 0x85, 0x20, // onSE - not patching + 0x80, 0x01, 0x87, 0x40, // onOK - not patching + 0x80, 0x01, 0x87, 0x60, // onCancel - not patching + 0x80, 0x01, 0x43, 0xf0, // textinput::EventObserver::doNothing + }, + }, + Patch{ + Name: "Insert patch table", + AtOffset: 3205088, + + Before: emptyBytes(40), + After: []byte{ + ////////////// + // PATCH #1 // + ////////////// + // We want to write to MEM_PROT at 0x0d8b420a. + // For us, this is mapped to 0xcd8b420a. + 0xcd, 0x8b, 0x42, 0x0a, + // We are going to write the value 0x2 to unlock everything. + 0x00, 0x00, 0x00, 0x02, + + ////////////// + // PATCH #2 // + ////////////// + // We want to write to IOSC_VerifyPublicKeySign at 0x13a73ad4. + // For us, this is mapped to 0xd3a73ad4. + 0xd3, 0xa7, 0x3a, 0xd4, + // 0x20004770 is equivalent in ARM THUMB to: + // mov r0, #0x0 + // bx lr + 0x20, 0x00, 0x47, 0x70, + + ////////////////////////// + // PATCH #3 - vWii only // + ////////////////////////// + // Patch location: + // We want to write at 0x20102100, aka "ES_AddTicket". + // (To us, this is mapped at 0x939f2100.) + 0x93, 0x9f, 0x21, 0x00, + // The original code has a few conditionals preventing system title usage. + // We simply branch off past these. + // 0x681a2a01 is equivalent in ARM THUMB to: + // ldr r2,[r3,#0x0] ; original code we wish to preserve + // ; so we can write 32 bits + // b +0x14 ; branch past conditionals + 0x68, 0x1a, 0x2a, 0x01, + + ////////////////////////// + // PATCH #4 - vWii only // + ////////////////////////// + // We want to write to 0x20103240, aka "ES_AddTitleStart". + // (For us, this is 0x939f3240.) + 0x93, 0x9f, 0x32, 0x40, + // The original code has a few conditionals preventing system title usage. + // 0xe00846c0 is equivalent in ARM THUMB to: + // b +0x8 ; branch past conditionals + // mov r8, r8 ; recommended THUMB nop + 0xe0, 0x08, 0x46, 0xc0, + + ////////////////////////// + // PATCH #5 - vWii only // + ////////////////////////// + // Lastly, we want to write to 0x20103564, aka "ES_AddContentStart". + // (We utilize memory cache and write at 0x939f3564.) + 0x93, 0x9f, 0x35, 0x64, + // The original code has a few conditionals preventing system title usage. + // We simply branch off past these. + // 0xe00c46c0 is equivalent in ARM THUMB to: + // b +0xc ; branch past conditionals + // mov r8, r8 ; recommended THUMB nop + 0xe0, 0x0c, 0x46, 0xc0, }, }, Patch{ Name: "Insert overwriteIOSMemory", - AtOffset: 20328, + AtOffset: 20276, - // This area should be cleared. - Before: emptyBytes(48), + // This area should be cleared in the patch + // "Clear extraneous functions". + Before: emptyBytes(108), After: Instructions{ - // We want r9 to store the location of MEM_PROT at 0x0d8b420a. - // For us, this is mapped to 0xcd8b420a. - LIS(R9, 0xcd8b), - ORI(R9, R9, 0x420a), + // Our patch table is available at 0x803126e0. + LIS(R8, 0x8031), + ORI(R8, R8, 0x26e0), - // We want to write 0x2 and unlock everything. - LI(R10, 0x02), - - // Write! + // Load address/value pair for MEM_PROT + LWZ(R9, 0x0, R8), + LWZ(R10, 0x4, R8), + // Apply lower half STH(R10, 0x0, R9), - // Flush memory - EIEIO(), - // Location of IOSC_VerifyPublicKeySign - LIS(R9, 0xd3a7), - ORI(R9, R9, 0x3ad4), + // Load address/value pair for IOSC_VerifyPublicKeySign + LWZ(R9, 0x8, R8), + LWZ(R10, 0xc, R8), - // Write our custom THUMB. - // 0x20004770 is equivalent to: - // mov r0, #0x0 - // bx lr - LIS(R10, 0x2000), - ORI(R10, R10, 0x4770), - - // Write! + // Apply! STW(R10, 0x0, R9), - // Possibly clear cache - // TODO(spotlightishere): Is this needed? - // dcbi 0, r10 - Instruction{0x7C, 0x00, 0x53, 0xAC}, - // And finish. + + // The remainder of our patches will determine if we are on a Wii U. + // Even in vWii mode, 0x0d8005a0 (LT_CHIPREVID) will have its upper + // 16 bits set to 0xCAFE. We can compare against this. + // See also: https://wiiubrew.org/wiki/Hardware/Latte_registers + // (However, we must access the cached version at 0xcd8005a0.) + LIS(R9, 0xcd80), + ORI(R9, R9, 0x05a0), + LWZ(R9, 0, R9), + + // Shift this value 16 bits to the right + // in order to compare its higher value. + // srawi r9, r9, 16 + Instruction{0x7d, 0x29, 0x86, 0x70}, + CMPWI(R9, 0xCAFE), + // If we're not a Wii U, carry on until the end. + // bne (last blr) + ORI(R0, R0, 0), + //Instruction{0x40, 0x82, 0x00, 0x28}, + + // Apply ES_AddTicket + LWZ(R9, 0x10, R8), + LWZ(R10, 0x14, R8), + STW(R10, 0x0, R9), + + // Apply ES_AddTicket + LWZ(R9, 0x18, R8), + LWZ(R10, 0x1c, R8), + STW(R10, 0x0, R9), + + // Apply ES_AddTicket + LWZ(R9, 0x20, R8), + LWZ(R10, 0x24, R8), + STW(R10, 0x0, R9), + + // We're finished patching! BLR(), + + BLR(), BLR(), BLR(), }.toBytes(), }, Patch{ @@ -118,7 +246,7 @@ var OverwriteIOSPatch = PatchSet{ After: Instructions{ LWZ(R0, 0x14, R1), // bl overwriteIOSMemory @ 0x80014428 - Instruction{0x4B, 0xDB, 0xB1, 0x01}, + Instruction{0x4b, 0xdb, 0xb0, 0xcd}, MTSPR(), ADDI(R1, R1, 0x10), BLR(), diff --git a/powerpc.go b/powerpc.go index 172edd5..a8ed0d0 100644 --- a/powerpc.go +++ b/powerpc.go @@ -35,6 +35,12 @@ func BLR() Instruction { return [4]byte{0x4E, 0x80, 0x00, 0x20} } +// CRXOR represents a common use of CRXOR on PowerPC. +// TODO: actually implement +func CRXOR() Instruction { + return [4]byte{0x4c, 0xc6, 0x31, 0x82} +} + // ADDI represents the addi PowerPC instruction. func ADDI(rT Register, rA Register, value uint16) Instruction { return EncodeInstrDForm(14, rT, rA, value) @@ -46,6 +52,7 @@ func LI(rT Register, value uint16) Instruction { } // SUBI represents the subi mnemonic on PowerPC. +// TODO: handle negative values properly? func SUBI(rT Register, rA Register, value uint16) Instruction { return ADDI(rT, 0, -value) }