mirror of
https://wiilab.wiimart.org/wiimart/WiiMart-Patcher
synced 2025-09-04 04:21:19 +02:00
Migrate instruction encoding to external library
The PowerPC instruction encoder and patching logic is now available at https://github.com/wii-tools/powerpc.
This commit is contained in:
parent
4a232c552b
commit
e17dbf9ce1
1
go.mod
1
go.mod
@ -6,5 +6,6 @@ require (
|
|||||||
github.com/logrusorgru/aurora/v3 v3.0.0
|
github.com/logrusorgru/aurora/v3 v3.0.0
|
||||||
github.com/wii-tools/GoNUSD v0.2.2
|
github.com/wii-tools/GoNUSD v0.2.2
|
||||||
github.com/wii-tools/arclib v1.0.0
|
github.com/wii-tools/arclib v1.0.0
|
||||||
|
github.com/wii-tools/powerpc v0.0.0-20220411041712-104089eba964
|
||||||
github.com/wii-tools/wadlib v0.3.1
|
github.com/wii-tools/wadlib v0.3.1
|
||||||
)
|
)
|
||||||
|
2
go.sum
2
go.sum
@ -4,5 +4,7 @@ github.com/wii-tools/GoNUSD v0.2.2 h1:vHiSLI9sK9Q4zbCt24jMiq/lo2FISLBuCHoaY3Bd88
|
|||||||
github.com/wii-tools/GoNUSD v0.2.2/go.mod h1:Wf0ZMf4jdyQYSaSmNyFsqfQbngFA/cM9mpJBZ63Qlzs=
|
github.com/wii-tools/GoNUSD v0.2.2/go.mod h1:Wf0ZMf4jdyQYSaSmNyFsqfQbngFA/cM9mpJBZ63Qlzs=
|
||||||
github.com/wii-tools/arclib v1.0.0 h1:OAmbL3NDUmlR0wa1VpJhxnKiIRFZz1CC40lTVPUm8Ms=
|
github.com/wii-tools/arclib v1.0.0 h1:OAmbL3NDUmlR0wa1VpJhxnKiIRFZz1CC40lTVPUm8Ms=
|
||||||
github.com/wii-tools/arclib v1.0.0/go.mod h1:uXFan/NSXoQ2pOVPN4ugZ4nJX7esBnjB1QUgVrEzK/4=
|
github.com/wii-tools/arclib v1.0.0/go.mod h1:uXFan/NSXoQ2pOVPN4ugZ4nJX7esBnjB1QUgVrEzK/4=
|
||||||
|
github.com/wii-tools/powerpc v0.0.0-20220411041712-104089eba964 h1:/ZeMBIoblxzyhKHQJncvBZaxqi6RZz4rm4QvL0QiguA=
|
||||||
|
github.com/wii-tools/powerpc v0.0.0-20220411041712-104089eba964/go.mod h1:bt/52tMfh1hmEXwFh1i1AOEMNHoe0jSXkcRunOSdFkc=
|
||||||
github.com/wii-tools/wadlib v0.3.1 h1:g0Szzof/YsBLghP+JpoVzT/6M6jpl+AH9PHiUuG3cd8=
|
github.com/wii-tools/wadlib v0.3.1 h1:g0Szzof/YsBLghP+JpoVzT/6M6jpl+AH9PHiUuG3cd8=
|
||||||
github.com/wii-tools/wadlib v0.3.1/go.mod h1:GK+f2POk+rVu1p4xqLSb4ll1SKKbfOO6ZAB+oPLV3uQ=
|
github.com/wii-tools/wadlib v0.3.1/go.mod h1:GK+f2POk+rVu1p4xqLSb4ll1SKKbfOO6ZAB+oPLV3uQ=
|
||||||
|
17
main.go
17
main.go
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/logrusorgru/aurora/v3"
|
"github.com/logrusorgru/aurora/v3"
|
||||||
"github.com/wii-tools/GoNUSD"
|
"github.com/wii-tools/GoNUSD"
|
||||||
"github.com/wii-tools/arclib"
|
"github.com/wii-tools/arclib"
|
||||||
|
"github.com/wii-tools/powerpc"
|
||||||
"github.com/wii-tools/wadlib"
|
"github.com/wii-tools/wadlib"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -137,6 +138,22 @@ func main() {
|
|||||||
writeOut("patched.wad", output)
|
writeOut("patched.wad", output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applyDefaultPatches applies the default patches to our main DOL.
|
||||||
|
func applyDefaultPatches() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
mainDol, err = powerpc.ApplyPatchSet(OverwriteIOSPatch, mainDol)
|
||||||
|
check(err)
|
||||||
|
mainDol, err = powerpc.ApplyPatchSet(LoadCustomCA(), mainDol)
|
||||||
|
check(err)
|
||||||
|
mainDol, err = powerpc.ApplyPatchSet(PatchBaseDomain(), mainDol)
|
||||||
|
check(err)
|
||||||
|
mainDol, err = powerpc.ApplyPatchSet(NegateECTitle, mainDol)
|
||||||
|
check(err)
|
||||||
|
mainDol, err = powerpc.ApplyPatchSet(PatchECCfgPath, mainDol)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
|
|
||||||
// check has an anxiety attack if things go awry.
|
// check has an anxiety attack if things go awry.
|
||||||
func check(err error) {
|
func check(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/logrusorgru/aurora/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrInconsistentPatch = errors.New("before and after data present within file are not the same size")
|
|
||||||
ErrPatchOutOfRange = errors.New("patch cannot be applied past binary size")
|
|
||||||
ErrInvalidPatch = errors.New("before data present within patch did not exist in file")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Patch represents a patch applied to the main binary.
|
|
||||||
type Patch struct {
|
|
||||||
// Name is an optional name for this patch.
|
|
||||||
// If present, its name will be logged upon application.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// AtOffset is the offset within the file this patch should be applied at.
|
|
||||||
// If not present, the patch will be recursively applied across the entire file.
|
|
||||||
// Relying on this behavior is highly discouraged, as it may damage other parts of the binary
|
|
||||||
// if gone unchecked.
|
|
||||||
AtOffset int
|
|
||||||
|
|
||||||
// Before is an array of the bytes to find for, i.e. present within the original file.
|
|
||||||
Before []byte
|
|
||||||
|
|
||||||
// After is an array of the bytes to replace with.
|
|
||||||
After []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// PatchSet represents multiple patches available to be applied.
|
|
||||||
type PatchSet []Patch
|
|
||||||
|
|
||||||
// applyPatch applies the given patch to the main DOL.
|
|
||||||
func applyPatch(patch Patch) error {
|
|
||||||
// Print name if present
|
|
||||||
if patch.Name != "" {
|
|
||||||
fmt.Println(" + Applying patch", aurora.Cyan(patch.Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure consistency
|
|
||||||
if len(patch.Before) != len(patch.After) {
|
|
||||||
return ErrInconsistentPatch
|
|
||||||
}
|
|
||||||
if patch.AtOffset != 0 && patch.AtOffset > len(mainDol) {
|
|
||||||
return ErrPatchOutOfRange
|
|
||||||
}
|
|
||||||
|
|
||||||
// Either Before or After should return the same length.
|
|
||||||
patchLen := len(patch.Before)
|
|
||||||
|
|
||||||
// Determine our patching behavior.
|
|
||||||
if patch.AtOffset != 0 {
|
|
||||||
// Ensure original bytes are present
|
|
||||||
originalBytes := mainDol[patch.AtOffset : patch.AtOffset+patchLen]
|
|
||||||
if !bytes.Equal(originalBytes, patch.Before) {
|
|
||||||
return ErrInvalidPatch
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply patch at the specified offset
|
|
||||||
copy(mainDol[patch.AtOffset:], patch.After)
|
|
||||||
} else {
|
|
||||||
// Recursively apply this patch.
|
|
||||||
// We cannot verify if the original contents are present via this.
|
|
||||||
mainDol = bytes.ReplaceAll(mainDol, patch.Before, patch.After)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// applyPatchSet iterates through all possible patches, noting their name.
|
|
||||||
func applyPatchSet(setName string, set PatchSet) {
|
|
||||||
fmt.Printf("Handling patch set \"%s\":\n", aurora.Yellow(setName))
|
|
||||||
|
|
||||||
for _, patch := range set {
|
|
||||||
err := applyPatch(patch)
|
|
||||||
check(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// emptyBytes returns an empty byte array of the given length.
|
|
||||||
func emptyBytes(length int) []byte {
|
|
||||||
return bytes.Repeat([]byte{0x00}, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
// applyDefaultPatches iterates through a list of default patches.
|
|
||||||
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)
|
|
||||||
applyPatchSet("Change EC Configuration Path", PatchECCfgPath)
|
|
||||||
}
|
|
@ -1,6 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
. "github.com/wii-tools/powerpc"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NintendoBaseDomain = "shop.wii.com"
|
NintendoBaseDomain = "shop.wii.com"
|
||||||
@ -15,39 +19,42 @@ const (
|
|||||||
// See docs/patch_base_domain.md for more information.
|
// See docs/patch_base_domain.md for more information.
|
||||||
func PatchBaseDomain() PatchSet {
|
func PatchBaseDomain() PatchSet {
|
||||||
return PatchSet{
|
return PatchSet{
|
||||||
Patch{
|
Name: "Change Base Domain",
|
||||||
|
Patches: []Patch{
|
||||||
|
{
|
||||||
Name: "Modify /startup domain",
|
Name: "Modify /startup domain",
|
||||||
|
|
||||||
Before: []byte(ShowManualURL),
|
Before: []byte(ShowManualURL),
|
||||||
After: padReplace(ShowManualURL),
|
After: padReplace(ShowManualURL),
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Modify oss-auth URL",
|
Name: "Modify oss-auth URL",
|
||||||
AtOffset: 3180692,
|
AtOffset: 3180692,
|
||||||
|
|
||||||
Before: []byte(GetLogURL),
|
Before: []byte(GetLogURL),
|
||||||
After: padReplace(GetLogURL),
|
After: padReplace(GetLogURL),
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Modify trusted base domain prefix",
|
Name: "Modify trusted base domain prefix",
|
||||||
AtOffset: 3323432,
|
AtOffset: 3323432,
|
||||||
|
|
||||||
Before: []byte(TrustedDomain),
|
Before: []byte(TrustedDomain),
|
||||||
After: padReplace(TrustedDomain),
|
After: padReplace(TrustedDomain),
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Modify ECS SOAP endpoint URL",
|
Name: "Modify ECS SOAP endpoint URL",
|
||||||
AtOffset: 3268896,
|
AtOffset: 3268896,
|
||||||
|
|
||||||
Before: []byte(ECommerceBaseURL),
|
Before: []byte(ECommerceBaseURL),
|
||||||
After: padReplace(ECommerceBaseURL),
|
After: padReplace(ECommerceBaseURL),
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Wildcard replace other instances",
|
Name: "Wildcard replace other instances",
|
||||||
|
|
||||||
Before: []byte(NintendoBaseDomain),
|
Before: []byte(NintendoBaseDomain),
|
||||||
After: padReplace(baseDomain),
|
After: padReplace(baseDomain),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,5 +67,5 @@ func padReplace(url string) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
padding := len(url) - len(replaced)
|
padding := len(url) - len(replaced)
|
||||||
return append([]byte(replaced), emptyBytes(padding)...)
|
return append([]byte(replaced), EmptyBytes(padding)...)
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,25 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/wii-tools/powerpc"
|
||||||
|
)
|
||||||
|
|
||||||
// LoadCustomCA loads our custom certificate, either generated or loaded,
|
// LoadCustomCA loads our custom certificate, either generated or loaded,
|
||||||
// into the IOS trust store for EC usage.
|
// into the IOS trust store for EC usage.
|
||||||
// It is assumed that rootCertificate has been loaded upon invoking this patchset.
|
// It is assumed that rootCertificate has been loaded upon invoking this patchset.
|
||||||
// See docs/patch_custom_ca_ios.md for more information.
|
// See docs/patch_custom_ca_ios.md for more information.
|
||||||
func LoadCustomCA() PatchSet {
|
func LoadCustomCA() PatchSet {
|
||||||
return PatchSet{
|
return PatchSet{
|
||||||
Patch{
|
Name: "Load Custom CA within IOS",
|
||||||
|
Patches: []Patch{
|
||||||
|
{
|
||||||
Name: "Insert custom CA into free space",
|
Name: "Insert custom CA into free space",
|
||||||
AtOffset: 3037368,
|
AtOffset: 3037368,
|
||||||
|
|
||||||
Before: emptyBytes(len(rootCertificate)),
|
Before: EmptyBytes(len(rootCertificate)),
|
||||||
After: rootCertificate,
|
After: rootCertificate,
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Modify NHTTPi_SocSSLConnect to load cert",
|
Name: "Modify NHTTPi_SocSSLConnect to load cert",
|
||||||
AtOffset: 644624,
|
AtOffset: 644624,
|
||||||
|
|
||||||
@ -67,7 +73,7 @@ func LoadCustomCA() PatchSet {
|
|||||||
LI(R3, 0xfc14),
|
LI(R3, 0xfc14),
|
||||||
// b FUNCTION_PROLOG
|
// b FUNCTION_PROLOG
|
||||||
B(0x800acb10, 0x800acbb0),
|
B(0x800acb10, 0x800acbb0),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
After: Instructions{
|
After: Instructions{
|
||||||
// Our certificate is present at 0x802e97b8.
|
// Our certificate is present at 0x802e97b8.
|
||||||
// r4 is the second parameter of SSLSetRootCA, the ca_cert pointer.
|
// r4 is the second parameter of SSLSetRootCA, the ca_cert pointer.
|
||||||
@ -98,7 +104,8 @@ func LoadCustomCA() PatchSet {
|
|||||||
|
|
||||||
// NOP the rest in order to allow execution to continue.
|
// NOP the rest in order to allow execution to continue.
|
||||||
NOP(), NOP(), NOP(), NOP(), NOP(), NOP(), NOP(),
|
NOP(), NOP(), NOP(), NOP(), NOP(), NOP(), NOP(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/wii-tools/powerpc"
|
||||||
|
)
|
||||||
|
|
||||||
var PatchECCfgPath = PatchSet{
|
var PatchECCfgPath = PatchSet{
|
||||||
Patch{
|
|
||||||
Name: "Change EC Configuration Path",
|
Name: "Change EC Configuration Path",
|
||||||
|
Patches: []Patch{
|
||||||
|
{
|
||||||
AtOffset: 3319968,
|
AtOffset: 3319968,
|
||||||
|
|
||||||
Before: []byte("ec.cfg\x00\x00"),
|
Before: []byte("ec.cfg\x00\x00"),
|
||||||
After: []byte("osc.cfg\x00"),
|
After: []byte("osc.cfg\x00"),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/wii-tools/powerpc"
|
||||||
|
)
|
||||||
|
|
||||||
var NegateECTitle = PatchSet{
|
var NegateECTitle = PatchSet{
|
||||||
|
Name: "Negate EC Title Check",
|
||||||
|
|
||||||
|
Patches: []Patch{
|
||||||
Patch{
|
Patch{
|
||||||
Name: "Permit downloading all titles",
|
Name: "Permit downloading all titles",
|
||||||
AtOffset: 619648,
|
AtOffset: 619648,
|
||||||
@ -9,13 +16,13 @@ var NegateECTitle = PatchSet{
|
|||||||
Before: Instructions{
|
Before: Instructions{
|
||||||
STWU(R1, R1, 0xffe0),
|
STWU(R1, R1, 0xffe0),
|
||||||
MFSPR(),
|
MFSPR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
|
|
||||||
// Immediately return true
|
// Immediately return true
|
||||||
After: Instructions{
|
After: Instructions{
|
||||||
LI(R3, 1),
|
LI(R3, 1),
|
||||||
BLR(),
|
BLR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
},
|
},
|
||||||
Patch{
|
Patch{
|
||||||
Name: "Mark all titles as managed",
|
Name: "Mark all titles as managed",
|
||||||
@ -24,11 +31,11 @@ var NegateECTitle = PatchSet{
|
|||||||
Before: Instructions{
|
Before: Instructions{
|
||||||
STWU(R1, R1, 0xfff0),
|
STWU(R1, R1, 0xfff0),
|
||||||
MFSPR(),
|
MFSPR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
After: Instructions{
|
After: Instructions{
|
||||||
LI(R3, 1),
|
LI(R3, 1),
|
||||||
BLR(),
|
BLR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
},
|
},
|
||||||
Patch{
|
Patch{
|
||||||
Name: "Mark all tickets as managed",
|
Name: "Mark all tickets as managed",
|
||||||
@ -36,11 +43,11 @@ var NegateECTitle = PatchSet{
|
|||||||
Before: Instructions{
|
Before: Instructions{
|
||||||
STWU(R1, R1, 0xfff0),
|
STWU(R1, R1, 0xfff0),
|
||||||
MFSPR(),
|
MFSPR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
After: Instructions{
|
After: Instructions{
|
||||||
LI(R3, 1),
|
LI(R3, 1),
|
||||||
BLR(),
|
BLR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
},
|
},
|
||||||
Patch{
|
Patch{
|
||||||
Name: "Nullify ec::removeAllTitles",
|
Name: "Nullify ec::removeAllTitles",
|
||||||
@ -48,10 +55,11 @@ var NegateECTitle = PatchSet{
|
|||||||
Before: Instructions{
|
Before: Instructions{
|
||||||
STWU(R1, R1, 0xffc0),
|
STWU(R1, R1, 0xffc0),
|
||||||
MFSPR(),
|
MFSPR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
After: Instructions{
|
After: Instructions{
|
||||||
LI(R3, 0),
|
LI(R3, 0),
|
||||||
BLR(),
|
BLR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/wii-tools/powerpc"
|
||||||
|
)
|
||||||
|
|
||||||
// OverwriteIOSPatch effectively nullifies IOSC_VerifyPublicKeySign.
|
// OverwriteIOSPatch effectively nullifies IOSC_VerifyPublicKeySign.
|
||||||
// See docs/patch_overwrite_ios.md for more information.
|
// See docs/patch_overwrite_ios.md for more information.
|
||||||
var OverwriteIOSPatch = PatchSet{
|
var OverwriteIOSPatch = PatchSet{
|
||||||
Patch{
|
Name: "Overwrite IOS Syscall for ES",
|
||||||
|
Patches: []Patch{
|
||||||
|
{
|
||||||
Name: "Clear extraneous functions",
|
Name: "Clear extraneous functions",
|
||||||
AtOffset: 20272,
|
AtOffset: 20272,
|
||||||
|
|
||||||
@ -29,30 +35,30 @@ var OverwriteIOSPatch = PatchSet{
|
|||||||
// b printf
|
// b printf
|
||||||
Instruction{0x48, 0x2a, 0x8b, 0x5c},
|
Instruction{0x48, 0x2a, 0x8b, 0x5c},
|
||||||
|
|
||||||
padding,
|
Padding,
|
||||||
|
|
||||||
// Function: textinput::EventObserver::onSE
|
// Function: textinput::EventObserver::onSE
|
||||||
BLR(),
|
BLR(),
|
||||||
padding, padding, padding,
|
Padding, Padding, Padding,
|
||||||
// Function: textinput::EventObserver::onEvent
|
// Function: textinput::EventObserver::onEvent
|
||||||
BLR(),
|
BLR(),
|
||||||
padding, padding, padding,
|
Padding, Padding, Padding,
|
||||||
// Function: textinput::EventObserver::onCommand
|
// Function: textinput::EventObserver::onCommand
|
||||||
BLR(),
|
BLR(),
|
||||||
padding, padding, padding,
|
Padding, Padding, Padding,
|
||||||
// Function: textinput::EventObserver::onInput
|
// Function: textinput::EventObserver::onInput
|
||||||
BLR(),
|
BLR(),
|
||||||
padding, padding, padding,
|
Padding, Padding, Padding,
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
|
|
||||||
// We wish to clear extraneous blrs so that our custom overwriteIOSMemory
|
// We wish to clear extraneous blrs so that our custom overwriteIOSMemory
|
||||||
// function does not somehow conflict.
|
// function does not somehow conflict.
|
||||||
// We only preserve onSE, which is this immediate BLR.
|
// We only preserve onSE, which is this immediate BLR.
|
||||||
After: append(Instructions{
|
After: append(Instructions{
|
||||||
BLR(),
|
BLR(),
|
||||||
}.toBytes(), emptyBytes(108)...),
|
}.Bytes(), EmptyBytes(108)...),
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Repair textinput::EventObserver vtable",
|
Name: "Repair textinput::EventObserver vtable",
|
||||||
AtOffset: 3095452,
|
AtOffset: 3095452,
|
||||||
|
|
||||||
@ -76,7 +82,7 @@ var OverwriteIOSPatch = PatchSet{
|
|||||||
0x80, 0x01, 0x43, 0xf0,
|
0x80, 0x01, 0x43, 0xf0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Repair ipl::keyboard::EventObserver vtable",
|
Name: "Repair ipl::keyboard::EventObserver vtable",
|
||||||
AtOffset: 3097888,
|
AtOffset: 3097888,
|
||||||
|
|
||||||
@ -99,11 +105,11 @@ var OverwriteIOSPatch = PatchSet{
|
|||||||
0x80, 0x01, 0x43, 0xf0, // textinput::EventObserver::doNothing
|
0x80, 0x01, 0x43, 0xf0, // textinput::EventObserver::doNothing
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Insert patch table",
|
Name: "Insert patch table",
|
||||||
AtOffset: 3205088,
|
AtOffset: 3205088,
|
||||||
|
|
||||||
Before: emptyBytes(52),
|
Before: EmptyBytes(52),
|
||||||
After: []byte{
|
After: []byte{
|
||||||
//////////////
|
//////////////
|
||||||
// PATCH #1 //
|
// PATCH #1 //
|
||||||
@ -176,13 +182,13 @@ var OverwriteIOSPatch = PatchSet{
|
|||||||
0x93, 0x00, 0x01, 0xff,
|
0x93, 0x00, 0x01, 0xff,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Insert overwriteIOSMemory",
|
Name: "Insert overwriteIOSMemory",
|
||||||
AtOffset: 20276,
|
AtOffset: 20276,
|
||||||
|
|
||||||
// This area should be cleared in the patch
|
// This area should be cleared in the patch
|
||||||
// "Clear extraneous functions".
|
// "Clear extraneous functions".
|
||||||
Before: emptyBytes(108),
|
Before: EmptyBytes(108),
|
||||||
After: Instructions{
|
After: Instructions{
|
||||||
// Our patch table is available at 0x803126e0.
|
// Our patch table is available at 0x803126e0.
|
||||||
LIS(R8, 0x8031),
|
LIS(R8, 0x8031),
|
||||||
@ -248,28 +254,29 @@ var OverwriteIOSPatch = PatchSet{
|
|||||||
|
|
||||||
// We're finished patching!
|
// We're finished patching!
|
||||||
BLR(),
|
BLR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Do not require input for exception handler",
|
Name: "Do not require input for exception handler",
|
||||||
AtOffset: 32032,
|
AtOffset: 32032,
|
||||||
Before: Instructions{
|
Before: Instructions{
|
||||||
STWU(R1, R1, 0xFC10),
|
STWU(R1, R1, 0xFC10),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
After: Instructions{
|
After: Instructions{
|
||||||
BLR(),
|
BLR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
},
|
},
|
||||||
Patch{
|
{
|
||||||
Name: "Modify ipl::Exception::__ct",
|
Name: "Modify ipl::Exception::__ct",
|
||||||
AtOffset: 31904,
|
AtOffset: 31904,
|
||||||
|
|
||||||
Before: Instructions{
|
Before: Instructions{
|
||||||
BLR(),
|
BLR(),
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
After: Instructions{
|
After: Instructions{
|
||||||
// b overwriteIOSMemory
|
// b overwriteIOSMemory
|
||||||
Instruction{0x42, 0x80, 0xd2, 0x94},
|
Instruction{0x42, 0x80, 0xd2, 0x94},
|
||||||
}.toBytes(),
|
}.Bytes(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
152
powerpc.go
152
powerpc.go
@ -1,152 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// uint24 returns
|
|
||||||
func uint24(num uint32) [3]byte {
|
|
||||||
if num > 0x00FFFFFF {
|
|
||||||
panic("invalid uint24 passed")
|
|
||||||
}
|
|
||||||
|
|
||||||
result := fourByte(num)
|
|
||||||
return [3]byte{result[1], result[2], result[3]}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instruction represents a 4-byte PowerPC instruction.
|
|
||||||
type Instruction [4]byte
|
|
||||||
|
|
||||||
// Instructions represents a group of PowerPC instructions.
|
|
||||||
type Instructions []Instruction
|
|
||||||
|
|
||||||
// toBytes returns the bytes necessary to represent these instructions.
|
|
||||||
func (i Instructions) toBytes() []byte {
|
|
||||||
var contents []byte
|
|
||||||
|
|
||||||
for _, instruction := range i {
|
|
||||||
contents = append(contents, instruction[:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return contents
|
|
||||||
}
|
|
||||||
|
|
||||||
// padding is not an actual instruction - it represents 4 zeros.
|
|
||||||
var padding Instruction = [4]byte{0x00, 0x00, 0x00, 0x00}
|
|
||||||
|
|
||||||
// BLR represents the blr mnemonic on PowerPC.
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LI represents the li mnemonic on PowerPC.
|
|
||||||
func LI(rT Register, value uint16) Instruction {
|
|
||||||
return ADDI(rT, 0, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ADDIS represents the addis PowerPC instruction.
|
|
||||||
func ADDIS(rT Register, rA Register, value uint16) Instruction {
|
|
||||||
return EncodeInstrDForm(15, rT, rA, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LIS represents the lis mnemonic on PowerPC.
|
|
||||||
func LIS(rT Register, value uint16) Instruction {
|
|
||||||
return ADDIS(rT, 0, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ORI represents the ori PowerPC instruction.
|
|
||||||
func ORI(rS Register, rA Register, value uint16) Instruction {
|
|
||||||
return EncodeInstrDForm(24, rS, rA, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// STH represents the sth PowerPC instruction.
|
|
||||||
func STH(rS Register, offset uint16, rA Register) Instruction {
|
|
||||||
return EncodeInstrDForm(44, rS, rA, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EIEIO represents the eieio PowerPC instruction.
|
|
||||||
func EIEIO() Instruction {
|
|
||||||
return [4]byte{0x7C, 0x00, 0x06, 0xAC}
|
|
||||||
}
|
|
||||||
|
|
||||||
// STW represents the stw PowerPC instruction.
|
|
||||||
func STW(rS Register, offset uint16, rA Register) Instruction {
|
|
||||||
return EncodeInstrDForm(36, rS, rA, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LWZ represents the lwz PowerPC instruction.
|
|
||||||
func LWZ(rT Register, offset uint16, rA Register) Instruction {
|
|
||||||
return EncodeInstrDForm(32, rT, rA, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOP represents the nop mnemonic for PowerPC.
|
|
||||||
func NOP() Instruction {
|
|
||||||
return ORI(R0, R0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CMPWI represents the cmpwi mnemonic for PowerPC.
|
|
||||||
// It does not support any other CR fields asides from 0.
|
|
||||||
func CMPWI(rA Register, value uint16) Instruction {
|
|
||||||
return EncodeInstrDForm(11, 0, rA, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SYNC is a hack, hardcoding sync 0.
|
|
||||||
// TODO(spotlightishere): actually encode this
|
|
||||||
func SYNC() Instruction {
|
|
||||||
return [4]byte{0x7c, 0x00, 0x04, 0xac}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// calcDestination determines the proper offset from a given
|
|
||||||
// calling address and target address.
|
|
||||||
func calcDestination(from uint, target uint) [3]byte {
|
|
||||||
// TODO(spotlightishere): Handle negative offsets properly
|
|
||||||
offset := target - from
|
|
||||||
|
|
||||||
// Sign-extend by two bytes
|
|
||||||
calc := uint32(offset >> 2)
|
|
||||||
return uint24(calc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BL represents the bl PowerPC instruction.
|
|
||||||
// It calculates the offset from the given current address and the given
|
|
||||||
// target address, saving the current address in the link register. It then branches.
|
|
||||||
func BL(current uint, target uint) Instruction {
|
|
||||||
return EncodeInstrIForm(18, calcDestination(current, target), false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// B represents the b PowerPC instruction.
|
|
||||||
// It calculates the offset from the given current address
|
|
||||||
// and the given target address, and then branches.
|
|
||||||
func B(current uint, target uint) Instruction {
|
|
||||||
return EncodeInstrIForm(18, calcDestination(current, target), false, false)
|
|
||||||
}
|
|
@ -1,160 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Register represents a value for a PowerPC register.
|
|
||||||
type Register byte
|
|
||||||
|
|
||||||
const (
|
|
||||||
R0 = iota
|
|
||||||
R1
|
|
||||||
R2
|
|
||||||
R3
|
|
||||||
R4
|
|
||||||
R5
|
|
||||||
R6
|
|
||||||
R7
|
|
||||||
R8
|
|
||||||
R9
|
|
||||||
R10
|
|
||||||
R11
|
|
||||||
R12
|
|
||||||
R13
|
|
||||||
R14
|
|
||||||
R15
|
|
||||||
R16
|
|
||||||
R17
|
|
||||||
R18
|
|
||||||
R19
|
|
||||||
R20
|
|
||||||
R21
|
|
||||||
R22
|
|
||||||
R23
|
|
||||||
R24
|
|
||||||
R25
|
|
||||||
R26
|
|
||||||
R27
|
|
||||||
R28
|
|
||||||
R29
|
|
||||||
R30
|
|
||||||
R31
|
|
||||||
)
|
|
||||||
|
|
||||||
// Bits represents bits for a byte.
|
|
||||||
// If set, considered as 1. If not, 0.
|
|
||||||
type Bits [8]bool
|
|
||||||
|
|
||||||
// getBits returns a usable array of bits for the given byte.
|
|
||||||
func getBits(in byte) Bits {
|
|
||||||
return [8]bool{
|
|
||||||
(in>>7)&1 == 1,
|
|
||||||
(in>>6)&1 == 1,
|
|
||||||
(in>>5)&1 == 1,
|
|
||||||
(in>>4)&1 == 1,
|
|
||||||
(in>>3)&1 == 1,
|
|
||||||
(in>>2)&1 == 1,
|
|
||||||
(in>>1)&1 == 1,
|
|
||||||
in&1 == 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getByte returns the byte represented by these bits.
|
|
||||||
func (b Bits) getByte() byte {
|
|
||||||
var result byte
|
|
||||||
for idx, truthy := range b {
|
|
||||||
if truthy {
|
|
||||||
result |= 1 << (7 - idx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeInstrDForm handles encoding a given opcode, RT, RA and SI.
|
|
||||||
// D-form assumes:
|
|
||||||
// - 6 bits for the opcode
|
|
||||||
// - 5 for rT
|
|
||||||
// - 5 for rA
|
|
||||||
// - 16 for SI
|
|
||||||
func EncodeInstrDForm(opcode byte, rT Register, rA Register, value uint16) Instruction {
|
|
||||||
var instr [2]Bits
|
|
||||||
opBits := getBits(opcode)
|
|
||||||
rTBits := getBits(byte(rT))
|
|
||||||
rABits := getBits(byte(rA))
|
|
||||||
|
|
||||||
instr[0] = Bits{
|
|
||||||
// We need the upper six bits for our opcode.
|
|
||||||
opBits[2],
|
|
||||||
opBits[3],
|
|
||||||
opBits[4],
|
|
||||||
opBits[5],
|
|
||||||
opBits[6],
|
|
||||||
opBits[7],
|
|
||||||
// Next, the lower two bits for rT.
|
|
||||||
rTBits[3],
|
|
||||||
rTBits[4],
|
|
||||||
}
|
|
||||||
instr[1] = Bits{
|
|
||||||
// Third, the lower three bits for rT.
|
|
||||||
rTBits[5],
|
|
||||||
rTBits[6],
|
|
||||||
rTBits[7],
|
|
||||||
// Finally, all five lowest bits for rA.
|
|
||||||
rABits[3],
|
|
||||||
rABits[4],
|
|
||||||
rABits[5],
|
|
||||||
rABits[6],
|
|
||||||
rABits[7],
|
|
||||||
}
|
|
||||||
|
|
||||||
firstInstr := instr[0].getByte()
|
|
||||||
secondInstr := instr[1].getByte()
|
|
||||||
valByte := twoByte(value)
|
|
||||||
|
|
||||||
return Instruction{firstInstr, secondInstr, valByte[0], valByte[1]}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeInstrIForm handles encoding a given opcode, LI, AA and LK.
|
|
||||||
// I-form assumes:
|
|
||||||
// - 6 bits for the opcode
|
|
||||||
// - 24 bits for LI
|
|
||||||
// - 1 bit for absolute (AA)
|
|
||||||
// - 1 bit for should store in link register (LK)
|
|
||||||
func EncodeInstrIForm(opcode byte, LI [3]byte, AA bool, LK bool) Instruction {
|
|
||||||
opBits := getBits(opcode)
|
|
||||||
liOne := getBits(LI[0])
|
|
||||||
liTwo := getBits(LI[1])
|
|
||||||
liThree := getBits(LI[2])
|
|
||||||
|
|
||||||
instr := [4]Bits{
|
|
||||||
{
|
|
||||||
// We need the upper six bits for our opcode.
|
|
||||||
opBits[2], opBits[3], opBits[4], opBits[5], opBits[6], opBits[7],
|
|
||||||
// Otherwise, copy LI as-is.
|
|
||||||
liOne[0], liOne[1],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
liOne[2], liOne[3], liOne[4], liOne[5], liOne[6], liOne[7], liTwo[0], liTwo[1],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
liTwo[2], liTwo[3], liTwo[4], liTwo[5], liTwo[6], liTwo[7], liThree[0], liThree[1],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
liThree[2], liThree[3], liThree[4], liThree[5], liThree[6], liThree[7],
|
|
||||||
// Copy AA and LK as-is.
|
|
||||||
AA,
|
|
||||||
LK,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return Instruction{instr[0].getByte(), instr[1].getByte(), instr[2].getByte(), instr[3].getByte()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// twoByte converts a uint16 to two big-endian bytes.
|
|
||||||
func twoByte(passed uint16) [2]byte {
|
|
||||||
result := make([]byte, 2)
|
|
||||||
binary.BigEndian.PutUint16(result, passed)
|
|
||||||
return [2]byte{result[0], result[1]}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user