diff options
| -rw-r--r-- | sploit/rev/elf.py | 107 | 
1 files changed, 107 insertions, 0 deletions
| diff --git a/sploit/rev/elf.py b/sploit/rev/elf.py index 5833bf5..990cfde 100644 --- a/sploit/rev/elf.py +++ b/sploit/rev/elf.py @@ -1,9 +1,95 @@ +""" +Definition of the ELF class +""" +  from sploit.rev import ldd, r2  from sploit.arch import lookup_arch  from itertools import zip_longest  class ELF: +    """ +    Representation of an ELF binary file. + +    This class is effectively a front-end for the r2 module.  Through ELF, you +    can get information about an ELF binary in a convenient, object-oriented +    interface and automate some of your static analysis reverse engineering. + +    Because much of the functionality of r2 is cached, much of the functionality +    of ELF is also implicitly cached.  Longer operations like retrieving the +    symbol table or looking up gadgets will be faster on subsequent attempts. +    This is mostly useful when sploit is run from the REPL or in Pipes mode +    where this cache is preserved across script runs. + +    Some of the behavior of this class is done upfront while other operations +    are performed lazily.  Retrieving symbols, binary info, security info, and +    the list of library dependencies are all done upfront when the object is +    constructed. + +    path (str): Absolute file path to the underlying ELF file. + +    sym (Symtbl): A collection of named address offsets exposed through the ELF. + +    libs (dict{str:ELF}): A dictionary of ELFs representing linked library +    dependencies of the current ELF. They are indexed by their base filename +    (i.e. elf.libs["libc.so.6"]).  The actual ELF is lazily constructed when it +    is requested. Pretty printing of the libs dict is implemented. + +    locals (->Symtbl): A psuedo-namespace to access Symtbls for the local +    variables of functions.  i.e. If a function existed in the elf called foo(), +    you could get a Symtbl of its local variables with elf.locals.foo + +    info (->str|int): A psuedo-namespace to access various info about the ELF +    file.  Printing elf.info will pretty-print this info in a tabulated form. + +    info.type (str): The type of file. + +    info.os (str): The os the binary was compiled for. + +    info.baddr (int): The virtual base address of the binary. + +    info.arch_string (str): A string given by r2 iI that helps identify the +    architecture the binary was compiled for. + +    info.wordsize (int): The natual width of an int on the architecture the +    binary was compiled for. + +    info.endianness (str): The byte order of an int on the architecture the +    binary was compiled for. + +    security (->bool|str): A psuedo-namespace to access security info about the +    binary.  Printing elf.security will pretty-print this info in a tabulated +    form. + +    security.stripped (bool): True if the binary was stripped of debugging +    information, symbols, and strings. + +    security.pic (bool): True if the binary's code is position independent. + +    security.relro (str): The level of "Relocation Read-Only" that the binary +    was compiled with. Pertains to if the Global Offset Table is read-only. +    This is often "partial" or "full". + +    security.relocs (bool): True if the binary uses dynamic runtime relocation. + +    security.canary (bool): True if the binary uses stack canaries. + +    security.nx (bool): True if the binary does not have stack execution +    privileges. + +    security.rpath (str): Runtime library lookup path. If there isn't one, this +    will say "NONE". + +    arch (Arch): On Construction, an ELF will automatically try to figure out if +    it was compiled for one of sploit's predefined Arch's. If so, it will set it +    here. Otherwise, this is None. +    """ +      def __init__(self, path): +        """ +        Construct an ELF. + +        path (str): The filepath to the ELF binary file. +        """          self.path = path          self.sym = r2.get_elf_symbols(self.path)          try: @@ -18,6 +104,7 @@ class ELF:          self.arch = lookup_arch(self.info.arch_string, self.info.wordsize, self.info.endianness)      def __repr__(self): +        """Pretty-print a summary of the ELF."""          s = 'ELF: '          s += self.path          s += f'\n{len(self.sym)} symbols @ {hex(self.sym)}' @@ -36,6 +123,7 @@ class ELF:          return s      class __LIBS__(dict): +        # Fancy magic dict of {filename:ELF} which will lazy load the ELF          def __init__(self, libs):              super().__init__({lib.name:lib.path for lib in libs.values() if lib.path})          def __getitem__(self, lib): @@ -49,6 +137,7 @@ class ELF:              return s.strip()      class __LOCALS__: +        # Fancy magic class that provides a psuedo-namespace to lookup locals for functions          def __init__(self, elf):              self.elf = elf          def __getattr__(self, sym): @@ -89,10 +178,28 @@ class ELF:                  }      def retaddr(self, caller, callee): +        """ +        Returns a list of addresses where a function returns into another +        function at. + +        caller (int): Address of the calling function to be returned into. + +        callee (int): Address of the function that was called and will return. +        """          return [c.ret_addr for c in r2.get_call_returns(self.path, caller, callee)]      def gadgets(self, *regexes, cont=False): +        """ +        Returns a list of gadgets that match the given regex list. + +        *regexes (str): All positional arguments are treated as regex strings +        for the gadget search. + +        cont (bool): If true, this function will return all of the assembly past +        the found gadget up to the next return point. +        """          return r2.rop_gadgets(self.path, *regexes, cont=cont)      def gadget(self, *regexes): +        """Returns the first gadget found that matches the given regex list."""          return r2.rop_gadget(self.path, *regexes) | 
