6

I am using ghidra to do some reverse engineering of an ARM binary. I am wondering whether there is a way to get the basic blocks related to all the listing. Is there a function through the IDE or a script through the script manager that I could used in order to get basic blocks at least within a function. Though I found scripts to decompile the binary I couldn't find a function that listed the basic blocks. Apart from ghidra is there any other reverse engineering tools that would help me to achieve this job? Thank you!

hEShaN
  • 281
  • 4
  • 11

4 Answers4

8

You can obtain the list of all defined basic blocks using BasicBlockModel

Example

from ghidra.program.model.block import BasicBlockModel
from ghidra.util.task import TaskMonitor

bbm = BasicBlockModel(currentProgram)
blocks = bbm.getCodeBlocks(TaskMonitor.DUMMY)
block = blocks.next()

while block:
    print "Label: {}".format(block.name)
    print "Min Address: {}".format(block.minAddress)
    print "Max address: {}".format(block.maxAddress)
    print
    block = blocks.next()

Output

Label: LAB_0048b428
Min Address: 0048b428
Max address: 0048b43f

Label: httpStringPut
Min Address: 0048b440
Max address: 0048b46b

Label: 0048b46c
Min Address: 0048b46c
Max address: 0048b47f

Label: LAB_0048b480
Min Address: 0048b480
Max address: 0048b4b3

Label: httpBoundaryGet
Min Address: 0048b4c0
Max address: 0048b4cf

<snip>

Update

If you want to print disassembly of the basic blocks you can modify the script as

from ghidra.program.model.block import BasicBlockModel
from ghidra.util.task import TaskMonitor

def print_disassembly(block):
    listing = currentProgram.getListing()
    ins_iter = listing.getInstructions(block, True)

    while ins_iter.hasNext():
        ins = ins_iter.next()
        print "{} {}".format(ins.getAddressString(False, True), ins)

bbm = BasicBlockModel(currentProgram)
blocks = bbm.getCodeBlocks(TaskMonitor.DUMMY)
block = blocks.next()

while block:
    print_disassembly(block)
    block = blocks.next()
    print

Output

00409fcc lui gp,0xb
00409fd0 addiu gp,gp,0x68b4
00409fd4 addu gp,gp,t9
00409fd8 addiu sp,sp,-0x20
00409fdc sw gp,0x10(sp)
00409fe0 sw ra,0x1c(sp)
00409fe4 sw gp,0x18(sp)
00409fe8 bal 0x00409ff0
00409fec _nop

00409ff0 lui gp,0x4c
00409ff4 addiu gp,gp,0x880
00409ff8 lw t9,-0x7fe8(gp)
00409ffc nop
0040a000 addiu t9,t9,-0x5e80
0040a004 jalr t9
0040a008 _nop
0040a00c lw gp,0x10(sp)
0040a010 nop
0040a014 bal 0x0040a01c
0040a018 _nop

<snip>
0xec
  • 6,090
  • 3
  • 23
  • 33
5

@0xec's answer is great. This script will help you get blocks function wise.

from ghidra.program.model.block import BasicBlockModel

blockiterator = BasicBlockModel(currentProgram).getCodeBlocks(monitor)
# dictionary contains function wise basic block information
functions = {}

def add_block(function, block):
    if function not in functions:
         functions[function] = []
    functions[function].append(block)

# For each block, look through the function list until we find a match
while blockiterator.hasNext():
    cur_block = blockiterator.next().getMinAddress()
    function = getFirstFunction()
    found = False

    # Search functions until we find a match or run out of functions
    while function is not None:
        b = function.getBody()
        if b.contains(cur_block):
            add_block(function.getName(), cur_block)
            found=True
            break

        # Update function to next and loop again
        function = getFunctionAfter(function)

    # Done searching functions. If we never found it, add to unknown list
    if not found:
        add_block("_unknown", cur_block)

print(functions)
R4444
  • 1,807
  • 10
  • 30
4

0xec has answered you but if you are interested in functions you can iterate as below

#TODO Lists Functions in a given program
#@author  blabb
#@category _NEW_

funcs = currentProgram.getFunctionManager().getFunctions(True)
f1 = funcs.next()
print("Function Name",f1.getName())
print("Function Body" , f1.getBody())
print("Function Entry" , f1.getEntryPoint())
print("Functions Calls",f1.getCalledFunctions(ghidra.util.task.TaskMonitor.DUMMY))
print("Function is Called From",f1.getCallingFunctions(ghidra.util.task.TaskMonitor.DUMMY))

will result in details as below for the first function use hasnext() or while( next) to loop

functions.py> Running...
('Function Name', u'MmFreeIndependentPages')

('Function Body', [[140001010, 140001172] [1401d4c1a, 1401d4c8c] ])

('Function Entry', 140001010)

('Functions Calls', [MiReturnPoolCharges, MiPteInShadowRange, memset, MiIsPfnFromSlabAllocation, 
MiWritePteShadow,MI_READ_PTE_LOCK_FREE,MiLockAndDecrementShareCount,MiReleasePtes, MiPteHasShadow])

('Function is Called From', [MmFreeIsrStack, FUN_14098fe9c, IopLiveDumpAllocateDumpBuffers, 
IopLiveDumpWriteDumpFile, KiStartDynamicProcessor, IopLiveDumpWriteDumpFileWithHvPages,   
HvlDeleteProcessor,IopLiveDumpFreeDumpBuffers,ExDeletePoolTagTable, HvlStartBootLogicalProcessors,  
KeStartAllProcessors, HvlpInitializeHvCrashdump, IopLiveDumpReleaseResources])
blabb
  • 16,376
  • 1
  • 15
  • 30
1

Pyhidra (github, website) is another API for interacting with Ghidra using Python.

Pyhidra can be used within Ghidra in addition to the built-in Python runtime, but when used standalone as in these examples, the from ghidra imports must be inside the context manager (with pyhidra.open_program(...) as this essentially takes the place of opening Ghidra and loading a program.

Here are some of the answers to this question, ported to Python 3.6+ and Pyhidra for standalone use:

0xec (1)

import pyhidra
program = 'path/to/my.exe'

with pyhidra.open_program(program) as flat_api: from ghidra.program.model.block import BasicBlockModel from ghidra.util.task import TaskMonitor monitor = TaskMonitor.DUMMY currentProgram = flat_api.currentProgram for b in BasicBlockModel(currentProgram).getCodeBlocks(monitor): print(f'Label: {b.name}') print(f'Min Address: {b.minAddress}') print(f'Max Address: {b.maxAddress}') print()

0xec (2)

import pyhidra
program = 'path/to/my.exe'

with pyhidra.open_program(program) as flat_api: from ghidra.program.model.block import BasicBlockModel from ghidra.util.task import TaskMonitor monitor = TaskMonitor.DUMMY currentProgram = flat_api.currentProgram for block in BasicBlockModel(currentProgram).getCodeBlocks(monitor): listing = currentProgram.getListing() for ins in listing.getInstructions(block, True): print(f'{ins.getAddressString(False, True)} {ins}')

  print()

Alex Shroyer
  • 143
  • 5