In this blog post, we are going to illustrate how to use some of the new UI features introduced in IDA Pro 6.1 (embedded choosers, custom icons, etc…) by writing a VirusTotal reporting and file submission plugin for IDA Pro. The plugin will allow you to get reports from VirusTotal based on the input file MD5 or a file of your choice. The plugin will offer to upload the file if the file was not analyzed before.
The VirusTotal API is web-service that uses HTTP POST requests with JSON object responses. To work with it you need an API key (get one by creating a VT Community account) and a programming language/library that can make HTTP POST requests and is able to parse JSON strings. In this article, we are going to borrow some code from Bryce Boe’s blog entry “Submitting Binaries to VirusTotal” and modify it a bit. The resulting changes can be found in the BboeVt module as part of this article’s files. Our plugin is going to use the get_file_report() to get a report given a file’s MD5 and the scan_file() to submit a new file to VT
Let us first breakdown the plugin requirements into small and simple steps and then at the end we can glue everything together.
Here are the components we need:
We need a simple class to store persistent data. The data store location will be determined using the idaapi.get_user_idadir(). It resolves to “%APPDATA%\Hex-Rays\IDA Pro” on MS Windows and to “~/.idapro” on Linux or Mac OS.
The persistent information we need to store are the apikey and the plugin dialog options. The other configuration fields are computed during runtime:
The chooser control will be a subclass of the Choose2 class. This Python class is a wrapper for the choose2() IDA Pro SDK function. Embedded choosers (introduced in IDA Pro 6.1) allow choosers not only to exist as separate dockable windows but also to be embedded inside forms. Please see Daniel’s post.
Before creating the chooser class, let us illustrate how to work with custom icons:
As you can see, two function calls are involved:
This is the chooser class (important aspects in the code are marked):
To create the chooser it is sufficient to create an instance (and pass the mandatory parameters) then call the Show() method.
The form control is implemented by subclassing the new Form class found in IDAPython >= 1.5.
In essence, the idaapi.Form class wraps around AskUsingForm() IDA Pro SDK function.
If you’ve worked with AskUsingForm() before then you will find it so easy to work with the Form class.
The advantage of using AskUsingForm() or IDAPython’s Form class, instead of operating system UI functions, is that your UI will be portable and will work across platforms and most importantly you don’t need any external dependencies or 3rd party UI libraries installed on the system.
For example, this is how the form will be rendered on Mac OS:
This is how the form creation code looks like (explanation will follow):
The following sections will explain in more details how to use this class.
The form string syntax is based on the description found in kernwin.hpp SDK header. The syntax is slightly different; the difference is that you should describe form controls using special tags (surrounded by { and }). Please search for “Format string for AskUsingForm_c()” inside the kernwin.hpp header file to get more documentation about the form string syntax.
The form string explained:
If you’re curious, this is how the form would look like if we did not using the Form class syntax:
As you see, all the {Control} strings are expanded to the actual syntax required by AskUsingForm() (also notice how the IDs are assigned as well).
All the allowed form controls (input or label controls) are declared as inner-classes in the Form class. When you create the form, you need to pass the form string (as we seen above) and a dictionary of controls with key=ControlName and value=Control_Object_Instance.
Please refer to Form documentation or the ex_askusingform.py example.
Embedded choosers cannot be directly embedded, first you need to create an embedded chooser control and then link it to the embedded chooser instance.
The FormChangeCb control will allow you to specify a callback that will be triggered on form events. Form change callback resemble dialog procedures on MS Windows. This callback will be triggered whenever a form control is focused or changed. From this callback you can hide/enable/move/modify other form controls.
In the code above, we check which control id generated an event and handle actions accordingly.
For example we are enabling/disabling certain checkboxes and handling the “Report” button click by calling the VtReport() function and updating the embedded chooser contents by calling Form.RefreshField().
A form must be compiled with Compile() before it can be displayed with Execute(). No need to compile the form more than once (unless you change the form string). To check if the form is already compiled use the Compiled() function.
It is possible to populate the initial form controls values in two ways:
This is how we show the form (first compile, populate and then display):
Now we need to glue all the components together by writing a plugin_t sub-class (a regular IDA Pro script plugin).
The run() method does the following:
The results shown in a chooser:
The results (but this time docked):
Before using the plugin, you need to do the following things:
Using the plugin:
That’s it! Comments, questions or suggestions are welcome.