mirror of
https://wiilab.wiimart.org/wiimart/WiiMart-Patcher
synced 2025-09-04 04:21:19 +02:00
99 lines
2.9 KiB
Go
99 lines
2.9 KiB
Go
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)
|
|
}
|