public MainItem(NsoHeader nsoHeader, SectionItem parentItem, DirectoryEntryEx directoryEntry) : base(parentItem, directoryEntry) { ParentItem = parentItem ?? throw new ArgumentNullException(nameof(parentItem)); NsoHeader = nsoHeader; }
public static byte[] ConvertElfToNso(ReadOnlySpan <byte> elf) { if (elf.Length < Elf64Ehdr.Length) { throw new ArgumentException("Length of ELF data is less than the ELF header", nameof(elf)); } var header = new Elf64Ehdr(elf); if (header.Machine != ElfConstants.EM_AARCH64) { throw new ArgumentException("ELF data must have machine of AArch64", nameof(elf)); } var phEnd = header.PhOff + (ulong)header.PHNum * Elf64Phdr.Length; if (phEnd < header.PhOff || phEnd > (ulong)elf.Length) { throw new ArgumentException("Physical header address outside of file", nameof(elf)); } using var sha256 = SHA256.Create(); var nsoHeader = new NsoHeader(); var compressedBuffers = new List <byte[]>(3); uint fileOffset = NsoHeader.Length; int j = 0; for (int i = 0; i < 3; i++) { Elf64Phdr phdr = null; while (j < header.PHNum) { var phOffset = (long)header.PhOff + j++ *Elf64Phdr.Length; var current = new Elf64Phdr(elf.Slice((int)phOffset, header.PHEntSize)); if (current.Type == ElfConstants.PT_LOAD) { phdr = current; break; } } if (phdr == null) { throw new ArgumentException("Invalid ELF: expected 3 loadable phdrs", nameof(elf)); } nsoHeader.Segments[i].FileOffset = fileOffset; nsoHeader.Segments[i].MemoryOffset = (uint)phdr.VAddr; nsoHeader.Segments[i].MemorySize = (uint)phdr.FileSize; // for .data segment this field contains bss size if (i == 2) { nsoHeader.Segments[i].AlignOrTotalSz = (uint)(phdr.MemSize - phdr.FileSize); } else { nsoHeader.Segments[i].AlignOrTotalSz = 1; } var sectionData = elf.Slice((int)phdr.Offset, (int)phdr.FileSize); nsoHeader.Hashes[i] = sha256.ComputeHash(sectionData.ToArray()); var compressedBuffer = new byte[LZ4Codec.MaximumOutputSize(sectionData.Length)]; var compressedLength = LZ4Codec.Encode(sectionData, compressedBuffer, LZ4Level.L00_FAST); compressedBuffers.Add(compressedBuffer); nsoHeader.SegmentFileSizes[i] = (uint)compressedLength; fileOffset += (uint)compressedLength; } // Iterate over sections to find build id. var currentSectionHeaderOffset = header.ShOff; for (int i = 0; i < header.SHNum; i++) { var currentShHeader = new Elf64Shdr(elf.Slice((int)currentSectionHeaderOffset, header.SHEntSize)); if (currentShHeader.Type == ElfConstants.SHT_NOTE) { var noteData = elf.Slice((int)currentShHeader.Offset, Elf64Nhdr.Length); var noteHeader = new Elf64Nhdr(noteData); var noteName = elf.Slice((int)currentShHeader.Offset + Elf64Nhdr.Length, (int)noteHeader.NameSize); var noteDesc = elf.Slice((int)currentShHeader.Offset + Elf64Nhdr.Length + (int)noteHeader.NameSize, (int)noteHeader.DescriptorSize); var noteNameString = Encoding.ASCII.GetString(noteName.Slice(0, 4).ToArray()); if (noteHeader.Type == ElfConstants.NT_GNU_BUILD_ID && noteHeader.NameSize == 4 && noteNameString == "GNU\0") { var buildIdSize = noteHeader.DescriptorSize; if (buildIdSize > 0x20) { buildIdSize = 0x20; } noteDesc.Slice(0, (int)buildIdSize).CopyTo(nsoHeader.BuildId); } } currentSectionHeaderOffset += header.SHEntSize; } var headerData = nsoHeader.ToByteArray(); var buffer = new List <byte>(headerData.Length + nsoHeader.SegmentFileSizes.Cast <int>().Sum()); buffer.AddRange(headerData); for (int i = 0; i < nsoHeader.SegmentFileSizes.Length; i++) { buffer.AddRange(compressedBuffers[i].Take((int)nsoHeader.SegmentFileSizes[i])); } return(buffer.ToArray()); }