Exemplo n.º 1
0
  def DisassembleChunkWithObjdump(self, data, bitness):
    """Disassemble chunk assuming it consists of valid instructions.

    Args:
      data: raw data as python string.
      bitness: 32 or 64

    Returns:
      List of objdump_parser.Instruction tuples. If data can't be disassembled
      (either contains invalid instructions or ends in a middle of instruction)
      exception is raised.
    """
    # TODO(shcherbina):
    # Replace this shameless plug with python interface to RDFA decoder once
    # https://code.google.com/p/nativeclient/issues/detail?id=3456 is done.

    arch = {32: '-Mi386', 64: '-Mx86-64'}[bitness]

    tmp = tempfile.NamedTemporaryFile(mode='wb', delete=False)
    try:
      tmp.write(data)
      tmp.close()

      objdump_proc = subprocess.Popen(
          ['objdump',
           '-mi386', arch, '--target=binary',
           '--disassemble-all', '--disassemble-zeroes',
           '--insn-width=15',
           tmp.name],
          stdout=subprocess.PIPE)

      instructions = []
      total_bytes = 0
      for line in objdump_parser.SkipHeader(objdump_proc.stdout):
        insn = objdump_parser.ParseLine(line)
        insn = objdump_parser.CanonicalizeInstruction(insn)
        instructions.append(insn)
        total_bytes += len(insn.bytes)

      assert len(data) == total_bytes

      return_code = objdump_proc.wait()
      assert return_code == 0, 'error running objdump'

      return instructions

    finally:
      tmp.close()
      os.remove(tmp.name)
Exemplo n.º 2
0
  def DisassembleChunk(self, data, bitness):
    data_ptr = ctypes.cast(data, ctypes.POINTER(ctypes.c_uint8))
    result = self.DisassembleChunk_(data_ptr, len(data), bitness)

    instructions = []
    total_bytes = 0
    for line in cStringIO.StringIO(result):
      m = re.match(r'rejected at ([\da-f]+)', line)
      if m is not None:
        offset = int(m.group(1), 16)
        raise DisassemblerError(offset, ' '.join('%02x' % ord(c) for c in data))
      insn = objdump_parser.ParseLine(line)
      insn = objdump_parser.CanonicalizeInstruction(insn)
      instructions.append(insn)
      total_bytes += len(insn.bytes)
    return instructions
Exemplo n.º 3
0
    def GetSectionContent(self, options, sections):
        spec_val_cls = {
            32: spec_val.Validator32,
            64: spec_val.Validator64
        }[options.bits]

        instructions = []
        for line in StringIO.StringIO(sections['dis']):
            insn = objdump_parser.ParseLine(line)
            insn = objdump_parser.CanonicalizeInstruction(insn)
            instructions.append(insn)

        messages = spec_val_cls().Validate(instructions)

        if messages == []:
            return 'SAFE\n'

        return ''.join('%x: %s\n' % (offset, message)
                       for offset, message in messages)
Exemplo n.º 4
0
def Disassemble(options, byte_sequences_iter):
  """Disassembles all byte sequences and returns it in old or new trie."""
  asm_file = None
  object_file = None
  old_trie_set = set()
  new_trie_set = set()
  bitness = int(options.bitness)
  try:
    file_prefix = "proof_decodes"
    asm_file = tempfile.NamedTemporaryFile(
        mode='wt',
        prefix=file_prefix,
        suffix='.s',
        delete=False)
    asm_file.write('.text\n')

    accepts = []
    for entry in byte_sequences_iter:
      byte_tuple, accept_info1, accept_info2 = entry
      accepts += [(accept_info1, accept_info2)]
      asm_file.write('  .byte %s\n' % ','.join(map(hex, map(int, byte_tuple))))
    asm_file.close()

    object_file = tempfile.NamedTemporaryFile(
        prefix=file_prefix,
        suffix='.o',
        delete=False)
    object_file.close()

    subprocess.check_call([
        options.gas,
        '--%s' % bitness,
        '--strip-local-absolute',
        asm_file.name,
        '-o', object_file.name])

    objdump_proc = subprocess.Popen(
        [options.objdump, '-d', '--insn-width=15', object_file.name],
        stdout=subprocess.PIPE)

    for line, (accept_info1, accept_info2) in itertools.izip(
        objdump_parser.SkipHeader(objdump_proc.stdout),
        iter(accepts)):
      instruction = objdump_parser.CanonicalizeInstruction(
            objdump_parser.ParseLine(line),
            simplify_condition_jumps=True)
      prefixes, mnemonic, operands = (spec.ParseInstruction(instruction))
      full_operands = tuple(prefixes + [mnemonic] + operands)
      if accept_info1 is not None:
        input_rr, output_rr = GetRRInfoFromTrie(accept_info1, bitness)
        old_trie_set.add(Operands(disasms=full_operands,
                                  input_rr=input_rr,
                                  output_rr=output_rr))
      if accept_info2 is not None:
        input_rr, output_rr = GetRRInfoFromTrie(accept_info2, bitness)
        new_trie_set.add(Operands(disasms=full_operands,
                                  input_rr=input_rr,
                                  output_rr=output_rr))

    return_code = objdump_proc.wait()
    assert return_code == 0

  finally:
    os.remove(asm_file.name)
    os.remove(object_file.name)

  return old_trie_set, new_trie_set
def ProcessSuperinstructionsFile(filename, bitness, gas, objdump, out_file):
  """Process superinstructions file.

  Each line produces either "True" or "False" plus text of original command
  (for the documentation purposes).  "True" means instruction is safe, "False"
  means instruction is unsafe.  This is needed since some instructions are
  incorrect but accepted by DFA (these should be rejected by actions embedded
  in DFA).

  If line contains something except valid set of x86 instruction assert
  error is triggered.

  Args:
      filename: name of file to process
      bitness: 32 or 64
      gas: path to the GAS executable
      objdump: path to the OBJDUMP executable
  Returns:
      None
  """

  try:
    object_file = tempfile.NamedTemporaryFile(
        prefix='verify_superinstructions_',
        suffix='.o',
        delete=False)
    object_file.close()

    subprocess.check_call([gas,
                           '--{0}'.format(bitness),
                           filename,
                           '-o{0}'.format(object_file.name)])

    objdump_proc = subprocess.Popen(
        [objdump, '-d', object_file.name, '--insn-width=15'],
        stdout=subprocess.PIPE)

    objdump_iter = iter(objdump_parser.SkipHeader(objdump_proc.stdout))

    line_prefix = '.byte '

    with open(filename) as superinstructions:
      for superinstruction_line in superinstructions:
        # Split the source line to find bytes
        assert superinstruction_line.startswith(line_prefix)
        # Leave only bytes here
        bytes_only = superinstruction_line[len(line_prefix):]
        superinstruction_bytes = [byte.strip(' \n')
                                  for byte in bytes_only.split(',')]
        superinstruction_validated = ValidateSuperinstruction(
            bytearray([int(byte, 16) for byte in superinstruction_bytes]),
            bitness)
        # Pick disassembled form of the superinstruction from objdump output
        superinstruction = []
        objdump_bytes = []
        while len(objdump_bytes) < len(superinstruction_bytes):
          nextline = next(objdump_iter).decode()
          instruction = objdump_parser.ParseLine(nextline)
          instruction = objdump_parser.CanonicalizeInstruction(instruction)
          superinstruction.append(instruction)
          objdump_bytes += instruction.bytes
        # Bytes in objdump output in and source file should match
        assert ['0x%02x' % b for b in objdump_bytes] == superinstruction_bytes
        if bitness == 32:
          validate_superinstruction = spec.ValidateSuperinstruction32
        else:
          validate_superinstruction = spec.ValidateSuperinstruction64

        try:
          validate_superinstruction(superinstruction)
          assert superinstruction_validated, (
              'validator rejected superinstruction allowed by spec',
              superinstruction)
        except spec.SandboxingError as e:
          assert not superinstruction_validated, (
              'validator allowed superinstruction rejected by spec',
              superinstruction,
              e)
        except spec.DoNotMatchError:
          raise
  finally:
    os.remove(object_file.name)