WiiMart-Patcher/main.go
Spotlight 8f0a067af7
Resolve contents not being fully updated
For whatever reason, this allows the patcher to use the correct hashes upon initial download via GoNUSD. This should probably be looked into eventually...
2022-08-19 17:21:56 -05:00

169 lines
4.5 KiB
Go

package main
import (
"errors"
"fmt"
"github.com/logrusorgru/aurora/v3"
"github.com/wii-tools/GoNUSD"
"github.com/wii-tools/arclib"
"github.com/wii-tools/powerpc"
"github.com/wii-tools/wadlib"
"io/fs"
"io/ioutil"
"log"
"os"
)
// baseDomain holds our needed base domain.
var baseDomain string
// mainDol holds the main DOL - our content at index 1.
var mainDol []byte
// mainArc holds the main ARC - our content at index 2.
var mainArc *arclib.ARC
// rootCertificate holds the public certificate, in DER form, to be patched in.
var rootCertificate []byte
// filePresent returns whether the specified path is present on disk.
func filePresent(path string) bool {
_, err := os.Stat(path)
return errors.Is(err, fs.ErrNotExist) == false
}
// createDir creates a directory at the given path if it is not already present.
func createDir(path string) {
if !filePresent(path) {
os.Mkdir(path, 0755)
}
}
func main() {
if len(os.Args) != 2 {
fmt.Printf("Usage: %s <base domain>\n", os.Args[0])
fmt.Println("For more information, please refer to the README.")
os.Exit(-1)
}
baseDomain = os.Args[1]
if len(baseDomain) > 12 {
fmt.Println("The given base domain must not exceed 12 characters.")
fmt.Println("For more information, please refer to the README.")
os.Exit(-1)
}
fmt.Println("===========================")
fmt.Println("= WSC-Patcher =")
fmt.Println("===========================")
// Create directories we may need later.
createDir("./output")
createDir("./cache")
var err error
// Determine whether the Wii Shop Channel is cached.
if !filePresent("./cache/original.wad") {
log.Println("Downloading a copy of the original Wii Shop Channel, please wait...")
var downloadedShop *wadlib.WAD
downloadedShop, err = GoNUSD.Download(0x00010002_48414241, 21, true)
check(err)
// Cache this downloaded WAD to disk.
var contents []byte
contents, err = downloadedShop.GetWAD(wadlib.WADTypeCommon)
check(err)
os.WriteFile("./cache/original.wad", contents, 0755)
}
var originalWad *wadlib.WAD
originalWad, err = wadlib.LoadWADFromFile("./cache/original.wad")
check(err)
// Determine whether a certificate authority was provided, or generated previously.
if !filePresent("./output/root.cer") {
fmt.Println(aurora.Green("Generating root certificates..."))
rootCertificate = createCertificates()
} else {
rootCertificate, err = ioutil.ReadFile("./output/root.cer")
check(err)
}
// Ensure the loaded certificate has a suitable length.
// It must not be longer than 928 bytes.
if len(rootCertificate) > 928 {
fmt.Println("The passed root certificate exceeds the maximum length possible, 928 bytes.")
fmt.Println("Please verify parameters passed for generation and reduce its size.")
os.Exit(-1)
}
// Load main DOL
mainDol, err = originalWad.GetContent(1)
check(err)
// Permit r/w access to MEM2_PROT via the TMD.
// See docs/patch_overwrite_ios.md for more information!
originalWad.TMD.AccessRightsFlags = 0x3
// Apply all DOL patches
fmt.Println(aurora.Green("Applying DOL patches..."))
applyDefaultPatches()
// Save main DOL
err = originalWad.UpdateContent(1, mainDol)
check(err)
// Load main ARC
arcData, err := originalWad.GetContent(2)
check(err)
mainArc, err = arclib.Load(arcData)
check(err)
// Generate filter list and certificate store
fmt.Println(aurora.Green("Applying Opera patches..."))
modifyAllowList()
generateOperaCertStore()
// Save main ARC
updated, err := mainArc.Save()
check(err)
err = originalWad.UpdateContent(2, updated)
check(err)
// Generate a patched WAD with our changes
output, err := originalWad.GetWAD(wadlib.WADTypeCommon)
check(err)
fmt.Println(aurora.Green("Done! Install ./output/patched.wad, sit back, and enjoy."))
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.
func check(err error) {
if err != nil {
panic(err)
}
}
// writeOut writes a file with the given name and contents to the output folder.
func writeOut(filename string, contents []byte) {
os.WriteFile("./output/"+filename, contents, 0755)
}