Example #1
0
def validate_bil(program, flow):
  r"""
  Runs the concrete executor, validating the the results are consistent with the trace.
  Returns a tuple of (Errors, Warnings)
  Currently only supports ARM, x86, and x86-64
  """

  trace = program.traces[0]
  libraries = [(m[3],m[1]) for m in trace.mapped]
  registers = program.tregs[0]
  regsize = 8 * program.tregs[1]
  arch = program.tregs[-1]

  if arch == "arm":
    cpu_flags = ["ZF", "CF", "NF", "VF"]
    PC = "PC"
  elif arch == "i386":
    cpu_flags = ["CF", "PF", "AF", "ZF", "SF", "OF", "DF"]
    PC = "EIP"
  elif arch == "x86-64":
    cpu_flags = ["CF", "PF", "AF", "ZF", "SF", "OF", "DF"]
    PC = "RIP"
  else:
    print "Architecture not supported"
    return [],[]


  errors = []
  warnings = []

  def new_state_for_clnum(clnum, include_flags=True):
    flags = cpu_flags if include_flags else []
    flagvalues = [0 for f in flags]
    varnames = registers + flags
    initial_regs = trace.db.fetch_registers(clnum)
    varvals = initial_regs + flagvalues
    varvals = map(lambda x: ConcreteBitVector(regsize, x), varvals)
    initial_vars = dict(zip(varnames, varvals))
    initial_mem_get = partial(trace.fetch_raw_memory, clnum)
    return State(initial_vars, initial_mem_get)

  state = new_state_for_clnum(0)

  for (addr,data,clnum,ins) in flow:
    instr = program.static[addr]['instruction']
    if not isinstance(instr, BapInsn):
      errors.append(Error(clnum, instr, "Could not make BAP instruction for %s" % str(instr)))
      state = new_state_for_clnum(clnum)
    else:
      bil_instrs = instr.insn.bil
      if bil_instrs is None:
        errors.append(Error(clnum, instr, "No BIL for instruction %s" % str(instr)))
        state = new_state_for_clnum(clnum)
      else:

        # this is bad.. fix this
        if arch == "arm":
          state[PC] += 8 #Qira PC is wrong

        executor = ConcreteExecutor(state, PC)

        try:
          adt.visit(executor, bil_instrs)
        except VariableException as e:
          errors.append(Error(clnum, instr, "No BIL variable %s!" % str(e.args[0])))
        except MemoryException as e:
          errors.append(Error(clnum, instr, "Used invalid address %x." % e.args[0]))

        if not executor.jumped:
          if arch == "arm":
            state[PC] -= 4
          elif arch == "i386" or arch == "x86-64":
            state[PC] += instr.size()

        validate = True
        PC_val = state[PC]
        if PC_val > 0xf0000000 or any([PC_val >= base and PC_val <= base+size for (base,size) in libraries]):
          # we are jumping into a library that we can't trace.. reset the state and continue
          warnings.append(Warning(clnum, instr, "Jumping into library. Cannot trace this"))
          state = new_state_for_clnum(clnum)
          continue

        error = False
        correct_regs = new_state_for_clnum(clnum, include_flags=False).variables

        for reg, correct in correct_regs.iteritems():
          if state[reg] != correct:
            error = True
            errors.append(Error(clnum, instr, "%s was incorrect! (%x != %x)." % (reg, state[reg] , correct)))
            state[reg] = correct

        for (addr, val) in state.memory.items():
          realval = trace.fetch_raw_memory(clnum, addr, 1)
          if len(realval) == 0 or len(val) == 0:
            errors.append(Error(clnum, instr, "Used invalid address %x." % addr))
            # this is unfixable, reset state
            state = new_state_for_clnum(clnum)
          elif val != realval:
            error = True
            errors.append(Error(clnum, instr, "Value at address %x is wrong! (%x != %x)." % (addr, ord(val), ord(realval))))
            state[addr] = realval

  return (errors, warnings)
Example #2
0
 def visit_While(self, op):
   while self.run(op.cond) == 1:
     adt.visit(self, op.stmts)
Example #3
0
 def visit_If(self, op):
   if self.run(op.cond) == 1:
     adt.visit(self, op.true)
   else:
     adt.visit(self, op.false)
Example #4
0
File: model.py Project: alpire/qira
 def jumps(bil):
   return visit(Jmp_visitor(), bil).jumps
Example #5
0
File: model.py Project: alpire/qira
 def accesses(bil):
   r = visit(Access_visitor(), bil)
   return (r.reads, r.writes)
Example #6
0
 def accesses(bil):
     r = visit(Access_visitor(), bil)
     return (r.reads, r.writes)
Example #7
0
 def jumps(bil):
     return visit(Jmp_visitor(), bil).jumps
def validate_bil(program, flow):
    r"""
  Runs the concrete executor, validating the the results are consistent with the trace.
  Returns a tuple of (Errors, Warnings)
  Currently only supports ARM, x86, and x86-64
  """

    trace = program.traces[0]
    libraries = [(m[3], m[1]) for m in trace.mapped]
    registers = program.tregs[0]
    regsize = 8 * program.tregs[1]
    arch = program.tregs[-1]

    if arch == "arm":
        cpu_flags = ["ZF", "CF", "NF", "VF"]
        PC = "PC"
    elif arch == "i386":
        cpu_flags = ["CF", "PF", "AF", "ZF", "SF", "OF", "DF"]
        PC = "EIP"
    elif arch == "x86-64":
        cpu_flags = ["CF", "PF", "AF", "ZF", "SF", "OF", "DF"]
        PC = "RIP"
    else:
        print "Architecture not supported"
        return [], []

    errors = []
    warnings = []

    def new_state_for_clnum(clnum, include_flags=True):
        flags = cpu_flags if include_flags else []
        flagvalues = [0 for f in flags]
        varnames = registers + flags
        initial_regs = trace.db.fetch_registers(clnum)
        varvals = initial_regs + flagvalues
        varvals = map(lambda x: ConcreteBitVector(regsize, x), varvals)
        initial_vars = dict(zip(varnames, varvals))
        initial_mem_get = partial(trace.fetch_raw_memory, clnum)
        return State(initial_vars, initial_mem_get)

    state = new_state_for_clnum(0)

    for (addr, data, clnum, ins) in flow:
        instr = program.static[addr]['instruction']
        if not isinstance(instr, BapInsn):
            errors.append(
                Error(clnum, instr,
                      "Could not make BAP instruction for %s" % str(instr)))
            state = new_state_for_clnum(clnum)
        else:
            bil_instrs = instr.insn.bil
            if bil_instrs is None:
                errors.append(
                    Error(clnum, instr,
                          "No BIL for instruction %s" % str(instr)))
                state = new_state_for_clnum(clnum)
            else:

                # this is bad.. fix this
                if arch == "arm":
                    state[PC] += 8  #Qira PC is wrong

                executor = ConcreteExecutor(state, PC)

                try:
                    adt.visit(executor, bil_instrs)
                except VariableException as e:
                    errors.append(
                        Error(clnum, instr,
                              "No BIL variable %s!" % str(e.args[0])))
                except MemoryException as e:
                    errors.append(
                        Error(clnum, instr,
                              "Used invalid address %x." % e.args[0]))

                if not executor.jumped:
                    if arch == "arm":
                        state[PC] -= 4
                    elif arch == "i386" or arch == "x86-64":
                        state[PC] += instr.size()

                validate = True
                PC_val = state[PC]
                if PC_val > 0xf0000000 or any([
                        PC_val >= base and PC_val <= base + size
                        for (base, size) in libraries
                ]):
                    # we are jumping into a library that we can't trace.. reset the state and continue
                    warnings.append(
                        Warning(clnum, instr,
                                "Jumping into library. Cannot trace this"))
                    state = new_state_for_clnum(clnum)
                    continue

                error = False
                correct_regs = new_state_for_clnum(
                    clnum, include_flags=False).variables

                for reg, correct in correct_regs.iteritems():
                    if state[reg] != correct:
                        error = True
                        errors.append(
                            Error(
                                clnum, instr, "%s was incorrect! (%x != %x)." %
                                (reg, state[reg], correct)))
                        state[reg] = correct

                for (addr, val) in state.memory.items():
                    realval = trace.fetch_raw_memory(clnum, addr, 1)
                    if len(realval) == 0 or len(val) == 0:
                        errors.append(
                            Error(clnum, instr,
                                  "Used invalid address %x." % addr))
                        # this is unfixable, reset state
                        state = new_state_for_clnum(clnum)
                    elif val != realval:
                        error = True
                        errors.append(
                            Error(
                                clnum, instr,
                                "Value at address %x is wrong! (%x != %x)." %
                                (addr, ord(val), ord(realval))))
                        state[addr] = realval

    return (errors, warnings)
 def visit_If(self, op):
     if self.run(op.cond) == 1:
         adt.visit(self, op.true)
     else:
         adt.visit(self, op.false)
 def visit_While(self, op):
     while self.run(op.cond) == 1:
         adt.visit(self, op.stmts)