diff options
| author | Camille Mougey <camille.mougey@cea.fr> | 2014-11-03 19:11:27 +0100 |
|---|---|---|
| committer | Camille Mougey <camille.mougey@cea.fr> | 2014-11-03 19:11:27 +0100 |
| commit | d224bd8b0e75afb551f8e94d8e4036c9f5132e79 (patch) | |
| tree | f1404f0a870ecb1ab2e8b7feb04387c1150c7803 /miasm2/analysis/binary.py | |
| parent | bf08353e23940f9e83c85c17eafcf997710a40c9 (diff) | |
| download | focaccia-miasm-d224bd8b0e75afb551f8e94d8e4036c9f5132e79.tar.gz focaccia-miasm-d224bd8b0e75afb551f8e94d8e4036c9f5132e79.zip | |
Container: Refactor in class and subclass for PE, ELF and Unknown
Diffstat (limited to 'miasm2/analysis/binary.py')
| -rw-r--r-- | miasm2/analysis/binary.py | 184 |
1 files changed, 144 insertions, 40 deletions
diff --git a/miasm2/analysis/binary.py b/miasm2/analysis/binary.py index 996ea4b9..bc662265 100644 --- a/miasm2/analysis/binary.py +++ b/miasm2/analysis/binary.py @@ -13,56 +13,84 @@ log.addHandler(console_handler) log.setLevel(logging.ERROR) +# Container +## Exceptions +class ContainerSignatureException(Exception): + "The container does not match the current container signature" + + +class ContainerParsingException(Exception): + "Error during container parsing" + + +## Parent class class Container(object): """Container abstraction layer This class aims to offer a common interface for abstracting container - such as PE and ELF. + such as PE or ELF. """ - def __init__(self, filename, vm = None, addr = None): - "Instanciate a container and parse the binary" + available_container = [] # Available container formats + fallback_container = None # Fallback container format - # Initialisation - with open(filename) as fdesc: - data = fdesc.read() - log.info('load binary') - e, bs, ep = None, None, None + @classmethod + def from_string(cls, data, vm=None, addr=None): + """Instanciate a container and parse the binary + @data: str containing the binary + @vm: (optional) VmMngr instance to link with the executable + @addr: (optional) Base address for the binary. If set, + force the unknown format + """ + log.info('Load binary') - # Parse container header and instanciate common elements - if data.startswith('MZ'): - try: - if vm is not None: - e = vm_load_pe(vm, filename) - else: - e = pe_init.PE(data) - if e.isPE() and e.NTsig.signature_value == 0x4550: - bs = bin_stream_pe(e.virt) - ep = e.rva2virt(e.Opthdr.AddressOfEntryPoint) - except: - log.error('Cannot read PE!') - elif data.startswith('\x7fELF'): - try: - if vm is not None: - e = vm_load_elf(vm, filename) - else: - e = elf_init.ELF(data) - bs = bin_stream_elf(e.virt) - ep = e.Ehdr.entry - except: - log.error('Cannot read ELF!') + if not addr: + addr = 0 else: - bs = bin_stream_str(data) - if vm is not None: - if addr is None: - raise ValueError('set load addr') - vm.add_memory_page(addr, - PAGE_READ, - data) + # Force fallback mode + log.warning('Fallback to string input (offset=%s)' % hex(addr)) + return cls.fallback_container(data, vm, addr) + + # Try each available format + for container_type in cls.available_container: + try: + return container_type(data, vm) + except ContainerSignatureException: + continue + except ContainerParsingException, error: + log.error(error) + + # Fallback mode + log.warning('Fallback to string input (offset=%s)' % hex(addr)) + return cls.fallback_container(data, vm, addr) + + @classmethod + def register_container(cls, container): + "Add a Container format" + cls.available_container.append(container) + + @classmethod + def register_fallback(cls, container): + "Set the Container fallback format" + cls.fallback_container = container - self._entry_point = ep - self._bin_stream = bs - self._executable = e + @classmethod + def from_stream(cls, stream, *args, **kwargs): + """Instanciate a container and parse the binary + @stream: stream to use as binary + @vm: (optional) VmMngr instance to link with the executable + @addr: (optional) Shift to apply before parsing the binary. If set, + force the unknown format + """ + return Container.from_string(stream.read(), *args, **kwargs) + + def parse(self, data, *args, **kwargs): + "Launch parsing of @data" + raise NotImplentedError("Abstract method") + + def __init__(self, *args, **kwargs): + "Alias for 'parse'" + self.parse(*args, **kwargs) @property def bin_stream(self): @@ -78,3 +106,79 @@ class Container(object): def entry_point(self): "Return the detected entry_point" return self._entry_point + + +## Format dependent classes +class ContainerPE(Container): + "Container abstraction for PE" + + def parse(self, data, vm=None): + # Parse signature + if not data.startswith('MZ'): + raise ContainerSignatureException() + + # Build executable instance + try: + if vm is not None: + self._executable = vm_load_pe(vm, filename) + else: + self._executable = pe_init.PE(data) + except Exception, error: + raise ContainerParsingException('Cannot read PE: %s' % error) + + # Check instance validity + if not self._executable.isPE() or \ + self._executable.NTsig.signature_value != 0x4550: + raise ContainerSignatureException() + + # Build the bin_stream instance and set the entry point + try: + self._bin_stream = bin_stream_pe(self._executable.virt) + ep_detected = self._executable.Opthdr.AddressOfEntryPoint + self._entry_point = self._executable.rva2virt(ep_detected) + except Exception, error: + raise ContainerParsingException('Cannot read PE: %s' % error) + + +class ContainerELF(Container): + "Container abstraction for ELF" + + def parse(self, data, vm=None): + # Parse signature + if not data.startswith('\x7fELF'): + raise ContainerSignatureException() + + # Build executable instance + try: + if vm is not None: + self._executable = vm_load_elf(vm, filename) + else: + self._executable = elf_init.ELF(data) + except Exception, error: + raise ContainerParsingException('Cannot read ELF: %s' % error) + + # Build the bin_stream instance and set the entry point + try: + self._bin_stream = bin_stream_elf(self._executable.virt) + self._entry_point = self._executable.Ehdr.entry + except Exception, error: + raise ContainerParsingException('Cannot read ELF: %s' % error) + + +class ContainerUnknown(Container): + "Container abstraction for unknown format" + + def parse(self, data, vm, addr): + self._bin_stream = bin_stream_str(data, shift=addr) + if vm is not None: + vm.add_memory_page(addr, + PAGE_READ, + data) + self._executable = None + self._entry_point = 0 + + +## Register containers +Container.register_container(ContainerPE) +Container.register_container(ContainerELF) +Container.register_fallback(ContainerUnknown) |