Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save SreejithKSGupta/844dd6b4d14cb4e0574c33eb1d2def08 to your computer and use it in GitHub Desktop.

Select an option

Save SreejithKSGupta/844dd6b4d14cb4e0574c33eb1d2def08 to your computer and use it in GitHub Desktop.

Revisions

  1. @psifertex psifertex renamed this gist Jan 14, 2022. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. @psifertex psifertex renamed this gist Jan 14, 2022. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. @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)
  4. @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()
  5. @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()
  6. @psifertex psifertex revised this gist Sep 16, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions clipboard.py
    Original file line number Diff line number Diff line change
    @@ -5,10 +5,10 @@
    # import os
    # modulename=os.path.basename(bv.file.original_filename)
    s = bv.get_segment_at(here)
    offset=here - s.start
    fileoffset=here - s.start + s.data_offset

    # Alternate implementation that copies as a file offset (requires above lines
    #offset=s.data_offset + offset

    clip = PySide2.QtGui.QGuiApplication.clipboard()
    clip.setText('%x' % (offset))
    clip.setText('%x' % (fileoffset))
  7. @psifertex psifertex revised this gist Jul 15, 2021. 1 changed file with 24 additions and 12 deletions.
    36 changes: 24 additions & 12 deletions toggle_arm_thumb.py
    Original file line number Diff line number Diff line change
    @@ -1,22 +1,34 @@
    # toggle arm thumb
    # toggle arm thumb
    #
    # ARM/Thumb have an odd quirk where the same architecture module handles both and
    # uses the lowest bit of the address to determine the correct architecture, so
    # the normal API usage of specifing the optional platform will not work. Here's a
    # quick snippet to show how to toggle the architecture of the current function by
    # removing/creating it

    if current_function.arch == Architecture['armv7']:
    new_arch = Architecture['thumb2']
    offset = 1
    elif current_function.arch == Architecture['thumb2']:
    new_arch = Architecture['armv7']
    offset = 0
    func = current_function

    if not func and (current_address & 1) == 0:
    address = current_address + 1
    funcs = bv.get_functions_at(address)
    func = funcs[0] if funcs else None

    if not func:
    log_error(f'Cannot find a function at current_address {current_address:#x}')
    else:
    raise AttributeError("This snippet only works on thumb or armv7 functions")
    address = func.start

    address = current_function.start + offset
    if func.arch == Architecture['armv7']:
    new_platform = Platform['thumb2']
    address |= 1
    elif func.arch == Architecture['thumb2']:
    new_platform = Platform['armv7']
    address &= ~3
    else:
    raise AttributeError("This snippet only works on thumb or armv7 functions")

    bv.remove_user_function(current_function)
    bv.create_user_function(address)
    log_info("Creating a %s function at %x" % (str(new_arch), address - (address % 2)))
    bv.remove_user_function(func)
    bv.create_user_function(address, new_platform)
    platform_name = str(new_platform)
    article = 'an' if platform_name[0].lower() in 'aeiou' else 'a'
    log_info(f"Creating {article} {str(new_platform)} function at {(address - (address % 2)):#x}")
  8. @psifertex psifertex renamed this gist Jul 13, 2021. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  9. @psifertex psifertex revised this gist Jul 7, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion save_decompilation.py
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # save HLIL
    #
    # save the HLIL decompilation for the current function to a file or all functions to a folder
    # DEPRECATED IN FAVOR OF "export to text" snippet

    def filtername(name):
    return "".join(x for x in name if x.isalnum() or x in ["_", "-"])
  10. @psifertex psifertex revised this gist Jul 7, 2021. 1 changed file with 69 additions and 0 deletions.
    69 changes: 69 additions & 0 deletions export_to_text.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    # export to text
    #
    # Can export IL and assembly forms for the current function or the entire binary

    import os
    import io

    def valid_filename(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 ["_", "-"])

    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])

    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

    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

    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()
  11. @psifertex psifertex revised this gist Jun 14, 2021. 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
    @@ -10,7 +10,7 @@

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

    def download(url):
    provider = DownloadProvider.list[0].create_instance()
  12. @psifertex psifertex revised this gist May 20, 2021. 1 changed file with 21 additions and 0 deletions.
    21 changes: 21 additions & 0 deletions new_file_from_selection.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,21 @@
    # new file from selection
    #
    # Opens the current selections contents into a new file

    import tempfile
    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])

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

    temp = tempfile.NamedTemporaryFile(delete=False)
    buf = get_selected_data()
    log_info(f"Writing {len(buf)} bytes to {temp.name}")
    temp.write(get_selected_data())
    temp.close()
    execute_on_main_thread_and_wait(lambda: openFile(temp.name))
  13. @psifertex psifertex revised this gist Apr 13, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion read_dword.py
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    #
    # Simple example showing how to read a dword at the current location

    dword = int.from_bytes(bv.read(here), "big" if bv.endianness == Endianness.BigEndian else "little")
    dword = int.from_bytes(bv.read(here, 4), "big" if bv.endianness == Endianness.BigEndian else "little")

    clip = PySide2.QtGui.QGuiApplication.clipboard()
    clip.setText('%x' % (dword))
  14. @psifertex psifertex revised this gist Apr 13, 2021. 1 changed file with 8 additions and 0 deletions.
    8 changes: 8 additions & 0 deletions read_dword.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    # read dword
    #
    # Simple example showing how to read a dword at the current location

    dword = int.from_bytes(bv.read(here), "big" if bv.endianness == Endianness.BigEndian else "little")

    clip = PySide2.QtGui.QGuiApplication.clipboard()
    clip.setText('%x' % (dword))
  15. @psifertex psifertex revised this gist Apr 7, 2021. 1 changed file with 10 additions and 4 deletions.
    14 changes: 10 additions & 4 deletions clipboard.py
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,14 @@
    # copy location as offset
    #
    # copies the currently selected value as an offset from the base to the clipboard
    import os
    modulename=os.path.basename(bv.file.original_filename)
    offset=bv.get_segment_at(here).start
    # Was used to include offset as a module name, not needed now
    # import os
    # modulename=os.path.basename(bv.file.original_filename)
    s = bv.get_segment_at(here)
    offset=here - s.start

    # Alternate implementation that copies as a file offset (requires above lines
    #offset=s.data_offset + offset

    clip = PySide2.QtGui.QGuiApplication.clipboard()
    clip.setText('%x' % (here-offset))
    clip.setText('%x' % (offset))
  16. @psifertex psifertex revised this gist Mar 24, 2021. No changes.
  17. @psifertex psifertex revised this gist Mar 12, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion selected_variable.py
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # get the selected variable
    #
    # Uses the UIContext to get the variable the user has currently selected
    # Uses the UIContext to get the variable the user has currently selected, copied from https://twitter.com/josh_watson/status/1352319354663178240

    ctx = UIContext.activeContext()
    h = ctx.contentActionHandler()
  18. @psifertex psifertex revised this gist Mar 12, 2021. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions selected_variable.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    # get the selected variable
    #
    # Uses the UIContext to get the variable the user has currently selected

    ctx = UIContext.activeContext()
    h = ctx.contentActionHandler()
    a = h.actionContext()
    token_state = a.token
    selectedVar = Variable.from_identifier(current_function, token_state.token.value)
  19. @psifertex psifertex revised this gist Mar 8, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion demangle_gnu_pe.py
    Original file line number Diff line number Diff line change
    @@ -11,5 +11,5 @@
    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)
    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)
  20. @psifertex psifertex revised this gist Mar 8, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion demangle_gnu_pe.py
    Original file line number Diff line number Diff line change
    @@ -11,5 +11,5 @@
    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='::'.join(map(str, symname)), raw_name=func_sym.name)
    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)
  21. @psifertex psifertex revised this gist Mar 8, 2021. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions demangle_gnu_pe.py
    Original file line number Diff line number Diff line change
    @@ -7,5 +7,9 @@
    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='::'.join(map(str, symname)), raw_name=func_sym.name)
    bv.define_user_symbol(new_sym)
  22. @psifertex psifertex revised this gist Mar 8, 2021. 1 changed file with 11 additions and 0 deletions.
    11 changes: 11 additions & 0 deletions demangle_gnu_pe.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    # demangle gnu pe
    #
    # 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}")
    new_sym = binaryninja.types.Symbol(SymbolType.FunctionSymbol, func_sym.address, short_name=symname[-1], full_name='::'.join(map(str, symname)), raw_name=func_sym.name)
    bv.define_user_symbol(new_sym)
  23. @psifertex psifertex revised this gist Feb 24, 2021. 1 changed file with 28 additions and 10 deletions.
    38 changes: 28 additions & 10 deletions export_settings.py
    Original file line number Diff line number Diff line change
    @@ -5,22 +5,40 @@
    import json
    from PySide2.QtGui import QGuiApplication
    settings = json.loads(binaryninja.Settings().serialize_schema())
    table = """|Category|Setting|Description|Type|Default|Key|
    |---|---|---|---|---|---|
    table = """|Category|Setting|Description|Type|Default|Scope|Key|
    |---|---|---|---|---|---|---|
    """

    excludeEnum = [ "analysis.unicode.blocks", "python.interpreter", "ui.theme"]
    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']
    type = str(settings[category]['settings'][setting]['type'])
    key = str(settings[category]['settings'][setting]['key'])
    if type:
    type = "`%s`" % type
    default = str(settings[category]['settings'][setting]['default'])
    if default:
    default = "`%s`" % default
    table += f"|{category}|{title}|{description}|{type}|{default}|<a name='{key}'>{key}</a>|\n"
    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.")
  24. @psifertex psifertex revised this gist Feb 3, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions function_comment.py
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,6 @@
    #
    # The UI currently lacks a way to add a "function" based comment that will be repeated when the function is called

    newcomment = get_text_line_input("Function plate comment", current_function.comment)
    newcomment = get_text_line_input("Current value: " + current_function.comment, "Function plate comment")
    if (newcomment):
    current_function.comment = newcomment
    current_function.comment = newcomment
  25. @psifertex psifertex revised this gist Feb 3, 2021. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion function_comment.py
    Original file line number Diff line number Diff line change
    @@ -2,4 +2,6 @@
    #
    # The UI currently lacks a way to add a "function" based comment that will be repeated when the function is called

    current_function.comment = get_text_line_input("Function plate comment", current_function.comment)
    newcomment = get_text_line_input("Function plate comment", current_function.comment)
    if (newcomment):
    current_function.comment = newcomment
  26. @psifertex psifertex revised this gist Feb 3, 2021. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions function_comment.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    # function comment
    #
    # The UI currently lacks a way to add a "function" based comment that will be repeated when the function is called

    current_function.comment = get_text_line_input("Function plate comment", current_function.comment)
  27. @psifertex psifertex revised this gist Jan 12, 2021. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions 2_LICENSE.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    Since these are starting to get a bit more complex and there's a lot of code gathered I figured I should be explicit that these are released under a public domain license (CC0):

    To the extent possible under law, Jordan Wiens (@psifertex) has waived all copyright and related or neighboring rights to this Binary Ninja Snippets Collection (https://gist.github.com/psifertex/6fbc7532f536775194edd26290892ef7). This work is published from: United States.

    For more information on a CC0 license, see: https://creativecommons.org/publicdomain/zero/1.0/deed.en
  28. @psifertex psifertex revised this gist Jan 11, 2021. 1 changed file with 12 additions and 2 deletions.
    14 changes: 12 additions & 2 deletions FUNctional_tags.py
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,23 @@
    # functional tags
    #
    # create common tags for function attributes like leaf, loop, stub, etc

    # 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'])

    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

    def iscomplex(fn):
    return cc(fn) > complex

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

    @@ -36,6 +44,8 @@ def hasloop(fn):
    {'emoji': '🔄', 'name': 'Loop Function', 'description': 'Function contains a loop', 'fn': hasloop},
    {'emoji': '🥾', 'name': 'Stub Function', 'description': 'Function is likely a stub (only contains one basic block and one call or indirect jump)', 'fn': isstub},
    {'emoji': '🐘', 'name': 'Large Function', 'description': 'Function is "large" (IE, it has more than the blocks defined above)', 'fn': islarge},
    {'emoji': '🤯', 'name': 'Complex Function', 'description': 'Function is "complex" (IE, it has a cyclomatic complexity greater than a defined constant)', 'fn': iscomplex},

    ]

    init_tags()
  29. @psifertex psifertex revised this gist Dec 17, 2020. 1 changed file with 79 additions and 0 deletions.
    79 changes: 79 additions & 0 deletions list_plugins.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,79 @@
    # list plugins
    #
    # 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()
    repos = ["community", "official"]

    html = '''<html>
    <head>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/jq-3.3.1/dt-1.10.22/datatables.min.css"/>
    <script type="text/javascript" src="https://cdn.datatables.net/v/bs4/jq-3.3.1/dt-1.10.22/datatables.min.js"></script>
    <script>'''

    for repo in repos:
    html += f'''$(document).ready( function () {{
    $('#{repo}').DataTable({{
    "paging": false,
    "info": false,
    "searching": false,
    "order": [[2, "desc"], [0, "asc"]]
    }});
    }} );
    '''

    html += f''' </script>
    <style>
    tr[data-state="Update Available"]{{
    color: {getThemeColor(ThemeColor.CyanStandardHighlightColor).name()};
    }}
    tr[data-state="Disabled"]{{
    color: {getThemeColor(ThemeColor.FalseBranchColor).name()};
    }}
    tr[data-state="Enabled"]{{
    color: {getThemeColor(ThemeColor.TrueBranchColor).name()};
    }}
    </style>
    </head>
    <body>
    <div style="margin: 50px">
    '''

    for repo in ["community", "official"]:
    html += f'''<h3>{repo.capitalize()} Plugins</h3>
    <table id="{repo}" class="sortable" cellspacing="0" width="100%">
    <thead>
    <tr>
    <th>Plugin Name</th>
    <th>Version</th>
    <th>Status</th>
    <th>Short Description</th>
    </tr>
    </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>
    </table>
    <hr />
    '''

    html += '''
    </div>
    </body>
    </html>
    '''

    show_html_report('Plugin List', html)
  30. @psifertex psifertex revised this gist Dec 7, 2020. 1 changed file with 32 additions and 0 deletions.
    32 changes: 32 additions & 0 deletions unimplemented
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,32 @@
    # 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]}")