7

How can I change color of node (or block?) with idapython? I know about SetColor, but this function does not work with blocks/nodes.

enter image description here

EDIT: Solved, see the code snippet below.

def get_bb_id(graph, ea):
    for block in graph:
        if block.startEA <= ea and block.endEA > ea:
            return block.id

start_ea = 0x15f9ad6
base_block_ea = 0x15f9a60

f = get_func(start_ea)
g = FlowChart(f, flags=FC_PREDS) #???
bb_id = get_bb_id(g, start_ea)

p = idaapi.node_info_t()
p.bg_color = 0x00ff00 # green

print idaapi.set_node_info2(base_block_ea, bb_id, p, 
                            idaapi.NIF_BG_COLOR | idaapi.NIF_FRAME_COLOR)
0

4 Answers 4

4

You can also use Sark:

import sark
code_block = sark.CodeBlock(some_ea)
code_block.color = 0x00ff0000

Disclaimer: I am the author of Sark.

0
2

Look over following functions and around (found in idaapi.py):

def SetNodeInfo(self, node_index, node_info, flags):
    """
    Set the properties for the given node.

    Example usage (set second nodes's bg color to red):
      inst = ...
      p = idaapi.node_info_t()
      p.bg_color = 0x00ff0000
      inst.SetNodeInfo(1, p, idaapi.NIF_BG_COLOR)

    @param node_index: The node index.
    @param node_info: An idaapi.node_info_t instance.
    @param flags: An OR'ed value of NIF_* values.
    """
    _idaapi.pygc_set_node_info(self, node_index, node_info, flags)

def SetNodesInfos(self, values):
    """
    Set the properties for the given nodes.

    Example usage (set first three nodes's bg color to purple):
      inst = ...
      p = idaapi.node_info_t()
      p.bg_color = 0x00ff00ff
      inst.SetNodesInfos({0 : p, 1 : p, 2 : p})

    @param values: A dictionary of 'int -> node_info_t' objects.
    """
    _idaapi.pygc_set_nodes_infos(self, values)
2

You can use SetColor API ether.
You should call SetColor on every lines of the block, as it colors only one instruction line at a time.

Here is my IDAPython code example:

class ColoringBB(): 
    flowchart = False 
    tgt_ea = 0 
    startea = 0 
    endea = 0 
    addr_fc = 0

    def __init__(self, addr_fc):
        self._set_fc_address(addr_fc)
        self._set_flowchart()

    def _set_fc_address(self, addr_fc):
        self.addr_fc = addr_fc 

    def _set_flowchart(self):
        f = idaapi.get_func(self.addr_fc)
        self.flowchart = idaapi.FlowChart(f)

    def coloring_bb(self, addr):
        self._set_bb_range(addr)
        for addr in range(self.startea, self.endea):
            idc.SetColor(addr, idc.CIC_ITEM, 0x8f8080) # olive

    def _set_bb_range(self, addr):
        for block in self.flowchart:
            if block.startEA <= addr and block.endEA > addr:
                self.startea, self.endea = block.startEA, block.endEA
                break

Set the flowchart information before coloring the block.

addr_fc = 0x8040DCF4 # set flow chart address
cb = ColoringBB(addr_fc)

cb.coloring_bb(0x8040DD40) # color the block containing those address
cb.coloring_bb(0x8040DD34) # color the block containing those address
2

There's a bit more to this question than meets the eye.

In IDA, each instruction can optionally have a color set on it. Additionally, each graph node can optionally have a color set on it.

If an instruction does not have a color set on it, its background color defaults to the node's color. If the node does not have a color set on it, its background color defaults to the background color for disassembly for the current IDA theme (Options | Colors... | Disassembly). Each node also has two narrow horizontal bands, one located just above the node's instructions and one located below. These bands are always colored with the node's own background color, or the disassembly theme color if no color has been set on the node.

When you use the color chooser in the upper-left corner of a graph node, IDA sets the color on the node as well as on each instruction within the node. You can set a color on an individual instruction via the UI with Edit | Other | Color instruction...

There does not seem to be any way to unset the color of a node or instruction using only the UI (aside from "Undo"). The programmatic way to unset a color from an item or node is to specify the color as idc.DEFCOLOR which equals 0xffffffff (not to be confused with the color white, which is represented by 0x00ffffff).

Key points:

  • If you want to programmatically perform the equivalent of setting a node color via the UI, you need to set the node color both on the node itself and also on each instruction within the node.
  • Unsetting the color from an instruction or node can be done using idc.DEFCOLOR.
  • A screen refresh is needed - see below.

Here's what's working for me, on IDA 8.2.230124:

from itertools import islice
import idautils

def setNodeColor(ea, color, nodeOnly=False):
    node_info = idaapi.node_info_t()
    node_info.bg_color = color
    func = idaapi.get_func(ea)
    flowchart = idaapi.FlowChart(func)
    block = list(islice(filter(lambda b: b.start_ea <= ea < b.end_ea, flowchart), 1))[0]
    idaapi.set_node_info(func.start_ea, block.id, node_info, idaapi.NIF_BG_COLOR)
    if not nodeOnly:
        for head in idautils.Heads(block.start_ea, block.end_ea):
            idc.set_color(head, CIC_ITEM, color)


# Example
ea = idc.get_screen_ea()
color = 0xffff00     # use idc.DEFCOLOR to revert to default
setNodeColor(ea, color) 
idaapi.refresh_idaview_anyway()

IMPORTANT: Note the last line: idc.refresh_idaview_anyway(). Without this line, the screen may be left in an outdated or inconsistent state. However, for performance reasons, if you are updating multiple nodes, you should only do this once at the end. That's why I didn't place it inside the function definition.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.