Added reading of sections and decoding their name from the string table
authorebenders <devnull@localhost>
Thu, 8 Sep 2011 09:37:48 +0000 (12:37 +0300)
committerebenders <devnull@localhost>
Thu, 8 Sep 2011 09:37:48 +0000 (12:37 +0300)
elftools/elf/elffile.py
elftools/elf/sections.py [new file with mode: 0644]
z.py

index 29dc095480e96905c500f290ea058cf5f94a22b6..11d37041c1d5e48023ac1e2534d440ecffdcd905 100644 (file)
@@ -7,9 +7,12 @@
 # This code is in the public domain\r
 #-------------------------------------------------------------------------------\r
 \r
-from .structs import ELFStructs\r
+from cStringIO import StringIO\r
+\r
 from ..exceptions import ELFError, ELFParseError\r
-from ..construct import ConstructError\r
+from ..construct import ConstructError, CString\r
+from .structs import ELFStructs\r
+from .sections import Section\r
 \r
 \r
 class ELFFile(object):\r
@@ -22,7 +25,7 @@ class ELFFile(object):
                 boolean - specifies the target machine's endianness     \r
 \r
             header:\r
-                the complete ELF file header
+                the complete ELF file header\r
     """
     def __init__(self, stream):
         self.stream = stream\r
@@ -31,6 +34,21 @@ class ELFFile(object):
             little_endian=self.little_endian,\r
             elfclass=self.elfclass)\r
         self.header = self._parse_elf_header()\r
+        self._stringtable = self._get_stringtable()\r
+    \r
+    def num_sections(self):
+        """ Get the number of sections in the file
+        """\r
+        return self['e_shnum']\r
+    \r
+    def get_section(self, n):
+        """ Get the section at index #n from the file (Section object)
+        """\r
+        section_header = self._get_section_header(n)\r
+        name = self._get_section_name(section_header)\r
+        return Section(section_header, name, self.stream)\r
+    \r
+    #-------------------------------- PRIVATE --------------------------------#\r
     \r
     def __getitem__(self, name):
         """ Implement dict-like access to header entries
@@ -64,6 +82,37 @@ class ELFFile(object):
         else:\r
             raise ELFError('Invalid EI_DATA %s' % repr(ei_data))\r
     \r
+    def _section_offset(self, n):
+        """ Compute the offset of section #n in the file
+        """\r
+        return self['e_shoff'] + n * self['e_shentsize']\r
+    \r
+    def _get_section_header(self, n):
+        """ Find the header of section #n, parse it and return the struct 
+        """\r
+        self.stream.seek(self._section_offset(n))\r
+        return self._struct_parse(self.structs.Elf_Shdr)\r
+    \r
+    def _get_section_name(self, section_header):
+        """ Given a section header, find this section's name in the file's\r
+            string table, and return it as a normal Python string.
+        """\r
+        offset = section_header['sh_name']\r
+        self._stringtable.seek(offset)\r
+        return CString('').parse_stream(self._stringtable)\r
+    \r
+    def _get_stringtable(self):
+        """ Find the file's string table section, read it and return the string\r
+            table as a StringIO object pointing to the section's contents.
+        """\r
+        # Find the section header for the stringtable header, and read the \r
+        # section's contents from it\r
+        #\r
+        stringtable_section_num = self['e_shstrndx']\r
+        stringtable_header = self._get_section_header(stringtable_section_num)\r
+        self.stream.seek(stringtable_header['sh_offset'])\r
+        return StringIO(self.stream.read(stringtable_header['sh_size']))\r
+    \r
     def _parse_elf_header(self):
         """ Parses the ELF file header and assigns the result to attributes\r
             of this object.
diff --git a/elftools/elf/sections.py b/elftools/elf/sections.py
new file mode 100644 (file)
index 0000000..4fb4249
--- /dev/null
@@ -0,0 +1,26 @@
+#-------------------------------------------------------------------------------\r
+# elftools: elf/sections.py\r
+#\r
+# ELF sections\r
+#\r
+# Eli Bendersky (eliben@gmail.com)\r
+# This code is in the public domain\r
+#-------------------------------------------------------------------------------\r
+\r
+class Section(object):
+    def __init__(self, header, name, stream):
+        self.header = header\r
+        self.name = name\r
+        self.stream = stream\r
+    \r
+    def data(self):
+        """ The section data from the file.
+        """\r
+        self.stream.seek(self['sh_offset'])\r
+        return self.stream.read(self['sh_size'])
+\r
+    def __getitem__(self, name):\r
+        """ Implement dict-like access to header entries\r
+        """\r
+        return self.header[name]\r
+\r
diff --git a/z.py b/z.py
index e959632c4051c1915a9d05c2f29718bedfe9ffd6..c74a4ff9f8de4279fbb954f2ab81dcfa314bc916 100644 (file)
--- a/z.py
+++ b/z.py
@@ -9,24 +9,34 @@ stream = open('binfiles/z.elf', 'rb')
 \r
 efile = ELFFile(stream)\r
 \r
+print 'num', efile.num_sections()\r
+sec = efile.get_section(39)\r
+#~ print sec.header\r
+print sec.name\r
+print sec['sh_type']\r
+print map(ord, sec.data())\r
+\r
+#~ print sec.stream\r
+#~ print map(ord, efile._stringtable)\r
+\r
 #~ print efile.header\r
 #~ print dir(efile)\r
 #~ print efile['e_type']\r
 \r
-shtable_offset = efile['e_shoff']\r
-strtable_section_offset = shtable_offset + efile['e_shstrndx'] * efile['e_shentsize']\r
+#~ shtable_offset = efile['e_shoff']\r
+#~ strtable_section_offset = shtable_offset + efile['e_shstrndx'] * efile['e_shentsize']\r
 \r
-# get to the section header for the sh string table\r
-print strtable_section_offset\r
-stream.seek(strtable_section_offset)\r
-sheader = es.Elf_Shdr.parse_stream(stream)\r
-print sheader\r
+#~ # get to the section header for the sh string table\r
+#~ print strtable_section_offset\r
+#~ stream.seek(strtable_section_offset)\r
+#~ sheader = es.Elf_Shdr.parse_stream(stream)\r
+#~ print sheader\r
 \r
-# yay, looks correct!!\r
-stream.seek(sheader.sh_offset)\r
-buf = stream.read(sheader.sh_size)\r
-for c in buf:\r
-    sys.stdout.write('%02X' % ord(c))\r
+#~ # yay, looks correct!!\r
+#~ stream.seek(sheader.sh_offset)\r
+#~ buf = stream.read(sheader.sh_size)\r
+#~ for c in buf:\r
+    #~ sys.stdout.write('%02X' % ord(c))\r
 \r
 \r
 \r