/// <summary> /// Initializes a new instance of the <see cref="ElfFile"/> class. /// </summary> /// /// <param name="header"> /// The ELF file header. /// </param> /// /// <param name="segments"> /// The program header table. /// </param> /// /// <param name="sections"> /// The section header table. /// </param> internal ElfFile(ElfHeader header, ElfProgramHeaderTable segments, ElfSectionHeaderTable sections) { Header = header; Segments = segments; Sections = sections; }
/// <summary> /// Initializes a new instance of the <see cref="ElfProgramHeaderTable"/> class by examining an ELF header. /// </summary> /// /// <param name="reader"> /// The reader used to extract the data needed to parse the ELF file. /// </param> /// /// <param name="header"> /// The ELF header used to extract the metadata about this program header table. /// </param> /// /// <param name="sections"> /// The list of sections which will be parsed to extract the sections corresponding to this segment. /// </param> internal ElfProgramHeaderTable(BinaryReader reader, ElfHeader header, ElfSectionHeaderTable sections) { // Initialize all segments for (var i = 0; i < header.ProgramHeaderEntryCount; i++) { ElfSegment segment; switch (header.Class) { case ElfClass.Elf32: { segment = new Bit32.ElfSegment(reader, (long)(header.ProgramHeaderOffset + (ulong)(i * header.ProgramHeaderSize))); break; } case ElfClass.Elf64: { segment = new Bit64.ElfSegment(reader, (long)(header.ProgramHeaderOffset + (ulong)(i * header.ProgramHeaderSize))); break; } default: { throw new InvalidOperationException("Unreachable case reached"); } } segment.Sections = sections.Where(s => s.Address >= segment.VirtualAddress && s.Address < segment.VirtualAddress + segment.MemorySize).ToList().AsReadOnly(); segments.Add(segment); } }
/// <summary> /// Reads an ELF file from a binary reader. /// </summary> /// /// <param name="reader"> /// The reader used to extract the data needed to parse the ELF file. /// </param> /// /// <returns> /// The ELF file parsed from the binary reader. /// </returns> /// /// <exception cref="FileFormatException"> /// <paramref name="reader"/> base stream does not represent a valid ELF file. /// </exception> public static ElfFile ReadElfFile(BinaryReader reader) { try { long savedPosition = reader.BaseStream.Position; byte magic0 = reader.ReadByte(); byte magic1 = reader.ReadByte(); byte magic2 = reader.ReadByte(); byte magic3 = reader.ReadByte(); if (magic0 != ElfHeader.ELFMAG0 || magic1 != ElfHeader.ELFMAG1 || magic2 != ElfHeader.ELFMAG2 || magic3 != ElfHeader.ELFMAG3) { throw new FileFormatException($"Invalid ELF magic bytes: 0x{magic0,0:X2} 0x{magic1,0:X2} 0x{magic2,0:X2} 0x{magic3,0:X2}"); } byte @class = reader.ReadByte(); if (@class != ElfHeader.ELFCLASS32 && @class != ElfHeader.ELFCLASS64) { throw new FileFormatException($"Invalid ELF class: 0x{@class,0:X2}"); } byte endianness = reader.ReadByte(); if (endianness != ElfHeader.ELFDATA2LSB && endianness != ElfHeader.ELFDATA2MSB) { throw new FileFormatException($"Invalid ELF endianness: 0x{endianness,0:X2}"); } // Re-materialize the reader with the parsed endianness reader = new EndianBinaryReader(reader.BaseStream, endianness == ElfHeader.ELFDATA2MSB ? Endianness.BigEndian : Endianness.LittleEndian, Encoding.UTF8, true); ElfHeader header; switch (@class) { case ElfHeader.ELFCLASS32: { header = new Bit32.ElfHeader(reader, savedPosition); break; } case ElfHeader.ELFCLASS64: { header = new Bit64.ElfHeader(reader, savedPosition); break; } default: { throw new InvalidOperationException("Unreachable case reached"); } } var sections = new ElfSectionHeaderTable(reader, header); var segments = new ElfProgramHeaderTable(reader, header, sections); reader.BaseStream.Position = savedPosition; return(new ElfFile(header, segments, sections)); } catch (InaccessibleAddressException exception) { throw new FileFormatException(exception.Message, exception); } }