0

For, e.g. disassembler or IDA view:

enter image description here

Decompiler or Hex View:

enter image description here

I can get the decompilation of whole function using something like:

decompiled = ida_hexrays.decompile(ea)

But, in this way I get the complete decompilation, but not the part which is only highlighted.

For. e.g. I want something like - let's say for the instruction:

.text:00000000004011BB                 call    rdx

The corresponding decompilation would only be:

v4 = ((__int64 (__fastcall *)(_QWORD))a2)(v7) + v3;

Any help is appreciated.

1 Answer 1

2

This probably takes more code than it should but here's an approach that could work:

The idea is to use the decompiled function's ctree to narrow down the pseudocode lines you care about. At a glance:

  1. decompile the function containing your ea of interest
  2. use citem_t::find_closest_addr() to find the item most closely matching the instruction at ea
  3. find the citem's parent statement (a cinsn_t) because the item you found could be anything (for example, a var reference that's an arg to a call that is itself an arg to a call.. etc)
  4. once you have your statement, find the corresponding pseudocode lines that match this statement. That also is non-trivial.
    1. each line in the pseudocode (cfunc_t::get_pseudocode()) contains 'embedded' references to the citems that contribute to generating that line
    2. the references are indices into the list of citems cfunc_t::treeitems
    3. You can find a reasonably simple example in the Hex-Rays Block Highlighter plugin (disclaimer: mine)

Here's some code that will find the parent statement for a given ea (steps 1 through 3 above):

def find_parent_cinsn(cfunc, citem):
    if not citem.is_expr():
        return citem
    cinsn = None
    class cvisitor(ida_hexrays.ctree_visitor_t):
        def __init__(self):
            super().__init__(ida_hexrays.CV_FAST | ida_hexrays.CV_PARENTS)

        def visit_expr(self, expr) -> int:
            nonlocal cinsn
            if expr.obj_id == citem.obj_id:
                for parent in reversed(self.parents):
                    if not parent.is_expr():
                        cinsn = parent
                        break
                return 1  # Stop enumeration
            return 0

    cvisitor().apply_to(cfunc.body, None)
    return cinsn


def pseudo_for_ea(ea):
    cfunc = ida_hexrays.decompile(ea)
    citem = cfunc.body.find_closest_addr(ea)
    citem = find_parent_cinsn(cfunc, citem)

    if citem:
        print("Most likely statement for {:X}: {:X}  {}".format(ea, citem.ea, citem.cinsn.opname))

        # Now, cross-ref the pseudocode lines to the citem using the citem
        # references embedded in each line of the cfunc's pseudocode
        #
        # cfunc.citems[] -> 0
        #

Good luck!

1
  • Hey, thanks for your answer! I designed in a way - assuming the first tag contains corresponds to the tag we receive from find_parent_cinsn citem if citem: for item in cfunc.get_pseudocode(): if format(citem.index, "X").zfill(16) in item.line.split()[0]: decomp = ida_lines.tag_remove(item.line) return len(re.findall('\((.*?)\)',decomp)[-1].split(","))
    – R4444
    Apr 26 at 0:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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