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 generateLines(self): if self.function is None: return [] il = self.function.mlil # Set up IL display options renderer = DisassemblyTextRenderer(il) renderer.settings.set_option(DisassemblyOption.ShowAddress) renderer.settings.set_option(DisassemblyOption.ShowVariableTypesWhenAssigned) # Sort basic blocks by IL instruction index blocks = il.basic_blocks blocks.sort(key = lambda block: block.start) # Function header result = [] result.append(LinearDisassemblyLine(LinearDisassemblyLineType.FunctionHeaderStartLineType, self.function, None, 0, DisassemblyTextLine([], self.function.start))) result.append(LinearDisassemblyLine(LinearDisassemblyLineType.FunctionHeaderLineType, self.function, None, 0, DisassemblyTextLine(self.function.type_tokens, self.function.start))) result.append(LinearDisassemblyLine(LinearDisassemblyLineType.FunctionHeaderEndLineType, self.function, None, 0, DisassemblyTextLine([], self.function.start))) # Display IL instructions in order lastAddr = self.function.start lastBlock = None lineIndex = 0 for block in il: if lastBlock is not None: # Blank line between basic blocks result.append(LinearDisassemblyLine(LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, block, 0, DisassemblyTextLine([], lastAddr))) for i in block: lines, length = renderer.get_disassembly_text(i.instr_index) lastAddr = i.address lineIndex = 0 for line in lines: result.append(LinearDisassemblyLine(LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, block, lineIndex, line)) lineIndex += 1 lastBlock = block result.append(LinearDisassemblyLine(LinearDisassemblyLineType.FunctionEndLineType, self.function, lastBlock, lineIndex, DisassemblyTextLine([], lastAddr))) return result
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 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 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 perform_get_lines_for_data( self, _, bv: BinaryView, addr: int, type: Type, prefix: List[InstructionTextToken], width: int, context: List[str]) -> List[DisassemblyTextLine]: end = addr + len(type) result: List[DisassemblyTextLine] = [] for tokens, size in bv.disassembly_tokens(addr, bv.arch): if addr + size > end: break result.append( DisassemblyTextLine( [*tokens], addr, color=HighlightStandardColor.RedHighlightColor)) addr += size return result
def generateLines(self): if self.function is None: return [] mlil = self.function.mlil # Set up IL display options renderer = DisassemblyTextRenderer(mlil) # renderer.settings.set_option(DisassemblyOption.ShowAddress) renderer.settings.set_option( DisassemblyOption.ShowVariableTypesWhenAssigned) ast = MediumLevelILAst(mlil) ast.generate() # Function header result = [] result.append( LinearDisassemblyLine( LinearDisassemblyLineType.FunctionHeaderStartLineType, self.function, None, 0, DisassemblyTextLine([], self.function.start), )) result.append( LinearDisassemblyLine( LinearDisassemblyLineType.FunctionHeaderLineType, self.function, None, 0, DisassemblyTextLine(self.function.type_tokens, self.function.start), )) result.append( LinearDisassemblyLine( LinearDisassemblyLineType.FunctionHeaderEndLineType, self.function, None, 0, DisassemblyTextLine([], self.function.start), )) line_index = 0 for il in ast.root.block: if (il.instr_index == ast.root.block[-1].instr_index) and il.operation in ( MediumLevelILOperation.MLIL_IF, MediumLevelILOperation.MLIL_JUMP_TO, MediumLevelILOperation.MLIL_GOTO, MediumLevelILOperation.MLIL_NORET, ): continue il_lines, _ = renderer.get_disassembly_text(il.instr_index) for line in il_lines: result.append( LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, line, )) line_index += 1 to_visit = [(n, 0) for header, n in sorted( ast._regions.items(), key=cmp_to_key(lambda i, j: 1 if ast.reaching_conditions.get( (i[0], j[0])) is None else 1 if i.start > j.start else -1), reverse=True)] prev_indent = 0 indent = 0 last_il = il use_else_condition = False while to_visit: current_node, indent = to_visit.pop() if indent < prev_indent: for i in range(prev_indent - 4, indent - 4, -4): result.append( LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, last_il.il_basic_block, line_index, DisassemblyTextLine( [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*i}}}', ) ], last_il.address, ), )) if isinstance(current_node, MediumLevelILAstSeqNode): if isinstance(current_node, MediumLevelILAstElseNode): il_line = DisassemblyTextLine([], current_node.header.start) if use_else_condition: il_line.tokens += [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken( InstructionTextTokenType.KeywordToken, "if"), InstructionTextToken( InstructionTextTokenType.TextToken, " ("), *current_node.condition.tokens, InstructionTextToken( InstructionTextTokenType.TextToken, ") {"), ] result.append( LinearDisassemblyLine( LinearDisassemblyLineType. CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) else: il_line.tokens += [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken( InstructionTextTokenType.KeywordToken, "else"), InstructionTextToken( InstructionTextTokenType.TextToken, " {"), ] result.append( LinearDisassemblyLine( LinearDisassemblyLineType. CodeDisassemblyLineType, self.function, current_node.header, line_index, il_line, )) indent += 4 line_index += 1 if isinstance(current_node.header, MediumLevelILBasicBlock): for il in current_node.header: if (il.instr_index == current_node.header.end - 1) and il.operation in ( MediumLevelILOperation.MLIL_IF, MediumLevelILOperation.MLIL_JUMP_TO, MediumLevelILOperation.MLIL_GOTO, MediumLevelILOperation.MLIL_NORET, ): continue il_lines, length = renderer.get_disassembly_text( il.instr_index) for line in il_lines: line.tokens.insert( 0, InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), ) result.append( LinearDisassemblyLine( LinearDisassemblyLineType. CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, line, )) elif isinstance(current_node.header, MediumLevelILAstBreakNode): il_line = DisassemblyTextLine([], current_node.header.address) il_line.tokens += [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken( InstructionTextTokenType.TextToken, "break") ] result.append( LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 to_visit += zip(reversed(current_node.children), repeat(indent)) elif isinstance(current_node, MediumLevelILAstBasicBlockNode): for il in current_node.block: if (il.instr_index == current_node.block.end - 1) and il.operation in ( MediumLevelILOperation.MLIL_IF, MediumLevelILOperation.MLIL_JUMP_TO, MediumLevelILOperation.MLIL_GOTO, MediumLevelILOperation.MLIL_NORET, ): continue il_lines, length = renderer.get_disassembly_text( il.instr_index) for line in il_lines: line.tokens.insert( 0, InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), ) result.append( LinearDisassemblyLine( LinearDisassemblyLineType. CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, line, )) line_index += 1 elif isinstance(current_node, MediumLevelILBasicBlock): for il in current_node: if (il.instr_index == current_node.end - 1) and il.operation in ( MediumLevelILOperation.MLIL_IF, MediumLevelILOperation.MLIL_JUMP_TO, MediumLevelILOperation.MLIL_GOTO, MediumLevelILOperation.MLIL_NORET, ): continue il_lines, length = renderer.get_disassembly_text( il.instr_index) for line in il_lines: line.tokens.insert( 0, InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), ) result.append( LinearDisassemblyLine( LinearDisassemblyLineType. CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, line, )) line_index += 1 elif isinstance(current_node, MediumLevelILAstCondNode): use_else_condition = False condition = ConstraintVisitor(self.function).visit( current_node.condition) il_line = DisassemblyTextLine([], current_node.address) if current_node[True] is not None: il_line.tokens += [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken( InstructionTextTokenType.KeywordToken, "if"), InstructionTextToken( InstructionTextTokenType.TextToken, " ("), *condition, InstructionTextToken( InstructionTextTokenType.TextToken, ") {"), ] result.append( LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 to_visit.append((current_node[False], indent)) if current_node[True] is not None: to_visit.append((current_node[True], indent + 4)) else: use_else_condition = True elif isinstance(current_node, MediumLevelILAstBreakNode): il_line = DisassemblyTextLine([], current_node.address) il_line.tokens += [ InstructionTextToken(InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken(InstructionTextTokenType.TextToken, "break") ] result.append( LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 elif isinstance(current_node, MediumLevelILAstLoopNode): if current_node.condition is not None: condition = ConstraintVisitor(self.function).visit( current_node.condition) il_line = DisassemblyTextLine([], current_node.loop[0].address) il_line.tokens += [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken( InstructionTextTokenType.KeywordToken, "while"), InstructionTextToken( InstructionTextTokenType.TextToken, " ("), *condition, InstructionTextToken( InstructionTextTokenType.TextToken, ") {"), ] result.append( LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 else: raise NotImplementedError("Don't know how to do this yet") indent += 4 for il in current_node.loop: if (il.instr_index == current_node.loop.end - 1) and il.operation in ( MediumLevelILOperation.MLIL_IF, MediumLevelILOperation.MLIL_JUMP_TO, MediumLevelILOperation.MLIL_GOTO, MediumLevelILOperation.MLIL_NORET, ): continue il_lines, length = renderer.get_disassembly_text( il.instr_index) for line in il_lines: line.tokens.insert( 0, InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), ) result.append( LinearDisassemblyLine( LinearDisassemblyLineType. CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, line, )) line_index += 1 to_visit += zip(reversed(current_node.children), repeat(indent)) elif isinstance(current_node, MediumLevelILAstSwitchNode): il_line = DisassemblyTextLine([], current_node.switch.address) il_line.tokens += [ InstructionTextToken(InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken(InstructionTextTokenType.KeywordToken, "switch"), InstructionTextToken(InstructionTextTokenType.TextToken, " ("), *current_node.switch.tokens, InstructionTextToken(InstructionTextTokenType.TextToken, ") {"), ] result.append( LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 to_visit += zip( reversed( sorted(current_node.cases.items(), key=lambda i: i[0])), repeat(indent + 4), ) elif isinstance(current_node, tuple): il_line = DisassemblyTextLine( [], current_node[1].header.source_block.start) il_line.tokens += [ InstructionTextToken(InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken(InstructionTextTokenType.OpcodeToken, "case "), InstructionTextToken( InstructionTextTokenType.IntegerToken, str(current_node[0]), current_node[0], ), InstructionTextToken(InstructionTextTokenType.TextToken, " {"), ] result.append( LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 to_visit += [(current_node[1], indent + 4)] prev_indent = indent last_il = il if indent != 0: for i in range(indent, 0, -4): result.append( LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, self.function, last_il.il_basic_block, line_index, DisassemblyTextLine( [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*(i-4)}}}') ], last_il.address, ), )) line_index += 1 result.append( LinearDisassemblyLine( LinearDisassemblyLineType.FunctionEndLineType, self.function, last_il.il_basic_block, line_index, DisassemblyTextLine([], last_il.instr_index), )) return result
def generateLines(self): if self.function is None: return [] if self.function in self.function_cache: return self.function_cache[self.function] mlil = self.function.mlil # Set up IL display options renderer = DisassemblyTextRenderer(mlil) # renderer.settings.set_option(DisassemblyOption.ShowAddress) # renderer.settings.set_option( # DisassemblyOption.ShowVariableTypesWhenAssigned # ) ast = MediumLevelILAst(mlil) ast.generate() # Function header result = [] result.append( LinearDisassemblyLine( LinearDisassemblyLineType.FunctionHeaderStartLineType, self.function, None, 0, DisassemblyTextLine([], self.function.start), )) result.append( LinearDisassemblyLine( LinearDisassemblyLineType.FunctionHeaderLineType, self.function, None, 0, DisassemblyTextLine(self.function.type_tokens, self.function.start), )) result.append( LinearDisassemblyLine( LinearDisassemblyLineType.FunctionHeaderEndLineType, self.function, None, 0, DisassemblyTextLine([], self.function.start), )) # add variables for var in self.function.vars: var_line = DisassemblyTextLine([], 0) var_line.tokens += var.type.get_tokens_before_name() var_line.tokens += [ InstructionTextToken(InstructionTextTokenType.TextToken, " "), InstructionTextToken( InstructionTextTokenType.LocalVariableToken, var.name, var.identifier, ), InstructionTextToken(InstructionTextTokenType.TextToken, " "), ] var_line.tokens += var.type.get_tokens_after_name() result.append( LinearDisassemblyLine( LinearDisassemblyLineType.LocalVariableLineType, self.function, None, 0, var_line, )) result.append( LinearDisassemblyLine( LinearDisassemblyLineType.LocalVariableListEndLineType, self.function, None, 0, DisassemblyTextLine([], 0), )) line_index = 0 to_visit = [(ast.regions[0][1], 0)] prev_indent = 0 indent = 0 il = self.function.mlil[0] last_il = self.function.mlil[0] do_while = [] while to_visit: current_node, indent = to_visit.pop() if indent < prev_indent: for i in range(prev_indent - 4, indent - 4, -4): il_line = DisassemblyTextLine( [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*i}}}', ) ], last_il.address, ) if do_while and do_while[-1][0] == i: condition = do_while.pop()[1] il_line.tokens += [ InstructionTextToken( InstructionTextTokenType.KeywordToken, " while"), InstructionTextToken( InstructionTextTokenType.TextToken, "("), *condition, InstructionTextToken( InstructionTextTokenType.TextToken, ")"), ] result.append( LinearDisassemblyLine( _CodeDisassemblyLineType, self.function, last_il.il_basic_block, line_index, il_line, )) if current_node.type == "seq": to_visit += zip(reversed(current_node.nodes), repeat(indent)) elif current_node.type == "block": for il in current_node.block: if (il.instr_index == current_node.block.end - 1) and il.operation in ( MediumLevelILOperation.MLIL_IF, MediumLevelILOperation.MLIL_JUMP_TO, MediumLevelILOperation.MLIL_GOTO, MediumLevelILOperation.MLIL_NORET, ): continue il_lines, _ = renderer.get_disassembly_text(il.instr_index) for line in il_lines: new_tokens = TokenVisitor().visit(il) line.tokens = [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}', ), *new_tokens ] result.append( LinearDisassemblyLine( _CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, line, )) line_index += 1 elif current_node.type == "break": il_line = DisassemblyTextLine([], current_node.address) il_line.tokens += [ InstructionTextToken(InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken(InstructionTextTokenType.TextToken, "break"), ] result.append( LinearDisassemblyLine( _CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 elif current_node.type == "cond": if is_false(current_node.condition): continue if current_node[True] is not None: condition = ConstraintVisitor(self.function).visit( current_node.condition) elif current_node[False] is not None: condition = ConstraintVisitor(self.function).visit( Not(current_node.condition)) il_line = DisassemblyTextLine([], current_node.address) il_line.tokens += [ InstructionTextToken(InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken(InstructionTextTokenType.KeywordToken, "if"), InstructionTextToken(InstructionTextTokenType.TextToken, " ("), *condition, InstructionTextToken(InstructionTextTokenType.TextToken, ") {"), ] result.append( LinearDisassemblyLine( _CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 if current_node[False] is not None: to_visit.append((current_node[False], indent + 4)) # Append a node that will tell us that the next node is # an else block if current_node[True] is not None: to_visit.append(( MediumLevelILAstElseNode(self, current_node.address), indent, )) if current_node[True] is not None: to_visit.append((current_node[True], indent + 4)) elif current_node.type == "else": il_line = DisassemblyTextLine([], current_node.address) il_line.tokens += [ InstructionTextToken(InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken(InstructionTextTokenType.KeywordToken, "else"), InstructionTextToken(InstructionTextTokenType.TextToken, " {"), ] result.append( LinearDisassemblyLine( _CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 elif current_node.type == "loop": condition = ConstraintVisitor(self.function).visit( current_node.condition) il_line = DisassemblyTextLine([], current_node.address) il_line.tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, f'{" "*indent}')) if current_node.loop_type in ("while", "endless"): il_line.tokens += [ InstructionTextToken( InstructionTextTokenType.KeywordToken, "while"), InstructionTextToken( InstructionTextTokenType.TextToken, " ("), *condition, InstructionTextToken( InstructionTextTokenType.TextToken, ") {"), ] elif current_node.loop_type == "dowhile": il_line.tokens += [ InstructionTextToken( InstructionTextTokenType.KeywordToken, "do"), InstructionTextToken( InstructionTextTokenType.TextToken, " {"), ] do_while.append((indent, condition)) result.append( LinearDisassemblyLine( _CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 to_visit += zip(reversed(current_node.body.nodes), repeat(indent + 4)) elif current_node.type == "switch": il_line = DisassemblyTextLine([], current_node.address) condition = ConstraintVisitor(self.function).visit( current_node.switch) il_line.tokens += [ InstructionTextToken(InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken(InstructionTextTokenType.KeywordToken, "switch"), InstructionTextToken(InstructionTextTokenType.TextToken, " ("), *condition, InstructionTextToken(InstructionTextTokenType.TextToken, ") {"), ] result.append( LinearDisassemblyLine( _CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 to_visit += zip(reversed(current_node.cases), repeat(indent + 4)) elif current_node.type == "case": il_line = DisassemblyTextLine([], current_node.address) for idx, v in enumerate(current_node.value): il_line.tokens += [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*indent}'), InstructionTextToken( InstructionTextTokenType.TextToken, "case "), (InstructionTextToken( InstructionTextTokenType.IntegerToken, str(v), v) if v != 'default' else InstructionTextToken( InstructionTextTokenType.TextToken, v)) ] if idx == len(current_node.value) - 1: il_line.tokens.append( InstructionTextToken( InstructionTextTokenType.TextToken, " {")) result.append( LinearDisassemblyLine( _CodeDisassemblyLineType, self.function, il.il_basic_block, line_index, il_line, )) line_index += 1 il_line = DisassemblyTextLine([], current_node.address) to_visit += zip(reversed(current_node.nodes), repeat(indent + 4)) prev_indent = indent last_il = il if indent != 0: for i in range(indent, 0, -4): result.append( LinearDisassemblyLine( _CodeDisassemblyLineType, self.function, last_il.il_basic_block, line_index, DisassemblyTextLine( [ InstructionTextToken( InstructionTextTokenType.TextToken, f'{" "*(i-4)}}}', ) ], last_il.address, ), )) line_index += 1 result.append( LinearDisassemblyLine( LinearDisassemblyLineType.FunctionEndLineType, self.function, last_il.il_basic_block, line_index, DisassemblyTextLine([], last_il.instr_index), )) self.function_cache[self.function] = result log_debug("generateLines finished") return result