예제 #1
0
        /// <summary>
        /// Looks for the first loadable segment which contains the address. Uses binary search.
        /// </summary>
        /// <param name="address">The address which should be inside segment.</param>
        /// <returns>Index of the loadable segment if it was found and -1 otherwise.</returns>
        int FindSegmentContainingAddress(ulong address)
        {
            int min = 0;
            int max = _sortedSegments.Count - 1;

            while (min <= max)
            {
                int           mid     = (min + max) / 2;
                ProgramHeader segment = _sortedSegments[mid];
                ulong         end     = segment.VirtualAddress + segment.SizeInFile;
                if (address < segment.VirtualAddress)
                {
                    max = mid - 1;
                    continue;
                }
                if (address >= end)
                {
                    min = mid + 1;
                    continue;
                }

                return(mid);
            }

            return(-1);
        }
예제 #2
0
        /// <summary>
        /// Try to read program 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 program header was successfully read and false otherwise.
        /// </returns>
        public static bool TryRead(BinaryReader reader, out ProgramHeader result)
        {
            result = EmptyHeader;
            if (!HeadersReadingUtils.IsEnoughBytes(reader, Size))
            {
                return(false);
            }

            var typeValue = reader.ReadUInt32();
            var flags     = reader.ReadUInt32();
            var offset    = reader.ReadUInt64();
            var vaddr     = reader.ReadUInt64();
            var paddr     = reader.ReadUInt64();
            var filesz    = reader.ReadUInt64();
            var memsz     = reader.ReadUInt64();
            var align     = reader.ReadUInt64();

            if (!Enum.TryParse(typeValue.ToString(), out Type type) ||
                !Enum.IsDefined(typeof(Type), type))
            {
                type = Type.Other;
            }

            result = new ProgramHeader(type, offset, vaddr, filesz);
            return(true);
        }
예제 #3
0
        /// <summary>
        /// Reads block of bytes from loadable segments.
        /// Looks for the first loadable segment which contains the start address and reads from
        /// necessary count of segments.
        /// </summary>
        /// <param name="startAddress">Start address.</param>
        /// <param name="size">Size of block.</param>
        /// <returns></returns>
        byte[] ReadBlockByAddress(ulong startAddress, int size)
        {
            int firstSegmentIndex = FindSegmentContainingAddress(startAddress);

            if (firstSegmentIndex < 0)
            {
                return(Array.Empty <byte>());
            }

            var result     = new byte[size];
            int remainSize = size;

            for (int i = firstSegmentIndex; i < _sortedSegments.Count && remainSize > 0; i++)
            {
                ProgramHeader segment = _sortedSegments[i];
                if (startAddress < segment.VirtualAddress)
                {
                    break;
                }

                ulong offsetInSegment = startAddress - segment.VirtualAddress;
                long  offsetInDump    = (long)(segment.OffsetInFile + offsetInSegment);
                int   blockSize       = Math.Min((int)(segment.SizeInFile - offsetInSegment), remainSize);

                _dumpReader.BaseStream.Seek(offsetInDump, SeekOrigin.Begin);

                byte[] blockBytes = _dumpReader.ReadBytes(blockSize);
                Array.Copy(blockBytes, 0, result, size - remainSize, blockBytes.Length);
                remainSize   -= blockBytes.Length;
                startAddress += (ulong)blockBytes.Length;
            }
            if (remainSize > 0)
            {
                byte[] shrunkResult = new byte[size - remainSize];
                Array.Copy(result, shrunkResult, shrunkResult.Length);
                result = shrunkResult;
            }

            return(result);
        }
예제 #4
0
        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));
        }
예제 #5
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);
        }