As you may already know1, Hex-Rays decompilers can generate HTML files from pseudocode windows.
That feature, however, is limited to generating HTML for a single function, or a portion of a function.
Recently, one of our customers asked us whether there was a way to generate HTML files for multiple functions all at once. I was at the regret of telling him that, no, we don’t have that feature (and it doesn’t really seem to be of interest to many, since AFAICT we have received no request for it)
However, after the Great Actions Refactoring™, decompiler action are now 1st class IDA citizens (just like any other plugin actions, really.) That means we can now invoke them, just like we could already invoke any IDA core action. We just need to take a few precaution, is all.
Here’s a piece of IDAPython code I hammered into shape, that will go through all the functions of the program and (if the current function is decompilable) will prompt the user for saving:
from idaapi import * from PySide import QtGui, QtCore # Our piece of code relies on the user having already opened a pseudocode view. That's a limitation, but oh well. tform = find_tform("Pseudocode-A") if not tform: raise Exception("Please open a pseudocode view") qwidget = PluginForm.FormToPySideWidget(tform) # Iterate all funcs for fidx in xrange(get_func_qty()): f = getn_func(fidx) try: if decompile(f): # Ok, we can jump there w/o being # switched to "IDA View-A" jumpto(f.startEA) # Needed. W/o that, focus might be # elsewhere, and the 'hx:GenHtml' # will refuse to work. qwidget.setFocus() process_ui_action("hx:GenHtml") except DecompilationFailure: print "Decompilation failure: %x. Skipping." % f.startEA pass
Notes:
A possibly nice improvement to this, would be to know what functions the user selected in the “Functions window”, and iterate over those only, prompting for save.
Here’s how I would go about it, knowing that:
We will:
from idaapi import * from PySide import QtGui, QtCore # Register action class GenMultiHTML(action_handler_t): def __init__(self): action_handler_t.__init__(self) def activate(self, ctx): tform = find_tform("Pseudocode-A") if not tform: raise Exception("Please open a pseudocode view") qwidget = PluginForm.FormToPySideWidget(tform) for fidx in ctx.chooser_selection: f = getn_func(fidx - 1) try: if decompile(f): # ok, we can jump there w/o being # switched to "IDA View-A" jumpto(f.startEA) qwidget.setFocus() process_ui_action("hx:GenHtml") except DecompilationFailure: print "Decompilation failure: %x. Skipping." % f.startEA pass return 1 def update(self, ctx): return AST_ENABLE_FOR_FORM if ctx.form_title == "Functions window" else AST_DISABLE_FOR_FORM register_action( action_desc_t( 'my:gen_multi_html', 'Generate HTML files', GenMultiHTML())) # Listen to 'finish populating popup' hook, to add our # action if the popup is for the "Functions window" class Hooks(idaapi.UI_Hooks): def finish_populating_tform_popup(self, form, popup): if get_tform_title(form) == "Functions window": attach_action_to_popup( form, popup, "my:gen_multi_html", None) hooks = Hooks() hooks.hook()
Happy hacking!
Footnotes
#1: And if you didn’t know: go to a pseudocode window, click on the function’s title (i.e., the first line), and open the context menu. You can also select a portion of text, and generate HTML just for that.