Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
binary.py
Go to the documentation of this file.
1 import logging
2 
3 from miasm2.core.bin_stream import bin_stream_str, bin_stream_elf, bin_stream_pe
4 from miasm2.jitter.csts import PAGE_READ
5 
6 
7 log = logging.getLogger("binary")
8 console_handler = logging.StreamHandler()
9 console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s"))
10 log.addHandler(console_handler)
11 log.setLevel(logging.ERROR)
12 
13 
14 # Container
15 ## Exceptions
17  "The container does not match the current container signature"
18 
19 
21  "Error during container parsing"
22 
23 
24 ## Parent class
26  """Container abstraction layer
27 
28  This class aims to offer a common interface for abstracting container
29  such as PE or ELF.
30  """
31 
32  available_container = [] # Available container formats
33  fallback_container = None # Fallback container format
34 
35  @classmethod
36  def from_string(cls, data, vm=None, addr=None):
37  """Instanciate a container and parse the binary
38  @data: str containing the binary
39  @vm: (optional) VmMngr instance to link with the executable
40  @addr: (optional) Base address for the binary. If set,
41  force the unknown format
42  """
43  log.info('Load binary')
44 
45  if not addr:
46  addr = 0
47  else:
48  # Force fallback mode
49  log.warning('Fallback to string input (offset=%s)', hex(addr))
50  return cls.fallback_container(data, vm, addr)
51 
52  # Try each available format
53  for container_type in cls.available_container:
54  try:
55  return container_type(data, vm)
56  except ContainerSignatureException:
57  continue
58  except ContainerParsingException, error:
59  log.error(error)
60 
61  # Fallback mode
62  log.warning('Fallback to string input (offset=%s)', hex(addr))
63  return cls.fallback_container(data, vm, addr)
64 
65  @classmethod
66  def register_container(cls, container):
67  "Add a Container format"
68  cls.available_container.append(container)
69 
70  @classmethod
71  def register_fallback(cls, container):
72  "Set the Container fallback format"
73  cls.fallback_container = container
74 
75  @classmethod
76  def from_stream(cls, stream, *args, **kwargs):
77  """Instanciate a container and parse the binary
78  @stream: stream to use as binary
79  @vm: (optional) VmMngr instance to link with the executable
80  @addr: (optional) Shift to apply before parsing the binary. If set,
81  force the unknown format
82  """
83  return Container.from_string(stream.read(), *args, **kwargs)
84 
85  def parse(self, data, *args, **kwargs):
86  "Launch parsing of @data"
87  raise NotImplementedError("Abstract method")
88 
89  def __init__(self, *args, **kwargs):
90  "Alias for 'parse'"
91  # Init attributes
92  self._executable = None
93  self._bin_stream = None
94  self._entry_point = None
95  self._arch = None
96 
97  # Launch parsing
98  self.parse(*args, **kwargs)
99 
100  @property
101  def bin_stream(self):
102  "Return the BinStream instance corresponding to container content"
103  return self._bin_stream
104 
105  @property
106  def executable(self):
107  "Return the abstract instance standing for parsed executable"
108  return self._executable
109 
110  @property
111  def entry_point(self):
112  "Return the detected entry_point"
113  return self._entry_point
114 
115  @property
116  def arch(self):
117  "Return the guessed architecture"
118  return self._arch
119 
120 
121 ## Format dependent classes
123  "Container abstraction for PE"
124 
125  def parse(self, data, vm=None):
126  from miasm2.jitter.loader.pe import vm_load_pe, preload_pe, guess_arch
127  from elfesteem import pe_init
128 
129  # Parse signature
130  if not data.startswith('MZ'):
132 
133  # Build executable instance
134  try:
135  if vm is not None:
136  self._executable = vm_load_pe(vm, data)
137  else:
138  self._executable = pe_init.PE(data)
139  except Exception, error:
140  raise ContainerParsingException('Cannot read PE: %s' % error)
141 
142  # Check instance validity
143  if not self._executable.isPE() or \
144  self._executable.NTsig.signature_value != 0x4550:
146 
147  # Guess the architecture
149 
150  # Build the bin_stream instance and set the entry point
151  try:
152  self._bin_stream = bin_stream_pe(self._executable.virt)
153  ep_detected = self._executable.Opthdr.AddressOfEntryPoint
154  self._entry_point = self._executable.rva2virt(ep_detected)
155  except Exception, error:
156  raise ContainerParsingException('Cannot read PE: %s' % error)
157 
158 
160  "Container abstraction for ELF"
161 
162  def parse(self, data, vm=None):
163  from miasm2.jitter.loader.elf import \
164  vm_load_elf, preload_elf, guess_arch
165  from elfesteem import elf_init
166 
167  # Parse signature
168  if not data.startswith('\x7fELF'):
170 
171  # Build executable instance
172  try:
173  if vm is not None:
174  self._executable = vm_load_elf(vm, data)
175  else:
176  self._executable = elf_init.ELF(data)
177  except Exception, error:
178  raise ContainerParsingException('Cannot read ELF: %s' % error)
179 
180  # Guess the architecture
182 
183  # Build the bin_stream instance and set the entry point
184  try:
185  self._bin_stream = bin_stream_elf(self._executable.virt)
186  self._entry_point = self._executable.Ehdr.entry
187  except Exception, error:
188  raise ContainerParsingException('Cannot read ELF: %s' % error)
189 
190 
192  "Container abstraction for unknown format"
193 
194  def parse(self, data, vm, addr):
195  self._bin_stream = bin_stream_str(data, shift=addr)
196  if vm is not None:
197  vm.add_memory_page(addr,
198  PAGE_READ,
199  data)
200  self._executable = None
201  self._entry_point = 0
202 
203 
204 ## Register containers
205 Container.register_container(ContainerPE)
206 Container.register_container(ContainerELF)
207 Container.register_fallback(ContainerUnknown)
Format dependent classes.
Definition: binary.py:122