Writing Scripts with Sidekick¶
Sidekick provides an interface through the Automation Workbench
to create, refine, and run scripts that blend both Python code and the capabilities of large language models (LLMs) to automate repeated tasks.
Elements of the Automation Workbench¶
Scripts¶
At the most fundamental level, a script in the Automation Workbench is Python code. The script executes within an environment that has built-in access to both the Binary Ninja Python API and a set of Sidekick Python APIs that include the following functionality:
- Perform a task carried out by a large language model
- Define parameters for the script
- Query the binary using BNQL
- Read from and write to Indexes
- Display progress
Since scripts are just Python code, you can do anything with them that you can with Python, provided you import and install the necessasary dependencies into your Python environment. Since scripts have access to the full Binary Ninja Python API, anything you can do within Binary Ninja using the Python API, you can do with a script (including modifying the binary).
One of the powerful features of the Automation Workbench is that it allows you to blend the capabilities of LLMs with Python code to automate tasks that would otherwise be difficult or time-consuming to do manually. This is accomplished through the use of LLM Operators
. To learn more about them and how to use them in your scripts, refer to LLM Operators.
Scripting Assistant¶
The Automation Workbench includes an AI-powered Scripting Assistant that provides interactive assistance for creating and refining scripts based on user request. The Scripting Assistant performs the following tasks:
- Interpret the user's requests within the context of the conversation and generate Python code that implements the given request
- Determine what LLM Operators are necessary for the described task and automatically generate the necessary LLM Operator definitions and their uses in the script
- Inspect the script's execution output as part of the conversation context (so that it can refine the script based on the output)
Scripts Tab¶
The Automation Workbench contains the Scripts
tab that has the following modes of operation:
- Search Mode: Allows users to search for existing scripts and run, edit, or delete them; or describe a task to generate a new script
- Edit Mode: Allows users to create, refine, and run scripts with optional support from the Scripting Assistant
Search Mode¶
The Scripts
tab of the Automation Workbench opens in Search Mode
by default. This mode provides the following UI elements:
- Search text box for entering a search term to find existing scripts, or enter a task description for a new script
- List of existing scripts that can be sorted by title, last modified, or last executed
- Hamburger menu for additional actions:
- New Script: Create a new script
- Sort by: Sort the list of scripts by title, last modified, or last executed
Run
button for executing selected scripts
Actions¶
The Search Mode
provides the following actions:
Action | Description | Steps |
---|---|---|
Search | Filters existing scripts based on a search term | Enter a search term in the search text box |
New Script from Description | Creates a new script from a task description, switches to Edit Mode, and prompts the Scripting Assistant to generate script code for the task | Enter a new task description in the search text box and press Enter |
Import Scripts | Imports scripts into the Workbench from a .sidekick-scripts file | Click the hamburger menu, select Import Scripts... , and select the sidekick-scripts file to import |
Export Scripts | Exports selected scripts to a .sidekick-scripts file | Select script(s), right-click the selection and select Export Scripts... or click the hamburger menu and select Export Selected Scripts... . In the Export Scripts dialog, click Export . (Note: Check option to include script revision history and Scripting Assistant messages if needed.) |
Filter by Active Binary Views | Filters the list of scripts to only show those associated with the currently active binary views | Click the hamburger menu and select Filter by Active Binary Views |
Associate Scripts with Binary | Associates the selected script(s) with the current binary | Select script(s), right-click the selection and select Associate with <binary> . (Note: This action associates the script(s) with the current binary, allowing them to be filtered using the Filter by Active Binary Views option.) |
Run Script(s) | Executes the selected script(s) | Select script(s) and press Cmd + Enter (on MacOS) or Cntrl + Enter (on Windows/Linux); or right-click the selected script(s) and select Run Script |
Edit Script | Opens the selected script in Edit Mode | Double-click the script, select the script and press Enter , right-click the selected script and select Edit Script , or select the script and press Cmd + ] (on MacOS) or Cntrl + ] (on Windows/Linux) |
Delete Script(s) | Deletes the selected script(s) | Select script(s), right-click it, and select Delete Script |
New Empty Script | Creates a new empty script | Click the hamburger menu and select New Script |
Sort by | Sorts the list of scripts by title, last modified, or last executed | Click the hamburger menu and select the desired sort option |
Note
When new scripts are added or imported into the script database, the list of scripts may not automatically update. One method for updating them is to enter any search term and then clear the search box.
Note
Scripts are executed sequentially from a queue as they are selected for execution by the user. Consequently, the user can queue up a script for execution while another is currently executing.
Edit Mode¶
The Scripts
tab of the Automation Workbench can be switched to Edit Mode
by selecting an existing script and performing one of the following actions:
- Double-click the script
- Select the script and press
Enter
- Right-click the selected script and select
Edit Script
Edit Mode
provides the following UI elements:
- Left arrow button for returning to
Search Mode
- Title text box for setting the title of the script
Run
button for executing the script codeCancel
button for canceling the execution of the script code (only while running)Revisions
drop-down combobox for viewing revisions of the script codeMain
tab for editing the script codeOperator: <llm_operator_name>
tab(s) containing a form for editing the LLM Operator (if included, one for each defined LLM Operator)- Name: Unique identifier used to reference the LLM Operator
- Task Description: Textual high-level description of the task for the LLM Operator
- Model Name: Name of the model used for this LLM Operator
- Prompt Definition:
- Input Variables: JSON description of variables required by the prompt instructions
- Instructions: Plain text description of the instructions for the LLM to follow for the task
- Output Schema: JSON description that defines the format of the desired output generated by the LLM
Scripting Assistant
chat widget for interactions with the Scripting Assistant:- Message box for entering a request to the Scripting Assistant
- Chat history for viewing the conversation with the Scripting Assistant
- Context Menu:
Revert script to here
: Reverts the script code to the revision associated with the selected message
- Output widget for displaying separate tabs for
Output
andExecution Details
for an execution - Hamburger menu for additional actions:
Show Chat
: Displays/hides the Scripting Assistant chat widgetShow Output
: Displays/hides the output widgetDelete Script
: Deletes the current scriptClone Script
: Makes a copy of the current scriptShow Snippet Code
: Displays the code necessary to run the current script from a code snippetAssociate with <binary>
: Associates the current script with the currently active binary viewDisassociate from <binary>
: Disassociates the current script from the currently active binary viewConfigure LLMs...
: Opens the LLM Operator Model CatalogCode Preferences...
: Sets coding preferences for the script (stored in the Binary Ninja settingsidekick.workbench.code_preferences
)Submit Feedback...
: Opens a dialog for submitting feedback on the Automation Workbench
Actions¶
The Edit Mode
provides the following actions:
Action | Description | Steps |
---|---|---|
Return to Search Mode | Returns to Search Mode | Click the left arrow button at the front of the title text box, or press Cmd + [ (on MacOS) or Cntrl + [ (on Windows/Linux) |
Set Script Title | Sets the title of the script | Enter the new title in the title text box |
Edit Script Code | Edits the script code | Enter text in the Main code editor |
Edit LLM Operator | Edits an LLM Operator definition | Select an Operator: <llm_operator_name> tab to edit, and apply edits in the form |
View Revisions | Views the revisions of the script code | Click the Revisions drop-down combobox and select a specific revision |
Save Revisions | Saves revisions of the script code | Revisions are automatically saved when the script is created, the Scripting Assistant updates the code, the Run or Build action is selected, or the user switches to Search/Edit Mode |
Run Script | Executes the current script code | Click the Run button. During execution of the script code, output will be displayed in the Output tab of the Output widget. |
Cancel Execution | Cancels the execution of the current script code | Click the Cancel button (only while running) |
Send Message | Sends a message containing a request for the Script Assistant to complete based the conversation context | Enter a request in the Message box and press Enter or click the Send a message button |
Revert Script to Here | Reverts the script code to the revision associated with the selected message in the chat history | Right-click a message in the chat history and select Revert script to here |
Clone Script | Makes a copy of the current script | Click the hamburger menu and select Clone Script . This action copies the current script with a new title and opens the new script in Edit Mode. |
Delete Script | Deletes the current script | Click the hamburger menu and select Delete Script . This action deletes the script and switches to Search Mode. |
Show Snippet Code | Displays the code necessary to run the current script from a code snippet | Click the hamburger menu and select Show Snippet Code . This action opens a dialog window that contains the code necessary to run the current script from a code snippet, which includes the UUID of the script. This allows a user to run the script programmatically using the API. |
Show Chat | Displays/hides the Scripting Assistant chat widget | Click the hamburger menu and select Show Chat |
Show Output | Displays/hides the output widget | Click the hamburger menu and select Show Output |
Associate with |
Associates the current script with the currently active binary view | Click the hamburger menu and select Associate with <binary> . This action associates the script with the current binary, allowing it to be filtered using the Filter by Active Binary Views option in Search Mode. |
Disassociate from |
Disassociates the current script from the currently active binary view | Click the hamburger menu and select Disassociate from <binary> . This action disassociates the script from the current binary, allowing it to be filtered out using the Filter by Active Binary Views option in Search Mode. |
Configure LLMs | Opens the LLM Operator Model Catalog | Click the hamburger menu and select Configure LLMs... |
Set Code Preferences | Sets coding preferences for the script | Click the hamburger menu and select Code Preferences... . In the Code Writing Preferences dialog window that opens, enter instructions that capture the preferences you want and click Save . |
Submit Feedback | Opens a dialog for submitting feedback on the Automation Workbench | Click the hamburger menu and select Submit Feedback... . This action opens a Feedback dialog window. Select whether or not the script accomplished your task and provide details on what worked or didn't work. Click Submit when finished. |
Execution Monitor Tab¶
The Automation Workbench contains the Execution Monitor
tab that displays the execution history of scripts. This tab includes a table that lists details for each script execution, including the following columns:
- Status: Indicates the current status of the script execution
- Started: Timestamp for when the script execution started
- Finished: Timestamp for when the script execution finished
- Script: Title of the script that was executed
- Binary: Name of the binary that the script was executed on
Actions¶
The Execution Monitor
tab provides the following actions:
Action | Description | Steps |
---|---|---|
Cancel Execution | Cancels the execution of a script that is currently running | Right-click the script execution entry and select Cancel Execution |
Clear History | Clears the execution history table | Right-click the Execution History table and select Clear History |
Handling Script Errors¶
Sometimes scripts will encounter errors during execution, which are displayed in the Output tab within Edit Mode
. The Scripting Assistant has access to this output to help refine the script and resolve errors, but it needs to be instructed to do something about it. When this happens, send a message to the Scripting Assistant to let it know about the error (e.g. "An error occurred" or "Please fix that error").
Setting Code Generation Preferences¶
The Binary Ninja setting sidekick.workbench.code_preferences
is used to store the code generation preferences for the Scripting Assistant. These preferences are used to generate code that aligns with your coding style and requirements. They are set from the Set Code Preferences
action within Edit Mode
(described above).
Setting Revisions to Keep¶
The Binary Ninja setting sidekick.workbench.revisions_to_keep
is used to set the number of revisions to keep for each script when not associated with conversation messages (default=5). These are revisions that the user applies manually to a script. All revisions generated by the Scripting Assistant as a result of conversation messages are kept.
Writing Scripts¶
Defining Parameters¶
When writing scripts, you can define parameters that can be passed to the script when it is executed. This allows you to create reusable scripts that can be customized based on the input parameters. When creating a new script from the Scripts
tab in Search Mode
, the script editor will include a default set of parameters that can be modified within the script tool definition. You can add, remove, or change the parameters as needed.
Example default script tool definition with parameters:
tool = {
"name": "my_tool",
"description": "my tool description",
"parameters": {
"properties": {
"arg1": {
"type": "string",
"description": "my arg1 description",
"default": "my default value"
}
},
"required": []
}
}
try:
# `get_tool_arguments` returns a dict containing the arguments
args = get_tool_arguments(tool)
except Exception as e:
print(f"Error: {e}")
exit(1)
# ... your code here ...
get_tool_arguments()
API defined above.
Querying Using BNQL¶
From within your scripts, you can use the Binary Ninja Query Language (BNQL) to search for items in the binary. The query_binary()
API defined below allows you to perform BNQL queries on a BinaryView object.
def query_binary(bv: BinaryView, query: str, limit: Optional[int] = None, time_limit_secs: Optional[int] = 30) -> Generator[Any, None, None]:
"""
Search for objects in the binary view that match the given query.
:param bv: The BinaryView to search.
:param query: The query to search.
:param limit: The maximum number of objects to return.
:param time_limit_secs: The maximum time in seconds to spend evaluating the query. If None, there is no time limit.
Examples:
```python
# Search for all functions in the binary view.
query_binary(bv, '/function')
# Search for all data variables that start with "g_var" or "f_var".
query_binary(bv, '/data[@name~=r"g_var.*|f_var.*"]')
# Search for all strings that contain "http".
query_binary(bv, '/string[@value~=".*http.*"]')
# Search with a time limit of 5 seconds.
query_binary(bv, '/function', time_limit_secs=5)
```
"""
Accessing Indexes¶
From within a script, you can access Indexes to store and retrieve entries related to your analysis.
Opening Indexes¶
In order to access an Index, you first need to open it. You can do this using the open_index()
API defined below:
def open_index(bv: BinaryView, index_name: str, mode: IndexMode = IndexMode.WRITE, source_id: Optional[str] = None):
"""
Opens an index for writing or appending entries.
:param bv: The BinaryView to which the index pertains.
:param index_name: The name of the index to open.
:param mode: The mode in which to open the index.
:param source_id: The unique identifier of the source script that is writing to the index.
"""
Example usage of open_index()
to open an index named "My Index":
Opening an index in either IndexMode.READ
or IndexMode.WRITE
will create the index if it does not already exist. If the index already exists, it will be opened in the specified mode.
Writing to Indexes¶
To write to an opened Index, you can use the add_entry()
method of the index
object to add an entry and optional metadata. The entry is a Binary Ninja API object (e.g., Function, Variable, String, Symbol, HighLevelILInstruction, BasicBlock, etc), and metadata is a dictionary containing additional information about the entry.
Example usage of writing to an index:
with open_index(bv, 'All Functions', mode=IndexMode.WRITE) as index:
for func in bv.functions:
entry = func
insn_cnt = len(list(func.instructions))
metadata = {"instruction_count": insn_cnt}
index.add_entry(entry, metadata)
Reading from Indexes¶
To read from an opened Index, you can iterate over the entries in the index using the index
object returned by open_index()
. The index
object provides access to the entries stored in the index, which includes the address, object, and metadata associated with each entry.
Example usage of reading from an index:
with open_index(bv, 'High-Level Functions', mode=IndexMode.READ) as index:
for entry in index:
print(f"Address: {entry.address:#x}, Object: {entry.object}, Metadata: {entry.metadata}")
Displaying Progress¶
You can display progress in your script using the notify_progress()
API defined below:
def notify_progress(current: int, total: int, message: str):
"""
Displays a progress message in the Automation Workbench.
:param current: The current progress value (e.g., the current iteration).
:param total: The total value for the progress (e.g., the total number of iterations).
:param message: The message to display with the progress.
"""
Example usage of notify_progress()
to display progress in a script:
funcs = list(bv.functions)
for i, func in enumerate(funcs)
notify_progress(i, len(funcs), f"Processing Function: {func.name}")
# Perform some operation on the function...
Progress messages can be viewed in the following locations while a script is running:
- In the area above the script editor widget within the
Scripts
tab while inEdit Mode
- In the
Status
column of the Execution History table within the Execution Monitor tab while inSearch Mode