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.