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)
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
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)
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)