Skip to content

Instantly share code, notes, and snippets.

@galenbwill
Forked from psifertex/1_Snippet_Instructions.txt
Last active September 28, 2022 18:17
Show Gist options
  • Select an option

  • Save galenbwill/553626eb0db8e45d1b5b55edd03a2dd7 to your computer and use it in GitHub Desktop.

Select an option

Save galenbwill/553626eb0db8e45d1b5b55edd03a2dd7 to your computer and use it in GitHub Desktop.

Revisions

  1. galenbwill revised this gist Sep 28, 2022. 1 changed file with 111 additions and 0 deletions.
    111 changes: 111 additions & 0 deletions call_targets.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,111 @@
    import time


    # 1. IL dests
    def find_calls_by_mlil():
    start = time.time()
    calls = {}
    for f in bv.functions:
    for c in f.call_sites:
    call_mlil = c.mlil
    if call_mlil is None:
    print(f'DBG: No MLIL @ {hex(c.address)}')
    continue
    try:
    call_dest_addr = call_mlil.dest.value.value
    except:
    print(f'Exception @ {hex(c.address)} : {c.mlil}')
    continue
    if call_dest_addr is None:
    #print(f'DBG: No IL value @ {hex(c.address)} : {c.mlil}')
    continue
    funcs = bv.get_function_at(call_dest_addr)
    if not funcs:
    #print(f'DBG: No funcs @ dest {hex(call_dest_addr)}: {hex(c.address)} : {c.mlil}')
    continue
    call_dest = funcs[0]
    calls[c.address] = (f, call_dest)
    duration = time.time() - start
    print(f'[*] 1. MLIL dest: Found {len(calls)} in {duration:.02f} seconds')
    return calls

    def find_calls_by_llil():
    start = time.time()
    calls = {}
    for f in bv.functions:
    for c in f.call_sites:
    call_llil = c.llil
    if call_llil is None:
    #print(f'DBG: No llil @ {hex(c.address)}')
    continue
    try:
    call_dest_addr = call_llil.dest.value.value
    except:
    #print(f'Exception @ {hex(c.address)} : {c.llil}')
    continue
    if call_dest_addr is None:
    #print(f'DBG: No IL value @ {hex(c.address)} : {c.mlil}')
    continue
    funcs = bv.get_function_at(call_dest_addr)
    if not funcs:
    #print(f'DBG: No funcs @ dest {hex(call_dest_addr)}: {hex(c.address)} : {c.mlil}')
    continue
    call_dest = funcs[0]
    calls[c.address] = (f, call_dest)
    duration = time.time() - start
    print(f'[*] 1.5. LLIL dest: Found {len(calls)} in {duration:.02f} seconds')
    return calls

    # 2. code refs
    def find_calls_by_xref():
    start = time.time()
    calls = {}
    for f in bv.functions:
    for c in f.call_sites:
    xrefs = bv.get_code_refs_from(c.address)
    if not xrefs:
    #print(f'DBG: No xrefs @ {hex(c.address)} : {c.mlil}')
    continue
    call_dest_addr = xrefs[0]
    funcs = bv.get_function_at(call_dest_addr)
    if not funcs:
    #print(f'DBG: No funcs @ dest {hex(call_dest_addr)}: {hex(c.address)} : {c.mlil}')
    continue
    call_dest = funcs[0]
    calls[c.address] = (f, call_dest)
    duration = time.time() - start
    print(f'[*] 2. code refs: Found {len(calls)} in {duration:.02f} seconds')
    return calls

    # 3. Intersection of call_sites and caller_sites
    def find_calls_by_caller_sites():
    start = time.time()
    calls = {}
    for f in bv.functions:
    call_destinations = {}
    for callee in f.callees:
    calls_to_callee = {c.address: callee for c in callee.caller_sites if c.function == f}
    call_destinations.update(calls_to_callee)
    for c in f.call_sites:
    call_dest = call_destinations.get(c.address)
    if not call_dest:
    #print(f'DBG: {hex(c.address)} not in caller_sites')
    continue
    calls[c.address] = (f, call_dest)
    duration = time.time() - start
    print(f'[*] 3. Intersection: Found {len(calls)} in {duration:.02f} seconds')
    return calls


    mlil_calls = find_calls_by_mlil()
    llil_calls = find_calls_by_llil()
    xref_calls = find_calls_by_xref()
    caller_calls = find_calls_by_caller_sites()

    for k, v in caller_calls.items():
    if k not in llil_calls:
    print(f'{hex(k)} -> {v} not in llil_calls')

    for k, v in llil_calls.items():
    if k not in xref_calls:
    print(f'{hex(k)} -> {v} not in xref_calls')
  2. galenbwill revised this gist Sep 22, 2022. No changes.
  3. galenbwill revised this gist Sep 22, 2022. 1 changed file with 67 additions and 0 deletions.
    67 changes: 67 additions & 0 deletions dump_il.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    # dump IL
    #
    # Dump the current function's IL in a verbose and structured text representation. Kinda what I want repr to do for
    # HLIL AST's, but also works on other ILs. Also supports SSA forms. Edit the last couple lines to control which ILs
    # get dumped. Needs some improvement.

    def dump_hlil(hlil, indent=0, op_num=None, name=None, kind='hlil', ssa=False, offset=0):
    if kind.endswith('_ssa'):
    ssa = True
    kind = kind[:-4]
    llil = hlil
    if hasattr(llil, 'mlil'):
    llil = llil.mlil
    if hasattr(llil, 'llil'):
    llil = llil.llil
    if hasattr(llil, 'address'):
    offset = llil.address
    def _print(msg):
    idx = f'[{op_num}] ' if op_num is not None else ''
    n = f'{name}: ' if name is not None else ''
    _ = print(f'{kind}:0x{offset:08x}:{" "*indent}{idx}{n}{msg}')
    if type(hlil) in [list, HighLevelILFunction, LowLevelILFunction, MediumLevelILFunction]:
    if hasattr(hlil, 'instructions'):
    if ssa:
    hlil = hlil.ssa_form
    hlil = hlil.instructions
    for i, h in enumerate(hlil):
    dump_hlil(h, indent, op_num=i, kind=kind, ssa=ssa, offset=offset)
    return
    if hasattr(hlil, kind):
    dump_hlil(getattr(hlil, kind), indent=indent, kind=kind, ssa=ssa, offset=offset)
    return
    if hasattr(hlil, 'operation'):
    try:
    rendered = str(hlil)
    if hlil.operation.name.endswith('_PTR'):
    value = hlil.constant
    symbols = bv.get_symbols(value)
    if symbols:
    rendered = f'{symbols[0].name} @ 0x{value:08x}'
    _ = _print(f'<{type(hlil).__name__.split(".")[-1]}:{hlil.operation.name}> {rendered!r}')
    except Exception as e:
    _ = _print(e)
    else:
    _ = _print(f'<{type(hlil).__name__.split(".")[-1]}> {hlil}')
    if hasattr(hlil, 'operands'):
    if hasattr(hlil, 'operation'):
    instruction_type = {
    'hlil': HighLevelILInstruction,
    'mlil': MediumLevelILInstruction,
    'llil': LowLevelILInstruction,
    }[kind]
    op_names = instruction_type.ILOperations[hlil.operation]
    else:
    op_names = []
    for i, op in enumerate(hlil.operands):
    if True or op is not None:
    n = None
    if len(op_names) > i:
    n = op_names[i][0]
    dump_hlil(op, indent+4, i, n, kind, ssa=ssa, offset=offset)

    #dump_hlil(current_function, kind='llil')
    print(' ')
    dump_hlil(current_function, kind='mlil_ssa')
    print(' ')
    dump_hlil(current_function, kind='hlil_ssa')
  4. galenbwill revised this gist Sep 22, 2022. 1 changed file with 158 additions and 0 deletions.
    158 changes: 158 additions & 0 deletions paste_types.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,158 @@

    #
    # Paste this def into the console, then run it, and then paste the output into the_types down below:
    #
    def dump_types(clip=True, void=True, verbose=False):
    def make_call_type(name, type):
    return f'{type.return_value} {name}({",".join(map(str,type.parameters))})'
    _print = print
    if not verbose:
    _print = lambda *a, **kw: None
    fun_dump = []
    for f in bv.functions:
    adjustments = []
    # for ref in f.caller_sites:
    for ref in sorted(f.call_sites,key=lambda ref:ref.address):
    # _print(f'{f = } {ref = }')
    adjustment = ref.function.get_call_type_adjustment(ref.address)

    if adjustment is not None:
    #adjustments.append((str(ref.hlil.dest), ref.function.name, str(adjustment)))
    dest = str(ref.hlil.dest)
    adjustments.append((dest, ref.function.name, make_call_type(dest, adjustment)))
    # _print(f'{adjustments = !r}')
    tag = f'{bv.arch.name}:{f.start:08X}'
    fun_dump.append(f'{tag!r}:(0x{f.start:08X},{bv.arch.name!r},"fun",({bv.get_sections_at(f.start)[0].name!r},{f.name!r},{str(f)!r},{str(f.clobbered_regs.regs)},{str(f.return_regs.regs)},{adjustments})),')
    _ = _print(fun_dump[-1])
    _ = _print()

    for v in bv.data_vars:
    f = bv.get_data_var_at(v)
    if f.type.type_class == TypeClass.FunctionTypeClass:
    sections = bv.get_sections_at(f.address)
    if not sections:
    sec_name = ''
    else:
    sec_name = sections[0].name
    #t = f'{f.type.return_value} {f.name}({",".join(map(str,f.type.parameters))})'
    t = make_call_type(f.name, f.type)
    tag = f'{bv.arch.name}:{f.address:08X}'
    fun_dump.append(f'{tag!r}:(0x{f.address:08X},{bv.arch.name!r},"var",({sec_name!r},{f.name!r},{t!r})),')
    _ = _print(fun_dump[-1])
    _ = _print()
    if clip:
    clipboard.text = '\n\t' + '\n\t'.join(fun_dump)
    if not void:
    return fun_dump

    the_types = {

    }

    bv.begin_undo_actions()

    for item in the_types.items():
    tag, (address, arch_name, fun_var, rest) = item

    print(f'0x{address:08x}:{item[1]}')

    if arch_name != bv.arch.name:
    continue
    sec_name, name, type_str = rest[:3]
    the_type = bv.parse_type_string(type_str)
    if not the_type:
    log_warn(f'failed to parse function type for {name} found 0x{address:08x}: {type_str!r}')
    continue

    is_fun = fun_var == "fun"

    if not is_fun:
    v = None
    v = bv.get_data_var_at(address)
    if v and sec_name:
    s = bv.get_sections_at(v.address)
    if s and s[0].name != sec_name:
    v = None
    if not v:
    for symbol in bv.get_symbols_by_name(name):
    s = bv.get_sections_at(symbol.address)
    log_warn(f'0x{symbol.address:08x} {symbol.name} {symbol.type.name} {s}')
    if s and s[0].name != sec_name:
    continue
    if symbol.type in [SymbolType.FunctionSymbol, SymbolType.ExternalSymbol, SymbolType.ImportedFunctionSymbol, SymbolType.DataSymbol]:
    v = bv.get_data_var_at(symbol.address)
    if v:
    log_warn(f'0x{v.address:08X}:({bv.arch.name!r},"var",{v.name!r},{str(v.type)!r},[],[]),')
    break
    if v is not None:
    print(f'0x{v.address:08X}:({bv.arch.name!r},"var",{v.name!r},{str(v.type)!r},[],[]),')
    v.name = name
    v.type = the_type[0]
    v = bv.get_data_var_at(v.address)
    print(f'0x{v.address:08X}:({bv.arch.name!r},"var",{v.name!r},{str(v.type)!r},[],[]),')
    else:
    log_warn(f'no appropriate var {name} found at 0x{address:08x} or in section {sec_name}')
    continue

    clobbered_regs, return_regs, adjustments = rest[3:]

    f = bv.get_function_at(address)
    if not f or f.name != name:
    fs = bv.get_functions_by_name(name)
    if fs:
    f = fs[0]

    if not f:
    log_warn(f'no function {name} found at 0x{address:08x}')
    continue

    if the_type:
    f.set_user_type(the_type[0])
    else:
    log_warn(f'failed to parse function type for {name} found 0x{address:08x}: {type_str!r}')
    continue
    if clobbered_regs:
    f.clobbered_regs = RegisterSet(clobbered_regs, 255)
    if return_regs:
    f.return_regs = RegisterSet(return_regs, 255)

    if f.name != name:
    f.name = name

    bv.update_analysis_and_wait()

    if adjustments:
    call_sites = sorted(f.call_sites,key=lambda ref:ref.address)
    for target, source, adjustment in adjustments:
    while call_sites:
    call_site = call_sites.pop(0)
    hlil = call_site.hlil
    if hlil.operation != HighLevelILOperation.HLIL_CALL:
    log_warn(f'0x{call_site.address:08x}: call site {hlil} is not HLIL_CALL')
    for op in hlil.operands:
    if hasattr(op, 'operation') and op.operation == HighLevelILOperation.HLIL_CALL:
    hlil = op
    break
    else:
    log_warn(f'0x{call_site.address:08x}: operand {op} is not HLIL_CALL')
    if hlil.operation != HighLevelILOperation.HLIL_CALL:
    log_warn(f'0x{call_site.address:08x}: call {hlil} is not a call')
    dest = str(hlil.dest)
    print(f'0x{call_site.address:08x}: call {dest!r} init: {(target,source,adjustment)}')
    if dest == target:
    f.set_call_type_adjustment(call_site.address, adjustment)
    #adjustment_type = bv.parse_type_string(adjustment)
    #if adjustment_type:
    # f.set_call_type_adjustment(call_site.address, adjustment)
    adjustment = f.get_call_type_adjustment(call_site.address)
    print(f'0x{call_site.address:08x}: call {str(call_site.hlil.dest)!r} set: {adjustment}')
    break
    for call_site in sorted(f.call_sites,key=lambda ref:ref.address):
    adjustment = f.get_call_type_adjustment(call_site.address)
    print(f'0x{call_site.address:08x}: call {str(call_site.hlil.dest)!r} final: {adjustment}')

    f = bv.get_function_at(f.start)

    print(f'0x{f.start:08X}:({f.name!r},{str(f)!r},{str(f.clobbered_regs.regs)},{str(f.return_regs.regs)}),')

    bv.commit_undo_actions()
  5. @psifertex psifertex revised this gist Sep 20, 2022. 1 changed file with 18 additions and 0 deletions.
    18 changes: 18 additions & 0 deletions highlight_dangerous_calls.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    # highlight dangerous calls
    #
    # Highlight with theme-aware colors any "dangerous" functions:

    # Note that prefixed versions like "_system" will not be highlighted using this sample code.

    dangerous = ["strcpy", "gets"]
    sus = ["printf", "system", "exec"]

    for fnname in dangerous + sus:
    if fnname in dangerous:
    color = HighlightStandardColor.RedHighlightColor
    if fname in sus:
    color = HighlightStandardColor.OrangeHighlightColor
    for sym in bv.get_symbols_by_name(fnname):
    for ref in bv.get_code_refs(sym.address):
    ref.function.set_user_instr_highlight(ref.address, color)

  6. @psifertex psifertex revised this gist Jul 20, 2022. 1 changed file with 0 additions and 32 deletions.
    32 changes: 0 additions & 32 deletions unimplemented.py
    Original file line number Diff line number Diff line change
    @@ -1,32 +0,0 @@
    # checks all LLIL operations to find any unlimiplemented lifting
    #
    # Especially useful when building a new architecture and wanting to see what disassembly you're running into with real binaries to prioritize

    from binaryninja.lowlevelil import LowLevelILInstruction

    def visit(unimp, expr):
    for field in LowLevelILInstruction.ILOperations[expr.operation]:
    if field[1] == "expr":
    visit(unimp, getattr(expr, field[0]))
    if expr.operation in [LowLevelILOperation.LLIL_UNIMPL, LowLevelILOperation.LLIL_UNIMPL_MEM]:
    if hasattr(expr, "expr_index"):
    index = expr.expr_index
    else:
    index = 0
    dis = bv.get_disassembly(expr.address)
    mnemonic = dis.split(" ")[0]
    if mnemonic in unimp.keys():
    unimp[mnemonic].append([expr.address, index])
    else:
    unimp[mnemonic] = [[expr.address, index]]

    unimp = {}

    for llili in bv.llil_instructions:
    visit(unimp, llili)

    log_info(f"Found {len(unimp)} total unimplemented mnemonics")
    for k, v in sorted(unimp.items(), key=len):
    log_info(f"Unimplemented mnemonic: {k}:")
    for x in v:
    log_info(f" {hex(x[0])} / {x[1]}")
  7. @psifertex psifertex revised this gist Jul 20, 2022. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions unimplemented_instructions.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    # unimplemented instructions
    #
    # Create a report showing unimplemented instructions

    from collections import defaultdict
    insts = defaultdict(lambda:0)
    addrs = {}
    for ins in bv.llil_instructions:
    if ins.operation == LowLevelILOperation.LLIL_UNIMPL:
    mnem = bv.get_disassembly(ins.address, ins.il_basic_block.arch).split()[0]
    insts[mnem + '-' + ins.il_basic_block.arch.name] = insts[mnem + '-' + ins.il_basic_block.arch.name] + 1
    addrs[mnem + '-' + ins.il_basic_block.arch.name] = ins.address

    lines = list(insts.items())
    lines = sorted(lines, key=lambda x: x[1], reverse=True)
    contents = "| Memonic-Arch | Count | Example Address |\n|---|---|---|\n"
    for mnem, count in lines:
    contents += f"|{mnem}|{count}|[{hex(addrs[mnem])}](binaryninja://?expr={hex(addrs[mnem])})|\n"

    bv.show_markdown_report("Unimplemented counts", contents, contents)
  8. @psifertex psifertex revised this gist Jul 2, 2022. 1 changed file with 12 additions and 0 deletions.
    12 changes: 12 additions & 0 deletions show_modifications.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    # show file modifications
    #
    # Use the get_modification API to show all places where bytes were modified in the file

    for offset in range(bv.start, len(bv) + bv.start):
    mod = bv.get_modification(offset,1)[0]
    if mod != ModificationStatus.Original:
    b = "0x" + bv.read(offset, 1).hex()
    if mod == ModificationStatus.Inserted:
    print(f"Looks like {b} was inserted at {hex(offset)}")
    else:
    print(f"Looks like {b} was written at {hex(offset)}")
  9. @psifertex psifertex revised this gist May 28, 2022. 1 changed file with 16 additions and 10 deletions.
    26 changes: 16 additions & 10 deletions save_search.py
    Original file line number Diff line number Diff line change
    @@ -2,15 +2,21 @@
    #
    # Save search results to a specified file

    # Currently hard-coded to HLIL, TODO: use an interaction API to let the user select from a drop-down.
    # Can just copy from export_to_text snippet
    search = interaction.get_text_line_input('Search test', 'Search text')
    output = interaction.get_save_filename_input("Output filename: ", "txt", "results.txt")

    if search and output:
    with open(output, 'wb') as f:
    for result in bv.find_all_text(bv.start, bv.end, search.decode('utf8'), graph_type=FunctionGraphType.HighLevelILFunctionGraph):
    addr = bytes(hex(result[0]) + "\t", 'utf8')
    targets = [FunctionGraphType.NormalFunctionGraph, FunctionGraphType.LowLevelILFunctionGraph, FunctionGraphType.MediumLevelILFunctionGraph, FunctionGraphType.HighLevelILFunctionGraph, FunctionGraphType.HighLevelLanguageRepresentationFunctionGraph]
    search_text = TextLineField("Search text")
    search_target = ChoiceField("Search target?", ["Assembly", "LLIL", "MLIL", "HLIL", "Pseudo C"])
    search_addresses = ChoiceField("Include addresses in output?", ["No", "Yes"])
    output_file = SaveFileNameField("Output filename: ", default_name=bv.file.filename + ".txt")
    choices = get_form_input(["Saved Search Plugin", search_text, search_target, output_file, search_addresses], "Saved Search")
    if choices and search_text.result and search_target.result and output_file.result:
    with open(output_file.result, 'wb') as f:
    target = targets[search_target.result]
    for result in bv.find_all_text(bv.start, bv.end, search_text.result, graph_type=target):
    if search_addresses.result and search_addresses.result == 1:
    addr = bytes(hex(result[0]) + "\t", 'utf8')
    else:
    addr = b""
    f.write(addr + bytes(str(result[2]), 'utf8') + b"\n")
    log_info(f"Search results saved to {output_file.result}")
    else:
    log_warn("Either search or filename not given.")
    log_warn("Search not saved, dialog cancelled or missing selection.")
  10. @psifertex psifertex revised this gist May 27, 2022. 1 changed file with 16 additions and 0 deletions.
    16 changes: 16 additions & 0 deletions save_search.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    # save search
    #
    # Save search results to a specified file

    # Currently hard-coded to HLIL, TODO: use an interaction API to let the user select from a drop-down.
    # Can just copy from export_to_text snippet
    search = interaction.get_text_line_input('Search test', 'Search text')
    output = interaction.get_save_filename_input("Output filename: ", "txt", "results.txt")

    if search and output:
    with open(output, 'wb') as f:
    for result in bv.find_all_text(bv.start, bv.end, search.decode('utf8'), graph_type=FunctionGraphType.HighLevelILFunctionGraph):
    addr = bytes(hex(result[0]) + "\t", 'utf8')
    f.write(addr + bytes(str(result[2]), 'utf8') + b"\n")
    else:
    log_warn("Either search or filename not given.")
  11. @psifertex psifertex revised this gist Apr 8, 2022. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion interesting_units.py
    Original file line number Diff line number Diff line change
    @@ -3,5 +3,6 @@
    # Log interesting components like the function and basic blocks with most incoming or outgoing edges

    log_info("Most connected function: " + repr(max(bv.functions, key=lambda x: len(x.callees) + len(x.callers))))
    log_info("Most connected bblock: " + repr(max(bv.basic_blocks, key=lambda x: len(x.incoming_edges) + len(x.outgoing_edges))))
    log_info("Most incoming callers: " + repr(max(bv.functions, key=lambda x: len(x.callers))))
    log_info("Most connected bblock: " + repr(max(bv.basic_blocks, key=lambda x: len(x.incoming_edges) + len(x.outgoing_edges))))
    log_info("Highest xrefs: " + repr(max(bv.functions, key=lambda x: len(x.callers))))
  12. @psifertex psifertex revised this gist Mar 17, 2022. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions append_file.py
    Original file line number Diff line number Diff line change
    @@ -2,8 +2,6 @@
    #
    # Will append a file's raw contents to the existing view (useful for working with firmware or memory dumps). Thanks to @mariomain for the snippet.


    # by default the convention is that files are named with their respctive address.
    def load_file(infilename):
    f = open(infilename, "rb")
    g = f.read()
  13. @psifertex psifertex revised this gist Mar 17, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion append_file.py
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # append file contents to view
    #
    # Will append a file's raw contents to the existing view (useful for working with firmware or memory dumps)
    # Will append a file's raw contents to the existing view (useful for working with firmware or memory dumps). Thanks to @mariomain for the snippet.


    # by default the convention is that files are named with their respctive address.
  14. @psifertex psifertex revised this gist Mar 17, 2022. 1 changed file with 68 additions and 0 deletions.
    68 changes: 68 additions & 0 deletions append_file.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,68 @@
    # append file contents to view
    #
    # Will append a file's raw contents to the existing view (useful for working with firmware or memory dumps)


    # by default the convention is that files are named with their respctive address.
    def load_file(infilename):
    f = open(infilename, "rb")
    g = f.read()
    f.close()
    faddr = None
    while (faddr is not None):
    faddr = interaction.get_int_input("Load address", "Load address")
    fsize = len(g)
    return g, faddr, fsize

    def overlap(reg1, reg1sz, reg2, reg2sz):
    if ((reg1 >= reg2) and (reg1 < (reg2 + reg2sz))):
    return True
    if (((reg1 + reg1sz) > reg2) and ((reg1 + reg1sz) < (reg2 + reg2sz))):
    return True
    if ((reg1 < reg2) and ((reg1 + reg1sz) >= (reg2 + reg2sz))):
    return True
    return False

    def add_some_file_sec(file_name):
    rv = bv.get_view_of_type("Raw")
    fblob, faddr, fsize = load_file(file_name)
    prev_sec = bv.get_segment_at(bv.start)
    succ_sec = None
    new_succ_blob = None
    new_succ_blob_addr = 0
    if (overlap(faddr, fsize, prev_sec.start, len(prev_sec)) == False) and (faddr < prev_sec.start):
    succ_sec = prev_sec
    else:
    for i in bv.sections:
    i = bv.get_section_by_name(i)
    if overlap(faddr, fsize, i.start, len(i)) == True:
    log_info("overlapping with region {}".format(hex(i.start)))
    return False
    if prev_sec.start != i.start:
    if (faddr >= (prev_sec.start + len(prev_sec))) and (faddr < i.start):
    succ_sec = i
    break
    prev_sec = i
    if succ_sec != None:
    follow_seg = bv.get_segment_at(succ_sec.start)
    the_rest = rv.read(follow_seg.data_offset, rv.length - follow_seg.data_offset)
    new_succ_blob = fblob + the_rest
    new_succ_blob_addr = follow_seg.data_offset
    else:
    new_succ_blob = fblob
    new_succ_blob_addr = rv.length
    rv.write(new_succ_blob_addr, new_succ_blob)
    if succ_sec != None:
    for i in bv.segments:
    if i.start > faddr:
    temp_start = i.start
    temp_off = i.data_offset
    temp_len = i.data_length
    bv.remove_auto_segment(i.start, len(i))
    temp_off += fsize
    bv.add_auto_segment(start=temp_start, length=temp_len, data_offset=temp_off, data_length=temp_len,
    flags=(SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable))
    bv.add_auto_section(os.path.basename(file_name), start=faddr, length=fsize,
    semantics=SectionSemantics.ReadOnlyCodeSectionSemantics)
    bv.add_auto_segment(start=faddr, length=fsize, data_offset=new_succ_blob_addr, data_length=fsize,
    flags=(SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable))
  15. @psifertex psifertex revised this gist Mar 16, 2022. 1 changed file with 0 additions and 59 deletions.
    59 changes: 0 additions & 59 deletions make_code.py
    Original file line number Diff line number Diff line change
    @@ -1,59 +0,0 @@
    # make code from raw bytes
    #
    # Only a snippeettt for now due to some inconsistencies around removing the symbol versus the renderer and some performance reasons

    from binaryninja import *
    from PySide6.QtGui import QKeySequence
    from binaryninjaui import UIActionHandler, UIAction, UIActionContext

    class CodeDataRenderer(DataRenderer):
    def __init__(self):
    DataRenderer.__init__(self)

    def perform_is_valid_for_data(self, _, bv: BinaryView, addr: int, type: Type, context: List[str]) -> bool:
    sym = bv.get_symbol_at(addr)
    return sym is not None and sym.name.startswith("CODE_") and type.type_class == TypeClass.ArrayTypeClass

    def perform_get_lines_for_data(self, _, bv: BinaryView, addr: int, type: Type, prefix: List[InstructionTextToken], width: int, context: List[str]) -> List[DisassemblyTextLine]:
    end = addr + len(type)
    result: List[DisassemblyTextLine] = []
    for tokens, size in bv.disassembly_tokens(addr, bv.arch):
    if addr + size > end:
    break
    result.append(DisassemblyTextLine([*tokens], addr, color=HighlightStandardColor.RedHighlightColor))
    addr += size
    return result

    def __del__(self):
    pass

    def make_code(bv: BinaryView, start: int, end: int) -> None:
    bv.begin_undo_actions()
    if bv.get_basic_blocks_at(start):
    return
    if end - start <= 1:
    # find the next basic block, data variable, or segment/section end
    data_var = bv.get_next_data_var_after(start)
    if data_var is not None:
    end = data_var.address
    else:
    end = bv.end
    end = min(bv.get_next_basic_block_start_after(start), end)
    seg = bv.get_segment_at(start)
    if seg is not None:
    end = min(seg.end, end)
    section_ends = [s.end for s in bv.get_sections_at(start)]
    end = min(*section_ends, end)
    bv.define_data_var(start, Type.array(Type.int(1, False), end-start), f"CODE_{start:08x}")
    bv.commit_undo_actions()

    def make_code_helper(ctx: UIActionContext):
    log_info(f"Making code region {ctx.address:08x}, {ctx.address + ctx.length:08x}")
    make_code(ctx.binaryView, ctx.address, ctx.address + ctx.length)

    def register():
    CodeDataRenderer().register_type_specific()
    UIAction.registerAction("Make Code", QKeySequence("C"))
    UIActionHandler.globalActions().bindAction("Make Code", UIAction(make_code_helper))

    register()
  16. @psifertex psifertex revised this gist Mar 16, 2022. 1 changed file with 59 additions and 0 deletions.
    59 changes: 59 additions & 0 deletions make_code.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@
    # make code from raw bytes
    #
    # Only a snippeettt for now due to some inconsistencies around removing the symbol versus the renderer and some performance reasons

    from binaryninja import *
    from PySide6.QtGui import QKeySequence
    from binaryninjaui import UIActionHandler, UIAction, UIActionContext

    class CodeDataRenderer(DataRenderer):
    def __init__(self):
    DataRenderer.__init__(self)

    def perform_is_valid_for_data(self, _, bv: BinaryView, addr: int, type: Type, context: List[str]) -> bool:
    sym = bv.get_symbol_at(addr)
    return sym is not None and sym.name.startswith("CODE_") and type.type_class == TypeClass.ArrayTypeClass

    def perform_get_lines_for_data(self, _, bv: BinaryView, addr: int, type: Type, prefix: List[InstructionTextToken], width: int, context: List[str]) -> List[DisassemblyTextLine]:
    end = addr + len(type)
    result: List[DisassemblyTextLine] = []
    for tokens, size in bv.disassembly_tokens(addr, bv.arch):
    if addr + size > end:
    break
    result.append(DisassemblyTextLine([*tokens], addr, color=HighlightStandardColor.RedHighlightColor))
    addr += size
    return result

    def __del__(self):
    pass

    def make_code(bv: BinaryView, start: int, end: int) -> None:
    bv.begin_undo_actions()
    if bv.get_basic_blocks_at(start):
    return
    if end - start <= 1:
    # find the next basic block, data variable, or segment/section end
    data_var = bv.get_next_data_var_after(start)
    if data_var is not None:
    end = data_var.address
    else:
    end = bv.end
    end = min(bv.get_next_basic_block_start_after(start), end)
    seg = bv.get_segment_at(start)
    if seg is not None:
    end = min(seg.end, end)
    section_ends = [s.end for s in bv.get_sections_at(start)]
    end = min(*section_ends, end)
    bv.define_data_var(start, Type.array(Type.int(1, False), end-start), f"CODE_{start:08x}")
    bv.commit_undo_actions()

    def make_code_helper(ctx: UIActionContext):
    log_info(f"Making code region {ctx.address:08x}, {ctx.address + ctx.length:08x}")
    make_code(ctx.binaryView, ctx.address, ctx.address + ctx.length)

    def register():
    CodeDataRenderer().register_type_specific()
    UIAction.registerAction("Make Code", QKeySequence("C"))
    UIActionHandler.globalActions().bindAction("Make Code", UIAction(make_code_helper))

    register()
  17. @psifertex psifertex revised this gist Mar 16, 2022. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion ptr_dl.py
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,7 @@
    import os

    USER="myusername"
    PASS="mypassword" #change to an interactive popup for more security but be aware os.system may leave history
    DOMAIN="mydomain"

    globalArea=uicontext.context.globalArea()
    @@ -20,7 +21,7 @@
    unc = lineSplit[0]
    pdbPath = lineSplit[1]
    unc = unc.replace("\\","\/")
    os.system(f"smbget -U {USER} -w {DOMAIN} -o {pdbPath} {unc}")
    os.system(f"smbget -U {USER}%{PASS} -w {DOMAIN} -o {pdbPath} {unc}")
    else:
    log_warn("Invalid PTR log message.")
    else:
  18. @psifertex psifertex revised this gist Mar 16, 2022. 1 changed file with 29 additions and 0 deletions.
    29 changes: 29 additions & 0 deletions ptr_dl.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,29 @@
    # PDB PTR Downloader
    #
    # Can be adapted to work together with the built in PDB support to fetch UNC paths from debug server file.ptr files. Also a good example of how to access GlobalArea widgets.
    import binaryninjaui
    import os

    USER="myusername"
    DOMAIN="mydomain"

    globalArea=uicontext.context.globalArea()
    logWidget=globalArea.widget("Log")
    for child in logWidget.children():
    if isinstance(child, binaryninjaui.LogListModel):
    if child.hasSelectedItems():
    items = child.getSelectedItems()
    if items:
    lastLine = items[0].text
    lineSplit = lastLine.split(" -> ")
    if len(lineSplit) == 2:
    unc = lineSplit[0]
    pdbPath = lineSplit[1]
    unc = unc.replace("\\","\/")
    os.system(f"smbget -U {USER} -w {DOMAIN} -o {pdbPath} {unc}")
    else:
    log_warn("Invalid PTR log message.")
    else:
    log_info("No selected PTR log message.")
    else:
    log_info("No selected PTR log message.")
  19. @psifertex psifertex revised this gist Mar 14, 2022. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions update_snippets.py
    Original file line number Diff line number Diff line change
    @@ -9,8 +9,8 @@
    #TODO: Merge remote with local description or hotkey changes (AKA: if filename matches, skip the first two lines, truncate, re-write the rest)

    domain = b'https://gist.github.com'
    path = b'/psifertex/6fbc7532f536775194edd26290892ef7' # Feel free to adapt to your own setup
    subfolder = 'default' # Change to save the snippets to a different sub-folder
    path = b'/psifertex/6fbc7532f536775194edd26290892ef7' # Feel free to adapt to your own setup
    subfolder = 'default' # Change to save the snippets to a different sub-folder
    tab2space = False
    width = 4

  20. @psifertex psifertex revised this gist Mar 14, 2022. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions update_snippets.py
    Original file line number Diff line number Diff line change
    @@ -15,6 +15,7 @@
    width = 4

    def download(url):
    # Can also use 'CoreDownloadProvider' or 'PythonDownloadProvider' as keys here
    provider = DownloadProvider[Settings().get_string('network.downloadProviderName')].create_instance()
    code, data = provider.get_response(url)
    if code == 0:
  21. @psifertex psifertex revised this gist Mar 14, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion update_snippets.py
    Original file line number Diff line number Diff line change
    @@ -15,7 +15,7 @@
    width = 4

    def download(url):
    provider = next(iter(DownloadProvider)).create_instance()
    provider = DownloadProvider[Settings().get_string('network.downloadProviderName')].create_instance()
    code, data = provider.get_response(url)
    if code == 0:
    return data
  22. @psifertex psifertex revised this gist Mar 8, 2022. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions pseudo_c.py
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,7 @@
    # print current function to pseudo c
    #
    # Adapt as necessary to save to file for example, though File / Export will also work

    def c_source(bv, func):
    lines = ''
    settings = DisassemblySettings()
  23. @psifertex psifertex revised this gist Mar 8, 2022. 2 changed files with 54 additions and 54 deletions.
    38 changes: 19 additions & 19 deletions unimplemented.py
    Original file line number Diff line number Diff line change
    @@ -2,31 +2,31 @@
    #
    # Especially useful when building a new architecture and wanting to see what disassembly you're running into with real binaries to prioritize

    from binaryninja.lowlevelil import LowLevelILInstruction
    from binaryninja.lowlevelil import LowLevelILInstruction

    def visit(unimp, expr):
    for field in LowLevelILInstruction.ILOperations[expr.operation]:
    if field[1] == "expr":
    visit(unimp, getattr(expr, field[0]))
    if expr.operation in [LowLevelILOperation.LLIL_UNIMPL, LowLevelILOperation.LLIL_UNIMPL_MEM]:
    if hasattr(expr, "expr_index"):
    index = expr.expr_index
    else:
    index = 0
    dis = bv.get_disassembly(expr.address)
    mnemonic = dis.split(" ")[0]
    if mnemonic in unimp.keys():
    unimp[mnemonic].append([expr.address, index])
    else:
    unimp[mnemonic] = [[expr.address, index]]
    for field in LowLevelILInstruction.ILOperations[expr.operation]:
    if field[1] == "expr":
    visit(unimp, getattr(expr, field[0]))
    if expr.operation in [LowLevelILOperation.LLIL_UNIMPL, LowLevelILOperation.LLIL_UNIMPL_MEM]:
    if hasattr(expr, "expr_index"):
    index = expr.expr_index
    else:
    index = 0
    dis = bv.get_disassembly(expr.address)
    mnemonic = dis.split(" ")[0]
    if mnemonic in unimp.keys():
    unimp[mnemonic].append([expr.address, index])
    else:
    unimp[mnemonic] = [[expr.address, index]]

    unimp = {}

    for llili in bv.llil_instructions:
    visit(unimp, llili)
    visit(unimp, llili)

    log_info(f"Found {len(unimp)} total unimplemented mnemonics")
    for k, v in sorted(unimp.items(), key=len):
    log_info(f"Unimplemented mnemonic: {k}:")
    for x in v:
    log_info(f" {hex(x[0])} / {x[1]}")
    log_info(f"Unimplemented mnemonic: {k}:")
    for x in v:
    log_info(f" {hex(x[0])} / {x[1]}")
    70 changes: 35 additions & 35 deletions update_snippets.py
    Original file line number Diff line number Diff line change
    @@ -8,49 +8,49 @@

    #TODO: Merge remote with local description or hotkey changes (AKA: if filename matches, skip the first two lines, truncate, re-write the rest)

    domain = b'https://gist.github.com'
    domain = b'https://gist.github.com'
    path = b'/psifertex/6fbc7532f536775194edd26290892ef7' # Feel free to adapt to your own setup
    subfolder = 'default' # Change to save the snippets to a different sub-folder
    tab2space = False
    width = 4

    def download(url):
    provider = next(iter(DownloadProvider)).create_instance()
    code, data = provider.get_response(url)
    if code == 0:
    return data
    else:
    raise ConnectionError("Unsuccessful download of %s" % url)
    provider = next(iter(DownloadProvider)).create_instance()
    code, data = provider.get_response(url)
    if code == 0:
    return data
    else:
    raise ConnectionError("Unsuccessful download of %s" % url)

    def update_snippets():
    if not interaction.show_message_box('Warning', "Use at your own risk. Do you want to automatically overwrite local snippets from gist?", buttons=MessageBoxButtonSet.YesNoButtonSet):
    return
    snippetPath = os.path.realpath(os.path.join(user_plugin_path(), '..', 'snippets', subfolder))
    if not os.path.isdir(snippetPath):
    os.makedirs(snippetPath)
    url = domain + path
    log_info("Downloading from: %s" % url)
    source = download(url)
    zipPath = [s for s in source.split(b'\"') if s.endswith(b'.zip')]
    if len(zipPath) != 1:
    log_error("Update failed.")
    return
    url = domain + zipPath[0]
    if not interaction.show_message_box('Warning', "Use at your own risk. Do you want to automatically overwrite local snippets from gist?", buttons=MessageBoxButtonSet.YesNoButtonSet):
    return
    snippetPath = os.path.realpath(os.path.join(user_plugin_path(), '..', 'snippets', subfolder))
    if not os.path.isdir(snippetPath):
    os.makedirs(snippetPath)
    url = domain + path
    log_info("Downloading from: %s" % url)
    source = download(url)
    zipPath = [s for s in source.split(b'\"') if s.endswith(b'.zip')]
    if len(zipPath) != 1:
    log_error("Update failed.")
    return
    url = domain + zipPath[0]

    log_info("Downloading from: %s" % url)
    zip = download(url)
    with TemporaryFile() as f:
    f.write(zip)
    with ZipFile(f, 'r') as zip:
    for item in zip.infolist():
    if item.filename[-1] == '/':
    continue
    basename = os.path.basename(item.filename)
    with open(os.path.join(snippetPath, basename), 'wb') as f:
    if tab2space:
    f.write(zip.read(item).replace(b'\t', b' ' * width))
    else:
    f.write(zip.read(item))
    log_info("Extracting %s" % item.filename)
    log_info("Downloading from: %s" % url)
    zip = download(url)
    with TemporaryFile() as f:
    f.write(zip)
    with ZipFile(f, 'r') as zip:
    for item in zip.infolist():
    if item.filename[-1] == '/':
    continue
    basename = os.path.basename(item.filename)
    with open(os.path.join(snippetPath, basename), 'wb') as f:
    if tab2space:
    f.write(zip.read(item).replace(b'\t', b' ' * width))
    else:
    f.write(zip.read(item))
    log_info("Extracting %s" % item.filename)

    update_snippets()
  24. @psifertex psifertex revised this gist Mar 8, 2022. 20 changed files with 328 additions and 309 deletions.
    53 changes: 27 additions & 26 deletions FUNctional_tags.py
    Original file line number Diff line number Diff line change
    @@ -1,43 +1,44 @@
    # create common tags for function attributes like leaf, loop, stub, etc
    #
    # Snippet replaced with a plugin, will be removed in the future: https://github.com/psifertex/tagteam

    # See below for the tags variable for the various tag types created/added
    large = 40
    complex = 40

    def init_tags():
    for tagType in tags:
    if tagType['name'] not in bv.tag_types.keys():
    bv.create_tag_type(tagType['name'], tagType['emoji'])
    for tagType in tags:
    if tagType['name'] not in bv.tag_types.keys():
    bv.create_tag_type(tagType['name'], tagType['emoji'])

    def cc(fn):
    nodes = len(fn.basic_blocks)
    edges = sum(len(x.outgoing_edges) for x in fn.basic_blocks)
    connected = 1 #always 1 for binary control flow graphs, kinda the whole point
    return edges - nodes + 2 * connected
    nodes = len(fn.basic_blocks)
    edges = sum(len(x.outgoing_edges) for x in fn.basic_blocks)
    connected = 1 #always 1 for binary control flow graphs, kinda the whole point
    return edges - nodes + 2 * connected
    def iscomplex(fn):
    return cc(fn) > complex
    return cc(fn) > complex

    def isleaf(fn):
    return len(fn.callees) == 0
    return len(fn.callees) == 0

    def islarge(fn):
    return len(fn.basic_blocks) >= large
    return len(fn.basic_blocks) >= large

    def isstub(fn):
    """Returns true if a function is likely only a stub"""
    if len(fn.basic_blocks) > 1 or len(fn.llil.basic_blocks) > 1:
    return False
    if fn.llil.basic_blocks[0].has_undetermined_outgoing_edges or len(fn.callees) == 1:
    return True
    return False
    """Returns true if a function is likely only a stub"""
    if len(fn.basic_blocks) > 1 or len(fn.llil.basic_blocks) > 1:
    return False
    if fn.llil.basic_blocks[0].has_undetermined_outgoing_edges or len(fn.callees) == 1:
    return True
    return False

    def hasloop(fn):
    """Returns true if a function has a 'strange loop' (ignore this, inside joke)"""
    for bb in fn.basic_blocks:
    if bb in bb.dominance_frontier:
    return True
    return False
    """Returns true if a function has a 'strange loop' (ignore this, inside joke)"""
    for bb in fn.basic_blocks:
    if bb in bb.dominance_frontier:
    return True
    return False

    tags = [ \
    {'emoji': '🍃', 'name': 'Leaf Function', 'description': 'Leaf function (does not call anything else)', 'fn': isleaf},
    @@ -51,6 +52,6 @@ def hasloop(fn):
    init_tags()

    for fn in bv.functions:
    for tagType in tags:
    if tagType['fn'](fn):
    fn.create_user_function_tag(bv.tag_types[tagType['name']], '', unique=True)
    for tagType in tags:
    if tagType['fn'](fn):
    fn.create_user_function_tag(bv.tag_types[tagType['name']], '', unique=True)
    14 changes: 7 additions & 7 deletions auto_strings.py
    Original file line number Diff line number Diff line change
    @@ -4,14 +4,14 @@

    count = 0
    for s in bv.strings:
    bv.define_user_data_var(s.start, Type.array(Type.char(), s.length))
    bv.define_user_data_var(s.start, Type.array(Type.char(), s.length))

    if bv.get_symbol_at(s.start) is None:
    sym = Symbol(types.SymbolType.DataSymbol, s.start, "str_{}".format(s.value))
    bv.define_user_symbol(sym)
    count += 1
    if bv.get_symbol_at(s.start) is None:
    sym = Symbol(types.SymbolType.DataSymbol, s.start, "str_{}".format(s.value))
    bv.define_user_symbol(sym)
    count += 1

    interaction.show_message_box(
    "Auto-Rename strings",
    f"Completed renaming variables based {count} strings!"
    "Auto-Rename strings",
    f"Completed renaming variables based {count} strings!"
    )
    22 changes: 11 additions & 11 deletions count_il.py
    Original file line number Diff line number Diff line change
    @@ -7,27 +7,27 @@
    from binaryninja.highlevelil import HighLevelILInstruction

    def visit(illest, expr, operations):
    for field in operations[expr.operation]:
    if field[1] == "expr":
    visit(illest, getattr(expr, field[0]), operations)
    illest.add(expr.operation)
    for field in operations[expr.operation]:
    if field[1] == "expr":
    visit(illest, getattr(expr, field[0]), operations)
    illest.add(expr.operation)

    llillest = set(())
    mlillest = set(())
    hlillest = set(())

    if current_llil:
    fnname = current_function.name
    for ins in current_llil.instructions:
    visit(llillest, ins, LowLevelILInstruction.ILOperations)
    fnname = current_function.name
    for ins in current_llil.instructions:
    visit(llillest, ins, LowLevelILInstruction.ILOperations)

    if current_mlil:
    for ins in current_mlil.instructions:
    visit(mlillest, ins, MediumLevelILInstruction.ILOperations)
    for ins in current_mlil.instructions:
    visit(mlillest, ins, MediumLevelILInstruction.ILOperations)

    if current_hlil:
    for ins in current_hlil.instructions:
    visit(hlillest, ins, HighLevelILInstruction.ILOperations)
    for ins in current_hlil.instructions:
    visit(hlillest, ins, HighLevelILInstruction.ILOperations)

    log_info("%s LLIL (%d): " % (fnname, len(llillest)))
    log_info(str(llillest))
    2 changes: 1 addition & 1 deletion create_symbol.py
    Original file line number Diff line number Diff line change
    @@ -4,4 +4,4 @@

    sym_name = get_text_line_input("Symbol name:", "Symbol Name")
    if sym_name not in [None, b'']:
    bv.define_user_symbol(Symbol(SymbolType.DataSymbol, here, sym_name))
    bv.define_user_symbol(Symbol(SymbolType.DataSymbol, here, sym_name))
    20 changes: 10 additions & 10 deletions demangle_gnu_pe.py
    Original file line number Diff line number Diff line change
    @@ -3,13 +3,13 @@
    # Will attempt to demangle GNU mangled C++ names in a PE file since that is not automatically done

    for func_sym in bv.get_symbols_of_type(SymbolType.FunctionSymbol):
    log_debug(f"Attempting to demangle {func_sym}")
    symtype, symname = demangle_gnu3(Architecture['x86'], func_sym.name)
    if symname != func_sym.name:
    log_info(f"Successfully demangled {func_sym.name}")
    if type(symname) == str:
    full_name = symname
    else:
    full_name = '::'.join(map(str, symname))
    new_sym = binaryninja.types.Symbol(SymbolType.FunctionSymbol, func_sym.address, short_name=symname[-1], full_name=full_name, raw_name=func_sym.name)
    bv.define_user_symbol(new_sym)
    log_debug(f"Attempting to demangle {func_sym}")
    symtype, symname = demangle_gnu3(Architecture['x86'], func_sym.name)
    if symname != func_sym.name:
    log_info(f"Successfully demangled {func_sym.name}")
    if type(symname) == str:
    full_name = symname
    else:
    full_name = '::'.join(map(str, symname))
    new_sym = binaryninja.types.Symbol(SymbolType.FunctionSymbol, func_sym.address, short_name=symname[-1], full_name=full_name, raw_name=func_sym.name)
    bv.define_user_symbol(new_sym)
    52 changes: 26 additions & 26 deletions export_settings.py
    Original file line number Diff line number Diff line change
    @@ -13,32 +13,32 @@
    allscope = set(["SettingsProjectScope", "SettingsUserScope", "SettingsResourceScope"])

    for category in settings:
    for setting in settings[category]['settings']:
    title = settings[category]['settings'][setting]['title']
    description = settings[category]['settings'][setting]['description']
    typ = settings[category]['settings'][setting]['type']
    key = settings[category]['settings'][setting]['key']
    default = settings[category]['settings'][setting]['default']
    if isinstance(default, list):
    default = "[" + ', '.join(["`%s`" % x for x in default]) + "]"
    else:
    default = f"`{str(default)}`"
    if default == "``":
    default = " ";
    print(settings[category]['settings'][setting])
    if 'ignore' in settings[category]['settings'][setting].keys():
    scope = allscope - set(settings[category]['settings'][setting]['ignore'])
    else:
    scope = allscope
    scope = "[" + ', '.join(["`%s`" % x for x in scope]) + "]"
    table += f"|{category}|{title}|{description}|`{typ}`|{default}|{scope}|<a id='{key}'>{key}</a>|\n"
    if settings[category]['settings'][setting].get("enum") and key not in excludeEnum:
    for idx, enum in enumerate(settings[category]['settings'][setting]["enum"]):
    if settings[category]['settings'][setting].get("enumDescriptions"):
    description = " enum: " + settings[category]['settings'][setting]["enumDescriptions"][idx]
    else:
    description = " "
    table += f"| | |{description}|`enum`|`{enum}`| | |\n"
    for setting in settings[category]['settings']:
    title = settings[category]['settings'][setting]['title']
    description = settings[category]['settings'][setting]['description']
    typ = settings[category]['settings'][setting]['type']
    key = settings[category]['settings'][setting]['key']
    default = settings[category]['settings'][setting]['default']
    if isinstance(default, list):
    default = "[" + ', '.join(["`%s`" % x for x in default]) + "]"
    else:
    default = f"`{str(default)}`"
    if default == "``":
    default = " ";
    print(settings[category]['settings'][setting])
    if 'ignore' in settings[category]['settings'][setting].keys():
    scope = allscope - set(settings[category]['settings'][setting]['ignore'])
    else:
    scope = allscope
    scope = "[" + ', '.join(["`%s`" % x for x in scope]) + "]"
    table += f"|{category}|{title}|{description}|`{typ}`|{default}|{scope}|<a id='{key}'>{key}</a>|\n"
    if settings[category]['settings'][setting].get("enum") and key not in excludeEnum:
    for idx, enum in enumerate(settings[category]['settings'][setting]["enum"]):
    if settings[category]['settings'][setting].get("enumDescriptions"):
    description = " enum: " + settings[category]['settings'][setting]["enumDescriptions"][idx]
    else:
    description = " "
    table += f"| | |{description}|`enum`|`{enum}`| | |\n"

    show_markdown_report("Settings Documentation", "Below table added to the clipboard:\n\n"+table)
    log_info("Saving result to the clipboard.")
    102 changes: 51 additions & 51 deletions export_to_text.py
    Original file line number Diff line number Diff line change
    @@ -6,64 +6,64 @@
    import io

    def valid_filename(s):
    s = s.strip().replace(' ', '_')
    return re.sub(r'(?u)[^-\w.]', '', s)
    s = s.strip().replace(' ', '_')
    return re.sub(r'(?u)[^-\w.]', '', s)

    def filtername(name):
    return "".join(x for x in name if x.isalnum() or x in ["_", "-"])
    return "".join(x for x in name if x.isalnum() or x in ["_", "-"])

    def fnsource(fn, form):
    if form == "HLIL":
    return ''.join(["\t" + x + "\n" for x in map(str, fn.hlil.root.lines)])
    if form == "MLIL":
    return ''.join(["\t" + x + "\n" for x in map(str, fn.mlil.instructions)])
    if form == "LLIL":
    return ''.join(["\t" + x + "\n" for x in map(str, fn.llil.instructions)])
    if form == "Assembly":
    return ''.join(["\t" + "".join(map(str, x[0])) + "\n" for x in fn.instructions])
    if form == "Assembly with offset":
    return ''.join([f'\t{x[1]:#04x}: {"".join(map(str, x[0]))}\n' for x in fn.instructions])
    if form == "HLIL":
    return ''.join(["\t" + x + "\n" for x in map(str, fn.hlil.root.lines)])
    if form == "MLIL":
    return ''.join(["\t" + x + "\n" for x in map(str, fn.mlil.instructions)])
    if form == "LLIL":
    return ''.join(["\t" + x + "\n" for x in map(str, fn.llil.instructions)])
    if form == "Assembly":
    return ''.join(["\t" + "".join(map(str, x[0])) + "\n" for x in fn.instructions])
    if form == "Assembly with offset":
    return ''.join([f'\t{x[1]:#04x}: {"".join(map(str, x[0]))}\n' for x in fn.instructions])

    def overwrite(fname):
    if show_message_box("File exists", "File exists, delete and overwrite?", buttons=MessageBoxButtonSet.YesNoButtonSet) == MessageBoxButtonResult.YesButton:
    os.unlink(fname)
    return True
    else:
    return False
    if show_message_box("File exists", "File exists, delete and overwrite?", buttons=MessageBoxButtonSet.YesNoButtonSet) == MessageBoxButtonResult.YesButton:
    os.unlink(fname)
    return True
    else:
    return False

    def main():
    #Maybe eventually add "Whole Binary" to include data from linear view
    all_or_func = ChoiceField("Scope?", ["All functions", "Current function"])
    asm_or_il = ChoiceField("Which form?", ["Assembly with offset", "Assembly", "LLIL", "MLIL", "HLIL"])
    folder = DirectoryNameField("Folder to save result", default_name=os.path.dirname(bv.file.filename))
    choices = get_form_input(["Which would you like to export?\n\nNote that \"whole binary\" will only dump IL contained in functions when IL is selected", all_or_func, asm_or_il, folder], "Export to text")
    if choices:
    current_only = all_or_func.result == 1
    form = asm_or_il.choices[asm_or_il.result]
    fname = os.path.splitext(os.path.basename(bv.file.filename))[0]
    if folder.result:
    if current_only:
    outputname = f"{os.path.join(folder.result, fname)}.{valid_filename(current_function.name)}.txt"
    if os.path.isfile(outputname):
    if not overwrite(outputname):
    log_warn("Stopping export to text due to existing file.")
    return
    log_info(f"Dumping {current_function.name} to {outputname}")
    with io.open(outputname, mode='w', encoding="utf-8") as f:
    f.write(fnsource(current_function, form))
    else:
    outputname = f"{os.path.join(folder.result, fname)}.txt"
    if os.path.isfile(outputname):
    if not overwrite(outputname):
    log_warn("Stopping export to text due to existing file.")
    return
    #Maybe eventually add "Whole Binary" to include data from linear view
    all_or_func = ChoiceField("Scope?", ["All functions", "Current function"])
    asm_or_il = ChoiceField("Which form?", ["Assembly with offset", "Assembly", "LLIL", "MLIL", "HLIL"])
    folder = DirectoryNameField("Folder to save result", default_name=os.path.dirname(bv.file.filename))
    choices = get_form_input(["Which would you like to export?\n\nNote that \"whole binary\" will only dump IL contained in functions when IL is selected", all_or_func, asm_or_il, folder], "Export to text")
    if choices:
    current_only = all_or_func.result == 1
    form = asm_or_il.choices[asm_or_il.result]
    fname = os.path.splitext(os.path.basename(bv.file.filename))[0]
    if folder.result:
    if current_only:
    outputname = f"{os.path.join(folder.result, fname)}.{valid_filename(current_function.name)}.txt"
    if os.path.isfile(outputname):
    if not overwrite(outputname):
    log_warn("Stopping export to text due to existing file.")
    return
    log_info(f"Dumping {current_function.name} to {outputname}")
    with io.open(outputname, mode='w', encoding="utf-8") as f:
    f.write(fnsource(current_function, form))
    else:
    outputname = f"{os.path.join(folder.result, fname)}.txt"
    if os.path.isfile(outputname):
    if not overwrite(outputname):
    log_warn("Stopping export to text due to existing file.")
    return

    with io.open(outputname, mode='w', encoding="utf-8") as f:
    for fn in bv.functions:
    log_info(f"Writing {fn.name}")
    f.write(f"\n{fn.name}: \n")
    f.write(fnsource(fn, form))
    log_info(f"Done dumping whole binary to {outputname}")
    with io.open(outputname, mode='w', encoding="utf-8") as f:
    for fn in bv.functions:
    log_info(f"Writing {fn.name}")
    f.write(f"\n{fn.name}: \n")
    f.write(fnsource(fn, form))
    log_info(f"Done dumping whole binary to {outputname}")

    main()
    main()
    12 changes: 6 additions & 6 deletions find_definition.py
    Original file line number Diff line number Diff line change
    @@ -2,10 +2,10 @@
    #

    if uicontext.token.localVarValid:
    log_info("Found a localvar")
    varname = uicontext.token.token.text
    log_info(str(dir(uicontext)))
    log_info("-----\n")
    instrIndex = 0
    log_info("Found a localvar")
    varname = uicontext.token.token.text
    log_info(str(dir(uicontext)))
    log_info("-----\n")
    instrIndex = 0
    else:
    log_warn("No variable selected")
    log_warn("No variable selected")
    2 changes: 1 addition & 1 deletion function_comment.py
    Original file line number Diff line number Diff line change
    @@ -4,4 +4,4 @@

    newcomment = get_text_line_input("Current value: " + current_function.comment, "Function plate comment")
    if (newcomment):
    current_function.comment = newcomment
    current_function.comment = newcomment
    28 changes: 14 additions & 14 deletions list_plugins.py
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    # Produce an HTML report showing how to use a sortable HTML table to make a slightly more useful UI. Appologies for the awful intermixing of code and HTMl, think it's actually more readable this way.

    from binaryninjaui import getThemeColor, ThemeColor
    r=RepositoryManager()
    r = RepositoryManager()
    repos = ["community", "official"]

    html = '''<html>
    @@ -14,7 +14,7 @@
    <script>'''

    for repo in repos:
    html += f'''$(document).ready( function () {{
    html += f'''$(document).ready( function () {{
    $('#{repo}').DataTable({{
    "paging": false,
    "info": false,
    @@ -43,7 +43,7 @@
    '''

    for repo in ["community", "official"]:
    html += f'''<h3>{repo.capitalize()} Plugins</h3>
    html += f'''<h3>{repo.capitalize()} Plugins</h3>
    <table id="{repo}" class="sortable" cellspacing="0" width="100%">
    <thead>
    <tr>
    @@ -55,17 +55,17 @@
    </thead>
    <tbody>
    '''
    for plugin in r.plugins[repo]:
    if plugin.update_available:
    status = "Update Available"
    elif plugin.installed and not plugin.enabled:
    status = "Disabled"
    elif plugin.installed:
    status = "Enabled"
    else:
    continue
    html += f'<tr data-state="{status}"><td>{plugin.name}</td><td>{plugin.version}</td><td>{status}</td><td>{plugin.description}</td></tr>'
    html += f'''</tbody>
    for plugin in r.plugins[repo]:
    if plugin.update_available:
    status = "Update Available"
    elif plugin.installed and not plugin.enabled:
    status = "Disabled"
    elif plugin.installed:
    status = "Enabled"
    else:
    continue
    html += f'<tr data-state="{status}"><td>{plugin.name}</td><td>{plugin.version}</td><td>{status}</td><td>{plugin.description}</td></tr>'
    html += f'''</tbody>
    </table>
    <hr />
    '''
    132 changes: 66 additions & 66 deletions load_borland_map.py
    Original file line number Diff line number Diff line change
    @@ -8,11 +8,11 @@
    #Load symbols from a MAP file
    mapfile = get_open_filename_input("filename:", "All Files (*)")
    if mapfile is not None and os.access(mapfile, os.R_OK):
    with open(mapfile, "r+", encoding="utf-8") as f:
    data = f.readlines()
    with open(mapfile, "r+", encoding="utf-8") as f:
    data = f.readlines()
    else:
    log_error("Unable to parse specified map file.")
    data = []
    log_error("Unable to parse specified map file.")
    data = []

    mylog = log_debug
    #uncomment to enable debugging even if BN debugging is off
    @@ -21,66 +21,66 @@
    segments = {}
    symcount = 0
    for line in data:
    line = line.strip()
    if line.startswith("0"):
    index = line.split(":")[0]
    if index in segments.keys(): #this is a record for a segment we know about
    offset = int(line.split(" ")[0].split(":")[1], 16)
    addr = offset + segments[index][0]
    symbol = line.split(" ")[-1]
    symtype=SymbolType.DataSymbol
    if symbol.endswith("()"):
    symbol = symbol[0:-2]
    if symbol.startswith("<-"):
    symbol = symbol[2:]
    symtype=SymbolType.FunctionSymbol
    contain = bv.get_functions_containing(addr)
    makenew = True
    for fn in contain:
    if fn.start == addr: #there should not be other functions around this
    makenew = False
    else:
    mylog(f'Removed bogus prior function at {hex(fn.start)}')
    bv.remove_user_function(fn)
    if makenew:
    mylog(f'Created function at {hex(addr)}')
    bv.create_user_function(addr)
    if symbol.startswith("->:"): #call to a function, name destination
    symbol = symbol[3:]
    symtype=SymbolType.FunctionSymbol
    dest = bv.get_callees(addr)
    if len(dest) == 0: #current function hasn't been analyzed yet, extract destination from disasssembly and create destination function and symbol
    destaddr = int(bv.get_disassembly(addr).split(' ')[-1], 16)
    bv.create_user_function(destaddr)
    bv.define_user_symbol(Symbol(symtype, destaddr, symbol))
    mylog(f'Created function at {hex(destaddr)}')
    continue
    else:
    destfn = bv.get_function_at(dest[0])
    destfn.name = symbol
    mylog(f'Renamed function {symbol} as destination of call at {hex(addr)}')
    if symbol.startswith("->"):
    symbol = symbol[2:]
    continue #just a pointer to an import, skip
    if symbol.startswith("*"):
    symbol = symbol[1:]
    bv.define_user_symbol(Symbol(symtype, addr, symbol))
    mylog(f'Creating symbol {symbol} at {hex(addr)}')
    symcount += 1
    else: #new memory segment
    records = re.split('\s+', line[5:])
    base = int(records[0], 16)
    size = int(records[1][:-1], 16)
    try:
    name = records[2]
    except IndexError:
    name = 'name'
    try:
    cls = records[3]
    except IndexError:
    cls = 'class'
    if name.endswith("END") or name.endswith("END_"):
    continue
    segments[index] = [ base, size, name, cls ]
    line = line.strip()
    if line.startswith("0"):
    index = line.split(":")[0]
    if index in segments.keys(): #this is a record for a segment we know about
    offset = int(line.split(" ")[0].split(":")[1], 16)
    addr = offset + segments[index][0]
    symbol = line.split(" ")[-1]
    symtype=SymbolType.DataSymbol
    if symbol.endswith("()"):
    symbol = symbol[0:-2]
    if symbol.startswith("<-"):
    symbol = symbol[2:]
    symtype=SymbolType.FunctionSymbol
    contain = bv.get_functions_containing(addr)
    makenew = True
    for fn in contain:
    if fn.start == addr: #there should not be other functions around this
    makenew = False
    else:
    mylog(f'Removed bogus prior function at {hex(fn.start)}')
    bv.remove_user_function(fn)
    if makenew:
    mylog(f'Created function at {hex(addr)}')
    bv.create_user_function(addr)
    if symbol.startswith("->:"): #call to a function, name destination
    symbol = symbol[3:]
    symtype=SymbolType.FunctionSymbol
    dest = bv.get_callees(addr)
    if len(dest) == 0: #current function hasn't been analyzed yet, extract destination from disasssembly and create destination function and symbol
    destaddr = int(bv.get_disassembly(addr).split(' ')[-1], 16)
    bv.create_user_function(destaddr)
    bv.define_user_symbol(Symbol(symtype, destaddr, symbol))
    mylog(f'Created function at {hex(destaddr)}')
    continue
    else:
    destfn = bv.get_function_at(dest[0])
    destfn.name = symbol
    mylog(f'Renamed function {symbol} as destination of call at {hex(addr)}')
    if symbol.startswith("->"):
    symbol = symbol[2:]
    continue #just a pointer to an import, skip
    if symbol.startswith("*"):
    symbol = symbol[1:]
    bv.define_user_symbol(Symbol(symtype, addr, symbol))
    mylog(f'Creating symbol {symbol} at {hex(addr)}')
    symcount += 1
    else: #new memory segment
    records = re.split('\s+', line[5:])
    base = int(records[0], 16)
    size = int(records[1][:-1], 16)
    try:
    name = records[2]
    except IndexError:
    name = 'name'
    try:
    cls = records[3]
    except IndexError:
    cls = 'class'
    if name.endswith("END") or name.endswith("END_"):
    continue
    segments[index] = [ base, size, name, cls ]

    log_info(f'Updated {symcount} total symbols')
    16 changes: 8 additions & 8 deletions navigate_to_offset.py
    Original file line number Diff line number Diff line change
    @@ -3,11 +3,11 @@
    # Takes a file offset, converts it to a virtual address and navigates there. Note that the relative checkbox wont work but we use this dialog to get calculation feature

    while True:
    offset=get_address_input("File offset: ", "Offset")
    if not offset:
    break
    if offset_to_vaddr(offset):
    vaddr = bv.get_address_for_data_offset(offset)
    log_info("Navigating to file offset %x" % vaddr)
    bv.navigate(bv.view, vaddr)
    break
    offset=get_address_input("File offset: ", "Offset")
    if not offset:
    break
    if offset_to_vaddr(offset):
    vaddr = bv.get_address_for_data_offset(offset)
    log_info("Navigating to file offset %x" % vaddr)
    bv.navigate(bv.view, vaddr)
    break
    8 changes: 4 additions & 4 deletions new_file_from_selection.py
    Original file line number Diff line number Diff line change
    @@ -6,12 +6,12 @@
    from binaryninjaui import UIContext

    def get_selected_data():
    #remove when snippets implements this first-class
    return bv.read(current_selection[0], current_selection[1]-current_selection[0])
    #remove when snippets implements this first-class
    return bv.read(current_selection[0], current_selection[1]-current_selection[0])

    def openFile(filename):
    ctx = UIContext.activeContext()
    ctx.openFilename(filename)
    ctx = UIContext.activeContext()
    ctx.openFilename(filename)

    temp = tempfile.NamedTemporaryFile(delete=False)
    buf = get_selected_data()
    18 changes: 18 additions & 0 deletions pseudo_c.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    def c_source(bv, func):
    lines = ''
    settings = DisassemblySettings()
    settings.set_option(DisassemblyOption.ShowAddress, False)
    obj = lineardisassembly.LinearViewObject.language_representation(bv, settings)
    cursor_end = lineardisassembly.LinearViewCursor(obj)
    cursor_end.seek_to_address(func.highest_address)
    body = bv.get_next_linear_disassembly_lines(cursor_end)
    cursor_end.seek_to_address(func.highest_address)
    header= bv.get_previous_linear_disassembly_lines(cursor_end)
    for line in header:
    lines += str(line) + '\n'
    for line in body:
    lines += str(line) + '\n'
    return lines

    for line in c_source(bv, current_function):
    print(line)
    4 changes: 2 additions & 2 deletions run_python_file.py
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,6 @@

    filename = get_open_filename_input("Python File:")
    if filename:
    exec(open(filename).read())
    exec(open(filename).read())
    else:
    show_message_box("Invalid python file", "Invalid python file selected.", MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon)
    show_message_box("Invalid python file", "Invalid python file selected.", MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon)
    54 changes: 27 additions & 27 deletions save_decompilation.py
    Original file line number Diff line number Diff line change
    @@ -3,37 +3,37 @@
    # DEPRECATED IN FAVOR OF "export to text" snippet

    def filtername(name):
    return "".join(x for x in name if x.isalnum() or x in ["_", "-"])
    return "".join(x for x in name if x.isalnum() or x in ["_", "-"])

    choice = get_choice_input("Save all functions or just current?", "choices", ["All", "Current"])


    if (choice == 0):
    import os
    fname = os.path.splitext(os.path.basename(bv.file.filename))[0]
    folder = get_directory_name_input("Where to save decompilation:").decode('utf-8')
    for fn in bv.functions:
    source = '\n'.join(map(str, fn.hlil.root.lines))
    output = os.path.join(folder, filtername(fn.name) + ".txt")
    try:
    with open(output, 'w') as f:
    f.write(source)
    log_info(f"Dumped {fn.name} to {output}")
    except:
    log_error(f"Unable to save {output}")
    import os
    fname = os.path.splitext(os.path.basename(bv.file.filename))[0]
    folder = get_directory_name_input("Where to save decompilation:").decode('utf-8')
    for fn in bv.functions:
    source = '\n'.join(map(str, fn.hlil.root.lines))
    output = os.path.join(folder, filtername(fn.name) + ".txt")
    try:
    with open(output, 'w') as f:
    f.write(source)
    log_info(f"Dumped {fn.name} to {output}")
    except:
    log_error(f"Unable to save {output}")
    if (choice == 1):
    source = '\n'.join(map(str, current_function.hlil.root.lines))
    while True:
    output = get_save_filename_input("Source filename:", "txt", "%s.txt" % filtername(current_function.name))
    if output == None:
    msg = "No file specified."
    interaction.show_message_box(msg, msg)
    break
    try:
    with open(output, "w") as f:
    f.write(source)
    except:
    msg = "Save failed. Try again?"
    if not interaction.show_message_box(msg, msg, buttons=MessageBoxButtonSet.YesNoButtonSet):
    break
    source = '\n'.join(map(str, current_function.hlil.root.lines))
    while True:
    output = get_save_filename_input("Source filename:", "txt", "%s.txt" % filtername(current_function.name))
    if output == None:
    msg = "No file specified."
    interaction.show_message_box(msg, msg)
    break
    try:
    with open(output, "w") as f:
    f.write(source)
    except:
    msg = "Save failed. Try again?"
    if not interaction.show_message_box(msg, msg, buttons=MessageBoxButtonSet.YesNoButtonSet):
    break

    64 changes: 32 additions & 32 deletions simple_ui.py
    Original file line number Diff line number Diff line change
    @@ -4,46 +4,46 @@
    from PySide2 import QtWidgets, QtGui, QtWidgets, QtCore

    def basic():
    popout = QtWidgets.QDialog()
    popout.setWindowTitle("test popout1")
    popout.exec_()
    popout = QtWidgets.QDialog()
    popout.setWindowTitle("test popout1")
    popout.exec_()

    def qpixmap():
    pixmap = QtGui.QPixmap("play-and-pause-button.png")
    mask = pixmap.createMaskFromColor(QtGui.QColor('black'), QtGui.Qt.MaskOutColor)
    pixmap.fill((QtGui.QColor('red')))
    pixmap.setMask(mask)
    window = QtWidgets.QDialog()
    window.setWindowTitle("View Image")
    label = QtWidgets.QLabel(window)
    label.setPixmap(pixmap)
    label.setGeometry(QtCore.QRect(10, 40, pixmap.width(), pixmap.height()))
    window.resize(pixmap.width()+20, pixmap.height()+100)
    window.exec_()
    pixmap = QtGui.QPixmap("play-and-pause-button.png")
    mask = pixmap.createMaskFromColor(QtGui.QColor('black'), QtGui.Qt.MaskOutColor)
    pixmap.fill((QtGui.QColor('red')))
    pixmap.setMask(mask)
    window = QtWidgets.QDialog()
    window.setWindowTitle("View Image")
    label = QtWidgets.QLabel(window)
    label.setPixmap(pixmap)
    label.setGeometry(QtCore.QRect(10, 40, pixmap.width(), pixmap.height()))
    window.resize(pixmap.width()+20, pixmap.height()+100)
    window.exec_()

    def qpixmap2():
    icon = QtGui.QIcon("play-and-pause-button.svg")
    button = QtWidgets.QPushButton(icon)
    msg_box = QtWidgets.QMessageBox()
    msg_box.setWindowTitle("Testing Icons")
    msg_box.exec_()
    icon = QtGui.QIcon("play-and-pause-button.svg")
    button = QtWidgets.QPushButton(icon)
    msg_box = QtWidgets.QMessageBox()
    msg_box.setWindowTitle("Testing Icons")
    msg_box.exec_()

    def colorize(img, color):
    pixmap = QtGui.QPixmap(img)
    mask = pixmap.createMaskFromColor(QtGui.QColor('black'), QtGui.Qt.MaskOutColor)
    pixmap.fill(color)
    pixmap.setMask(mask)
    return pixmap
    pixmap = QtGui.QPixmap(img)
    mask = pixmap.createMaskFromColor(QtGui.QColor('black'), QtGui.Qt.MaskOutColor)
    pixmap.fill(color)
    pixmap.setMask(mask)
    return pixmap

    def qicon():
    ico = QtGui.QIcon("play-and-pause-button.svg")
    ico2 = QtGui.QIcon(colorize(ico.pixmap(ico.actualSize(QtCore.QSize(1024, 1024))), QtGui.QColor('red')))
    msg_box = QtWidgets.QMessageBox()
    msg_box.setWindowTitle("Show Icon")
    button = QtWidgets.QPushButton(msg_box)
    button.setIcon(ico2)
    button.setText("PlayPause")
    msg_box.exec_()
    ico = QtGui.QIcon("play-and-pause-button.svg")
    ico2 = QtGui.QIcon(colorize(ico.pixmap(ico.actualSize(QtCore.QSize(1024, 1024))), QtGui.QColor('red')))
    msg_box = QtWidgets.QMessageBox()
    msg_box.setWindowTitle("Show Icon")
    button = QtWidgets.QPushButton(msg_box)
    button.setIcon(ico2)
    button.setText("PlayPause")
    msg_box.exec_()

    #qpixmap2()
    #qpixmap()
    18 changes: 9 additions & 9 deletions string_annotator.py
    Original file line number Diff line number Diff line change
    @@ -2,14 +2,14 @@
    #
    annotation=""
    for instruction in current_basic_block.get_disassembly_text():
    if instruction.address >= current_selection[0] and instruction.address < current_selection[1]:
    address = instruction.address
    value = instruction.tokens[-1].value
    operand = instruction.tokens[-1].operand
    type = IntegerDisplayType.CharacterConstantDisplayType
    current_function.set_int_display_type(address, value, operand, type)
    while (value > 0):
    annotation += chr(value % 256)
    value = value >> 8
    if instruction.address >= current_selection[0] and instruction.address < current_selection[1]:
    address = instruction.address
    value = instruction.tokens[-1].value
    operand = instruction.tokens[-1].operand
    type = IntegerDisplayType.CharacterConstantDisplayType
    current_function.set_int_display_type(address, value, operand, type)
    while (value > 0):
    annotation += chr(value % 256)
    value = value >> 8
    log_info("Adding comment for string: %s" % annotation)
    current_function.set_comment_at(current_selection[0], annotation)
    12 changes: 6 additions & 6 deletions swift_demangler.py
    Original file line number Diff line number Diff line change
    @@ -3,10 +3,10 @@
    import subprocess
    result = subprocess.run(['/usr/bin/xcrun', '--find', 'swift-demangle'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
    if result.returncode == 0:
    demangle_str = result.stdout.decode('utf-8')
    for f in bv.functions:
    result = subprocess.run([demangle_str, '-simplified', '-compact', symbol], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
    if result.returncode == 0:
    f.name = demangle(f.name)
    demangle_str = result.stdout.decode('utf-8')
    for f in bv.functions:
    result = subprocess.run([demangle_str, '-simplified', '-compact', symbol], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
    if result.returncode == 0:
    f.name = demangle(f.name)
    else:
    log_error('Unable to find swift-demangle.')
    log_error('Unable to find swift-demangle.')
    4 changes: 2 additions & 2 deletions trigger_actions.py
    Original file line number Diff line number Diff line change
    @@ -7,8 +7,8 @@
    from binaryninjaui import UIActionHandler, DockHandler

    def triggerAction(action):
    handler = UIActionHandler().actionHandlerFromWidget(DockHandler.getActiveDockHandler().parent())
    handler.executeAction(action)
    handler = UIActionHandler().actionHandlerFromWidget(DockHandler.getActiveDockHandler().parent())
    handler.executeAction(action)

    action="About..."
    execute_on_main_thread_and_wait(lambda: triggerAction(action))
  25. @psifertex psifertex revised this gist Feb 11, 2022. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion string_annotator.py
    Original file line number Diff line number Diff line change
    @@ -8,6 +8,8 @@
    operand = instruction.tokens[-1].operand
    type = IntegerDisplayType.CharacterConstantDisplayType
    current_function.set_int_display_type(address, value, operand, type)
    annotation += chr(instruction.tokens[-1].value)
    while (value > 0):
    annotation += chr(value % 256)
    value = value >> 8
    log_info("Adding comment for string: %s" % annotation)
    current_function.set_comment_at(current_selection[0], annotation)
  26. @psifertex psifertex renamed this gist Jan 14, 2022. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  27. @psifertex psifertex renamed this gist Jan 14, 2022. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  28. @psifertex psifertex revised this gist Jan 14, 2022. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions run_python_file
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    # run python file
    #
    # Run a file from disk with the current python context

    filename = get_open_filename_input("Python File:")
    if filename:
    exec(open(filename).read())
    else:
    show_message_box("Invalid python file", "Invalid python file selected.", MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon)
  29. @psifertex psifertex revised this gist Dec 9, 2021. 1 changed file with 7 additions and 2 deletions.
    9 changes: 7 additions & 2 deletions update_snippets.py
    Original file line number Diff line number Diff line change
    @@ -11,9 +11,11 @@
    domain = b'https://gist.github.com'
    path = b'/psifertex/6fbc7532f536775194edd26290892ef7' # Feel free to adapt to your own setup
    subfolder = 'default' # Change to save the snippets to a different sub-folder
    tab2space = False
    width = 4

    def download(url):
    provider = DownloadProvider.list[0].create_instance()
    provider = next(iter(DownloadProvider)).create_instance()
    code, data = provider.get_response(url)
    if code == 0:
    return data
    @@ -45,7 +47,10 @@ def update_snippets():
    continue
    basename = os.path.basename(item.filename)
    with open(os.path.join(snippetPath, basename), 'wb') as f:
    f.write(zip.read(item))
    if tab2space:
    f.write(zip.read(item).replace(b'\t', b' ' * width))
    else:
    f.write(zip.read(item))
    log_info("Extracting %s" % item.filename)

    update_snippets()
  30. @psifertex psifertex revised this gist Oct 6, 2021. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions get action context
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    # get action context
    #
    # Useful for quering what is selected from a snippet or plugin instead of using various register_for APIs

    def get_current_context() -> Optional[Any]:
    ctx = UIContext.activeContext()
    if not ctx:
    ctx = UIContext.allContexts()[0]
    if not ctx:
    binaryninja.log_warn(f'No UI Context available')
    return None
    handler = ctx.contentActionHandler()
    if not handler:
    binaryninja.log_warn(f'No Action Context available')
    return None

    return handler.actionContext()