diff --git a/libexeinfo/ELF/ELF.cs b/libexeinfo/ELF/ELF.cs index 9935123..8e66e62 100644 --- a/libexeinfo/ELF/ELF.cs +++ b/libexeinfo/ELF/ELF.cs @@ -4,18 +4,17 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; -using System.Threading; namespace libexeinfo { public partial class ELF : IExecutable { - List architectures; - Elf64_Ehdr Header; - string interpreter; - string[] sectionNames; - Elf64_Shdr[] sections; + List architectures; + Elf64_Ehdr Header; + string interpreter; Dictionary notes; + string[] sectionNames; + Elf64_Shdr[] sections; /// /// Initializes a new instance of the class. @@ -58,7 +57,7 @@ namespace libexeinfo public IEnumerable Architectures => architectures; public OperatingSystem RequiredOperatingSystem { get; private set; } public IEnumerable Strings { get; private set; } - public IEnumerable Segments { get; } + public IEnumerable Segments { get; private set; } /// /// The that contains the executable represented by this instance @@ -181,7 +180,7 @@ namespace libexeinfo len++; } - + notes = new Dictionary(); // Sections that contain an array of null-terminated strings by definition @@ -214,40 +213,55 @@ namespace libexeinfo } else if(sectionNames[i].StartsWith(".note")) { - uint namesz = BitConverter.ToUInt32(buffer, 0); - uint descsz = BitConverter.ToUInt32(buffer, 4); + uint namesz = BitConverter.ToUInt32(buffer, 0); + uint descsz = BitConverter.ToUInt32(buffer, 4); uint notetype = BitConverter.ToUInt32(buffer, 8); pos = 12; if(IsBigEndian) { - namesz= Swapping.Swap(namesz); - descsz = Swapping.Swap(descsz); + namesz = Swapping.Swap(namesz); + descsz = Swapping.Swap(descsz); notetype = Swapping.Swap(notetype); } - + ElfNote note = new ElfNote { - name = Encoding.ASCII.GetString(buffer, pos, (int)(namesz - 1)), - type = notetype, + name = Encoding.ASCII.GetString(buffer, pos, (int)(namesz - 1)), + type = notetype, contents = new byte[descsz] }; pos += (int)namesz; - switch(Header.ei_class) { - case eiClass.ELFCLASS32: pos += pos % 4; + switch(Header.ei_class) + { + case eiClass.ELFCLASS32: + pos += pos % 4; break; - case eiClass.ELFCLASS64: pos += pos % 8; + case eiClass.ELFCLASS64: + pos += pos % 8; break; } - + Array.Copy(buffer, pos, note.contents, 0, descsz); - + notes.Add(sectionNames[i], note); } } + if(notes.TryGetValue(".note.ABI-tag", out ElfNote abiTag)) + { + GnuAbiTag gnuAbiTag = DecodeGnuAbiTag(abiTag, IsBigEndian); + if(gnuAbiTag != null) + RequiredOperatingSystem = new OperatingSystem + { + Name = $"{gnuAbiTag.system}", + MajorVersion = (int)gnuAbiTag.major, + MinorVersion = (int)gnuAbiTag.minor + }; + } + if(strings.Count > 0) { strings.Remove(null); @@ -255,6 +269,8 @@ namespace libexeinfo strings.Sort(); Strings = strings.Distinct(); } + + Segments = segments; } static Elf64_Ehdr UpBits(byte[] buffer, bool bigEndian) diff --git a/libexeinfo/ELF/Enums.cs b/libexeinfo/ELF/Enums.cs index ae7b6d9..98ec325 100644 --- a/libexeinfo/ELF/Enums.cs +++ b/libexeinfo/ELF/Enums.cs @@ -941,5 +941,10 @@ namespace libexeinfo /// PA-RISC 2.0 EFA_PARISC_2_0 = 0x0214 } + + enum GnuAbiSystem : uint + { + Linux = 0 + } } } \ No newline at end of file diff --git a/libexeinfo/ELF/GNU.cs b/libexeinfo/ELF/GNU.cs new file mode 100644 index 0000000..b4ef4b6 --- /dev/null +++ b/libexeinfo/ELF/GNU.cs @@ -0,0 +1,37 @@ +using System; +using System.Text; + +namespace libexeinfo +{ + public partial class ELF + { + static GnuAbiTag DecodeGnuAbiTag(ElfNote note, bool bigEndian) + { + if(note.name != "GNU") return null; + + return bigEndian + ? new GnuAbiTag + { + system = (GnuAbiSystem)Swapping.Swap(BitConverter.ToUInt32(note.contents, 0)), + major = Swapping.Swap(BitConverter.ToUInt32(note.contents, 4)), + minor = Swapping.Swap(BitConverter.ToUInt32(note.contents, 8)), + revision = Swapping.Swap(BitConverter.ToUInt32(note.contents, 0)) + } + : new GnuAbiTag + { + system = (GnuAbiSystem)BitConverter.ToUInt32(note.contents, 0), + major = BitConverter.ToUInt32(note.contents, 4), + minor = BitConverter.ToUInt32(note.contents, 8), + revision = BitConverter.ToUInt32(note.contents, 0) + }; + } + + static string DecodeGnuBuildId(ElfNote note) + { + StringBuilder sb = new StringBuilder(); + foreach(byte b in note.contents) { sb.AppendFormat("{0:x2}", b); } + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/libexeinfo/ELF/Info.cs b/libexeinfo/ELF/Info.cs index 1e7b5d3..e562391 100644 --- a/libexeinfo/ELF/Info.cs +++ b/libexeinfo/ELF/Info.cs @@ -74,7 +74,7 @@ namespace libexeinfo sb.AppendFormat("\t\tSection is aligned to {0} bytes", sections[i].sh_addralign).AppendLine(); if(sections[i].sh_entsize > 0) sb.AppendFormat("\t\tIndex to name: {0}", sections[i].sh_entsize).AppendLine(); - + if(!notes.TryGetValue(sectionNames[i], out ElfNote note)) continue; sb.AppendLine("\t\tNote contents:"); @@ -83,6 +83,17 @@ namespace libexeinfo sb.AppendFormat("\t\t\tLength: {0} bytes", note.contents.Length).AppendLine(); } + if(notes.TryGetValue(".note.ABI-tag", out ElfNote abiTag)) + { + GnuAbiTag gnuAbiTag = DecodeGnuAbiTag(abiTag, IsBigEndian); + if(gnuAbiTag != null) + sb.AppendFormat("\tGNU ABI tag: Requires {0} version {1}.{2}.{3}", gnuAbiTag.system, + gnuAbiTag.major, gnuAbiTag.minor, gnuAbiTag.revision).AppendLine(); + } + + if(notes.TryGetValue(".note.gnu.build-id", out ElfNote buildId)) + sb.AppendFormat("\tGNU build ID: {0}", DecodeGnuBuildId(buildId)); + return sb.ToString(); } } diff --git a/libexeinfo/ELF/Structs.cs b/libexeinfo/ELF/Structs.cs index 7c4d8d1..6d62ba1 100644 --- a/libexeinfo/ELF/Structs.cs +++ b/libexeinfo/ELF/Structs.cs @@ -376,5 +376,13 @@ namespace libexeinfo public uint type; public byte[] contents; } + + class GnuAbiTag + { + public GnuAbiSystem system; + public uint major; + public uint minor; + public uint revision; + } } } \ No newline at end of file diff --git a/libexeinfo/libexeinfo.csproj b/libexeinfo/libexeinfo.csproj index 94030d2..7c7b39a 100644 --- a/libexeinfo/libexeinfo.csproj +++ b/libexeinfo/libexeinfo.csproj @@ -57,6 +57,7 @@ +