def get_instruction_text(self, data, addr): instr = self.disassembler.instrs[addr // self.address_size] if instr is None: return None tokens = [] tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, type(instr).__name__.lower())) tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, " ")) for i in range(len(instr.operands)): operand = instr.operands[i] if self.disassembler.is_register(operand): tokens.append( InstructionTextToken( InstructionTextTokenType.RegisterToken, self.disassembler.symbol[operand], )) else: tokens.append( InstructionTextToken( InstructionTextTokenType.PossibleAddressToken, hex(operand * self.address_size), )) if i != len(instr.operands) - 1: tokens.append( InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ", ")) return tokens, instr.width * self.address_size
def _call(self, opcode): addr = opcode & 0xfff return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'CALL'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, hex(addr), addr) ]
def perform_get_lines_for_data(self, ctxt, view, addr, type, prefix, width, context): value = struct.unpack('!H',view.read(addr, 2))[0] if value == 0x0800: prefix.append( InstructionTextToken(InstructionTextTokenType.TextToken, 'IPv4') ) else: prefix.append( InstructionTextToken(InstructionTextTokenType.IntegerToken, value) ) return [DisassemblyTextLine(prefix, addr)]
def _get_lines_for_data(self, ctxt, view, addr, type, prefix, prefixCount, width, count, typeCtx, ctxCount): try: file_metadata = FileMetadata(handle=core.BNGetFileForView(view)) view = BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) type = Type(handle=core.BNNewTypeReference(type)) prefixTokens = InstructionTextToken.get_instruction_lines( prefix, prefixCount) pycontext = [] for i in range(ctxCount): pycontext.append(Type(core.BNNewTypeReference(typeCtx[i]))) result = self.perform_get_lines_for_data(ctxt, view, addr, type, prefixTokens, width, pycontext) count[0] = len(result) line_buf = (core.BNDisassemblyTextLine * len(result))() for i in range(len(result)): line = result[i] color = line.highlight if not isinstance(color, HighlightStandardColor) and not isinstance( color, highlight.HighlightColor): raise ValueError( "Specified color is not one of HighlightStandardColor, highlight.HighlightColor" ) if isinstance(color, HighlightStandardColor): color = highlight.HighlightColor(color) line_buf[i].highlight = color._get_core_struct() if line.address is None: if len(line.tokens) > 0: line_buf[i].addr = line.tokens[0].address else: line_buf[i].addr = 0 else: line_buf[i].addr = line.address if line.il_instruction is not None: line_buf[i].instrIndex = line.il_instruction.instr_index else: line_buf[i].instrIndex = 0xffffffffffffffff line_buf[i].count = len(line.tokens) line_buf[ i].tokens = InstructionTextToken.get_instruction_lines( line.tokens) return ctypes.cast(line_buf, ctypes.c_void_p).value except: log_error(traceback.format_exc()) return None
def _jp_v0(self, opcode): addr = opcode & 0xfff return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'JP'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.RegisterToken, 'V0'), InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ', '), InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, hex(addr), addr) ]
def makeToken(tokenType, text, data=None): tokenType = { 'inst':InstructionTextTokenType.InstructionToken, 'text':InstructionTextTokenType.TextToken, 'addr':InstructionTextTokenType.PossibleAddressToken, 'int': InstructionTextTokenType.IntegerToken, 'sep':InstructionTextTokenType.OperandSeparatorToken, "reg": InstructionTextTokenType.RegisterToken, }[tokenType] if data is None: return InstructionTextToken(tokenType, text) return InstructionTextToken(tokenType, text, data)
def _rnd(self, opcode): vars = self._vars(opcode) x, kk = vars['x'], vars['kk'] return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'RND'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.RegisterToken, self.V[x]), InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ', '), InstructionTextToken(InstructionTextTokenType.IntegerToken, hex(kk), kk) ]
def _sne(self, opcode): vars = self._vars(opcode) x, y = vars['x'], vars['y'] return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'SNE'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.RegisterToken, self.V[x]), InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ', '), InstructionTextToken(InstructionTextTokenType.RegisterToken, self.V[y]) ]
def populate_nodes(self): func = self.function view = self.view nodes = {f: FlowGraphNode(self) for f in view.functions} for function, node in nodes.items(): if function.symbol.type == SymbolType.ImportedFunctionSymbol: token_type = InstructionTextTokenType.ImportToken else: token_type = InstructionTextTokenType.CodeSymbolToken node.lines = [ DisassemblyTextLine( [ InstructionTextToken(token_type, function.name, function.start) ], function.start, ) ] self.append(node) for function in view.functions: node = nodes[function] for callee in set(function.callees): callee_node = nodes[callee] node.add_outgoing_edge(BranchType.IndirectBranch, callee_node)
def populate_nodes(self): nodes = {} # create nodes for every block in the function for irb in viewvalues(self.ircfg.blocks): node = FlowGraphNode(self) nodes[irb.loc_key] = node self.append(node) for irb in viewvalues(self.ircfg.blocks): if not irb: continue # add edges for each block if irb.dst.is_cond(): if irb.dst.src1.is_loc() and irb.dst.src1.loc_key in nodes: nodes[irb.loc_key].add_outgoing_edge( BranchType.TrueBranch, nodes[irb.dst.src1.loc_key]) if irb.dst.src2.is_loc() and irb.dst.src2.loc_key in nodes: nodes[irb.loc_key].add_outgoing_edge( BranchType.FalseBranch, nodes[irb.dst.src2.loc_key]) elif irb.dst.is_loc() and irb.dst.loc_key in nodes: nodes[irb.loc_key].add_outgoing_edge( BranchType.UnconditionalBranch, nodes[irb.dst.loc_key]) lines = [] irb_token = self.expr_to_token(ExprLoc(irb.loc_key, irb.dst.size)) irb_token += [ InstructionTextToken(InstructionTextTokenType.TextToken, ":") ] lines.append(irb_token) for assignblk in irb: for dst, src in sorted(viewitems(assignblk)): tokens = [] tokens.append( InstructionTextToken( InstructionTextTokenType.TextToken, " ")) tokens += self.expr_to_token(dst) tokens.append( InstructionTextToken( InstructionTextTokenType.TextToken, " = ")) tokens += self.expr_to_token(src) lines.append(tokens) lines.append("") lines.pop() # remove last empty line nodes[irb.loc_key].lines = lines
def get_token(self, mnemonic, operand, data): if re.search(r'(d|r|a)8', operand) is not None: value = data[1] if re.match(r'(d|r|a)8', operand) is not None: token = InstructionTextToken( InstructionTextTokenType.IntegerToken, "0x%.2x" % value, value) elif re.match(r'\(a8\)', operand) is not None: token = InstructionTextToken( InstructionTextTokenType.PossibleAddressToken, "0xff%.2x" % value, value | 0xff00) else: token = InstructionTextToken( InstructionTextTokenType.PossibleAddressToken, "0x%.4x" % value, value) elif re.search(r'(d|r|a)16', operand) is not None: value = struct.unpack('<H', data[1:3])[0] if re.match(r'(d|r|a)16', operand) is not None: if mnemonic == "CALL": token = InstructionTextToken( InstructionTextTokenType.DataSymbolToken, "sub_%x" % value, value) elif re.match(r'\(a16\)', operand) is not None: token = InstructionTextToken( InstructionTextTokenType.PossibleAddressToken, "0x%.4x" % value, value) else: token = InstructionTextToken( InstructionTextTokenType.IntegerToken, "0x%.4x" % value, value) else: token = InstructionTextToken( InstructionTextTokenType.PossibleAddressToken, "0x%.4x" % value, value) elif re.search(r'A|B|C|D|E|F|H|L|(SP)|(PC)', operand) is not None: if re.match(r'A|B|C|D|E|F|H|L|(SP)|(PC)', operand) is not None: token = InstructionTextToken( InstructionTextTokenType.RegisterToken, operand.lower()) else: token = InstructionTextToken( InstructionTextTokenType.RegisterToken, operand.lower()) else: token = InstructionTextToken( InstructionTextTokenType.RegisterToken, operand.lower()) return token
def get_instruction_text(self, data, addr): """ Display text for tokanized instruction """ if len(data) > 2: data = data[:2] tokens = self.dis.disasm(data, addr) if not tokens: tokens = [ InstructionTextToken(InstructionTextTokenType.InstructionToken, '_emit'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.IntegerToken, hex(data[0]), data[0]), InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ', '), InstructionTextToken(InstructionTextTokenType.IntegerToken, hex(data[1]), data[1]) ] return tokens, 2
def get_instruction_text(self, data, addr): tmp = self.qualifies(data, addr) if not tmp: return super(X86DeobfuscateHook, self).get_instruction_text(data, addr) (push_addr, length) = tmp print('%08X: push+ret found, disassembling as jmp to 0x%X' % (addr, push_addr)) tok_jmp = InstructionTextToken( InstructionTextTokenType.InstructionToken, "jmp") tok_space = InstructionTextToken(InstructionTextTokenType.TextToken, ' ') tok_dest = InstructionTextToken( InstructionTextTokenType.PossibleAddressToken, hex(push_addr), push_addr) return [tok_jmp, tok_space, tok_dest], length
def perform_get_instruction_text(self, data, addr): instr, operand, length, value = self.decode_instruction(data, addr) if instr is None: return None tokens = [] tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, "%-7s " % instr.replace("@", ""))) tokens += OperandTokens[operand](value) return tokens, length
def perform_get_instruction_text(self, data, addr): valid, instr = get_instruction(data, addr) if not valid: # This is _EXCEEDINGLY_ important to return on failure. # Things will break in creative ways if anything other than None # is returned for invalid data return None if instr.opcode not in InstructionNames: log('debug: %s' % instr) return ( [InstructionTextToken(InstructionTextTokenType.InstructionToken, "unk opcode 0x%x" % instr.opcode)], 8) tokens = [] instr_name = InstructionNames[instr.opcode] tokens.append(InstructionTextToken(InstructionTextTokenType.InstructionToken, instr_name)) formatter = InstructionFormatters[instr.opcode] extra_tokens = formatter(instr) if len(extra_tokens) > 0: tokens += [InstructionTextToken(InstructionTextTokenType.TextToken, " ")] + extra_tokens return tokens, 8
def _rcs(self, opcode): if opcode == 0x00EE: return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'RET') ] if opcode == 0x00E0: return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'CLS') ] addr = opcode & 0xfff return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'SYS'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, hex(addr), addr) ]
def add_node(self, func): func_node = FlowGraphNode(self) line = DisassemblyTextLine([]) line.tokens.append( InstructionTextToken(InstructionTextTokenType.CodeSymbolToken, func.name, value=func.start, address=func.start)) func_node.lines = [line] self.append(func_node)
def _get_lines_for_data(self, ctxt, view, addr, type, prefix, prefixCount, width, count, typeCtx, ctxCount): try: file_metadata = FileMetadata(handle=core.BNGetFileForView(view)) view = BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) type = Type(handle=core.BNNewTypeReference(type)) prefixTokens = InstructionTextToken.get_instruction_lines(prefix, prefixCount) pycontext = [] for i in range(ctxCount): pycontext.append(Type(core.BNNewTypeReference(typeCtx[i]))) result = self.perform_get_lines_for_data(ctxt, view, addr, type, prefixTokens, width, pycontext) count[0] = len(result) line_buf = (core.BNDisassemblyTextLine * len(result))() for i in range(len(result)): line = result[i] color = line.highlight if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor") if isinstance(color, HighlightStandardColor): color = highlight.HighlightColor(color) line_buf[i].highlight = color._get_core_struct() if line.address is None: if len(line.tokens) > 0: line_buf[i].addr = line.tokens[0].address else: line_buf[i].addr = 0 else: line_buf[i].addr = line.address if line.il_instruction is not None: line_buf[i].instrIndex = line.il_instruction.instr_index else: line_buf[i].instrIndex = 0xffffffffffffffff line_buf[i].count = len(line.tokens) line_buf[i].tokens = InstructionTextToken.get_instruction_lines(line.tokens) return ctypes.cast(line_buf, ctypes.c_void_p).value except: log_error(traceback.format_exc()) return None
def get_instruction_text(self, data, addr): ins_mnem, ins_len, operands, _, _ = self._decode_instruction( data, addr) if ins_mnem is None: return None tokens = [] tokens.append(InstructionTextToken( InstructionTextTokenType.InstructionToken, ins_mnem.lower())) if len(operands) >= 1: tokens.append(InstructionTextToken( InstructionTextTokenType.IndentationToken, ''.rjust(8 - len(ins_mnem)))) tokens += self._get_token(ins_mnem, operands[0], data, addr, ins_len) if len(operands) == 2: tokens.append(InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ', ')) tokens += self._get_token(ins_mnem, operands[1], data, addr, ins_len) return tokens, ins_len
def get_instruction_text(self, data, addr): log_info(str(data)) (instruction_text, instruction_len) = dis.lazy_disasm(addr) tokens = [ InstructionTextToken(InstructionTextTokenType.TextToken, instruction_text) ] text_tokens = instruction_text.split() instruction = text_tokens[1].lower() raw_offset = text_tokens[-1] if op.instruction_is_call(instruction): call_offset = addr + int(raw_offset, 16) tokens.append( InstructionTextToken( InstructionTextTokenType.PossibleAddressToken, hex(call_offset), call_offset)) return tokens, instruction_len
def perform_get_instruction_text(self, data, addr): instr, length, operands, flags, value = self.decode_instruction( data, addr) tokens = [] opcode = data[0] if instr is None: return None tokens.append( InstructionTextToken(InstructionTextTokenType.InstructionToken, instr.lower())) if len(operands) >= 1: tokens.append( InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ''.rjust(8 - len(instr)))) tokens.append(self.get_token(instr, operands[0], data)) if len(operands) == 2: tokens.append( InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ', ')) tokens.append(self.get_token(instr, operands[1], data)) return tokens, length
def add_func_node(self, func): if func in self.func_nodes: print(f"{func} already in, returning existing...") return self.func_nodes[func] func_node = FlowGraphNode(self) line = DisassemblyTextLine([]) line.tokens.append( InstructionTextToken(InstructionTextTokenType.CodeSymbolToken, func.name, value=func.start, address=func.start)) func_node.lines = [line] self.append(func_node) self.func_nodes[func] = func_node return func_node
def get_instruction_text(self, data, addr): # instruction lookup instruction = self.instructions[ord(data[0])] if instruction is None: return None (opcode, length) = instruction[0] # opcode tokens = [InstructionTextToken(InstructionTextTokenType.InstructionToken, '{:6}'.format(opcode))] # operands for operand in instruction[1]: # add a separator if needed if len(tokens) > 1: tokens += [InstructionTextToken(InstructionTextTokenType.OperandSeparatorToken, ',')] # append suffix for second bank working registers if self.rb == 1 and re.match('\@?R\d', operand) is not None: operand += '\'' if operand == '#IMM8': immediate = ord(data[1]) tokens += [InstructionTextToken(InstructionTextTokenType.IntegerToken, '#{:X}H'.format(immediate), immediate)] elif operand == 'ADDR8': address = (addr & 0xf00) | ord(data[1]) tokens += [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, '{:X}H'.format(address), CODE_ADDR(0, address))] elif operand == 'ADDR11': # TODO: memory bank selection address = ((ord(data[0]) & 0xe0) << 3) | ord(data[1]) tokens += [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, '{:X}H'.format(address), CODE_ADDR(0, address))] elif operand in self.regs: tokens += [InstructionTextToken(InstructionTextTokenType.RegisterToken, operand)] elif operand[0] == '@' and operand[1:] in self.regs: tokens += [InstructionTextToken(InstructionTextTokenType.InstructionToken, '@'), InstructionTextToken(InstructionTextTokenType.RegisterToken, operand[1:])] else: tokens += [InstructionTextToken(InstructionTextTokenType.TextToken, operand)] return tokens, length
def _draw(self, opcode): vars = self._vars(opcode) x, y, n = vars['x'], vars['y'], vars['n'] return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'DRW'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.RegisterToken, self.V[x]), InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ', '), InstructionTextToken(InstructionTextTokenType.RegisterToken, self.V[y]), InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ', '), InstructionTextToken(InstructionTextTokenType.IntegerToken, hex(n), n) ]
def _skip(self, opcode): vars = self._vars(opcode) x, kk = vars['x'], vars['kk'] if kk == 0x9E: return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'SKP'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.RegisterToken, self.V[x]) ] if kk == 0xA1: return [ InstructionTextToken(InstructionTextTokenType.InstructionToken, 'SKNP'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.RegisterToken, self.V[x]) ]
def RegisterToken(txt): return InstructionTextToken(InstructionTextTokenType.RegisterToken, txt)
def SeperatorToken(txt=","): return InstructionTextToken(InstructionTextTokenType.OperandSeparatorToken, txt)
def IntegerToken(num): return InstructionTextToken(InstructionTextTokenType.IntegerToken, '#0x%x' % num, value=num)
def TextToken(txt): return InstructionTextToken(InstructionTextTokenType.TextToken, txt)
def AddressToken(num): return InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, '0x%x' % num, value=num)
1, # IND_X_DEST 1, # IND_Y 1, # IND_Y_DEST 1, # REL 1, # ZERO 1, # ZREO_DEST 1, # ZERO_X 1, # ZERO_X_DEST 1, # ZERO_Y 1 # ZERO_Y_DEST ] OperandTokens = [ lambda value: [], # NONE lambda value: [ InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value) ], # ABS lambda value: [ InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value) ], # ABS_DEST lambda value: [ InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "x") ], # ABS_X lambda value: [ InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), InstructionTextToken(InstructionTextTokenType.TextToken, ", "),