public static bool LoadNsos(KernelContext context, out ProcessTamperInfo tamperInfo, Npdm metaData, byte[] arguments = null, params IExecutable[] executables) { ulong argsStart = 0; uint argsSize = 0; ulong codeStart = metaData.Is64Bit ? 0x8000000UL : 0x200000UL; uint codeSize = 0; var buildIds = executables.Select(e => (e switch { NsoExecutable nso => BitConverter.ToString(nso.BuildId.Bytes.ToArray()), NroExecutable nro => BitConverter.ToString(nro.Header.BuildId), _ => "" }).Replace("-", "").ToUpper());
public NroInfo( NroExecutable executable, byte[] hash, ulong nroAddress, ulong nroSize, ulong bssAddress, ulong bssSize, ulong totalSize) { Executable = executable; Hash = hash; NroAddress = nroAddress; NroSize = nroSize; BssAddress = bssAddress; BssSize = bssSize; TotalSize = totalSize; }
public ResultCode ParseNro(out NroInfo res, ServiceCtx context, ulong nroAddress, ulong nroSize, ulong bssAddress, ulong bssSize) { res = null; if (_nroInfos.Count >= MaxNro) { return(ResultCode.TooManyNro); } else if (nroSize == 0 || nroAddress + nroSize <= nroAddress || (nroSize & 0xFFF) != 0) { return(ResultCode.InvalidSize); } else if (bssSize != 0 && bssAddress + bssSize <= bssAddress) { return(ResultCode.InvalidSize); } else if ((nroAddress & 0xFFF) != 0) { return(ResultCode.InvalidAddress); } uint magic = _owner.CpuMemory.Read <uint>(nroAddress + 0x10); uint nroFileSize = _owner.CpuMemory.Read <uint>(nroAddress + 0x18); if (magic != NroMagic || nroSize != nroFileSize) { return(ResultCode.InvalidNro); } byte[] nroData = new byte[nroSize]; _owner.CpuMemory.Read(nroAddress, nroData); byte[] nroHash = null; MemoryStream stream = new MemoryStream(nroData); using (SHA256 hasher = SHA256.Create()) { nroHash = hasher.ComputeHash(stream); } if (!IsNroHashPresent(nroHash)) { return(ResultCode.NotRegistered); } if (IsNroLoaded(nroHash)) { return(ResultCode.AlreadyLoaded); } stream.Position = 0; NroExecutable nro = new NroExecutable(stream.AsStorage(), nroAddress, bssAddress); // Check if everything is page align. if ((nro.Text.Length & 0xFFF) != 0 || (nro.Ro.Length & 0xFFF) != 0 || (nro.Data.Length & 0xFFF) != 0 || (nro.BssSize & 0xFFF) != 0) { return(ResultCode.InvalidNro); } // Check if everything is contiguous. if (nro.RoOffset != nro.TextOffset + nro.Text.Length || nro.DataOffset != nro.RoOffset + nro.Ro.Length || nroFileSize != nro.DataOffset + nro.Data.Length) { return(ResultCode.InvalidNro); } // Check the bss size match. if ((ulong)nro.BssSize != bssSize) { return(ResultCode.InvalidNro); } uint totalSize = (uint)nro.Text.Length + (uint)nro.Ro.Length + (uint)nro.Data.Length + nro.BssSize; // Apply patches context.Device.FileSystem.ModLoader.ApplyNroPatches(nro); res = new NroInfo( nro, nroHash, nroAddress, nroSize, bssAddress, bssSize, (ulong)totalSize); return(ResultCode.Success); }
public ResultCode ParseNro(out NroInfo res, ServiceCtx context, ulong nroAddress, ulong nroSize, ulong bssAddress, ulong bssSize) { res = null; if (_nroInfos.Count >= MaxNro) { return(ResultCode.TooManyNro); } else if (nroSize == 0 || nroAddress + nroSize <= nroAddress || (nroSize & 0xFFF) != 0) { return(ResultCode.InvalidSize); } else if (bssSize != 0 && bssAddress + bssSize <= bssAddress) { return(ResultCode.InvalidSize); } else if ((nroAddress & 0xFFF) != 0) { return(ResultCode.InvalidAddress); } uint magic = context.Memory.ReadUInt32((long)nroAddress + 0x10); uint nroFileSize = context.Memory.ReadUInt32((long)nroAddress + 0x18); if (magic != NroMagic || nroSize != nroFileSize) { return(ResultCode.InvalidNro); } byte[] nroData = context.Memory.ReadBytes((long)nroAddress, (long)nroSize); byte[] nroHash = null; MemoryStream stream = new MemoryStream(nroData); using (SHA256 hasher = SHA256.Create()) { nroHash = hasher.ComputeHash(stream); } if (!IsNroHashPresent(nroHash)) { return(ResultCode.NotRegistered); } if (IsNroLoaded(nroHash)) { return(ResultCode.AlreadyLoaded); } stream.Position = 0; NroExecutable executable = new NroExecutable(stream, nroAddress, bssAddress); // check if everything is page align. if ((executable.Text.Length & 0xFFF) != 0 || (executable.Ro.Length & 0xFFF) != 0 || (executable.Data.Length & 0xFFF) != 0 || (executable.BssSize & 0xFFF) != 0) { return(ResultCode.InvalidNro); } // check if everything is contiguous. if (executable.RoOffset != executable.TextOffset + executable.Text.Length || executable.DataOffset != executable.RoOffset + executable.Ro.Length || nroFileSize != executable.DataOffset + executable.Data.Length) { return(ResultCode.InvalidNro); } // finally check the bss size match. if ((ulong)executable.BssSize != bssSize) { return(ResultCode.InvalidNro); } int totalSize = executable.Text.Length + executable.Ro.Length + executable.Data.Length + executable.BssSize; res = new NroInfo( executable, nroHash, nroAddress, nroSize, bssAddress, bssSize, (ulong)totalSize); return(ResultCode.Success); }
public void LoadProgram(string filePath) { Npdm metaData = GetDefaultNpdm(); bool isNro = Path.GetExtension(filePath).ToLower() == ".nro"; IExecutable staticObject; if (isNro) { FileStream input = new FileStream(filePath, FileMode.Open); NroExecutable obj = new NroExecutable(input); staticObject = obj; // homebrew NRO can actually have some data after the actual NRO if (input.Length > obj.FileSize) { input.Position = obj.FileSize; BinaryReader reader = new BinaryReader(input); uint asetMagic = reader.ReadUInt32(); if (asetMagic == 0x54455341) { uint asetVersion = reader.ReadUInt32(); if (asetVersion == 0) { ulong iconOffset = reader.ReadUInt64(); ulong iconSize = reader.ReadUInt64(); ulong nacpOffset = reader.ReadUInt64(); ulong nacpSize = reader.ReadUInt64(); ulong romfsOffset = reader.ReadUInt64(); ulong romfsSize = reader.ReadUInt64(); if (romfsSize != 0) { Device.FileSystem.SetRomFs(new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset)); } if (nacpSize != 0) { input.Seek(obj.FileSize + (long)nacpOffset, SeekOrigin.Begin); reader.Read(ControlData.ByteSpan); ref ApplicationControlProperty nacp = ref ControlData.Value; metaData.TitleName = nacp.Titles[(int)State.DesiredTitleLanguage].Name.ToString(); if (string.IsNullOrWhiteSpace(metaData.TitleName)) { metaData.TitleName = nacp.Titles.ToArray().FirstOrDefault(x => x.Name[0] != 0).Name.ToString(); } if (nacp.PresenceGroupId != 0) { metaData.Aci0.TitleId = nacp.PresenceGroupId; } else if (nacp.SaveDataOwnerId.Value != 0) { metaData.Aci0.TitleId = nacp.SaveDataOwnerId.Value; } else if (nacp.AddOnContentBaseId != 0) { metaData.Aci0.TitleId = nacp.AddOnContentBaseId - 0x1000; } else { metaData.Aci0.TitleId = 0000000000000000; } } } else { Logger.PrintWarning(LogClass.Loader, $"Unsupported ASET header version found \"{asetVersion}\""); } } } }