I would like to automate calling the DeepScanVariable function from the HexRaysPyTools right-click menu (that serves to reconstruct structures).

I have changed the arguments types for a list of functions, based on data gathered at run-time. Now, I would like to go over that list of functions, and for each argument of a given type, select that argument, right-click, and select Deep Scan Variable.

What that HexRaysPyTools function does is roughly:

def activate(self, ctx):
    hx_view = idaapi.get_widget_vdui(ctx.widget)
    obj = api.ScanObject.create(hx_view.cfunc, hx_view.item)

I already found the action name by calling idaapi.get_registered_actions(). Then I give focus to the decompilation view, to make get_widget_vdui happy and fire the action:

widget = idaapi.find_widget('Pseudocode-A')
idaapi.activate_widget(widget, 1)

What's missing is that I'm supposed to select the item, so that hx_view.item has the correct value and I cannot find any way to do that. I can iterate over arguments of a decompiled function just fine, I just cannot find a way to actually mark an item as selected.

1 Answer 1


If you look closer at that code in HexRaysPyTools, you'll see the following:

    def create(cfunc, arg):
        # Creates object suitable for scaning either from cexpr_t or ctree_item_t
        if isinstance(arg, idaapi.ctree_item_t):
            # ... code for ctree_item_t ...
            cexpr = arg

        if cexpr.op == idaapi.cot_var:
            lvar = cfunc.get_lvars()[cexpr.v.idx]
            result = VariableObject(lvar, cexpr.v.idx)
            result.ea = ScanObject.get_expression_address(cfunc, cexpr)
            return result

So if you can get your hands on a cexpr_t containing the lvar_t that you want, you're good to go. For example, you could write a small visitor class whose visit_expr method looks for cexpr_t objects of type cot_var, whose .var field refers to the lvar_t object that you want. Alternatively, you could perhaps edit the code to accept a raw lvar_t (though pay close attention to the call to ScanObject.get_expression_address).

What I would do would be to edit the code so that it reads as follows:

def create(cfunc, arg):
    # Creates object suitable for scaning either from cexpr_t or ctree_item_t OR lvar_t
    if isinstance(arg, idaapi.lvar_t):
        index = list(cfunc.get_lvars()).index(arg)
        return VariableObject(arg, index)
    # ... rest of function as before ...

Then you can simply call the function above with an lvar_t object you get from mba_t::vars. You can use mba_t::argidx to look up arguments by their index, and if you need to look up a variable by location, note that lvar_t derives from lvar_locator_t, which in turn contains a vdloc_t (which derives from argloc_t). I.e., you can use lvar_t::location to inspect the physical location of a given lvar_t if you need to look up arguments by location instead of by numeric index.

In general, it seems like you've made a lot of progress getting to this point. Don't let the Hex-Rays SDK scare you; if HexRaysPyTools doesn't do what you want, try modifying it. If that still doesn't work, read the code deeper to figure out why not, and reimplement the logic if you have to.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.