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