Skip to content

Instantly share code, notes, and snippets.

@alexander-hanel
Last active May 5, 2024 12:10
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save alexander-hanel/ab801910e594ec60f07d7583873ddac0 to your computer and use it in GitHub Desktop.
Save alexander-hanel/ab801910e594ec60f07d7583873ddac0 to your computer and use it in GitHub Desktop.
Cheat Sheet for Binary Ninja

Binary Ninja Python API Cheat Sheet

This is a work in progress by someone who is learning about Binary Ninja.

References

Metadata Details

Get database name

bv.file.database.file

Get original file name

bv.file.original_filename

APIs for accessing snapshots

[x for x in dir(bv.file.database) if "snapshot" in x]
['current_snapshot', 'get_snapshot', 'remove_snapshot', 'snapshots', 'trim_snapshot']

Get Architecture

bv.arch
<arch: x86_64>

Get entry point

"0x%x" %bv.entry_point
'0x140002130'

Get endianness

bv.endianness
<Endianness.LittleEndian: 0>

Segments

Get a list of segments

bv.segments

Get a list of segments and print them

for seg in bv.segments:print(seg)
<segment: 0x140000000-0x140000400, r-->
<segment: 0x140001000-0x140008d6e, r-x>
<segment: 0x140009000-0x140009c66, r-->
<segment: 0x14000a000-0x14000a450, rw->
<segment: 0x14000b000-0x14000b33c, r-->

Segment attributes

[x for x in dir(seg) if "__" not in x]
['auto_defined', 'data_end', 'data_length', 'data_offset', 'end', 'executable', 'handle', 'readable', 'relocation_count', 'relocation_ranges', 'relocation_ranges_at', 'start', 'writable']

Get segment at address

bv.get_segment_at(here)
<segment: 0x140001000-0x140008d6e, r-x>

APIs for working with segments

[x for x in dir(bv) if "segment" in x]
['add_auto_segment', 'add_user_segment', 'get_segment_at', 'remove_auto_segment', 'remove_user_segment', 'segments']

Sections

Get all sections

bv.sections

Get section at address

bv.get_sections_at(here)  # here is the address of cursor
[<section .text: 0x140001000-0x140008d6e>]

APIs for working with sections

[x for x in dir(bv) if "_section" in x]
['add_auto_section', 'add_user_section', 'get_section_by_name', 'get_sections_at', 'get_unique_section_names', 'remove_auto_section', 'remove_user_section']

Via Vector 35 Blog Post

First a lesson in how Binary Ninja organizes functions, basic blocks and instructions.

  • All Function objects are contained within a BinaryView object.
  • All BasicBlock objects are contained within a Function.
  • All instruction objects are contained within BasicBlock objects. "

source

Functions

Get all functions

bv.functions

Loop through all functions

for func in bv.functions:
  print(func)

Function type

 type(func)
<class 'binaryninja.function.Function'>

Get function start address by address

bv.get_functions_containing(here)  # returns list
[<func: x86_64@0x140008260>]

Get function name by start address

bv.get_function_at(0x140008260)
<func: x86_64@0x140008260>

Get function address by name

bv.get_functions_by_name("start_address")
[<func: x86_64@0x1400029b0>] # returns list

Get function arguments

>>> ff = bv.get_function_at(0x140008260)
>>> ff.function_type.parameters
[uint64_t* arg1]

Basic Blocks

Get basic blocks in a function

>>> for bb in ff.basic_blocks:print(bb)
<block: x86_64@0x140008260-0x140008284>
>>>
>>> ff = bv.get_function_at(here)
>>> for bb in ff.basic_blocks:print(bb)
<block: x86_64@0x140001740-0x140001767>
<block: x86_64@0x14000176f-0x140001775>
<block: x86_64@0x140001787-0x14000178c>
<block: x86_64@0x140001775-0x140001787>
<block: x86_64@0x140001767-0x14000176f>

Get basic block at address

bv.get_basic_blocks_at(0x140001770)
[<block: x86_64@0x14000176f-0x140001775>] # returns list

Get next basic block start address after address

bv.get_next_basic_block_start_after(here)

Get the end address of the previous basic block from an address

bv.get_previous_basic_block_end_before(here)

Get the start address of the previous basic block from an address

bv.get_previous_basic_block_start_before(here)

Instructions

Get disassembly instruction at address

>>> bv.get_disassembly(here)  # here is the address of cursor
'xor     edx, edx'

Loop through all instructions in function

ff = bv.get_function_at(0x140008260)
>>> for instru in ff.instructions:print(instru)
(['mov', '     ', 'qword ', '[', 'rsp', '+', '0x8', ']', ', ', 'rcx'], 5368742496)
(['sub', '     ', 'rsp', ', ', '0x28'], 5368742501)
(['call', '    ', 'qword ', '[', 'rel ', '0x1400090d0', ']'], 5368742505)
(['mov', '     ', 'r8', ', ', 'qword ', '[', 'rsp', '+', '0x30', ']'], 5368742511)
(['xor', '     ', 'edx', ', ', 'edx'], 5368742516)
(['mov', '     ', 'rcx', ', ', 'rax'], 5368742518)
(['call', '    ', 'qword ', '[', 'rel ', '0x1400090c0', ']'], 5368742521)
(['add', '     ', 'rsp', ', ', '0x28'], 5368742527)
(['retn', '    '], 5368742531)

Loop through Medium Level IL (MLIL) instructions in function

for i in ff.mlil_instructions:
... 	print("0x%x %s" % (i.address, i))
...
...
0x140008260 arg_8 = arg1
0x140008269 rax = GetProcessHeap()
0x14000826f r8 = arg_8
0x140008276 rcx = rax
0x140008279 rax_1 = HeapAlloc(rcx, HEAP_NONE, r8)
0x140008283 return rax_1

Operands

Get Operand

instru[0][0]
'retn'

Attributes for working with operands

[x for x in dir(instru[0][0]) if "__" not in x]
['_from_core_struct', '_get_core_struct', 'address', 'confidence', 'context', 'operand', 'size', 'text', 'type', 'typeNames', 'value', 'width']

Symbols/Imported API

Get all symbols

bv.get_symbols()

Get symbol by name

bv.symbols["GetCommandLineW"]
[<ImportAddressSymbol: "GetCommandLineW" @ 0x140009000>] # returns list

APIs for working with symbols

[x for x in dir(bv) if "symbol" in x]
['bulk_modify_symbols', 'define_auto_symbol', 'define_auto_symbol_and_var_or_function', 'define_user_symbol', 'get_symbol_at', 'get_symbol_by_raw_name', 'get_symbols', 'get_symbols_by_name', 'get_symbols_by_raw_name', 'get_symbols_of_type', 'has_symbols', 'symbols', 'undefine_auto_symbol', 'undefine_user_symbol']

Strings

Get offsets to string references

bv.strings
[<AsciiString: 0x14000004d, len 0x2c>, <AsciiString: 0x1400000b8,.... removed...

Get ASCII string at address

ss = bv.get_ascii_string_at(here)
ss.value
'blah.exe"

Cross-references

Binary ninja has multiple cross-reference (aka xrefs) types

Type Description
Code References References to and from code
Data References References created by data
Variable References Variable References are all the set of uses of a given variable.
Type References Type-to-Type-References

source

APIs for working with cross-references

>>> [x for x in dir(bv) if "refs" in x]
['get_code_refs', 'get_code_refs_for_type', 'get_code_refs_for_type_field', 'get_code_refs_for_type_fields_from', 'get_code_refs_for_type_from', 'get_code_refs_from', 'get_data_refs', 'get_data_refs_for_type', 'get_data_refs_for_type_field', 'get_data_refs_from', 'get_type_refs_for_type', 'get_type_refs_for_type_field']

Code References

Get code references from an address

>>> for ea in bv.get_code_refs(here):print("0x%x, %s, %s" % (ea.address, ea.arch, ea.function))
0x14000241e, x86_64, int64_t sub_1400023f0(char* arg1, void* arg2, char* arg3, void* arg4, char* arg5)
0x140002473, x86_64, int64_t sub_1400023f0(char* arg1, void* arg2, char* arg3, void* arg4, char* arg5)
0x1400024f5, x86_64, int64_t sub_1400023f0(char* arg1, void* arg2, char* arg3, void* arg4, char* arg5)
>>> type(ea)
<class 'binaryninja.binaryview.ReferenceSource'>
>>> type(ea.function)
<class 'binaryninja.function.Function'>

Data References

API referencing data cross-references

'get_data_refs', 'get_data_refs_from',

Variable References

Unknown

Type References

API referencing type cross-references

'get_code_refs_for_type', 'get_code_refs_for_type_field', 'get_code_refs_for_type_fields_from', 'get_code_refs_for_type_from', 'get_data_refs_for_type', 'get_data_refs_for_type_field', 'get_type_refs_for_type', 'get_type_refs_for_type_field'

Types

There are a lot of variations with creating types. The following link is the most useful description of Types usage.

Searching

There are two approaches that can be used by Binary Ninja for searching. The first approach uses Binary Ninja APIs.

Find all offsets of a constant by value.

bv.find_all_constant(bv.start, bv.end, constant) # example constant 0x90

Find all offset of a data.

bv.find_all_data(bv.start, bv.end, byte_pattern) # example byte_pattern b"\x90\x90\x90\x90"

Find all offsets to a string

bv.find_all_text(bv.start, bv.end, find_string) # example find_string "FindClose"

Find next address of constant by value

bv.find_next_constant(bv.start, constant)# example constant 0x90

Find next address of data by byte

bv.find_next_data(bv.start, byte_pattern) # example byte_pattern b"\x90\x90\x90\x90"

Find next address of text by string

bv.find_next_text(bv.start, find_string) # example find_string "FindClose"

The second approach treats each segment, iterates through them and searches the data.

find_me = b"\xe8\x16\x12\x00\x00"
reader = BinaryReader(bv)
for segment in bv.segments:
    offset = 0
    reader.seek(segment.start)
    data = reader.read(segment.data_length)
    offset = data.find(find_me)
    if offset != -1:
        print("found at 0x%x" % (offset + segment.start))

Comments

Note: Comments inserted through the GUI to functions are not accessible through the binary view (bv) APIs. For example, a comment of 'test one two three' was inserted via the GUI (;) but the comment is not accessible through the bv api. Binary Ninja functions that start with `current_* are not available through headless mode.

>>> current_function.get_comment_at(here)
'test one two three'
>>> bv.get_comment_at(here)
''

Add comment to address

bv.set_comment_at(here, "hi")

Get Comment

bv.get_comment_at(here)

Get all API (non-function) Comments

>>> bv.address_comments
{5368718021: 'hi', 5368718150: 'test', 5368718335: 'hi'}

Note: Function comments are not the same as function comments in IDA. Function comments in Binary Ninja appear to be related to the usage of adding comments in a function using the GUI.

Get function comment address

current_function.get_comment_at(here)

Set function comment at address

current_function.set_comment_at(here)

Selecting Data Through the UI

Get highlighted data in the GUI

get_selected_data()
b'\xff\x15\xdcm\x00\x00H\xc7D$ \x00\x00\x00\x00E3\xc9\x8bL$<D\x8b\xc1'

Persistent Storage

Write persistent data to the database

bv.store_metadata(key, value)

Get persistent data from the database

bv.get_metadata(key, value)

The first argument is a key that can be of type int, bool, str, bytes, float and list. The second argument is the value to be save or retrieved from the database.

Coloring

Highlight a selected address

ff = bv.get_functions_containing(here) # the first argument is an address
ff[0].set_auto_instr_highlight(here, highlight.HighlightColor(red=12, green=0, blue=0))

Details on color mixing

>>> help(highlight.HighlightColor)
Help on class HighlightColor in module binaryninja.highlight:

class HighlightColor(builtins.object)
 |  HighlightColor(color=None, mix_color=None, mix=None, red=None, green=None, blue=None, alpha=255)

Accessing Raw Data and Patching

Read and write bytes

data = bv.read(address, length) # read data
bv.write(address, data) # patch address

Batch File Generation

Simple script for printing all instructions.

import sys

try:
    import binaryninja
except ModuleNotFoundError:
    exit()

with binaryninja.open_view(sys.argv[1]) as bv:
    for func in bv.functions:
        for instru in func.instructions:
            print("0x%x: %s" % (instru[1], bv.get_disassembly(instru[1])))

Enumerate all XOR Instructions Example

from collections import Counter

XOR_FUNC_THRESHOLD = 8

def get_xor_instru(instru):
    if not instru:
        return False
    ins_type = instru[0][0]
    # skip XOR instructions
    if ins_type.text != "xor":
        return False
    src = instru[0][2]
    dst = instru[0][4]
    if src == dst:
        return False
    return True


def loop_through_all(bv, *options):
    """

    :param bv:
    :param options:
    :return: list []
    """
    output = ""
    # loop through all functions
    for func in bv.functions:
        temp_func_xor_instru = []
        temp_func_addr_xor = []
        # loop through all instruction
        for ins in func.instructions:
            # options is a list that can be passed a mnemonic
            if "xor" in options:
                # check if xor is the mnemonic
                tt = get_xor_instru(ins)
                # if so,
                if tt:
                    # used as a counter object to count unique xor instructions
                    temp_func_xor_instru.append(bv.get_disassembly(ins[1]))
                    # used to store XOR instruction and address
                    temp_func_addr_xor.append((ins[1], bv.get_disassembly(ins[1])))
        if not temp_func_xor_instru:
            continue
        # calculate uniqueness of xor for function
        count_dracula = Counter(temp_func_xor_instru)
        # get count of XOR instructions
        count = sum([x for x in count_dracula.values()])
        # assume manual analysis is needed, code is likely a packer or encryption
        if count > XOR_FUNC_THRESHOLD:
            output += "XOR Function:\n"
            output += "Complex XOR threshold of 0x%x found in function 0x%x\n" % (count, func.start)
            for vk in count_dracula.keys():
                output += "%s appeared 0x%x times\n" % (vk, count_dracula[vk])
            continue
        # get individual instructions
        for entry in temp_func_addr_xor:
            output += "XOR Instruction: 0x%x %s\n" % (entry[0], entry[1])
    return output

def dev():
    print(loop_through_all(bv,"xor"))

dev()

Binary Ninja API Exploration

import logging

logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)

file_name = ""

try:
    import binaryninja
    logging.debug("BinaryNinja has been imported")
except ModuleNotFoundError:
    logging.critical("BinaryNinja module is not installed.")
    exit()

with binaryninja.open_view(file_name) as bv:
    print("bv.address_comments, %s" % (bv.address_comments))
    print("bv.address_size, %s" % (bv.address_size))
    print("bv.allocated_ranges, %s" % (bv.allocated_ranges))
    print("bv.analysis_changed, %s" % (bv.analysis_changed))
    print("bv.analysis_info, %s" % (bv.analysis_changed))
    print("bv.analysis_progress, %s" % (bv.analysis_progress))
    print("bv.arch %s " % (bv.arch))
    print("bv.available_view_types %s" % (bv.available_view_types))
    print("bv.basic_blocks, type: Generator")
    for cc, gg in enumerate(bv.basic_blocks):
        print("\tbasic block:", gg)
        print ("\tbasic block instances:", [tt for tt in dir(gg) if "__" not in tt])
        if cc == 3:
            break
    print("bv.data_tags, %s" % (bv.data_tags))
    print("bv.data_vars, %s" % (bv.data_vars))
    print("bv.end, %s" % (bv.end))
    print("bv.endianness, %s" % (bv.endianness))
    print("bv.entry_function, %s" % (bv.entry_function))
    print("bv.entry_point, %s" % (bv.entry_point))
    print("bv.executable, %s" % (bv.executable))
    print("bv.functions, %s" % (bv.functions))
    for cc, gg in enumerate(bv.functions):
        print("\tfunctions:", gg)
        print ("\tfunctions instance:", [tt for tt in dir(gg) if "__" not in tt])
        if cc == 3:
            break
    print("bv.global_pointer_value, %s" % (bv.global_pointer_value))
    print("bv.has_data_variables, %s" % (bv.has_data_variables))
    print("bv.has_database, %s" % (bv.has_database))
    print("bv.has_functions, %s" % (bv.has_functions))
    print("bv.has_symbols, %s" % (bv.has_symbols))
    print("bv.hlil_basic_blocks, %s" % (bv.hlil_basic_blocks))
    print("v.hlil_basic_blocks, %s" % (bv.hlil_basic_blocks))
    print("bv.hlil_instructions, %s" % (bv.hlil_instructions))
    print("bv.instructions, %s" % (bv.instructions))
    print("bv.linear_disassembly, %s" % (bv.linear_disassembly))
    for cc, gg in enumerate(bv.linear_disassembly):
        print("\tlinear_disassembly:", gg)
        print ("\tlinear_disassembly instance:", [tt for tt in dir(gg) if "__" not in tt])
        if cc == 3:
            break
    print("bv.llil_basic_blocks, %s" % (bv.llil_basic_blocks))
    for cc, gg in enumerate(bv.llil_basic_blocks):
        print("\tllil_basic_blocks:", gg)
        print ("\tllil_basic_blocks instance:", [tt for tt in dir(gg) if "__" not in tt])
        if cc == 3:
            break
    print("bv.llil_instructions, %s" % (bv.llil_basic_blocks))
    for cc, gg in enumerate(bv.llil_basic_blocks):
        print("\tllil_basic_blocks:", gg)
        print ("\tllil_basic_blocks instance:", [tt for tt in dir(gg) if "__" not in tt])
        if cc == 3:
            break
    print("bv.long_name, %s" % (bv.long_name))
    print("bv.llil_instructions, %s" % (bv.llil_instructions))
    for cc, gg in enumerate(bv.llil_instructions):
        print("\tllil_instructions:", gg)
        print ("\tllil_instructions instance:", [tt for tt in dir(gg) if "__" not in tt])
        if cc == 3:
            break
    print("bv.long_name, %s" % (bv.long_name))
    print("bv.max_function_size_for_analysis, %s" % (bv.max_function_size_for_analysis))
    print("bv.mlil_basic_blocks, %s" % (bv.mlil_basic_blocks))
    for cc, gg in enumerate(bv.mlil_basic_blocks):
        print("\tmlil_basic_blocks:", gg)
        print ("\tmlil_basic_blocks instance:", [tt for tt in dir(gg) if "__" not in tt])
        if cc == 3:
            break
    print("bv.mlil_instructions, %s" % (bv.mlil_instructions))
    for cc, gg in enumerate(bv.llil_basic_blocks):
        print("\tmlil_instructions:", gg)
        print ("\tmlil_instructions instance:", [tt for tt in dir(gg) if "__" not in tt])
        if cc == 3:
            break
    print("bv.modified), %s" % (bv.modified))
    print("bv.name, %s" % (bv.name))
    print("bv.namespaces, %s" % (bv.namespaces))
    print("bv.new_auto_function_analysis_suppressed, %s" % (bv.new_auto_function_analysis_suppressed))
    print("bv.offset, %s" % (bv.offset))
    print("bv.parameters_for_analysis, %s" % (bv.parameters_for_analysis))
    print("bv.parent_view, %s" % (bv.parent_view))
    print("bv.platform, %s" % (bv.platform))
    print("bv.registered_view_type, %s" % (bv.registered_view_type))
    print("bv.relocatable, %s" % (bv.relocatable))
    print("bv.relocation_ranges, %s" % (bv.relocation_ranges))
    print("bv.saved, %s" % (bv.saved))
    print("bv.sections, %s" % (bv.sections))
    print("v.segments), %s" % (bv.segments))
    print("bv.session_data, %s" % (bv.session_data))
    print("bv.start, 0x%x" % (bv.start))
    print("bv.strings, %s" % (bv.strings))
    print("bv.symbols, %s" % (bv.symbols))
    print("bv.tag_types, %s" % (bv.tag_types))
    print("bv.type_libraries, %s" % (bv.type_libraries))
    print("bv.type_names, %s" % (bv.type_names))
    print("bv.types, %s" % (bv.types))
    print("bv.view_type, %s" % (bv.view_type))

Exploring LowLevelILInstruction

from binaryninja import LowLevelILInstruction

def explore_LowLevelILInstruction(bv, func=None):
    ll = set([])
    for func in bv.functions:
        for block in func.low_level_il.basic_blocks:
            for instr in block:
                if isinstance(instr, LowLevelILInstruction):
                    tt = instr.operation 
                    if tt not in ll:
                        ll.add(tt)
                        print(binaryninja.LowLevelILOperation(tt).name)
                        print("\t0x%x %s" % (instr.address, instr))
                        print("\t%s" % (bv.get_disassembly(instr.address)))
                for oper in instr.operands:
                    if isinstance(oper, LowLevelILInstruction):
                        tt = oper.operation 
                        if tt not in ll:
                            ll.add(tt)
                            print(binaryninja.LowLevelILOperation(tt).name)
                            print("\t0x%x %s" % (instr.address, instr))
                            print("\t%s" % (bv.get_disassembly(instr.address)))

explore_LowLevelILInstruction(bv)

Output

LLIL_UNDEF
	0x1400b1d6c undefined
	ret far 0xb18
LLIL_SET_REG
	0x140001000 rsp = rsp - 0x28
	sub     rsp, 0x28
LLIL_SUB
	0x140001000 rsp = rsp - 0x28
	sub     rsp, 0x28
LLIL_CONST_PTR
	0x140001004 r8d = 4
	mov     r8d, 0x4
LLIL_CALL
	0x140001018 call(0x140019390)
	call    0x140019390
LLIL_ADD
	0x140001024 rsp = rsp + 0x28
	add     rsp, 0x28
LLIL_TAILCALL
	0x140001028 <return> tailcall(0x1400ea35c)
	jmp     0x1400ea35c
LLIL_LOAD
	0x14000130b call([0x14017e000].q)
	call    qword [rel 0x14017e000]
LLIL_PUSH
	0x140001960 push(rbp)
	push    rbp
LLIL_REG
	0x140001960 push(rbp)
	push    rbp
LLIL_CONST
	0x140001971 r14d = 0
	xor     r14d, r14d
LLIL_STORE
	0x140001974 [rbp + 0x38 {arg_10}].q = r14
	mov     qword [rbp+0x38], r14
LLIL_LOW_PART
	0x140001978 ecx = (r14 + 0x18).d
	lea     ecx, [r14+0x18]
LLIL_IF
	0x1400019df if ([0x14024f1c0].d s<= ecx) then 32 @ 0x140001a9c else 39 @ 0x1400019e5
	jle     0x140001a9c
LLIL_CMP_SLE
	0x1400019df if ([0x14024f1c0].d s<= ecx) then 32 @ 0x140001a9c else 39 @ 0x1400019e5
	jle     0x140001a9c
LLIL_CMP_NE
	0x1400019f8 if ([0x14024f1c0].d != -1) then 32 @ 0x140001a9c else 67 @ 0x1400019fe
	jne     0x140001a9c
LLIL_CMP_E
	0x140001c24 if ([0x1402488c0].q == 0) then 72 @ 0x140001c48 else 77 @ 0x140001c26
	je      0x140001c48
LLIL_GOTO
	0x140001c60 goto 107 @ 0x140001c61
	nop
LLIL_ZX
	0x140001a5d xmm1 = zx.o([0x140189cc0].q)
	movsd   xmm1, qword [rel 0x140189cc0]
LLIL_CMP_SGE
	0x140001d0b if (eax s>= 0) then 185 @ 0x140001c91 else 187 @ 0x140001d0d
	jns     0x140001c91
LLIL_NORET
	0x140001d0d noreturn
	call    qword [rel 0x14017e750]
LLIL_POP
	0x140001cfe r14 = pop
	pop     r14
LLIL_RET
	0x14000367e <return> jump(pop)
	retn
LLIL_XOR
	0x1400038b8 rax = rax ^ rsp
	xor     rax, rsp
LLIL_CMP_SLT
	0x14000777e if (eax s< 0) then 15 @ 0x140007807 else 18 @ 0x140007784
	js      0x140007807
LLIL_SET_FLAG
	0x1400078b5 cond:0 = temp1.d s>= 0
	test    eax, eax
LLIL_FLAG
	0x140007904 if (cond:0) then 37 @ 0x1400078d4 else 64 @ 0x140007906
	jns     0x1400078ce
LLIL_CMP_UGE
	0x140007928 [0x14024c960].b = [0x14024c938].q u>= -1
	setae   byte [rel 0x14024c960]
LLIL_CMP_UGT
	0x14000793e [0x14024c961].b = [0x14024c938].q u> rax
	seta    byte [rel 0x14024c961]
LLIL_CMP_ULT
	0x1400079ba if ([0x14024c938].q u< rax) then 7 @ 0x140007a89 else 9 @ 0x1400079c0
	jb      0x140007a89
LLIL_SET_REG_SPLIT
	0x14000bf04 rdx:rax = mulu.dp.q(rax, rbx)
	mul     rbx
LLIL_MULU_DP
	0x14000bf04 rdx:rax = mulu.dp.q(rax, rbx)
	mul     rbx
LLIL_CMP_ULE
	0x14000c042 cond:0 = rax u<= rcx
	cmp     rax, rcx
LLIL_BP
	0x14000c33c breakpoint
	int3
LLIL_OR
	0x14000d8f6 eax = eax | 1
	or      eax, 0x1
LLIL_TEST_BIT
	0x14000edf7 flag:c = test_bit(r14d, 7)
	bts     r14d, 0x7
LLIL_AND
	0x14000ef63 r14d = r14d & 0xfffffffb
	and     r14d, 0xfffffffb
LLIL_NOT
	0x14000fdcb if (not(flag:z)) then 67 @ 0x14000fde5 else 72 @ 0x14000fdcd
	jne     0x14000fde5
LLIL_LSL
	0x140010fbb rcx = rcx << 4
	shl     rcx, 0x4
LLIL_LSR
	0x140011c0f rsi = rsi u>> 1
	shr     rsi, 0x1
LLIL_ASR
	0x14001237a rdx = rdx s>> 3
	sar     rdx, 0x3
LLIL_SX
	0x140012690 rcx = sx.q([rcx + 0x18].d)
	movsxd  rcx, dword [rcx+0x18]
LLIL_NEG
	0x140015799 r8d = neg.d(r8d)
	neg     r8d
LLIL_TRAP
	0x140017d15 trap(0xd)
	int     0x29
LLIL_MULS_DP
	0x14001b3b6 rdx:rax = muls.dp.q(rax, rcx)
	imul    rcx
LLIL_MUL
	0x14001b496 r14 = r9 * 0x78
	imul    r14, r9, 0x78
LLIL_CMP_SGT
	0x14001c754 if (r15d s> 0xb) then 372 @ 0x14001c791 else 373 @ 0x14001c756
	jg      0x14001c78d
LLIL_FLOAT_TO_INT
	0x14001df0b rax = int.q(ftrunc(fconvert.t([rbp + 0xd8 {var_90}].q)))
	cvttsd2si rax, qword [rbp+0xd8]
LLIL_DIVU_DP
	0x14001e858 temp0.d = divu.dp.d(temp3.d:temp4.d, temp2.d)
	div     r10d
LLIL_MODU_DP
	0x14001e858 temp1.d = modu.dp.d(temp5.d:temp6.d, temp2.d)
	div     r10d
LLIL_INT_TO_FLOAT
	0x1400239b4 xmm0.q = float.d(rax)
	cvtsi2sd xmm0, rax
LLIL_FADD
	0x1400239b9 xmm0.q = xmm0.q f+ xmm0.q
	addsd   xmm0, xmm0
LLIL_FMUL
	0x1400239cb xmm0.q = xmm0.q f* fconvert.t([0x1401a2d48].q)
	mulsd   xmm0, qword [rel 0x1401a2d48]
LLIL_FDIV
	0x1400239fb xmm0.q = xmm0.q f/ xmm1.q
	divsd   xmm0, xmm1
LLIL_SBB
	0x14002617d eax = sbb.d(eax, eax, flag:c)
	sbb     eax, eax
LLIL_INTRINSIC
	0x14002f8a6 xmm0 = _mm_cvtepi32_pd(xmm0.q)
	cvtdq2pd xmm0, xmm0
LLIL_CALL_PARAM
	0x14002f8a6 xmm0 = _mm_cvtepi32_pd(xmm0.q)
	cvtdq2pd xmm0, xmm0
LLIL_FCMP_UO
	0x14002f8aa flag:p = is_unordered.q(xmm7.q, xmm0.q)
	comisd  xmm7, xmm0
LLIL_ROL
	0x1400ea089 rcx = rol.q(rcx, 0x10)
	rol     rcx, 0x10
LLIL_ROR
	0x1400ea095 rcx = ror.q(rcx, 0x10)
	ror     rcx, 0x10
LLIL_JUMP
	0x140032306 jump(rcx)
	jmp     rcx
LLIL_FSUB
	0x1400356af xmm1.q = xmm1.q f- xmm0.q
	subsd   xmm1, xmm0
LLIL_DIVS_DP
	0x140037cd1 temp0.q = divs.dp.q(rdx:rax, rbx)
	idiv    rbx
LLIL_MODS_DP
	0x140037cd1 temp1.q = mods.dp.q(rdx:rax, rbx)
	idiv    rbx
LLIL_JUMP_TO
	0x14003b4e5 jump(rcx => 167 @ 0x14003b4e7, 170 @ 0x14003b4f1, 174 @ 0x14003b4ff, 178 @ 0x14003b50d, 182 @ 0x14003b51b, 186 @ 0x14003b529)
	jmp     rcx
Function 0x14006e370 at 0x14006e5fb has HLIL condition that exceeds maximum complexity, omitting condition (step 90)
LLIL_UNDEF
	0x1400b1d6c undefined
	ret far 0xb18
LLIL_ROL
	0x1400ea089 rcx = rol.q(rcx, 0x10)
	rol     rcx, 0x10
LLIL_ROR
	0x1400ea095 rcx = ror.q(rcx, 0x10)
	ror     rcx, 0x10

Exploring LowLevelILInstruction (Single Function)

func = bv.get_functions_containing(here)[0]  
for block in func.low_level_il.basic_blocks:
    for instr in block:
        if isinstance(instr, LowLevelILInstruction):
            tt = instr.operation 
            print("Instruction")
            print(binaryninja.LowLevelILOperation(tt).name)
            print("\t0x%x %s" % (instr.address, instr))
            print("\t%s" % (bv.get_disassembly(instr.address)))
        
        for oper in instr.operands:
            if isinstance(oper, LowLevelILInstruction):
                tt = oper.operation 
                print("Operand:")
                print(binaryninja.LowLevelILOperation(tt).name)
                print("\t0x%x %s" % (instr.address, instr))
                print("\t%s" % (bv.get_disassembly(instr.address)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment