Beispiel #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="r"></param>
        /// <param name="sec"></param>
        /// <returns></returns>
        private ELFRelocA[] ParseRelocationSection(BinaryReaderExt r, ELFSection sec)
        {
            ELFRelocA[] relocA = new ELFRelocA[0];

            if (sec.sh_type == SectionType.SHT_RELA || sec.sh_type == SectionType.SHT_REL)
            {
                uint relSize = 0x0C;
                var  count   = (sec.sh_size / relSize);

                relocA = new ELFRelocA[count];
                for (uint i = 0; i < count; i++)
                {
                    r.Seek(sec.sh_offset + relSize * i);

                    relocA[i] = new ELFRelocA()
                    {
                        r_offset = r.ReadUInt32(),
                        r_info   = r.ReadUInt32(),
                        r_addend = (sec.sh_type == SectionType.SHT_RELA ? r.ReadUInt32() : 0)
                    };
                }
            }
            return(relocA);
        }
Beispiel #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="elfFile"></param>
        public RelocELF(byte[] elfFile)
        {
            using (MemoryStream mstream = new MemoryStream(elfFile))
                using (BinaryReaderExt r = new BinaryReaderExt(mstream))
                {
                    // Parse Header

                    if (!(r.ReadByte() == 0x7F && r.ReadByte() == 0x45 && r.ReadByte() == 0x4C && r.ReadByte() == 0x46))
                    {
                        throw new InvalidDataException("Not a valid ELF file");
                    }

                    byte bitType = r.ReadByte(); // 1 - 32, 2 - 64
                    if (bitType != 1)
                    {
                        throw new NotSupportedException("Only 32 bit ELF files are currently supported");
                    }

                    r.BigEndian = r.ReadByte() == 2;

                    // I only care about the sections
                    r.Seek(0x20);
                    var sectionOffset = r.ReadUInt32();
                    r.Seek(0x2E);
                    var sectionHeaderSize  = r.ReadUInt16();
                    var numOfSections      = r.ReadInt16();
                    var StringSectionIndex = r.ReadUInt16();

                    List <SectionData> DataSections = new List <SectionData>();

                    // Parse Sections
                    var Sections = new ELFSection[numOfSections];
                    for (uint i = 0; i < numOfSections; i++)
                    {
                        r.Seek(sectionOffset + sectionHeaderSize * i);

                        Sections[i] = new ELFSection()
                        {
                            sh_name      = r.ReadUInt32(),
                            sh_type      = (SectionType)r.ReadInt32(),
                            sh_flags     = r.ReadUInt32(),
                            sh_addr      = r.ReadUInt32(),
                            sh_offset    = r.ReadUInt32(),
                            sh_size      = r.ReadUInt32(),
                            sh_link      = r.ReadUInt32(),
                            sh_info      = r.ReadUInt32(),
                            sh_addralign = r.ReadUInt32(),
                            sh_entsize   = r.ReadUInt32()
                        };

                        DataSections.Add(new SectionData());
                    }

                    // Parse Symbols
                    var symbolSection = Array.Find(Sections, e => r.ReadString((int)(Sections[StringSectionIndex].sh_offset + e.sh_name), -1) == ".symtab");

                    var Symbols = new ELFSymbol[symbolSection.sh_size / 0x10];
                    for (uint i = 0; i < Symbols.Length; i++)
                    {
                        r.Seek(symbolSection.sh_offset + 0x10 * i);

                        Symbols[i] = new ELFSymbol()
                        {
                            st_name  = r.ReadUInt32(),
                            st_value = r.ReadUInt32(),
                            st_size  = r.ReadUInt32(),
                            st_info  = r.ReadByte(),
                            st_other = r.ReadByte(),
                            st_shndx = r.ReadInt16()
                        };

                        SymbolSections.Add(new SymbolData());
                    }

                    // Grab Relocation Data

                    for (int i = 0; i < Sections.Length; i++)
                    {
                        var section = Sections[i];

                        var data = DataSections[i];
                        data.Name = r.ReadString((int)(Sections[StringSectionIndex].sh_offset + Sections[i].sh_name), -1);

                        data.Data = r.GetSection(section.sh_offset, (int)section.sh_size);

                        if (section.sh_type == SectionType.SHT_RELA || section.sh_type == SectionType.SHT_REL)
                        {
                            var relocs = ParseRelocationSection(r, section);

                            foreach (var v in relocs)
                            {
                                DataSections[(int)section.sh_info].Relocations.Add(new RelocData()
                                {
                                    Offset      = v.r_offset,
                                    AddEnd      = v.r_addend,
                                    Symbol      = SymbolSections[(int)v.R_SYM],
                                    Type        = (RelocType)v.R_TYP,
                                    SymbolIndex = v.R_SYM
                                });
                            }
                        }
                    }

                    var symbolStringSection = Sections[symbolSection.sh_link];

                    // rip out symbol data

                    for (int i = 0; i < Symbols.Length; i++)
                    {
                        var sym = Symbols[i];

                        var section = sym.st_shndx >= 0 ? DataSections[sym.st_shndx] : null;

                        byte[]           symbolData  = new byte[sym.st_size];
                        List <RelocData> relocations = new List <RelocData>();

                        if (section != null)
                        {
                            SymbolSections[i].SectionName = section.Name;

                            if (Sections[sym.st_shndx].sh_type == SectionType.SHT_NOBITS)
                            {
                                symbolData = new byte[section.Data.Length];
#if DEBUG
                                // Console.WriteLine($"{section.Name} {(Sections[sym.st_shndx].sh_offset + sym.st_value).ToString("X")} {sym.st_size} {sym.st_value} {symbolData.Length} {Sections[sym.st_shndx].sh_type}");
#endif
                            }
                            else
                            {
                                // If size of section is 0, get all data?
                                if (sym.st_size == 0)
                                {
                                    symbolData = section.Data;
                                }
                                //else
                                //if ((sym.st_value & 0x80000000) != 0)
                                //{
                                //    Array.Copy(section.Data, sym.st_value - 0x80000000 - Sections[sym.st_shndx].sh_offset, symbolData, 0, sym.st_size);
                                //    Debug.WriteLine($"LONG CALL {section.Relocations.Count} Off: {(sym.st_value - 0x80000000).ToString("X")} SectionOff: {Sections[sym.st_shndx].sh_offset.ToString("X")} {sym.st_value.ToString("X")} Size: {sym.st_size.ToString("X")} Total Size: {section.Data.Length.ToString("X")}");
                                //}
                                else
                                {
                                    Array.Copy(section.Data, sym.st_value, symbolData, 0, sym.st_size);
                                }

                                // TODO: when to get relocations?
                                relocations = section.Relocations.Where(
                                    e => e.Offset >= sym.st_value &&
                                    (e.Offset < sym.st_value + symbolData.Length)
                                    ).ToList();

                                // make relative
                                foreach (var rel in relocations)
                                {
                                    rel.Offset -= sym.st_value;
                                }
                            }

                            // if the offset is 0 the function is usually in another file
                            SymbolSections[i].External = Sections[sym.st_shndx].sh_offset == 0;
#if DEBUG
                            //Console.WriteLine(section.Name + " " + r.ReadString((int)(symbolStringSection.sh_offset + sym.st_name), -1)
                            //    + " " + Sections[sym.st_shndx].sh_info + " " + Sections[sym.st_shndx].sh_addr + " " + relocations.Count);

                            //Debug.WriteLine($"{section.Name} {r.ReadString((int)(symbolStringSection.sh_offset + sym.st_name), -1)} {(Sections[sym.st_shndx].sh_offset + + sym.st_value).ToString("X")} {sym.st_size.ToString("X")}");


                            if (section.Name == ".debug_line")
                            {
                                //r.Seek(Sections[sym.st_shndx].sh_offset + +sym.st_value);
                                //ParseDebugLine(r);
                            }
#endif
                        }

                        SymbolSections[i].Symbol      = r.ReadString((int)(symbolStringSection.sh_offset + sym.st_name), -1);
                        SymbolSections[i].Data        = symbolData;
                        SymbolSections[i].Relocations = relocations;
                    }
                }
        }