/// <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); }
/// <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; } } }