PyGhidra - List Blocks of a Function
Tested with Ghidra 12.0.3
Introduction
List the code blocks of a randomly (or not; more information in previous post) choosen function and disassemble them. Also, the source(s) and destination(s) of each blocks are listed.
Keywords to dig in the doc:
BasicBlockModelCodeBlockImplCodeBlockReferenceAddressRangeAddressSet
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# List basic blocks of a randomly selected function
# List basic blocks of a randomly selected function
#@author silma
#@category _MyScripts
#@keybinding
#@menupath
#@toolbar
# Set USE_RANDOM = False to work with the function at funcs_list[INDEX]
INDEX = 11
USE_RANDOM = True
import random
from ghidra.program.model.listing import FunctionIterator, Function, CodeUnit
from ghidra.program.model.lang import OperandType
from ghidra.program.model.address import AddressSet
from ghidra.program.model.block import BasicBlockModel
from ghidra.util.task import ConsoleTaskMonitor
def choose_function(all_funcs: FunctionIterator) -> Function:
funcs_list = []
for f in all_funcs:
funcs_list.append(f)
if USE_RANDOM:
random.seed()
idx = random.randrange(0, len(funcs_list), step=1)
else:
idx = INDEX
f = funcs_list[idx]
return f
def list_function_blocks(f: Function):
bbm = BasicBlockModel(currentProgram)
blocks = bbm.getCodeBlocksContaining(f.getBody(), monitor) # SimpleBlockIterator
for i, b in enumerate(blocks): # CodeBlockImpl
block_start_addr = b.getFirstStartAddress() # Address
#block_all_entrypoints = b.getStartAddresses()
n_sources = b.getNumSources(monitor) # int
n_dests = b.getNumDestinations(monitor)
block_ranges = b.getAddressRanges(True) # AddressRangeIterator
for range_ in block_ranges:
block_min_addr = range_.getMinAddress() # Address
block_max_addr = range_.getMaxAddress() # Address
break
assert(block_min_addr == block_start_addr)
block_sources = b.getSources(monitor) # CodeBlockReferenceIterator
block_destinations = b.getDestinations(monitor) # CodeBlockReferenceIterator
print(f"block {i} disassembly:")
as_ = AddressSet(block_min_addr, block_max_addr) # AddressSet
cu = listing.getCodeUnits(as_, True)
for insn in cu:
print(f" {insn.getAddress()} {insn}")
print(f"Block {i} details:")
print(f" block range: {block_min_addr} - {block_max_addr}")
print(f" sources flow (n = {n_sources}):")
while block_sources.hasNext():
n = block_sources.next() # CodeBlockReference
s = n.getSourceAddress() # Address
r = n.getReferent() # Address
d = n.getReference() # Address
print(f" {n}: source block @{s} flows from {r} to {d}")
assert(d == block_start_addr)
print(f" destinations flow: (n = {n_dests})")
while block_destinations.hasNext():
n = block_destinations.next() # CodeBlockReference
s = n.getSourceAddress()
r = n.getReferent() # Address
d = n.getReference() # Address
print(f" {n}: block {i} flows from {r} to {d}")
assert(s == block_start_addr)
print("===============")
i += 1
monitor = ConsoleTaskMonitor()
f_mgr = currentProgram.getFunctionManager()
listing = currentProgram.getListing() # Listing
all_funcs = f_mgr.getFunctions(True)
f = choose_function(all_funcs)
print(f"Using function '{f}'")
list_function_blocks(f)
EOF
This post is licensed under CC BY 4.0 by the author.