/* This file is part of libWiiSharp * Copyright (C) 2009 Leathl * * libWiiSharp is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * libWiiSharp is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //Patches based on Dop-Mii - Thanks to Arikado and Lunatik using System; using System.ComponentModel; using System.Text; namespace libWiiSharp { /// /// An IOS patcher which can patch fakesigning, es_identify and nand permissions. /// public class IosPatcher { private WAD wadFile; private int esIndex = -1; #region Public Functions /// /// Loads an IOS wad to patch the es module. /// /// public void LoadIOS(ref WAD iosWad) { if ((iosWad.TitleID >> 32) != 1 || (iosWad.TitleID & 0xFFFFFFFF) < 3 || (iosWad.TitleID & 0xFFFFFFFF) > 255) throw new Exception("Only IOS WADs can be patched!"); wadFile = iosWad; getEsIndex(); } /// /// Patches fakesigning. /// Returns the number of applied patches. /// /// public int PatchFakeSigning() { if (esIndex < 0) return -1; return patchFakeSigning(ref wadFile.Contents[esIndex]); } /// /// Patches es_identify. /// Returns the number of applied patches. /// /// public int PatchEsIdentify() { if (esIndex < 0) return -1; return patchEsIdentify(ref wadFile.Contents[esIndex]); } /// /// Patches nand permissions. /// Returns the number of applied patches. /// /// public int PatchNandPermissions() { if (esIndex < 0) return -1; return patchNandPermissions(ref wadFile.Contents[esIndex]); } /// /// Patches fakesigning, es_identify and nand permissions. /// Returns the number of applied patches. /// /// public int PatchAll() { if (esIndex < 0) return -1; return patchAll(ref wadFile.Contents[esIndex]); } /// /// Patches fakesigning. /// Returns the number of applied patches. /// /// public int PatchFakeSigning(ref byte[] esModule) { return patchFakeSigning(ref esModule); } /// /// Patches es_identify. /// Returns the number of applied patches. /// /// public int PatchEsIdentify(ref byte[] esModule) { return patchEsIdentify(ref esModule); } /// /// Patches nand permissions. /// Returns the number of applied patches. /// /// public int PatchNandPermissions(ref byte[] esModule) { return patchNandPermissions(ref esModule); } /// /// Patches fakesigning, es_identify and nand permissions. /// Returns the number of applied patches. /// /// public int PatchAll(ref byte[] esModule) { return patchAll(ref esModule); } #endregion #region Private Functions private int patchFakeSigning(ref byte[] esModule) { fireDebug("Patching Fakesigning..."); int patchCount = 0; byte[] oldHashCheck = { 0x20, 0x07, 0x23, 0xA2 }; byte[] newHashCheck = { 0x20, 0x07, 0x4B, 0x0B }; for (int i = 0; i < esModule.Length - 4; i++) { fireProgress((i + 1) * 100 / esModule.Length); if (Shared.CompareByteArrays(esModule, i, oldHashCheck, 0, 4) || Shared.CompareByteArrays(esModule, i, newHashCheck, 0, 4)) { fireDebug(" Patching at Offset: 0x{0}", i.ToString("x8").ToUpper()); esModule[i + 1] = 0x00; i += 4; patchCount++; } } fireDebug("Patching Fakesigning Finished... (Patches applied: {0})", patchCount); return patchCount; } private int patchEsIdentify(ref byte[] esModule) { fireDebug("Patching ES_Identify..."); int patchCount = 0; byte[] identifyCheck = { 0x28, 0x03, 0xD1, 0x23 }; for (int i = 0; i < esModule.Length - 4; i++) { fireProgress((i + 1) * 100 / esModule.Length); if (Shared.CompareByteArrays(esModule, i, identifyCheck, 0, 4)) { fireDebug(" Patching at Offset: 0x{0}", i.ToString("x8").ToUpper()); esModule[i + 2] = 0x00; esModule[i + 3] = 0x00; i += 4; patchCount++; } } fireDebug("Patching ES_Identify Finished... (Patches applied: {0})", patchCount); return patchCount; } private int patchNandPermissions(ref byte[] esModule) { fireDebug("Patching NAND Permissions..."); int patchCount = 0; byte[] permissionTable = { 0x42, 0x8B, 0xD0, 0x01, 0x25, 0x66 }; for (int i = 0; i < esModule.Length - 6; i++) { fireProgress((i + 1) * 100 / esModule.Length); if (Shared.CompareByteArrays(esModule, i, permissionTable, 0, 6)) { fireDebug(" Patching at Offset: 0x{0}", i.ToString("x8").ToUpper()); esModule[i + 2] = 0xE0; i += 6; patchCount++; } } fireDebug("Patching NAND Permissions Finished... (Patches applied: {0})", patchCount); return patchCount; } private int patchAll(ref byte[] esModule) { fireDebug("Patching Fakesigning, ES_Identify and NAND Permissions..."); int patchCount = 0; byte[] oldHashCheck = { 0x20, 0x07, 0x23, 0xA2 }; byte[] newHashCheck = { 0x20, 0x07, 0x4B, 0x0B }; byte[] identifyCheck = { 0x28, 0x03, 0xD1, 0x23 }; byte[] permissionTable = { 0x42, 0x8B, 0xD0, 0x01, 0x25, 0x66 }; for (int i = 0; i < esModule.Length - 6; i++) { fireProgress((i + 1) * 100 / esModule.Length); if (Shared.CompareByteArrays(esModule, i, oldHashCheck, 0, 4) || Shared.CompareByteArrays(esModule, i, newHashCheck, 0, 4)) { fireDebug(" Patching Fakesigning at Offset: 0x{0}", i.ToString("x8").ToUpper()); esModule[i + 1] = 0x00; i += 4; patchCount++; } else if (Shared.CompareByteArrays(esModule, i, identifyCheck, 0, 4)) { fireDebug(" Patching ES_Identify at Offset: 0x{0}", i.ToString("x8").ToUpper()); esModule[i + 2] = 0x00; esModule[i + 3] = 0x00; i += 4; patchCount++; } else if (Shared.CompareByteArrays(esModule, i, permissionTable, 0, 6)) { fireDebug(" Patching NAND Permissions at Offset: 0x{0}", i.ToString("x8").ToUpper()); esModule[i + 2] = 0xE0; i += 6; patchCount++; } } fireDebug("Patching Fakesigning, ES_Identify and NAND Permissions Finished... (Patches applied: {0})", patchCount); return patchCount; } private void getEsIndex() { fireDebug("Scanning for ES Module..."); string iosTag = "$IOSVersion:"; for (int i = wadFile.NumOfContents - 1; i >= 0; i--) { fireDebug(" Scanning Content #{0} of {1}...", i + 1, wadFile.NumOfContents); fireProgress((i + 1) * 100 / wadFile.NumOfContents); for (int j = 0; j < wadFile.Contents[i].Length - 64; j++) { if (ASCIIEncoding.ASCII.GetString(wadFile.Contents[i], j, 12) == iosTag) { int curIndex = j + 12; while (wadFile.Contents[i][curIndex] == ' ') { curIndex++; } if (ASCIIEncoding.ASCII.GetString(wadFile.Contents[i], curIndex, 3) == "ES:") { fireDebug(" -> ES Module found!"); fireDebug("Scanning for ES Module Finished..."); esIndex = i; fireProgress(100); return; } } } } fireDebug(@"/!\/!\/!\ ES Module wasn't found! /!\/!\/!\"); throw new Exception("ES module wasn't found!"); } #endregion #region Events /// /// Fires the Progress of various operations /// public event EventHandler Progress; /// /// Fires debugging messages. You may write them into a log file or log textbox. /// public event EventHandler Debug; private void fireDebug(string debugMessage, params object[] args) { EventHandler debug = Debug; if (debug != null) debug(new object(), new MessageEventArgs(string.Format(debugMessage, args))); } private void fireProgress(int progressPercentage) { EventHandler progress = Progress; if (progress != null) progress(new object(), new ProgressChangedEventArgs(progressPercentage, string.Empty)); } #endregion } }