def run(self, arg):
     for function in idautils.Functions():
         values = {}
         #function = ida_kernwin.get_screen_ea()
         function_start = idc.get_func_attr(function, idc.FUNCATTR_START)
         function_end = idc.get_func_attr(function, idc.FUNCATTR_END)
         function_name = idc.get_func_name(function)
         if "func" in function_name:
             try:
                 values[function_name] = []
                 for z in re.findall("= (0[xX][0-9a-fA-F]+)",str(ida_hexrays.decompile(function))):
                             values[function_name].append(binascii.hexlify(struct.pack('<Q', int(int(z.replace("0x", ""), base=16)))).decode("windows-1252").replace("00",""))
                             
                            
             except idaapi.DecompilationFailure:
                 pass
                             
             lenght = int(len(values[function_name]) / 2)
             string = self.to_decimal(values[function_name][0:lenght])
             key = self.to_decimal(values[function_name][lenght::])
             str_decrypted = ""
             for i in range(0, len(string)):
                 str_decrypted += chr(string[i] ^ key[i % len(key)])
                 #idaapi.msg(f"{string[i]} ^ {key[i % len(key)]}\n")
             if str_decrypted != "":    
                 #idaapi.msg(str_decrypted+"\n")
                  idc.set_func_cmt(function_start, str_decrypted, 0)
                  rowPosition = self.plg.table.rowCount()
                  self.plg.table.insertRow(rowPosition)
                  self.plg.table.setItem(rowPosition, 0, QtWidgets.QTableWidgetItem(function_name))
                  self.plg.table.setItem(rowPosition, 1, QtWidgets.QTableWidgetItem(str_decrypted))
def main():
    log("plugin run")
    if not is_jni_header_loaded():
        idaapi.warning('Please load jni.h first')
        load_jni_header()
    st = idc.set_ida_state(idc.IDA_STATUS_WORK)
    infos = load_methods()
    failed = []
    succ = 0
    for ea in idautils.Functions():
        fname = idc.get_func_name(ea)
        if fname.startswith('Java_'):
            info = infos.get(fname)
            if info is None:
                failed.append(fname)
            else:
                succ += 1
            apply_signature(ea, info)
        if fname == 'JNI_OnLoad':
            apply_load_unload(ea, True)
            succ += 1
        if fname == 'JNI_OnUnload':
            apply_load_unload(ea, False)
            succ += 1
    idaapi.info('JNI functions loaded, {} success. {} failed. \n{}'.format(
        succ, len(failed), '\n'.join(failed)))
    idc.set_ida_state(st)
Exemple #3
0
def _get_tif_with_guess_type(address: int) -> Optional[ida_typeinf.tinfo_t]:
    """
    Attempt to get the tinfo_t object for the function using the "guess_type" function.

    :raises: RuntimeError on failure.
    :returns: tinfo_t object on success.
    """
    guessed_type = idc.guess_type(address)
    if guessed_type is None:
        return None

    func_name = idc.get_func_name(address)
    if func_name is None:
        return None

    # Documentation states the type must be ';' terminated, also the function name must be inserted
    guessed_type = re.sub(r"\(", f" {func_name}(", f"{guessed_type};")
    set_type_result = idc.SetType(address, guessed_type)
    if not set_type_result:
        logger.warning(
            f"Failed to SetType for function at 0x{address:X} with guessed type {guessed_type!r}"
        )

    tif = ida_typeinf.tinfo_t()
    if not ida_nalt.get_tinfo(tif, address):
        return None
    return tif
def RenameMod(orig, new):
    i = idc.get_next_func(0)
    while (i != BADADDR):
        n = idc.get_func_name(i)
        if n.startswith(orig + "_"):
            RenameFuncWithNewMod(i, new)
        i = NextFunction(i)
Exemple #5
0
def format_rules(fva, rules):
    '''
    given the address of a function, and the byte signatures for basic blocks in
     the function, format a complete YARA rule that matches all of the
     basic block signatures.
    '''
    name = idc.get_func_name(fva)

    # some characters aren't valid for YARA rule names
    safe_name = name
    BAD_CHARS = '@ /\\!@#$%^&*()[]{};:\'",./<>?'
    for c in BAD_CHARS:
        safe_name = safe_name.replace(c, '')

    md5 = idautils.GetInputFileMD5().hex()
    ret = []
    ret.append(f'rule a_{md5}_{safe_name}')
    ret.append('  meta:')
    ret.append(f'    sample_md5 = "{md5}"')
    ret.append(f'    function_address = "0x{fva}"')
    ret.append(f'    function_name = "{name}"')
    ret.append('  strings:')
    for rule in rules:
        formatted_rule = ' '.join(rule.masked_bytes)
        ret.append(f'    {rule.name} = {{{formatted_rule}}}')
    ret.append('  condition:')
    ret.append('    all of them')
    ret.append('}')
    return '\n'.join(ret)
Exemple #6
0
def GetCanonicalName(f):
    n = idc.get_func_name(f)
    parts = n.split("_")
    if len(parts) == 3:
        return parts[1]
    else:
        return None
Exemple #7
0
    def enum_func(self):

        ### iterate to all functions of the malware
        ea = here()
        func_addr = 0
        seg_start = idc.get_segm_start(ea)
        seg_end = idc.get_segm_end(ea)
        for func_addr in idautils.Functions(seg_start, seg_end):
            func_name = idc.get_func_name(func_addr)
            if self.seh_func_name in func_name:
                print("[+] STATUS: Found Needed Function -> {} {}".format(
                    hex(func_addr), func_name))
                break
            else:
                pass
                #print("[-] STATUS: Skipped this Function -> {} {}".format(hex(func_addr),func_name))

        self.find_xref_func(func_addr)

        ### find the ehFuncInfo Address which is the mov address before the jmp to ___CxxFrameHandler
        ### .text:00407B60                 mov     eax, offset stru_408928
        ### .text:00407B65                 jmp     ___CxxFrameHandler

        self.find_ehfuncinfo_addr()

        return
Exemple #8
0
def jtool2_information():
    print("[-] Other method information construction")
    fd = open(kernelcache_path)
    data = fd.readlines()
    fd.close()

    for line in data:
        t = line[:-1].strip()
        addr = int(t.split("|")[0], 0)
        sym = t.split("|")[1]

        segName = idc.get_segm_name(addr)
        if segName != "__TEXT_EXEC:__text" or "." in sym:
            if "__DATA" in segName:
                idaapi.set_name(addr, sym, idaapi.SN_FORCE)
            continue

        if not idau.is_function_start(addr):
            print("[jtool2] Current '{}'' - [{}] is not defined as function".
                  format(sym, hex(addr)))
            if not idau.force_function(addr):
                print("[jtool2] Can't convert '{}' - [{}] to function".format(
                    sym, hex(addr)))
                continue

        curSym = idc.get_func_name(addr)
        if "sub_" in curSym:
            idaapi.set_name(addr, sym, idaapi.SN_FORCE)

    print("[-] Done")
Exemple #9
0
def iter_functions(
    func_names: Union[None, str,
                      List[str]] = None) -> Iterable[Tuple[int, str]]:
    """
    Iterate all defined functions and yield their address and name.
    (This includes imported and dynamically generated functions)

    :param func_names: Filter based on specific function names.

    :yield: (ea, name)
    """
    if isinstance(func_names, str):
        func_names = [func_names]

    # Yield declared functions.
    for ea in idautils.Functions():
        name = idc.get_func_name(ea)
        if (not func_names or name in func_names
                or name.strip("_") in func_names or any(
                    re.match("_*{}_[0-9]?".format(name_), name)
                    for name_ in func_names)):
            yield ea, name

    # Also yield from imported.
    for ea, name, _ in iter_imports(api_names=func_names):
        yield ea, name

    # Yield dynamically resolved functions.
    for ea, name in iter_dynamic_functions():
        if (not func_names or name in func_names
                or name.strip("_") in func_names or any(
                    re.match("_*{}_[0-9]?".format(name_), name)
                    for name_ in func_names)):
            yield ea, name
Exemple #10
0
    def Create(self):
        ea = idc.get_screen_ea()
        if not idaapi.simplecustviewer_t.Create(
                self, '%s - Nao' % (idc.get_func_name(ea))):
            return False
        self.instruction_list = idautils.GetInstructionList()
        self.instruction_list.extend(['ret'])
        self.register_list = idautils.GetRegisterList()
        self.register_list.extend([
            'r8l', 'r9l', 'r10l', 'r11l', 'r12l', 'r13l', 'r14l', 'r15l',
            'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w',
            'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d',
            'eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'rax',
            'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp'
        ])

        f = idaapi.get_func(ea)
        self.fc = idaapi.FlowChart(f)
        self.block_list = []
        for block in self.fc:
            self.block_list.append(format(block.start_ea, 'x').upper())

        self.load(ea)

        action_desc = idaapi.action_desc_t(
            'nao:jump',  # The action name.
            'Jump',  # The action text.
            JumpHandler(self),  # The action handler.
            '',  # Optional: the action shortcut
            '',  # Optional: the action tooltip (available in menus/toolbar)
        )  # Optional: the action icon (shows when in menus/toolbars) use numbers 1-255
        idaapi.register_action(action_desc)
        idaapi.attach_action_to_popup(self.GetWidget(), None, 'nao:jump', None)
        return True
def apply_load_unload(ea, load=True):
    name = idc.get_func_name(ea)
    log('apply 0x%x %s', ea, name)
    decl = "{} {}(JavaVM *vm, void *reserved)".format(
        "jint" if load else "void", "JNI_OnLoad" if load else "JNI_OnUnload")
    prototype_details = idc.parse_decl(decl, idc.PT_SILENT)
    idc.apply_type(ea, prototype_details)
Exemple #12
0
        def make_new_name(start_addr, end_addr, off_new_name, off_func_addr):
            # offset1 -> handle string -> get new func name
            # offset2 -> handle func   -> get func addr
            for addr in range(start_addr, end_addr, off_new_name):
                # first addr is string using to new func name
                name_addr = [ref for ref in idautils.DataRefsFrom(addr)]
                if len(name_addr) < 1:
                    frn_log("can't get name addr")
                    continue

                new_name = idc.et_strlit_contents(name_addr[0])
                frn_log("Get new func name is :{}".format(new_name))

                # Get the address of the function to be renamed
                # name_addr = [ref for ref in DataRefsFrom(0x5B200)][0]
                func_addr = [
                    ref for ref in idautils.DataRefsFrom(addr + off_func_addr)
                ][0]
                # for xref in idautils.XrefsFrom(addr+off_func_addr, 0):
                #     func_addr = xref.to

                # --- Check if the function needs to be renamed
                old_name = idc.get_func_name(func_addr)
                if 'sub_' not in old_name:
                    frn_log("The function has been renamed")
                    continue

                name = 'func_' + new_name.decode()
                frn_log("The new func name is :{}".format(new_name))
                frn_log("The func addr is :{:#x}".format(func_addr))
                idc.set_name(func_addr, name)
Exemple #13
0
    def activate(self, ctx):
        import json

        filepath = ida_kernwin.ask_file(False, "*.zmu;*.overlay;*",
                                        "Load Zelos Overlay...")
        if filepath is None:
            return
        f = open(filepath, "r")
        zelos_data = f.read()
        f.close()

        zelos_data = zelos_data[len("DISAS\n"):]
        zelos_dump = json.loads(zelos_data)

        # Apply the overlay data
        for comment in zelos_dump["comments"]:
            ea = comment["address"]
            try:
                comment_text = str(comment["text"])
            except UnicodeEncodeError:
                comment_text = ""
            color = comment.get("color", 0x73F0DF)

            # Set color of instruction line
            idaapi.set_item_color(ea, color)
            idaapi.set_cmt(ea, comment_text, False)

            # Set function name if not already changed
            idc.get_func_attr(ea, idc.FUNCATTR_START)
            name = idc.get_func_name(ea)
            if len(name) > 0 and name.startswith("zmu_") is False:
                idc.set_name(ea, "zmu_" + name)

        return 1
def _get_function_tif_with_guess_type(offset):
    """
    Attempt to get the tinfo_t object of a function using the "guess_type" function.

    :param offset: Offset of function.
    :raises: RuntimeError on failure.
    :returns: tinfo_t object on success.
    """
    tif = ida_typeinf.tinfo_t()

    guessed_type = idc.guess_type(offset)
    if guessed_type is None:
        raise RuntimeError(
            "Failed to guess function type for offset 0x{:X}".format(offset))

    func_name = idc.get_func_name(offset)
    if func_name is None:
        raise RuntimeError(
            "Failed to get function name for offset 0x{:X}".format(offset))

    # Documentation states the type must be ';' terminated, also the function name must be inserted
    guessed_type = re.sub(r"\(", " {}(".format(func_name),
                          "{};".format(guessed_type))
    set_type_result = idc.SetType(offset, guessed_type)
    if not set_type_result:
        logger.warning(
            "Failed to SetType for function at 0x{:X} with guessed type {!r}".
            format(offset, guessed_type))
    # Try one more time to get the tinfo_t object
    if not ida_nalt.get_tinfo(tif, offset):
        raise RuntimeError(
            "Failed to obtain tinfo_t object for offset 0x{:X}".format(offset))

    return tif
Exemple #15
0
    def scanDatabase(self, json_configuration):
        configuration = ""

        try:
            configuration = json.loads(json_configuration)
        except:
            print("IDA Function Tagger: Invalid configuration file")
            return

        print("IDA Function Tagger: Loading configuration: %s" %
              configuration["name"])

        print("IDA Function Tagger: Configuration comment: %s" %
              configuration["comment"])

        for tag in configuration["tag_list"]:
            print("IDA Function Tagger: Scanning for tag '%s'..." %
                  tag["name"])

            for imported_function in tag["import_list"]:
                function_address = idc.get_name_ea_simple(
                    str(imported_function))

                if function_address == BADADDR:
                    continue

                cross_reference_list = idautils.CodeRefsTo(function_address, 0)
                for xref in cross_reference_list:
                    function_name = idc.get_func_name(xref)
                    self._addTagToFunction(function_name, str(tag["name"]))
Exemple #16
0
    def update(self):
        global OPEN_TAG
        global CLOSE_TAG
        global TAG_SEPARATOR

        self.clear()

        for function_address in idautils.Functions():
            function_comment = idc.get_func_cmt(function_address, False)

            tag_list_start = function_comment.find(OPEN_TAG)
            if tag_list_start == -1:
                continue

            tag_list_end = function_comment.find(CLOSE_TAG, tag_list_start)
            if tag_list_end == -1:
                continue

            tag_list = function_comment[tag_list_start +
                                        len(OPEN_TAG): tag_list_end]
            if len(tag_list) == 0:
                continue

            current_function_name = idc.get_func_name(function_address)
            self._function_list[current_function_name] = tag_list.split(
                TAG_SEPARATOR)

            tag_list = tag_list.split(TAG_SEPARATOR)
            for tag_name in tag_list:
                if tag_name not in self._tag_list:
                    self._tag_list[tag_name] = []

                self._tag_list[tag_name].append(current_function_name)
Exemple #17
0
def find_game_init():
    strings = idautils.Strings()
    
    taint_ea = None
    
    # Find the string which is referenced only in CGameUI::Initialize
    for i in strings:
        if taint_ea is None and str(i) == 'Whether taint logging is enabled':
            taint_ea = i.ea
            break
            
    if taint_ea is None:
        raise RuntimeError('Unable to find CGGameUI::Initialize (1)')
        
    refs = list(idautils.DataRefsTo(taint_ea))
    
    if len(refs) != 1:
        raise RuntimeError('Unable to find CGGameUI::Initialize (2)')
    
    func_start = find_func_containing(refs[0])
    func_name = idc.get_func_name(func_start)
    
    mangled_name = '__ZN8CGGameUI10InitializeEv'
    
    if func_name != mangled_name:
        idc.set_name(func_start, mangled_name, SN_CHECK)

    print('CGGameUI::Initialize:  0x%x ' % func_start)
        
    return func_start
Exemple #18
0
def apply_signature(ea, sig):
    name = idc.get_func_name(ea)
    ret, args = sig
    log('apply 0x%x %s', ea, name)
    decl = '{} {}({})'.format(ret, name, args)
    # log(decl)
    prototype_details = idc.parse_decl(decl, idc.PT_SILENT)
    # idc.set_name(ea, name)
    idc.apply_type(ea, prototype_details)
Exemple #19
0
def PrefixRange(start, end, prefix):
    x = start
    while x < end:
        n = idc.get_func_name(x)
        if n.startswith("sub_"):
            nn = prefix + n
            print "Renaming %s to %s\n" % (n, nn)
            ida_name.set_name(x, nn)
        x = NextFunction(x)
def function_xrefs(name):
    import idc
    import idautils
    functions_that_exit = []
    wf_addr = idc.get_name_ea_simple(name)
    print hex(wf_addr), idc.generate_disasm_line(wf_addr, 0)
    for addr in idautils.CodeRefsTo(wf_addr, 0):
        functions_that_exit.append(idc.get_func_name(addr))
    return functions_that_exit
Exemple #21
0
def get_xref_code_to_func(func_addr):
    a = idautils.XrefsTo(func_addr, 1)
    addr = {}
    for xref in a:
        frm = xref.frm  # ea in func
        start = idc.get_func_attr(frm, idc.FUNCATTR_START)  # to_xref func addr
        func_name = idc.get_func_name(start)  # to_xref func name
        addr[func_name] = [xref.iscode, start]
    return addr
Exemple #22
0
    def get_conflict(self):
        """

        :return: None if there's no conflict, empty string if there's no change, data if there's a change.
        """
        # TODO: Fill docstring, plus, make the function return 0,1,2 and save the current data by itself.
        if not idc.get_func_name(self.address):
            return None
        return ''
Exemple #23
0
def CompileFuncNamesFromRangeAsText(start, end, sep):
    x = start
    s = ""
    while (x <= end):
        n = idc.get_func_name(x)
        if (not n.startswith("sub_")):
            s += " " + sep + " " + n
        x = NextFunction(x)
    return s
Exemple #24
0
def RenameRangeWithAddr(start, end, s):
    x = start
    while (x <= end):
        n = idc.get_func_name(x)
        if (n.startswith("sub_")):
            RenameFuncWithAddr(x, s)
        else:
            NameCanonical(x, s, n)
        x = NextFunction(x)
Exemple #25
0
def track_ke_event_callback_set():
    logger = CustomLogger()
    m = CodeEmulator()
    at = ArgumentTracker()

    event_dict = {}

    target_addr = idaapi.get_name_ea(idaapi.BADADDR, "ke_event_callback_set")
    print "ke_event_callback_set: 0x{:X}".format(target_addr)
    for xref in XrefsTo(target_addr, 0):
        frm_func = idc.get_func_name(xref.frm)

        r1_ret = at.track_register(xref.frm, "r1")
        r0_ret = at.track_register(xref.frm, "r0")
        if r0_ret.has_key("target_ea") and r1_ret.has_key("target_ea"):

            start_ea = min(r0_ret['target_ea'], r1_ret['target_ea'])

            if m.emulate(start_ea, xref.frm):
                r1 = m.mu.reg_read(UC_ARM_REG_R1)
                r0 = m.mu.reg_read(UC_ARM_REG_R0)
                callback_func_name = idc.get_func_name(r1)

                if callback_func_name == "":
                    define_func(r1, "event_{}_callback_func".format(r0))
                    callback_func_name = idc.get_func_name(r1)

                if r1 & 1:
                    r1 -= 1
                event_dict[r0] = r1
                logger.log(
                    "addr: 0x{:X}, event: 0x{:X}, callback: {} @ 0x{:X}".
                    format(xref.frm, r0, callback_func_name, r1))

    target_addr = idaapi.get_name_ea(idaapi.BADADDR, "ke_event_set")
    print "ke_event_set: 0x{:X}".format(target_addr)
    for xref in XrefsTo(target_addr, 0):
        r0_ret = at.track_register(xref.frm, "r0")
        if r0_ret.has_key("target_ea"):
            start_ea = r0_ret['target_ea']
            if m.emulate(start_ea, xref.frm):
                r0 = m.mu.reg_read(UC_ARM_REG_R0)
                logger.log("addr: 0x{:X}, use event: {}".format(xref.frm, r0))
                add_ref(xref.frm, event_dict[r0])
Exemple #26
0
def strip_names(name_dict_path):
    names = {}
    for i, func_ea in enumerate(idautils.Functions()):
        n = idc.get_func_name(func_ea)
        new_name = "f_{i}".format(i=i)
        names[n] = new_name
        idc.set_name(func_ea, new_name)
    with open(name_dict_path, "w") as f:
        json.dump(names, f, indent=4)
    return names
Exemple #27
0
def _getArgsDescription(ea: int) -> str:
    name = demangle_name(get_func_name(ea), get_inf_attr(INF_SHORT_DN))  # get from mangled name
    if not name:
        name = get_type(ea)  # get from type
        if not name:
            return parse_function_args(ea)  # cannot get params from the mangled name
    args_start = name.find('(')
    if args_start is not None and args_start != (-1):
        return name[args_start:]
    return ""
Exemple #28
0
def _getFunctionNameAt(ea: int) -> str:
    name = get_func_name(ea)
    disable_mask = get_inf_attr(INF_SHORT_DN)
    demangled_name = demangle_name(name, disable_mask)
    if demangled_name is None:
        return name
    args_start = demangled_name.find('(')
    if args_start is None:
        return demangled_name
    return demangled_name[:args_start]
Exemple #29
0
def obtain_function_by_name(func_name):
    """
    Obtain a function in the list of functions for the application by name, or idc.BADADDR.

    :param func_name: Name of function to obtain

    :return: start_ea of function or idc.BADADDR
    """
    for func in idautils.Functions():
        if func_name == idc.get_func_name(func):
            return func
    return idc.BADADDR
Exemple #30
0
 def __init__(self, frm_va, to_va, old_to_va):
     """Create a new ObjcMethodXref object
     
     Arguments:
         frm_va {number} -- Virtual address location of the reference
         to_va {[type]} -- Virtual address that is pointed to by the reference
         old_to_va {[type]} -- Virtual address that was pointed to by the reference prior to patching
     """
     self.frm_va = frm_va
     self.to_va = to_va
     self.old_to_va = old_to_va
     self.method_name = get_func_name(self.to_va)
Exemple #31
0
    def get_items_for_ea(self, ea):

        frm = [x.frm for x in idautils.XrefsTo(self.__ea)]

        items = []
        for ea in frm:
            try:
                cfunc = idaapi.decompile(ea)

                self.functions.append(cfunc.entry_ea)
                self.items.append((ea, idc.get_func_name(cfunc.entry_ea), self.get_decompiled_line(cfunc, ea)))

            except Exception as e:
                print('could not decompile: %s' % (str(e), ))
                raise

        return
Exemple #32
0
def get_symbol_name(from_ea, ea=None, allow_dummy=False):
  if ea is None:
    ea = from_ea

  global _FORCED_NAMES
  if ea in _FORCED_NAMES:
    return _FORCED_NAMES[ea]

  flags = idc.get_full_flags(ea)
  if not allow_dummy and idaapi.has_dummy_name(flags):
    return ""

  name = ""
  try:
    name = name or idc.get_name(ea, 0) #calc_gtn_flags(from_ea, ea))
  except:
    pass

  try:
    name = name or idc.get_func_name(ea)
  except:
    pass

  return name
Exemple #33
0
    def get_items_for_type(self):

        x = self.target.operands['x']
        m = self.target.operands['m']

        xtype = x.type
        xtype.remove_ptr_or_array()
        typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '')

        addresses = []
        for ea in idautils.Functions():

            try:
                cfunc = idaapi.decompile(ea)
            except:
                print('Decompilation of %x failed' % (ea, ))
                continue

            str(cfunc)

            for citem in cfunc.treeitems:
                citem = citem.to_specific_type
                if not (type(citem) == idaapi.cexpr_t and citem.opname in ('memptr', 'memref')):
                    continue

                _x = citem.operands['x']
                _m = citem.operands['m']
                _xtype = _x.type
                _xtype.remove_ptr_or_array()
                _typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, _xtype, '', '')

                #~ print 'in', hex(cfunc.entry_ea), _typename, _m

                if not (_typename == typename and _m == m):
                    continue

                parent = citem
                while parent:
                    if type(parent.to_specific_type) == idaapi.cinsn_t:
                        break
                    parent = cfunc.body.find_parent_of(parent)

                if not parent:
                    print('cannot find parent statement (?!)')
                    continue

                if parent.ea in addresses:
                    continue

                if parent.ea == idaapi.BADADDR:
                    print('parent.ea is BADADDR')
                    continue

                addresses.append(parent.ea)

                self.functions.append(cfunc.entry_ea)
                self.items.append((
                        parent.ea,
                        idc.get_func_name(cfunc.entry_ea),
                        self.get_decompiled_line(cfunc, parent.ea)))


        return []