コード例 #1
0
def Heads(start=idaapi.cvar.inf.minEA, end=idaapi.cvar.inf.maxEA):
    """
    Get a list of heads (instructions or data)

    @param start: start address (default: inf.minEA)
    @param end:   end address (default: inf.maxEA)

    @return: list of heads between start and end
    """
    ea = start
    if not idc.isHead(idc.GetFlags(ea)):
        ea = idaapi.next_head(ea, end)
    while ea != idaapi.BADADDR:
        yield ea
        ea = idaapi.next_head(ea, end)
コード例 #2
0
def Heads(start=idaapi.cvar.inf.minEA, end=idaapi.cvar.inf.maxEA):
    """
    Get a list of heads (instructions or data)

    @param start: start address (default: inf.minEA)
    @param end:   end address (default: inf.maxEA)

    @return: list of heads between start and end
    """
    ea = start
    if not idc.isHead(idc.GetFlags(ea)):
        ea = idaapi.next_head(ea, end)
    while ea != idaapi.BADADDR:
        yield ea
        ea = idaapi.next_head(ea, end)
コード例 #3
0
ファイル: enumerators.py プロジェクト: nihilus/idascripts
def Texts(*args):
    """
    Enumerate text search matches

    @param <range>: see getrange
    @param searchstr:    string or regex
    @param flags:        for instance SEARCH_REGEX

    @return: list of addresses matching searchstr

    Example::

        for ea in Texts(FirstSeg(), BADADDR, "LDR *PC, =", SEARCH_REGEX):
            f = idaapi.get_func(ea)
            if f and f.startEA==ea:
                n= idaapi.get_name(BADADDR, ea)
                if not n.startswith("sub_"):
                    MakeName(ea, "j_%s" %n)

    Will search for functions containing only  "LDR PC, =xxxxx",
    and rename them as j_XXXXX.
    """
    (first, last)= getrange(args)
    i= getstringpos(args)
    if i<0:
        raise Exception("missing searchstring")

    searchstr= args[i]
    flags = args[i+1] if i+1<len(args) else 0

    ea= idaapi.find_text(first, 0, 0, searchstr, idaapi.SEARCH_DOWN|flags)
    while ea!=idaapi.BADADDR and ea<last:
        yield ea
        ea= idaapi.find_text(idaapi.next_head(ea, last), 0, 0, searchstr, idaapi.SEARCH_DOWN|flags)
コード例 #4
0
    def __init__(self, func):
        self.src = func
        ea = func.startEA
        self.ea = ea
        self.name = idaapi.get_func_name(ea)

        self.elts = []

        if idaapi.is_func_tail(func):
            self.name += "_tail_" + str(ea)

        fr = idaapi.get_frame(func)
        struc_vars = []
        if fr == None:
            self.frame = None
        else:
            self.frame = struct.frame_node(fr, func)
            struc_vars = self.frame.struct_vars

        while ea < func.endEA:
            if idaapi.isData(idaapi.getFlags(ea)):
                self.elts.append(data.data_node(ea, idaapi.next_not_tail(ea)))
            else:
                if ea == func.startEA and not (idaapi.is_func_tail(func)):
                    self.elts.append(insn.insn_node(ea, struc_vars))
                else:
                    self.elts.append(
                        names.name_wrap_insn(ea,
                                             insn.insn_node(ea, struc_vars)))

            ea = idaapi.next_head(ea, func.endEA)
コード例 #5
0
ファイル: function.py プロジェクト: Joubei/project-ironfist
    def __init__(self, func):
        self.src = func
        ea = func.startEA
        self.ea = ea
        self.name = idaapi.get_func_name(ea)

        self.elts = []

        if idaapi.is_func_tail(func):
            self.name += "_tail_"+str(ea)

        fr = idaapi.get_frame(func)
        struc_vars = []
        if fr == None:
            self.frame = None
        else:
            self.frame = struct.frame_node(fr, func)
            struc_vars = self.frame.struct_vars

        while ea < func.endEA:
            if idaapi.isData(idaapi.getFlags(ea)):
                self.elts.append(data.data_node(ea, idaapi.next_not_tail(ea)))
            else:
                if ea == func.startEA and not (idaapi.is_func_tail(func)):
                    self.elts.append(insn.insn_node(ea, struc_vars))
                else:
                    self.elts.append(names.name_wrap_insn(ea, insn.insn_node(ea, struc_vars)))

            ea = idaapi.next_head(ea, func.endEA)
コード例 #6
0
ファイル: enumerators.py プロジェクト: XorgX304/idascripts-1
def Texts(*args):
    """
    Enumerate text search matches

    @param <range>: see getrange
    @param searchstr:    string or regex
    @param flags:        for instance SEARCH_REGEX

    @return: list of addresses matching searchstr

    Example::

        for ea in Texts((FirstSeg(), BADADDR), "LDR *PC, =", SEARCH_REGEX):
            f = idaapi.get_func(ea)
            if f and f.start_ea==ea:
                n= idaapi.get_name(BADADDR, ea)
                if not n.startswith("sub_"):
                    MakeName(ea, "j_%s" %n)

    Will search for functions containing only  "LDR PC, =xxxxx",
    and rename them as j_XXXXX.
    """
    (first, last) = getrange(args)
    i = getstringpos(args)
    if i < 0:
        raise Exception("missing searchstring")

    searchstr = args[i]
    flags = args[i + 1] if i + 1 < len(args) else 0

    ea = idaapi.find_text(first, idaapi.SEARCH_DOWN | flags, 0, 0, searchstr)
    while ea != idaapi.BADADDR and ea < last:
        yield ea
        ea = idaapi.find_text(idaapi.next_head(ea, last),
                              idaapi.SEARCH_DOWN | flags, 0, 0, searchstr)
コード例 #7
0
ファイル: enumerators.py プロジェクト: XorgX304/idascripts-1
def Heads(*args):
    """
    Enumerate array items

    @param <range>: see getrange

    @return: list of all heads

    """
    (first, last) = getrange(args)

    ea = first
    if ea < last and not idaapi.is_head(idaapi.get_full_flags(ea)):
        ea = idaapi.next_head(ea, last)
    while ea != BADADDR and ea < last:
        yield ea
        ea = idaapi.next_head(ea, last)
コード例 #8
0
ファイル: enumerators.py プロジェクト: nihilus/idascripts
def Heads(*args):
    """
    Enumerate array items

    @param <range>: see getrange

    @return: list of all heads

    """
    (first, last)= getrange(args)

    ea= first
    if ea<last and not idaapi.isHead(idaapi.getFlags(ea)):
        ea= idaapi.next_head(ea, last)
    while ea!=BADADDR and ea<last:
        yield ea
        ea= idaapi.next_head(ea, last)
コード例 #9
0
    def _build_metadata(self):
        """
        Collect node metadata from the underlying database.
        """
        current_address = self.address
        node_end = self.address + self.size

        # loop through the node's entire range and count its instructions
        #   NOTE: we are assuming that every defined 'head' is an instruction
        while current_address != idaapi.BADADDR:
            self.instruction_count += 1
            current_address = idaapi.next_head(current_address, node_end)
コード例 #10
0
    def append_cmt(self, ea, cmt, rptble=False):
        if len(cmt) > 1024:
            rs_log("warning, comment needs to be splitted (from 0x%x)" % ea)
            nh = idaapi.next_head(ea, ida_idaapi.BADADDR)
            if nh == ida_idaapi.BADADDR:
                rs_log('[x] failed to find next instruction candidate')
                return

            self.append_cmt(nh, cmt[1024:], rptble)
            cmt = cmt[:1024]

        idaapi.append_cmt(ea, cmt, rptble)
コード例 #11
0
ファイル: SyncPlugin.py プロジェクト: nihilus/qb-sync
    def append_cmt(self, ea, cmt, rptble=False):
        if len(cmt) > 1024:
            print "[*] warning, comment needs to be splitted (from 0x%x)" % ea
            nh = idaapi.next_head(ea, idaapi.BADADDR)
            if nh == idaapi.BADADDR:
                print "[*] failed to find next instruction candidate"
                return

            self.append_cmt(nh, cmt[1024:], rptble)
            cmt = cmt[:1024]

        idaapi.append_cmt(ea, cmt, rptble)
コード例 #12
0
    def trace_block(self, blk, node, operand):
        """
        在一个基本块内回溯
        """
        operand_t = operand
        cur_t = node['addr']

        while operand_t != None and cur_t >= blk.start_ea:
            cur_t, operand_t = self.trace_handle(cur_t, operand_t)
            if cur_t == self.func.start_ea:
                FELogger.info("查找到函数起始")
                if check_operand_arg(operand_t):
                    FELogger.info("由函数参数传入: %s" % (operand_t.name))
                operand_t = None

        return (idaapi.next_head(cur_t, idaapi.BADADDR), operand_t)
コード例 #13
0
def NonFuncs(*args):
    """
    Enumerate code which is not in a function

    @param ea:    where to start
    @param endea: BADADDR, or end address

    @return: list of addresses containing code, but not in a function

    Example::

        for ea in NonFuncs(FirstSeg(), BADADDR):
            if not MakeFunction(ea):
                Jump(ea)
                break
            Wait()

    Will try to change non-function code to function
    until MakeFunction fails
    """

    (first, last)= getrange(args)

    ea = first
    while ea!=idaapi.BADADDR and ea<last:
        nextcode= idaapi.find_code(ea, idaapi.SEARCH_NEXT|idaapi.SEARCH_DOWN)
        thischunk= idaapi.get_fchunk(ea)
        nextchunk= idaapi.get_next_fchunk(ea)
        if thischunk:
            ea= thischunk.endEA
        elif idaapi.isCode(idaapi.getFlags(ea)):
            yield ea
            ea= idaapi.next_head(ea, last)
        elif nextchunk is None:
            return
        elif nextcode<nextchunk.startEA:
            yield nextcode
            ea= nextcode
        else:
            ea= nextchunk.endEA
コード例 #14
0
ファイル: enumerators.py プロジェクト: XorgX304/idascripts-1
def NonFuncs(*args):
    """
    Enumerate code which is not in a function

    @param <range>: see getrange

    @return: list of addresses containing code, but not in a function

    Example::

        for ea in NonFuncs((FirstSeg(), BADADDR)):
            if not MakeFunction(ea):
                Jump(ea)
                break
            Wait()

    Will try to change non-function code to function
    until MakeFunction fails
    """

    (first, last) = getrange(args)

    ea = first
    while ea != idaapi.BADADDR and ea < last:
        nextcode = idaapi.find_code(ea,
                                    idaapi.SEARCH_NEXT | idaapi.SEARCH_DOWN)
        thischunk = idaapi.get_fchunk(ea)
        nextchunk = idaapi.get_next_fchunk(ea)
        if thischunk:
            ea = thischunk.end_ea
        elif idaapi.is_code(idaapi.get_full_flags(ea)):
            yield ea
            ea = idaapi.next_head(ea, last)
        elif nextchunk is None:
            return
        elif nextcode < nextchunk.start_ea:
            yield nextcode
            ea = nextcode
        else:
            ea = nextchunk.end_ea
コード例 #15
0
def Heads(start, end):
    """
    Get a list of heads (instructions or data)

    @param start: start address (this one is always included)
    @param end:   end address

    @return: list of heads between start and end
    """
    headlist = []
    headlist.append(start)

    ea = start

    while 1:
        ea = idaapi.next_head(ea, end)

        if ea == idaapi.BADADDR:
            break
        else:
            headlist.append(ea)

    return headlist
コード例 #16
0
def Heads(start, end):
    """
    Get a list of heads (instructions or data)

    @param start: start address (this one is always included)
    @param end:   end address

    @return: list of heads between start and end
    """
    headlist = []
    headlist.append(start)

    ea = start

    while 1:
        ea = idaapi.next_head(ea, end)

        if ea == idaapi.BADADDR:
            break
        else:
            headlist.append(ea)
    
    return headlist
コード例 #17
0
ファイル: ida_to_sql.py プロジェクト: L4ys/cissrfuzzer
def workaround_Functions(start=idaapi.cvar.inf.minEA, end=idaapi.cvar.inf.maxEA):
    """
    Get a list of functions

    @param start: start address (default: inf.minEA)
    @param end:   end address (default: inf.maxEA)

    @return: list of heads between start and end

    @note: The last function that starts before 'end' is included even
    if it extends beyond 'end'.
    """
    func = idaapi.get_func(start)
    if not func:
        func = idaapi.get_next_func(start)
    while func and func.startEA < end:
        startea = func.startEA
        yield startea
        func = idaapi.get_next_func(startea)
        addr = startea
        while func and startea == func.startEA:
            addr = idaapi.next_head(addr, end)
            func = idaapi.get_next_func(addr)
コード例 #18
0
ファイル: ida_to_sql.py プロジェクト: houcy/cissrfuzzer
def workaround_Functions(start=idaapi.cvar.inf.minEA,
                         end=idaapi.cvar.inf.maxEA):
    """
    Get a list of functions

    @param start: start address (default: inf.minEA)
    @param end:   end address (default: inf.maxEA)

    @return: list of heads between start and end

    @note: The last function that starts before 'end' is included even
    if it extends beyond 'end'.
    """
    func = idaapi.get_func(start)
    if not func:
        func = idaapi.get_next_func(start)
    while func and func.startEA < end:
        startea = func.startEA
        yield startea
        func = idaapi.get_next_func(startea)
        addr = startea
        while func and startea == func.startEA:
            addr = idaapi.next_head(addr, end)
            func = idaapi.get_next_func(addr)
コード例 #19
0
ファイル: ida_to_sql.py プロジェクト: houcy/cissrfuzzer
def process_function(arch, func_ea):

    func_end = idc.FindFuncEnd(func_ea)

    packet = DismantlerDataPacket()

    ida_chunks = get_chunks(func_ea)
    chunks = set()

    # Add to the chunks only the main block, containing the
    # function entry point
    #
    chunk = get_flow_code_from_address(func_ea)
    if chunk:
        chunks.add(chunk)

    # Make "ida_chunks" a set for faster searches  within
    ida_chunks = set(ida_chunks)
    ida_chunks_idx = dict(zip([c[0] for c in ida_chunks], ida_chunks))

    func = idaapi.get_func(func_ea)
    comments = [idaapi.get_func_cmt(func, 0), idaapi.get_func_cmt(func, 1)]

    # Copy the list of chunks into a queue to process
    #
    chunks_todo = [c for c in chunks]

    while True:

        # If no chunks left in the queue, exit
        if not chunks_todo:

            if ida_chunks:
                chunks_todo.extend(ida_chunks)
            else:
                break

        chunk_start, chunk_end = chunks_todo.pop()
        if ida_chunks_idx.has_key(chunk_start):
            ida_chunks.remove(ida_chunks_idx[chunk_start])
            del ida_chunks_idx[chunk_start]

        for head in idautils.Heads(chunk_start, chunk_end):

            comments.extend((idaapi.get_cmt(head, 0), idaapi.get_cmt(head, 1)))
            comment = '\n'.join([c for c in comments if c is not None])
            comment = comment.strip()
            if comment:
                packet.add_comment(head, comment)
            comments = list()

            if idc.isCode(idc.GetFlags(head)):

                instruction = arch.process_instruction(packet, head)

                # if there are other references than
                # flow add them all.
                if list(idautils.CodeRefsFrom(head, 0)):

                    # for each reference, including flow ones
                    for ref_idx, ref in enumerate(
                            idautils.CodeRefsFrom(head, 1)):

                        if arch.is_call(instruction):

                            # This two conditions must remain separated, it's
                            # necessary to enter the enclosing "if" whenever
                            # the instruction is a call, otherwise it will be
                            # added as an uncoditional jump in the last else
                            #
                            if ref in list(idautils.CodeRefsFrom(head, 0)):
                                packet.add_direct_call(head, ref)

                        elif ref_idx > 0 and arch.is_conditional_branch(
                                instruction):
                            # The ref_idx is > 0 in order to avoid processing the
                            # normal flow reference which would effectively imply
                            # that the conditional branch is processed twice.
                            # It's done this way instead of changing the loop's head
                            # from CodeRefsFrom(head, 1) to CodeRefsFrom(head, 0) in
                            # order to avoid altering the behavior of other conditions
                            # which rely on it being so.

                            # FIXME
                            # I don't seem to check for the reference here
                            # to point to valid, defined code. I suspect
                            # this could lead to a failure when exporting
                            # if such situation appears. I should test if
                            # it's a likely scenario and probably just add
                            # an isHead() or isCode() to address it.

                            packet.add_conditional_branch_true(head, ref)
                            packet.add_conditional_branch_false(
                                head, idaapi.next_head(head, chunk_end))

                            # If the target is not in our chunk list
                            if not address_in_chunks(ref, chunks):
                                new_chunk = get_flow_code_from_address(ref)
                                # Add the chunk to the chunks to process
                                # and to the set containing all visited
                                # chunks
                                if new_chunk is not None:
                                    chunks_todo.append(new_chunk)
                                    chunks.add(new_chunk)

                        elif arch.is_unconditional_branch(instruction):
                            packet.add_unconditional_branch(head, ref)

                            # If the target is not in our chunk list
                            if not address_in_chunks(ref, chunks):
                                new_chunk = get_flow_code_from_address(ref)
                                # Add the chunk to the chunks to process
                                # and to the set containing all visited
                                # chunks
                                if new_chunk is not None:
                                    chunks_todo.append(new_chunk)
                                    chunks.add(new_chunk)

                        #skip = False

                for ref in idautils.DataRefsFrom(head):
                    packet.add_data_reference(head, ref)

                    # Get a data reference from the current reference's
                    # location. For instance, if 'ref' points to a valid
                    # address and such address contains a data reference
                    # to code.
                    target = list(idautils.DataRefsFrom(ref))
                    if target:
                        target = target[0]
                    else:
                        target = None

                    if target is None and arch.is_call(instruction):
                        imp_name = idc.Name(ref)

                        imp_module = get_import_module_name(ref)

                        imported_functions.add((ref, imp_name, imp_module))
                        packet.add_indirect_virtual_call(head, ref)

                    elif target is not None and idc.isHead(target):
                        # for calls "routed" through this reference
                        if arch.is_call(instruction):
                            packet.add_indirect_call(head, target)

                        # for unconditional jumps "routed" through this reference
                        elif arch.is_unconditional_branch(instruction):
                            packet.add_unconditional_branch(head, target)

                        # for conditional "routed" through this reference
                        elif arch.is_conditional_branch(instruction):
                            packet.add_conditional_branch_true(head, target)
                            packet.add_conditional_branch_false(
                                head, idaapi.next_head(head, chunk_end))

    f = FunctionAnalyzer(arch, func_ea, packet)

    instrumentation.new_packet(packet)
    instrumentation.new_function(f)
コード例 #20
0
ファイル: ida_to_sql.py プロジェクト: L4ys/cissrfuzzer
def process_function(arch, func_ea):
    
    func_end = idc.FindFuncEnd(func_ea)
    
    packet = DismantlerDataPacket()
    
    ida_chunks = get_chunks(func_ea)
    chunks = set()
    
    # Add to the chunks only the main block, containing the
    # function entry point
    #
    chunk = get_flow_code_from_address(func_ea)
    if chunk:
        chunks.add( chunk )
    
    # Make "ida_chunks" a set for faster searches  within
    ida_chunks = set(ida_chunks)
    ida_chunks_idx = dict(zip([c[0] for c in ida_chunks], ida_chunks))
    
    func = idaapi.get_func(func_ea)
    comments = [idaapi.get_func_cmt(func, 0), idaapi.get_func_cmt(func, 1)]
    
    # Copy the list of chunks into a queue to process
    #
    chunks_todo = [c for c in chunks]
    
    while True:
        
        # If no chunks left in the queue, exit
        if not chunks_todo:
        
            if ida_chunks:
                chunks_todo.extend(ida_chunks)
            else:   
               break
        
        chunk_start, chunk_end = chunks_todo.pop()
        if ida_chunks_idx.has_key(chunk_start):
            ida_chunks.remove(ida_chunks_idx[chunk_start])
            del ida_chunks_idx[chunk_start]
        
        for head in idautils.Heads(chunk_start, chunk_end):
        
            comments.extend( (idaapi.get_cmt(head, 0), idaapi.get_cmt(head, 1)) )
            comment = '\n'.join([c for c in comments if c is not None])
            comment = comment.strip()
            if comment:
                packet.add_comment(head, comment)
            comments = list()
            
            if idc.isCode(idc.GetFlags(head)):
                
                instruction = arch.process_instruction(packet, head)
                
                # if there are other references than
                # flow add them all.
                if list( idautils.CodeRefsFrom(head, 0) ):
                    
                    # for each reference, including flow ones
                    for ref_idx, ref in enumerate(idautils.CodeRefsFrom(head, 1)):
                        
                        if arch.is_call(instruction):
                            
                            # This two conditions must remain separated, it's
                            # necessary to enter the enclosing "if" whenever
                            # the instruction is a call, otherwise it will be
                            # added as an uncoditional jump in the last else
                            #
                            if ref in list( idautils.CodeRefsFrom(head, 0) ):
                                packet.add_direct_call(head, ref)
                        
                        elif ref_idx>0 and arch.is_conditional_branch(instruction):
                            # The ref_idx is > 0 in order to avoid processing the
                            # normal flow reference which would effectively imply
                            # that the conditional branch is processed twice.
                            # It's done this way instead of changing the loop's head
                            # from CodeRefsFrom(head, 1) to CodeRefsFrom(head, 0) in
                            # order to avoid altering the behavior of other conditions
                            # which rely on it being so.
                            
                            # FIXME
                            # I don't seem to check for the reference here
                            # to point to valid, defined code. I suspect
                            # this could lead to a failure when exporting
                            # if such situation appears. I should test if
                            # it's a likely scenario and probably just add
                            # an isHead() or isCode() to address it.
                            
                            packet.add_conditional_branch_true(head, ref)
                            packet.add_conditional_branch_false(
                                head, idaapi.next_head(head, chunk_end))
                                
                            # If the target is not in our chunk list
                            if not address_in_chunks(ref, chunks):
                                new_chunk = get_flow_code_from_address(ref)
                                # Add the chunk to the chunks to process
                                # and to the set containing all visited
                                # chunks
                                if new_chunk is not None:
                                    chunks_todo.append(new_chunk)
                                    chunks.add(new_chunk)
                                    
                        elif arch.is_unconditional_branch(instruction):
                            packet.add_unconditional_branch(head, ref)
                            
                            # If the target is not in our chunk list
                            if not address_in_chunks(ref, chunks):
                                new_chunk = get_flow_code_from_address(ref)
                                # Add the chunk to the chunks to process
                                # and to the set containing all visited
                                # chunks
                                if new_chunk is not None:
                                    chunks_todo.append(new_chunk)
                                    chunks.add(new_chunk)
                                
                        #skip = False
                
                for ref in idautils.DataRefsFrom(head):
                    packet.add_data_reference(head, ref)
                    
                    # Get a data reference from the current reference's
                    # location. For instance, if 'ref' points to a valid
                    # address and such address contains a data reference
                    # to code.
                    target = list( idautils.DataRefsFrom(ref) )
                    if target:
                        target = target[0]
                    else:
                        target = None
                    
                    if target is None and arch.is_call(instruction):
                        imp_name = idc.Name(ref)

                        imp_module = get_import_module_name(ref)

                        imported_functions.add((ref, imp_name, imp_module))
                        packet.add_indirect_virtual_call(head, ref)
                    
                    elif target is not None and idc.isHead(target):
                        # for calls "routed" through this reference
                        if arch.is_call(instruction):
                            packet.add_indirect_call(head, target)
                            
                        # for unconditional jumps "routed" through this reference
                        elif arch.is_unconditional_branch(instruction):
                            packet.add_unconditional_branch(head, target)
                        
                        # for conditional "routed" through this reference
                        elif arch.is_conditional_branch(instruction):
                            packet.add_conditional_branch_true(head, target)
                            packet.add_conditional_branch_false(
                                head, idaapi.next_head(head, chunk_end))
    
    
    f = FunctionAnalyzer(arch, func_ea, packet)
    
    instrumentation.new_packet(packet)
    instrumentation.new_function(f)
コード例 #21
0
 def next(cls, ea=None, count=1):
     ea = ui.current.address() if ea is None else ea
     res = idaapi.next_head(ea, idaapi.BADADDR)
     return cls.next(res, count - 1) if count > 1 else res
コード例 #22
0
ファイル: database.py プロジェクト: nihilus/idascripts-2
 def next(ea):
     return idaapi.next_head(ea, idaapi.BADADDR)
コード例 #23
0
 def next(ea):
     return idaapi.next_head(ea, idaapi.BADADDR)
コード例 #24
0
ファイル: eop_analyzer.py プロジェクト: ispoleet/ctf-writeups
            continue

        ptr2 = Qword(ptr1)
        func = Qword(ptr2)

        # Rename function
        idaapi.set_name(func, 'func_%02x_%lx' % (i, func))

        print '[+] Processing: %lx %lx %lx %lx' % (addr, ptr1, ptr2,
                                                   func), GetFunctionName(func)

        # functions end at `call ___cxa_throw` instrucion.
        # extend endEA to `call __Unwind_Resume`
        for x in Heads(func, func + 512):
            if GetDisasm(x) == 'call    __Unwind_Resume':
                SetFunctionEnd(func, idaapi.next_head(x, func + 512))
                break

        # Find next hop. Look for instruction: `mov dword ptr [rax], XXh`
        # where XX is the func_tbl_5555557671E0 entry of the next function.
        end = GetFunctionAttr(func, FUNCATTR_END)
        node = {'id': i, 'ea': func, 'next': -1, 'insns': []}
        start_log = False

        # for each instruction in function
        for insn in Heads(func, end):
            # Check for next hop instruction
            if idc.GetMnem(insn) == 'mov':
                if idc.GetOpnd(insn, 0) == 'dword ptr [rax]':
                    node['next'] = idc.GetOperandValue(insn, 1)
                    print '\tNext hop found: %x -> %x' % (i, node['next'])