Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
sandbox.py
Go to the documentation of this file.
1 import logging
2 from argparse import ArgumentParser
3 
4 from miasm2.analysis.machine import Machine
5 from miasm2.os_dep import win_api_x86_32_seh
6 from miasm2.jitter.csts import PAGE_READ, PAGE_WRITE
7 from miasm2.analysis import debugging
8 from miasm2.jitter.jitload import log_func
9 
10 class Sandbox(object):
11  """
12  Parent class for Sandbox abstraction
13  """
14 
15  @staticmethod
16  def code_sentinelle(jitter):
17  jitter.run = False
18  return False
19 
20  @classmethod
21  def _classes_(cls):
22  """
23  Iterator on parent classes except Sanbox
24  """
25  for base_cls in cls.__bases__:
26  # Avoid infinite loop
27  if base_cls == Sandbox:
28  continue
29 
30  yield base_cls
31 
32  classes = property(lambda x:x.__class__._classes_())
33 
34  def __init__(self, fname, options, custom_methods = {}):
35  """
36  Initialize a sandbox
37  @fname: str file name
38  @options: namespace instance of specific options
39  @custom_methods: { str => func } for custom API implementations
40  """
41 
42  # Initialize
43  self.fname = fname
44  self.options = options
45  for cls in self.classes:
46  if cls == Sandbox:
47  continue
48  if issubclass(cls, OS):
49  cls.__init__(self, custom_methods)
50  else:
51  cls.__init__(self)
52 
53  # Logging options
54  if self.options.singlestep:
55  self.jitter.jit.log_mn = True
56  self.jitter.jit.log_regs = True
57 
58  if not self.options.quiet_function_calls:
59  log_func.setLevel(logging.INFO)
60 
61  if self.options.dumpblocs:
62  self.jitter.jit.log_newbloc = True
63 
64  @classmethod
65  def parser(cls, *args, **kwargs):
66  """
67  Return instance of instance parser with expecting options.
68  Extra parameters are passed to parser initialisation.
69  """
70 
71  parser = ArgumentParser(*args, **kwargs)
72  parser.add_argument('-a', "--address",
73  help="Force entry point address", default=None)
74  parser.add_argument('-x', "--dumpall", action="store_true",
75  help="Load base dll")
76  parser.add_argument('-b', "--dumpblocs", action="store_true",
77  help="Log disasm blocks")
78  parser.add_argument('-z', "--singlestep", action="store_true",
79  help="Log single step")
80  parser.add_argument('-d', "--debugging", action="store_true",
81  help="Debug shell")
82  parser.add_argument('-g', "--gdbserver", type=int,
83  help="Listen on port @port")
84  parser.add_argument("-j", "--jitter",
85  help="Jitter engine. Possible values are: tcc (default), llvm, python",
86  default="tcc")
87  parser.add_argument('-q', "--quiet-function-calls", action="store_true",
88  help="Don't log function calls")
89 
90  for base_cls in cls._classes_():
91  base_cls.update_parser(parser)
92  return parser
93 
94  def run(self, addr=None):
95  """
96  Launch emulation (gdbserver, debugging, basic JIT).
97  @addr: (int) start address
98  """
99  if addr is None and self.options.address is not None:
100  addr = int(self.options.address, 0)
101 
102  if any([self.options.debugging, self.options.gdbserver]):
103  dbg = debugging.Debugguer(self.jitter)
104  self.dbg = dbg
105  dbg.init_run(addr)
106 
107  if self.options.gdbserver:
108  port = self.options.gdbserver
109  print "Listen on port %d" % port
110  gdb = self.machine.gdbserver(dbg, port)
111  self.gdb = gdb
112  gdb.run()
113  else:
114  cmd = debugging.DebugCmd(dbg)
115  self.cmd = cmd
116  cmd.cmdloop()
117 
118  else:
119  self.jitter.init_run(addr)
120  self.jitter.continue_run()
121 
122 
123 class OS(object):
124  """
125  Parent class for OS abstraction
126  """
127 
128  def __init__(self, custom_methods):
129  pass
130 
131  @classmethod
132  def update_parser(cls, parser):
133  pass
134 
135 
136 class Arch(object):
137  """
138  Parent class for Arch abstraction
139  """
140 
141  # Architecture name
142  _ARCH_ = None
143  def __init__(self):
144  self.machine = Machine(self._ARCH_)
145  self.jitter = self.machine.jitter(self.options.jitter)
146 
147  @classmethod
148  def update_parser(cls, parser):
149  pass
150 
151 
152 class OS_Win(OS):
153  # DLL to import
154  ALL_IMP_DLL = ["ntdll.dll", "kernel32.dll", "user32.dll",
155  "ole32.dll", "urlmon.dll",
156  "ws2_32.dll", 'advapi32.dll', "psapi.dll",
157  ]
158 
159  def __init__(self, custom_methods, *args, **kwargs):
160  from miasm2.jitter.loader.pe import vm_load_pe, vm_load_pe_libs, preload_pe, libimp_pe
161  from miasm2.os_dep import win_api_x86_32
162  methods = win_api_x86_32.__dict__
163  methods.update(custom_methods)
164 
165  super(OS_Win, self).__init__(methods, *args, **kwargs)
166 
167  # Import manager
168  libs = libimp_pe()
169  self.libs = libs
170  win_api_x86_32.winobjs.runtime_dll = libs
171 
172  # Load library
173  if self.options.loadbasedll:
174  all_pe = []
175 
176  # Load libs in memory
177  all_pe = vm_load_pe_libs(self.jitter.vm, self.ALL_IMP_DLL, libs)
178 
179  # Patch libs imports
180  for pe in all_pe.values():
181  preload_pe(self.jitter.vm, pe, libs)
182 
183  # Load main pe
184  with open(self.fname) as fstream:
185  self.pe = vm_load_pe(self.jitter.vm, fstream.read())
186 
187  win_api_x86_32.winobjs.current_pe = self.pe
188 
189  # Fix pe imports
190  preload_pe(self.jitter.vm, self.pe, libs)
191 
192  # Library calls handler
193  self.jitter.add_lib_handler(libs, methods)
194 
195  # Manage SEH
196  if self.options.use_seh:
197  win_api_x86_32_seh.main_pe_name = self.fname
198  win_api_x86_32_seh.main_pe = self.pe
199  win_api_x86_32_seh.loaded_modules = self.ALL_IMP_DLL
200  win_api_x86_32_seh.init_seh(self.jitter)
201  win_api_x86_32_seh.set_win_fs_0(self.jitter)
202 
203  self.entry_point = self.pe.rva2virt(self.pe.Opthdr.AddressOfEntryPoint)
204 
205  @classmethod
206  def update_parser(cls, parser):
207  parser.add_argument('-o', "--loadhdr", action="store_true",
208  help="Load pe hdr")
209  parser.add_argument('-e', "--loadmainpe", action="store_true",
210  help="Load main pe")
211  parser.add_argument('-y', "--use-seh", action="store_true",
212  help="Use windows SEH")
213  parser.add_argument('-l', "--loadbasedll", action="store_true",
214  help="Load base dll (path './win_dll')")
215  parser.add_argument('-r', "--parse-resources",
216  action="store_true", help="Load resources")
217 
218 
219 class OS_Linux(OS):
220 
221  def __init__(self, custom_methods, *args, **kwargs):
222  from miasm2.jitter.loader.elf import vm_load_elf, preload_elf, libimp_elf
223  from miasm2.os_dep import linux_stdlib
224  methods = linux_stdlib.__dict__
225  methods.update(custom_methods)
226 
227  super(OS_Linux, self).__init__(methods, *args, **kwargs)
228 
229  # Import manager
230  self.libs = libimp_elf()
231 
232  with open(self.fname) as fstream:
233  self.elf = vm_load_elf(self.jitter.vm, fstream.read())
234  preload_elf(self.jitter.vm, self.elf, self.libs)
235 
236  self.entry_point = self.elf.Ehdr.entry
237 
238  # Library calls handler
239  self.jitter.add_lib_handler(self.libs, methods)
240 
242  def __init__(self, custom_methods, *args, **kwargs):
243  from miasm2.jitter.loader.elf import libimp_elf
244  from miasm2.os_dep import linux_stdlib
245  methods = linux_stdlib.__dict__
246  methods.update(custom_methods)
247 
248  super(OS_Linux_str, self).__init__(methods, *args, **kwargs)
249 
250  # Import manager
251  libs = libimp_elf()
252  self.libs = libs
253 
254  data = open(self.fname).read()
255  self.options.load_base_addr = int(self.options.load_base_addr, 0)
256  self.jitter.vm.add_memory_page(self.options.load_base_addr, PAGE_READ | PAGE_WRITE, data)
257 
258  # Library calls handler
259  self.jitter.add_lib_handler(libs, methods)
260 
261  @classmethod
262  def update_parser(cls, parser):
263  parser.add_argument("load_base_addr", help="load base address")
264 
265 
266 class Arch_x86(Arch):
267  _ARCH_ = None # Arch name
268  STACK_SIZE = 0x10000
269  STACK_BASE = 0x130000
270 
271  def __init__(self):
272  super(Arch_x86, self).__init__()
273 
274  if self.options.usesegm:
275  self.jitter.ir_arch.do_stk_segm= True
276  self.jitter.ir_arch.do_ds_segm= True
277  self.jitter.ir_arch.do_str_segm = True
278  self.jitter.ir_arch.do_all_segm = True
279 
280  # Init stack
281  self.jitter.stack_size = self.STACK_SIZE
282  self.jitter.stack_base = self.STACK_BASE
283  self.jitter.init_stack()
284 
285 
286  @classmethod
287  def update_parser(cls, parser):
288  parser.add_argument('-s', "--usesegm", action="store_true",
289  help="Use segments")
290 
291 
293  _ARCH_ = "x86_32"
294 
295 
297  _ARCH_ = "x86_64"
298 
299 
301  _ARCH_ = "arml"
302  STACK_SIZE = 0x100000
303  STACK_BASE = 0x100000
304 
305  def __init__(self):
306  super(Arch_arml, self).__init__()
307 
308  # Init stack
309  self.jitter.stack_size = self.STACK_SIZE
310  self.jitter.stack_base = self.STACK_BASE
311  self.jitter.init_stack()
312 
314  _ARCH_ = "armb"
315  STACK_SIZE = 0x100000
316  STACK_BASE = 0x100000
317 
318  def __init__(self):
319  super(Arch_armb, self).__init__()
320 
321  # Init stack
322  self.jitter.stack_size = self.STACK_SIZE
323  self.jitter.stack_base = self.STACK_BASE
324  self.jitter.init_stack()
325 
327  _ARCH_ = "aarch64l"
328  STACK_SIZE = 0x100000
329  STACK_BASE = 0x100000
330 
331  def __init__(self):
332  super(Arch_aarch64l, self).__init__()
333 
334  # Init stack
335  self.jitter.stack_size = self.STACK_SIZE
336  self.jitter.stack_base = self.STACK_BASE
337  self.jitter.init_stack()
338 
339 
341  _ARCH_ = "aarch64b"
342  STACK_SIZE = 0x100000
343  STACK_BASE = 0x100000
344 
345  def __init__(self):
346  super(Arch_aarch64b, self).__init__()
347 
348  # Init stack
349  self.jitter.stack_size = self.STACK_SIZE
350  self.jitter.stack_base = self.STACK_BASE
351  self.jitter.init_stack()
352 
353 
354 
356 
357  def __init__(self, *args, **kwargs):
358  Sandbox.__init__(self, *args, **kwargs)
359 
360  # Pre-stack some arguments
361  self.jitter.push_uint32_t(2)
362  self.jitter.push_uint32_t(1)
363  self.jitter.push_uint32_t(0)
364  self.jitter.push_uint32_t(0x1337beef)
365 
366  # Set the runtime guard
367  self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
368 
369 
370  def run(self, addr = None):
371  """
372  If addr is not set, use entrypoint
373  """
374  if addr is None and self.options.address is None:
375  addr = self.entry_point
376  super(Sandbox_Win_x86_32, self).run(addr)
377 
378 
380 
381  def __init__(self, *args, **kwargs):
382  Sandbox.__init__(self, *args, **kwargs)
383 
384  # reserve stack for local reg
385  for i in xrange(0x4):
386  self.jitter.push_uint64_t(0)
387 
388  # Pre-stack return address
389  self.jitter.push_uint64_t(0x1337beef)
390 
391  # Set the runtime guard
392  self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
393 
394 
395  def run(self, addr = None):
396  """
397  If addr is not set, use entrypoint
398  """
399  if addr is None and self.options.address is None:
400  addr = self.entry_point
401  super(Sandbox_Win_x86_64, self).run(addr)
402 
403 
405 
406  def __init__(self, *args, **kwargs):
407  Sandbox.__init__(self, *args, **kwargs)
408 
409  # Pre-stack some arguments
410  self.jitter.push_uint32_t(2)
411  self.jitter.push_uint32_t(1)
412  self.jitter.push_uint32_t(0)
413  self.jitter.push_uint32_t(0x1337beef)
414 
415  # Set the runtime guard
416  self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
417 
418 
419  def run(self, addr = None):
420  """
421  If addr is not set, use entrypoint
422  """
423  if addr is None and self.options.address is None:
424  addr = self.entry_point
425  super(Sandbox_Linux_x86_32, self).run(addr)
426 
427 
429 
430  def __init__(self, *args, **kwargs):
431  Sandbox.__init__(self, *args, **kwargs)
432 
433  # reserve stack for local reg
434  for i in xrange(0x4):
435  self.jitter.push_uint64_t(0)
436 
437  # Pre-stack return address
438  self.jitter.push_uint64_t(0x1337beef)
439 
440  # Set the runtime guard
441  self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
442 
443 
444  def run(self, addr = None):
445  """
446  If addr is not set, use entrypoint
447  """
448  if addr is None and self.options.address is None:
449  addr = self.entry_point
450  super(Sandbox_Linux_x86_64, self).run(addr)
451 
452 
454 
455  def __init__(self, *args, **kwargs):
456  Sandbox.__init__(self, *args, **kwargs)
457 
458  self.jitter.cpu.LR = 0x1337beef
459 
460  # Set the runtime guard
461  self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
462 
463 
464  def run(self, addr = None):
465  if addr is None and self.options.address is not None:
466  addr = int(self.options.address, 16)
467  super(Sandbox_Linux_arml, self).run(addr)
468 
470 
471  def __init__(self, *args, **kwargs):
472  Sandbox.__init__(self, *args, **kwargs)
473 
474  self.jitter.cpu.LR = 0x1337beef
475 
476  # Set the runtime guard
477  self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
478 
479 
480  def run(self, addr = None):
481  if addr is None and self.options.address is not None:
482  addr = int(self.options.address, 0)
483  super(Sandbox_Linux_armb_str, self).run(addr)
484 
485 
487 
488  def __init__(self, *args, **kwargs):
489  Sandbox.__init__(self, *args, **kwargs)
490 
491  self.jitter.cpu.LR = 0x1337beef
492 
493  # Set the runtime guard
494  self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
495 
496 
497  def run(self, addr = None):
498  if addr is None and self.options.address is not None:
499  addr = int(self.options.address, 0)
500  super(Sandbox_Linux_arml_str, self).run(addr)
501 
502 
504 
505  def __init__(self, *args, **kwargs):
506  Sandbox.__init__(self, *args, **kwargs)
507 
508  self.jitter.cpu.LR = 0x1337beef
509 
510  # Set the runtime guard
511  self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
512 
513 
514  def run(self, addr = None):
515  if addr is None and self.options.address is not None:
516  addr = int(self.options.address, 0)
517  super(Sandbox_Linux_aarch64l, self).run(addr)