Example #1
0
        /// <summary>
        /// Try to read elf header.
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        /// Thrown if the stream was disposed.
        /// </exception>
        /// <exception cref="IOException">
        /// Thrown in case of any problems during reading.
        /// </exception>
        /// <param name="reader">Input stream reader.</param>
        /// <param name="result">Read header or empty header.</param>
        /// <returns>
        /// True if x64 elf header with little endianness and correct elf version was successfully
        /// read and false otherwise.
        /// </returns>
        public static bool TryRead(BinaryReader reader, out ElfHeader result)
        {
            result = EmptyHeader;
            if (!HeadersReadingUtils.IsEnoughBytes(reader, Size))
            {
                return(false);
            }

            var ei_magic       = reader.ReadInt32();
            var ei_bitness     = reader.ReadByte();
            var ei_endianness  = reader.ReadByte();
            var ei_version     = reader.ReadByte();
            var ei_abi         = reader.ReadByte();
            var ei_abi_version = reader.ReadByte();
            var ei_padding     = reader.ReadBytes(PaddingSize);
            var e_type         = reader.ReadInt16();
            var e_machine      = reader.ReadInt16();
            var e_version      = reader.ReadInt32();
            var e_entry        = reader.ReadInt64();

            // Points to the start of the program header table.
            var e_phoff  = reader.ReadUInt64();
            var e_shoff  = reader.ReadUInt64();
            var e_flags  = reader.ReadInt32();
            var e_ehsize = reader.ReadUInt16();

            // Contains the size of a program header table entry.
            var e_phentsize = reader.ReadUInt16();

            // Contains the number of entries in the program header table.
            var e_phnum     = reader.ReadUInt16();
            var e_shentsize = reader.ReadUInt16();
            var e_shnum     = reader.ReadUInt16();
            var e_shstrndx  = reader.ReadUInt16();

            if (ei_magic != ElfMagicNumber)
            {
                Trace.WriteLine($"Invalid ELF magic {ElfMagicNumber} expected {ei_magic}.");
                return(false);
            }

            if (ei_bitness != (byte)Bitness.x64)
            {
                Trace.WriteLine("Only 64-bit elf supported.");
                return(false);
            }

            if (ei_endianness != (byte)Endianness.Little)
            {
                Trace.WriteLine("Only little endian supported.");
                return(false);
            }

            if (ei_version != CurrentElfVersion)
            {
                Trace.WriteLine($"Invalid elf version: {ei_version} expected: " +
                                $"{CurrentElfVersion}.");
                return(false);
            }

            result = new ElfHeader(e_phoff, e_phentsize, e_phnum, e_type == (byte)Type.Executable);
            return(true);
        }
        DumpReadResult GetModules(BinaryReader dumpReader)
        {
            ulong dumpSize   = (ulong)dumpReader.BaseStream.Length;
            var   moduleList = new List <DumpModule>();

            if (!ElfHeader.TryRead(dumpReader, out ElfHeader elfHeader))
            {
                return(new DumpReadResult(moduleList, DumpReadWarning.ElfHeaderIsCorrupted));
            }

            var             fileSections = new List <FileSection>();
            var             loadSegments = new List <ProgramHeader>();
            DumpReadWarning warning      = DumpReadWarning.None;

            // Go through each program header sections, look for the notes sections and the
            // loadable segments.
            for (ulong i = 0; i < elfHeader.EntriesCount; ++i)
            {
                ulong headerOffset = elfHeader.StartOffset + i * elfHeader.EntrySize;
                dumpReader.BaseStream.Seek((long)headerOffset, SeekOrigin.Begin);

                if (!ProgramHeader.TryRead(dumpReader, out ProgramHeader header))
                {
                    return(new DumpReadResult(moduleList, DumpReadWarning.FileIsTruncated));
                }

                // Set the warning if the program header is outside of the file.
                if (header.OffsetInFile + header.SizeInFile > dumpSize &&
                    warning == DumpReadWarning.None)
                {
                    warning = DumpReadWarning.FileIsTruncated;
                }

                switch (header.HeaderType)
                {
                // We found the notes section. Now we need to extract module section from
                // the NT_FILE notes.
                case ProgramHeader.Type.NoteSegment:
                    if (header.SizeInFile > int.MaxValue)
                    {
                        Trace.WriteLine("Can't extract note segment sections from program" +
                                        "header. Note size is more then int.Max.");
                        continue;
                    }

                    int size = (int)header.SizeInFile;
                    dumpReader.BaseStream.Seek((long)header.OffsetInFile, SeekOrigin.Begin);
                    byte[] notesBytes  = dumpReader.ReadBytes(size);
                    var    notesStream = new MemoryStream(notesBytes);
                    using (var notesReader = new BinaryReader(notesStream))
                    {
                        IEnumerable <FileSection> moduleSections =
                            NoteSection.ReadModuleSections(notesReader, size);
                        fileSections.AddRange(moduleSections);
                    }

                    break;

                // Collect memory mappings for the core files.
                case ProgramHeader.Type.LoadableSegment:
                    loadSegments.Add(header);
                    break;
                }
            }

            var loadableSegmentsReader = new ModuleReader(loadSegments, dumpReader);

            // Go through each module and try to find build id in the mapped regions.
            foreach (FileSection file in fileSections)
            {
                DumpModule module = loadableSegmentsReader.GetModule(file);
                if (module.Id == BuildId.Empty)
                {
                    Trace.WriteLine($"Can't find build id for module {module.Path}.");
                }
                else
                {
                    moduleList.Add(module);
                }
            }

            return(new DumpReadResult(moduleList, warning));
        }
Example #3
0
        /// <summary>
        /// Looks for build id for specified module index in core dump.
        /// Method also returns information about the module: is it executable and path.
        /// </summary>
        /// <returns>Dump module or DumpModule.Empty.</returns>
        public DumpModule GetModule(FileSection file)
        {
            byte[] elfHeaderBytes = ReadBlockByAddress(file.StartAddress, ElfHeader.Size);
            using (var elfHeaderReader = new BinaryReader(new MemoryStream(elfHeaderBytes)))
            {
                if (!ElfHeader.TryRead(elfHeaderReader, out ElfHeader moduleHeader))
                {
                    Trace.WriteLine($"Failed to read elf header for module {file.Path}.");
                    return(DumpModule.Empty);
                }

                int    headersSize = moduleHeader.EntriesCount * moduleHeader.EntrySize;
                byte[] headerBytes =
                    ReadBlockByAddress(file.StartAddress + moduleHeader.StartOffset, headersSize);

                using (var headerReader = new BinaryReader(new MemoryStream(headerBytes)))
                {
                    // Iterate through the program headers, until we find the note with the build
                    // id.
                    for (ulong i = 0; i < moduleHeader.EntriesCount; ++i)
                    {
                        ulong offset = i * moduleHeader.EntrySize;
                        headerReader.BaseStream.Seek((long)offset, SeekOrigin.Begin);
                        if (!ProgramHeader.TryRead(headerReader, out ProgramHeader header))
                        {
                            Trace.WriteLine(
                                $"Failed to read program header with offset: {offset} " +
                                $"from module {file.Path}.");
                            continue;
                        }

                        if (header.HeaderType != ProgramHeader.Type.NoteSegment)
                        {
                            continue;
                        }

                        ulong fileSize  = file.EndAddress - file.StartAddress;
                        ulong headerEnd = header.OffsetInFile + header.SizeInFile;
                        if (headerEnd > fileSize)
                        {
                            Trace.WriteLine(
                                "Can't extract note sections from program header. " +
                                "Note section is outside of the first mapped location.");
                            continue;
                        }

                        if (header.SizeInFile > int.MaxValue)
                        {
                            Trace.WriteLine("Can't extract note sections from program header. " +
                                            "Note size is more then int.Max.");
                            continue;
                        }

                        int    size             = (int)header.SizeInFile;
                        byte[] noteSegmentBytes =
                            ReadBlockByAddress(file.StartAddress + header.OffsetInFile, size);
                        if (noteSegmentBytes.Length < size)
                        {
                            Trace.WriteLine("Can't extract build ids from note section. " +
                                            "Note is not fully in load segments.");
                            continue;
                        }

                        var notesStream = new MemoryStream(noteSegmentBytes);
                        using (var notesReader = new BinaryReader(notesStream))
                        {
                            BuildId buildId = NoteSection.ReadBuildId(notesReader, size);
                            if (buildId != BuildId.Empty)
                            {
                                return(new DumpModule(file.Path, buildId,
                                                      moduleHeader.IsExecutable));
                            }
                        }
                    }
                }
            }

            return(DumpModule.Empty);
        }