private ResultCode MapNro(ServiceCtx context, NroInfo info, out ulong nroMappedAddress) { nroMappedAddress = 0; KMemoryManager memMgr = context.Process.MemoryManager; ulong targetAddress = memMgr.GetAddrSpaceBaseAddr(); while (true) { if (targetAddress + info.TotalSize >= memMgr.AddrSpaceEnd) { return(ResultCode.InvalidMemoryState); } KMemoryInfo memInfo = memMgr.QueryMemory(targetAddress); if (memInfo.State == MemoryState.Unmapped && memInfo.Size >= info.TotalSize) { if (!memMgr.InsideHeapRegion(targetAddress, info.TotalSize) && !memMgr.InsideAliasRegion(targetAddress, info.TotalSize)) { break; } } targetAddress += memInfo.Size; } KernelResult result = memMgr.MapProcessCodeMemory(targetAddress, info.NroAddress, info.NroSize); if (result != KernelResult.Success) { return(ResultCode.InvalidMemoryState); } ulong bssTargetAddress = targetAddress + info.NroSize; if (info.BssSize != 0) { result = memMgr.MapProcessCodeMemory(bssTargetAddress, info.BssAddress, info.BssSize); if (result != KernelResult.Success) { memMgr.UnmapProcessCodeMemory(targetAddress, info.NroAddress, info.NroSize); return(ResultCode.InvalidMemoryState); } } result = LoadNroIntoMemory(context.Process, info.Executable, targetAddress); if (result != KernelResult.Success) { memMgr.UnmapProcessCodeMemory(targetAddress, info.NroAddress, info.NroSize); if (info.BssSize != 0) { memMgr.UnmapProcessCodeMemory(bssTargetAddress, info.BssAddress, info.BssSize); } return(ResultCode.Success); } info.NroMappedAddress = targetAddress; nroMappedAddress = targetAddress; 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.MaxNro); } else if (nroSize == 0 || nroAddress + nroSize <= nroAddress || (nroSize & 0xFFF) != 0) { return(ResultCode.BadSize); } else if (bssSize != 0 && bssAddress + bssSize <= bssAddress) { return(ResultCode.BadSize); } else if ((nroAddress & 0xFFF) != 0) { return(ResultCode.UnalignedAddress); } 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.NroHashNotPresent); } if (IsNroLoaded(nroHash)) { return(ResultCode.NroAlreadyLoaded); } stream.Position = 0; NxRelocatableObject executable = new NxRelocatableObject(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); }