public void InjectIntoDol(Dol dol) { if (_baseAddress.Type == WordType.RelativeAddr) { throw new InvalidOperationException("cannot pack a dynamically linked binary into a DOL"); } // find an empty text section int victimSection = -1; for (int i = dol.Sections.Length - 1; i >= 0; i--) { if (dol.Sections[i].Data.Length == 0) { victimSection = i; break; } } if (victimSection == -1) { throw new InvalidOperationException("cannot find an empty text section in the DOL"); } // throw the code blob into it dol.Sections[victimSection].LoadAddress = _baseAddress.Value; dol.Sections[victimSection].Data = _codeBlob; // apply all patches foreach (var pair in _commands) { pair.Value.ApplyToDol(dol); } }
static void Main(string[] args) { Console.WriteLine("Kamek 2.0 by Ninji/Ash Wolf - https://github.com/Treeki/Kamek"); Console.WriteLine(); // Parse the command line arguments and do cool things! var modules = new List <Elf>(); uint? baseAddress = null; string outputKamekPath = null, outputRiivPath = null, outputGeckoPath = null, outputCodePath = null; string inputDolPath = null, outputDolPath = null; var externals = new Dictionary <string, uint>(); VersionInfo versions = null; var selectedVersions = new List <String>(); foreach (var arg in args) { if (arg.StartsWith("-")) { if (arg == "-h" || arg == "-help" || arg == "--help") { ShowHelp(); return; } if (arg == "-dynamic") { baseAddress = null; } else if (arg.StartsWith("-static=0x")) { baseAddress = uint.Parse(arg.Substring(10), System.Globalization.NumberStyles.HexNumber); } else if (arg.StartsWith("-output-kamek=")) { outputKamekPath = arg.Substring(14); } else if (arg.StartsWith("-output-riiv=")) { outputRiivPath = arg.Substring(13); } else if (arg.StartsWith("-output-gecko=")) { outputGeckoPath = arg.Substring(14); } else if (arg.StartsWith("-output-code=")) { outputCodePath = arg.Substring(13); } else if (arg.StartsWith("-input-dol=")) { inputDolPath = arg.Substring(11); } else if (arg.StartsWith("-output-dol=")) { outputDolPath = arg.Substring(12); } else if (arg.StartsWith("-externals=")) { ReadExternals(externals, arg.Substring(11)); } else if (arg.StartsWith("-versions=")) { versions = new VersionInfo(arg.Substring(10)); } else if (arg.StartsWith("-select-version=")) { selectedVersions.Add(arg.Substring(16)); } else { Console.WriteLine("warning: unrecognised argument: {0}", arg); } } else { Console.WriteLine("adding {0} as object..", arg); using (var stream = new FileStream(arg, FileMode.Open)) { modules.Add(new Elf(stream)); } } } // We need a default VersionList for the loop later if (versions == null) { versions = new VersionInfo(); } // Can we build a thing? if (modules.Count == 0) { Console.WriteLine("no input files specified"); return; } if (outputKamekPath == null && outputRiivPath == null && outputGeckoPath == null && outputCodePath == null && outputDolPath == null) { Console.WriteLine("no output path(s) specified"); return; } if (outputDolPath != null && inputDolPath == null) { Console.WriteLine("input dol path not specified"); return; } // Do safety checks if (versions.Mappers.Count > 1 && selectedVersions.Count != 1) { bool ambiguousOutputPath = false; ambiguousOutputPath |= (outputKamekPath != null && !outputKamekPath.Contains("$KV$")); ambiguousOutputPath |= (outputRiivPath != null && !outputRiivPath.Contains("$KV$")); ambiguousOutputPath |= (outputGeckoPath != null && !outputGeckoPath.Contains("$KV$")); ambiguousOutputPath |= (outputCodePath != null && !outputCodePath.Contains("$KV$")); ambiguousOutputPath |= (outputDolPath != null && !outputDolPath.Contains("$KV$")); if (ambiguousOutputPath) { Console.WriteLine("ERROR: this configuration builds for multiple game versions, and some of the outputs will be overwritten"); Console.WriteLine("add the $KV$ placeholder to your output paths, or use -select-version=.. to only build one version"); return; } } foreach (var version in versions.Mappers) { if (selectedVersions.Count > 0 && !selectedVersions.Contains(version.Key)) { Console.WriteLine("(skipping version {0} as it's not selected)", version.Key); continue; } Console.WriteLine("linking version {0}...", version.Key); var linker = new Linker(version.Value); foreach (var module in modules) { linker.AddModule(module); } if (baseAddress.HasValue) { linker.LinkStatic(baseAddress.Value, externals); } else { linker.LinkDynamic(externals); } var kf = new KamekFile(); kf.LoadFromLinker(linker); if (outputKamekPath != null) { File.WriteAllBytes(outputKamekPath.Replace("$KV$", version.Key), kf.Pack()); } if (outputRiivPath != null) { File.WriteAllText(outputRiivPath.Replace("$KV$", version.Key), kf.PackRiivolution()); } if (outputGeckoPath != null) { File.WriteAllText(outputGeckoPath.Replace("$KV$", version.Key), kf.PackGeckoCodes()); } if (outputCodePath != null) { File.WriteAllBytes(outputCodePath.Replace("$KV$", version.Key), kf.CodeBlob); } if (outputDolPath != null) { var dol = new Dol(new FileStream(inputDolPath.Replace("$KV$", version.Key), FileMode.Open)); kf.InjectIntoDol(dol); var outpath = outputDolPath.Replace("$KV$", version.Key); using (var outStream = new FileStream(outpath, FileMode.Create)) { dol.Write(outStream); } } } }
static void Main(string[] args) { Console.WriteLine("Kamek 2.0 by Treeki"); Console.WriteLine(); // Parse the command line arguments and do cool things! var modules = new List <Elf>(); uint? baseAddress = null; string outputKamekPath = null, outputRiivPath = null, outputGeckoPath = null, outputCodePath = null; string inputDolPath = null, outputDolPath = null; var externals = new Dictionary <string, uint>(); VersionInfo versions = null; foreach (var arg in args) { if (arg.StartsWith("-")) { if (arg == "-dynamic") { baseAddress = null; } else if (arg.StartsWith("-static=0x")) { baseAddress = uint.Parse(arg.Substring(10), System.Globalization.NumberStyles.HexNumber); } else if (arg.StartsWith("-output-kamek=")) { outputKamekPath = arg.Substring(14); } else if (arg.StartsWith("-output-riiv=")) { outputRiivPath = arg.Substring(13); } else if (arg.StartsWith("-output-gecko=")) { outputGeckoPath = arg.Substring(14); } else if (arg.StartsWith("-output-code=")) { outputCodePath = arg.Substring(13); } else if (arg.StartsWith("-input-dol=")) { inputDolPath = arg.Substring(11); } else if (arg.StartsWith("-output-dol=")) { outputDolPath = arg.Substring(12); } else if (arg.StartsWith("-externals=")) { ReadExternals(externals, arg.Substring(11)); } else if (arg.StartsWith("-versions=")) { versions = new VersionInfo(arg.Substring(10)); } else { Console.WriteLine("warning: unrecognised argument: {0}", arg); } } else { Console.WriteLine("adding {0} as object..", arg); using (var stream = new FileStream(arg, FileMode.Open)) { modules.Add(new Elf(stream)); } } } // We need a default VersionList for the loop later if (versions == null) { versions = new VersionInfo(); } // Can we build a thing? if (modules.Count == 0) { Console.WriteLine("no input files specified"); return; } if (outputKamekPath == null && outputRiivPath == null && outputGeckoPath == null && outputCodePath == null && outputDolPath == null) { Console.WriteLine("no output path(s) specified"); return; } if (outputDolPath != null && inputDolPath == null) { Console.WriteLine("input dol path not specified"); return; } foreach (var version in versions.Mappers) { Console.WriteLine("linking version {0}...", version.Key); var linker = new Linker(version.Value); foreach (var module in modules) { linker.AddModule(module); } if (baseAddress.HasValue) { linker.LinkStatic(baseAddress.Value, externals); } else { linker.LinkDynamic(externals); } var kf = new KamekFile(); kf.LoadFromLinker(linker); if (outputKamekPath != null) { File.WriteAllBytes(outputKamekPath.Replace("$KV$", version.Key), kf.Pack()); } if (outputRiivPath != null) { File.WriteAllText(outputRiivPath.Replace("$KV$", version.Key), kf.PackRiivolution()); } if (outputGeckoPath != null) { File.WriteAllText(outputGeckoPath.Replace("$KV$", version.Key), kf.PackGeckoCodes()); } if (outputCodePath != null) { File.WriteAllBytes(outputCodePath.Replace("$KV$", version.Key), kf.CodeBlob); } if (outputDolPath != null) { var dol = new Dol(new FileStream(inputDolPath, FileMode.Open)); kf.InjectIntoDol(dol); var outpath = outputDolPath.Replace("$KV$", version.Key); using (var outStream = new FileStream(outpath, FileMode.Create)) { dol.Write(outStream); } } } }