Beispiel #1
0
 def slot_item_double_clicked(self, o, column):
     """ """
     if column == CapaExplorerRulegenFeatures.get_column_address_index(
     ) and o.text(column):
         idc.jumpto(int(o.text(column), 0x10))
     elif o.capa_type == CapaExplorerRulegenFeatures.get_node_type_leaf():
         self.editor.update_features([o.data(0, 0x100)])
Beispiel #2
0
    def setAddr(self, address):

        if self.current_focused_addr == address:
            return
        else:
            idc.jumpto(address)
        f = idaapi.get_func(address)
        # print(f)
        if f == None:
            print("not found function address...")
            return
        g = idaapi.FlowChart(f, flags=idaapi.FC_PREDS)
        target_bb_id = get_bb_id(g, address)
        # print(target_bb_id)

        if self.current_block_start_ea == f.start_ea and self.current_bb_id == target_bb_id:
            return
        else:

            self.recoverColor()
            self.current_block_start_ea = f.start_ea
            self.current_focused_addr = address
            self.current_bb_id = target_bb_id
            self.changeColor()
            ida_graph.refresh_viewer(self.widget_a)
Beispiel #3
0
def goto_file_ofs():
    fofs = 0
    txt = clip_text()
    if txt.isdigit():
        try:
            fofs = int(txt, 10)
        except:
            pass
    elif txt.isalnum():
        try:
            fofs = int(txt, 16)
        except:
            pass
    fofs = ida_kernwin.ask_addr(fofs, "Enter the file offset to jump to")
    if fofs is None:
        return 0

    ea = idaapi.get_fileregion_ea(fofs)
    if ea != idc.BADADDR:
        plg_print("File offset = 0x%X -> EA = 0x%X" % (fofs, ea))
        idc.jumpto(ea)
        return 1
    else:
        plg_print("Invalid file offset 0x%X" % fofs)
        return 0
Beispiel #4
0
    def handle_methods_interaction(self, row, column):
        if self.edit_class is None:
            return

        m = self.methods.item(row, 0).data(QtCore.Qt.UserRole)
        if type(
                m
        ) != database_entries.Method or m not in self.edit_class.methods:
            return

        elif column == 0:  # Go to address
            idc.jumpto(m.ea)
        elif column == 1:  # Edit signature
            dlg = SignatureDialog(m.return_type,
                                  m.owner.name,
                                  m.name,
                                  m.args,
                                  m.is_const,
                                  m.ctor_type,
                                  m.dtor_type,
                                  fixed_owner_type=True)
            if dlg.exec_() != QtWidgets.QDialog.Accepted:
                return
            m.set_signature(dlg.name, dlg.args, dlg.return_type, dlg.is_const,
                            dlg.ctor_type, dlg.dtor_type)
            self.methods.setItem(row, 1,
                                 QtWidgets.QTableWidgetItem(m.get_signature()))
            idaapi.refresh_idaview_anyway()
Beispiel #5
0
    def handle_vtable_interaction(self, row, column):
        if self.edit_class is None:
            return

        vm = self.edit_class.vmethods[row]

        if column == 0:  # Go to vtable offset
            idc.jumpto(self.edit_class.vtable_start + row * 4)
        elif column == 1:  # Go to address
            idc.jumpto(vm.ea)
        elif column == 2:  # Edit signature
            dlg = SignatureDialog(vm.return_type,
                                  vm.owner.name,
                                  vm.name,
                                  vm.args,
                                  vm.is_const,
                                  vm.ctor_type,
                                  vm.dtor_type,
                                  fixed_owner_type=True)
            if dlg.exec_() != QtWidgets.QDialog.Accepted:
                return
            vm.set_signature(dlg.name, dlg.args, dlg.return_type, dlg.is_const,
                             dlg.ctor_type, dlg.dtor_type)
            self.vtable.setItem(row, 2,
                                QtWidgets.QTableWidgetItem(vm.get_signature()))
            idaapi.refresh_idaview_anyway()
Beispiel #6
0
    def context_menu(self, position):
        sender = self.sender()
        menu = QtWidgets.QMenu()

        copy_action = menu.addAction("Copy value")
        copy_row = menu.addAction("Copy row")
        view_chunk = menu.addAction("View chunk")
        jump_to = menu.addAction("Jump to chunk")
        jump_to_u = menu.addAction("Jump to user-data")
        check_freaable = menu.addAction("Check freeable")

        chunk_addr = int(sender.item(sender.currentRow(), 0).text(), 16)
        action = menu.exec_(sender.mapToGlobal(position))

        if action == copy_action:
            sender.copy_selected_value()

        if action == copy_row:
            sender.copy_selected_row()

        elif action == jump_to:
            idc.jumpto(chunk_addr)

        elif action == jump_to_u:
            idc.jumpto(chunk_addr + (config.ptr_size * 2))

        elif action == view_chunk:
            self.view_selected_chunk()

        elif action == check_freaable:
            self.parent.check_freeable(chunk_addr)
Beispiel #7
0
 def OnSelectLine(self, n):
     self.selcount += 1
     ea = int(self.items[n][0], 16)
     idc.jumpto(ea)
     if DEBUG:
         print('[{}] jump to {addr:#010x}'.format(NAME, addr=ea))
     return n
Beispiel #8
0
    def callback(self, event, *args):
        if event == idaapi.hxe_populating_popup:
            form, phandle, vu = args
            if vu.item.citype == idaapi.VDI_FUNC or (
                    vu.item.citype == idaapi.VDI_EXPR and vu.item.e.is_expr()
                    and vu.item.e.type.is_funcptr()):
                idaapi.attach_action_to_popup(form, phandle,
                                              ACTION_HX_REMOVERETTYPE, None)
        elif event == idaapi.hxe_double_click:
            vu, shift_state = args
            # auto jump to target if clicked item is xxx->func();
            if vu.item.citype == idaapi.VDI_EXPR and vu.item.e.is_expr():
                expr = idaapi.tag_remove(vu.item.e.print1(None))
                if "->" in expr:
                    # find target function
                    name = expr.split("->")[-1]
                    addr = idc.get_name_ea_simple(name)
                    if addr == idaapi.BADADDR:
                        # try class::function
                        e = vu.item.e
                        while e.x:
                            e = e.x
                        addr = idc.get_name_ea_simple(
                            "%s::%s" % (str(e.type).split()[0], name))

                    if addr != idaapi.BADADDR:
                        idc.jumpto(addr)
                        return 1
        return 0
Beispiel #9
0
    def go_to(self):
        """
        Transfers user to the relevant address of the update

        :return: None
        """
        idc.jumpto(self.address)
Beispiel #10
0
def goto_clip_text():
    loc = parse_location(clip_text())
    if loc != idaapi.BADADDR:
        plg_print("Goto location 0x%X" % loc)
        idc.jumpto(loc)
        return 1

    plg_print("Failed to get a valid ea")
    return 0
Beispiel #11
0
 def jumpto():
     model = self.ui.regsView.model()
     sel = self.ui.regsView.selectedIndexes()
     if len(sel) > 0:
         try:
             addr = int(_idangr_ctx.simregs[sel[0].row()][2], 16)
             idc.jumpto(addr)
         except:
             pass
Beispiel #12
0
def jump_addr_next_func():
    import idc
    end = 0x0402220
    ea = idc.get_screen_ea()
    while idc.find_func_end(ea) < end:
        next_func = get_next_func(ea)
        print(hex(next_func))
        idc.jumpto(next_func)
        ea = idc.get_screen_ea()
Beispiel #13
0
 def view_dblclick(self, viewer, point):
     widget_type = ida_kernwin.get_widget_type(viewer)
     if not (widget_type == 48 or widget_type == 28):
         return
     # Decompiler or Structures window
     place, x, y = ida_kernwin.get_custom_viewer_place(viewer, False)
     line = utils.get_curline_striped_from_viewer(viewer)
     func_cand_name = cpp_utils.find_valid_cppname_in_line(line, x)
     if func_cand_name is not None:
         func_cand_ea = ida_name.get_name_ea(BADADDR, func_cand_name)
         if func_cand_ea is not None and utils.is_func(func_cand_ea):
             idc.jumpto(func_cand_ea)
Beispiel #14
0
 def activate(self, ctx):
     if self.action == ACTION_COPYEA:
         ea = idc.get_screen_ea()
         if ea != idaapi.BADADDR:
             copy_to_clip("0x%X" % ea)
             print("Address 0x%X has been copied to clipboard" % ea)
     elif self.action == ACTION_GOTOCLIP:
         loc = parse_location(clip_text())
         if loc != idaapi.BADADDR:
             print("Goto location 0x%x" % loc)
             idc.jumpto(loc)
     return 1
    def _onSignatureTreeItemDoubleClicked(self, item, column):
        """Action for the double clicked.

        Arguments:
            item (QTreeWidgetItem): Item that was clicked.
            column (int): Selected column.
        """
        # Jump to the match address

        if item.data(1, 0):
            addr = int(item.data(2, 0), 16)
            idc.jumpto(addr)
Beispiel #16
0
    def patchIDB(self,buff):
        for i in buff: # process file contents

            i=i.strip() # strip new line
            jumpaddr,datastr=self.extractStackData(i) # extract jump address and four double words from each line 
            
            for rawbytes in datastr: # process each double word
                
                idc.jumpto(jumpaddr) # jump to segment address 
                temp = self.convertRawHexData(rawbytes)  # process word string into bytes
                idaapi.patch_many_bytes(jumpaddr,temp) # patch bytes at jumpaddr
                self.setComment("Address: 0x%x \tStack Value: %s" % (jumpaddr,rawbytes)) # create a comment at each double word in segment
                jumpaddr +=4 # increment jumpaddr by 4 bytes
    def _onSignatureTreeItemDoubleClicked(self, item, column):
        """Action for the double clicked.

        Arguments:
            item (QTreeWidgetItem): Item that was clicked.
            column (int): Selected column.
        """
        # Jump to the match address
        if item in self.qtreewidgetitems_to_addresses:
            try:
                idc.jumpto(self.qtreewidgetitems_to_addresses[item])
            except:
                idc.Jump(self.qtreewidgetitems_to_addresses[item])
Beispiel #18
0
    def createStackSegment(self,start_addr,end_addr):

        idc.AddSeg(start_addr,end_addr,0,1,0, idaapi.saRelDble) #add new segment
        idc.set_segm_combination(start_addr,idaapi.saRelDble) #set segm comb
        idc.jumpto(start_addr) #jumpt to seg start address
        align_start_addr=start_addr #temp align start address value 
        #print "Making DWORDs from 0x%X - 0x%X" % (align_start_addr, end_addr) # debugging statement
        
        while align_start_addr < end_addr: # aligning into 4 byte dw
            MakeDword(align_start_addr) #make the double word alignment
            align_start_addr += 4 #inc address by four bytes
        
        #set segment combination to 'stack'    
        MakeUnknown(align_start_addr, (end_addr-align_start_addr), DOUNK_SIMPLE)
Beispiel #19
0
    def nextOneWordArr():
        d = Data.Data(ea)
        while (d.ea < pointerRange[1]):
            content = d.getContent()

            # case: byte array that's 4 elements. Likely a word
            if type(content) == list and len(content) == 4 and (d.getSize() / len(content) == 1):
                break
            d = Data.Data(d.ea + d.getSize())

        if d.ea >= pointerRange[1]:
            print(False)
        else:
            print('%07X' % d.ea)
            idc.jumpto(d.ea)
Beispiel #20
0
def fakered(ea, end_ea=None, ui=True, hexOut=True):
    """
    This finds the next occurrance of a not a red code segment that has no return pattern to it, making it unlikely
    to belong to a function.
    :param ea: ea to start searching from
    :param ui: if True, jump to address automatically
    :param end_ea: the last address of the search range. If not specified, default is used.
    :param hexOut: output hex formatted ea range instead
    :return: range of ea of next fake red code segment
    """
    # TODO: change implementation to be based on return patterns?
    ea = red(ea, end_ea, ui=False, hexOut=False)
    start_ea = ea
    end_red_ea = idaapi.BADADDR
    # flag for when the whole red segment is finished and we can go to the next red code segment
    finishedSegment = False
    # condition for if the segment has already been invalidated before reaching its end
    isFake = True

    if not end_ea: end_ea = end_ea
    while ea < end_ea:
        d = Data.Data(ea)
        inst = InstDecoder.Inst(ea).fields

        # traverse red code, and find the end of the red segment
        if Function.isFunction(ea) and d.isCode() or not d.isCode():
            # update region end to this red code region
            end_red_ea = ea
            # confirm if the return is within range, then this isn't fake code. Find the next red!
            if isFake:  # or start_ea <= unkret(start_ea-instLimit, end_ea, ui=False, hexOut=False) < end_ea:
                break
            # search the next red region
            isFake = True
            start_ea = ea = red(end_red_ea, end_ea, ui=False, hexOut=False)

        # advance through the red code
        else:
            # simple function pattern,s, if it sorta looks like it can be a function, don't count it as fake.
            # this includes return patterns, and push/pop.
            if inst and (inst['magic'] == InstDecoder.INST_MOV_PC_LR
                         or inst['magic'] == InstDecoder.INST_BX
                         and inst['reg'] == 14 or inst['magic']
                         == InstDecoder.INST_PUSHPOP and inst['lr']):
                isFake = False
            ea += d.getSize()
    if ui: idc.jumpto(end_red_ea - 2)
    if hexOut: return '(%07X, %07X)' % (start_ea, end_red_ea)
    return (start_ea, end_red_ea)
Beispiel #21
0
 def OnDblClick(self, node_id):
     is_thread, value, label = self[node_id]
     if is_thread:
         idc.select_thread(value)
         self.Show()
         s = "SEH chain for " + hex(value)
         t = "-" * len(s)
         print t
         print s
         print t
         for handler in self.result[value]:
             print "%x: %s" % (handler, self.names[handler])
         print t
     else:
         idc.jumpto(value)
     return True
Beispiel #22
0
def remake_main():
    # 先新建好所有函数, 再执行
    # -- 脚本将start~end所有函数 undefined, 在start处make function
    import ida_bytes

    start_addr = 0x0402126
    end_addr = 0x0402220

    for i in range(start_addr, end_addr):
        ida_bytes.del_items(i)

    idc.jumpto(start_addr)
    idc.add_func(start_addr)

    import ida_hexrays  # open pseudocode view
    ida_hexrays.open_pseudocode(0x0402126, ida_hexrays.OPF_NO_WAIT)
Beispiel #23
0
    def jumpto(self, item, offset):
        """Jump to offset in IDA view"""
        try:
            self.ret = idc.jumpto(offset)
        except:
            self.ret = False

        return self.ret
Beispiel #24
0
def deadfunc(ea, end_ea=None, ui=True, hexOut=True):
    """
    This finds the next occurrance of a dead function not recognized as a function (ie, red code or data)
    This can only find functions ranges it can guarantee, ie, only PUSH {..., LR} POP {..., PC} patterns.
    :param ea: ea to start searching from
    :param end_ea: the last address of the search range
    :param ui: if True, jump to address automatically
    :param hexOut: output hex formatted ea range instead
    :return: range of ea of next dead function
    """
    # don't count this item
    ea = Data.Data(ea).ea + Data.Data(ea).getSize()
    foundPush = False
    push_ea = idaapi.BADADDR
    pop_ea = idaapi.BADADDR
    push_regs = None
    if not end_ea: end_ea = end_ea
    while ea < end_ea:
        # the current item must not belong to a function, or have any data xrefs
        if not Function.isFunction(ea) and not Data.Data(ea).getXRefsTo()[1]:
            try:
                inst = InstDecoder.Inst(ea).fields
            except ValueError:
                ea += 2
                continue
            # if PUSH {..., LR}
            if inst and inst['magic'] == InstDecoder.INST_PUSHPOP and not inst[
                    'pop'] and inst['lr']:
                foundPush = True
                push_ea = ea
                push_regs = inst['Rlist']
            # detected a POP {..., PC} after the PUSH {..., LR}, and the registers match
            if (foundPush and inst
                    and inst['magic'] == InstDecoder.INST_PUSHPOP
                    and inst['pop'] and inst['lr']
                    and inst['Rlist'] == push_regs):
                pop_ea = ea
                break
        else:
            foundPush = False
        ea += 2

    if ui: idc.jumpto(push_ea)
    if hexOut: return '(%07X, %07X)' % (push_ea, pop_ea)
    return (push_ea, pop_ea)
Beispiel #25
0
    def _step_into(self):
        #
        if self.data == None:
            self.browser.append("please load file before")
            return

        #
        if not self.addr_is_load:
            self.browser.append("please load base addr before")
            return

        #
        ir_list = []
        mark_num = 0
        min_dist = 0xffffffff
        for i in range(self.curr_line, len(self.data)):
            one_ir = self.data[i]
            if 'IMark' in one_ir:
                if mark_num >= 1:
                    self.curr_line = i
                    break
                else:
                    ir_list.append(one_ir)
                    cur_addr = self._get_curr_base(one_ir) - self.module_base
                    self.or_ins = self.cur_ins
                    self.cur_ins = cur_addr

                    if self.or_ins != 0:
                        idc.SetColor(self.or_ins, CIC_ITEM, 0xFFFFFFFF)

                mark_num = mark_num + 1
            else:
                if 'func_' in one_ir:
                    if min_dist == 0xffffffff:
                        ref_addr = self.cur_ins
                        for addr in idautils.CodeRefsTo(ref_addr, 1):
                            if abs(addr - self.or_ins) <= min_dist:
                                min_dist = abs(addr - self.or_ins)
                                self.cur_ins = addr
                ir_list.append(one_ir)

        idc.jumpto(self.cur_ins)
        idc.SetColor(self.cur_ins, CIC_ITEM, 0x2020c0)
        for one_ir in ir_list:
            self.browser.append(one_ir)
Beispiel #26
0
    def slot_double_click(self, model_index):
        """slot connected to double click event

        @param model_index: QModelIndex*
        """
        if not model_index.isValid():
            return

        item = self.map_index_to_source_item(model_index)
        column = model_index.column()

        if CapaExplorerDataModel.COLUMN_INDEX_VIRTUAL_ADDRESS == column and item.location:
            # user double-clicked virtual address column - navigate IDA to address
            idc.jumpto(item.location)

        if CapaExplorerDataModel.COLUMN_INDEX_RULE_INFORMATION == column:
            # user double-clicked information column - un/expand
            self.collapse(model_index) if self.isExpanded(model_index) else self.expand(model_index)
Beispiel #27
0
    def _run(self):
        if self.data == None:
            self.browser.append("please load file before")
            return

        if not self.addr_is_load:
            self.browser.append("please load base addr before")
            return

        if len(self.addr_list) == 0:
            self.browser.append("please bp addr")
            return

        #
        ir_list = []
        mark_num = 0
        for i in range(self.curr_line, len(self.data)):
            one_ir = self.data[i]
            if 'IMark' in one_ir:
                if mark_num >= 1:
                    self.curr_line = i
                    break
                #
                cur_addr = self._get_curr_base(one_ir) - self.module_base
                for bp_addr in self.addr_list:
                    if bp_addr == cur_addr:
                        idc.jumpto(cur_addr)
                        idc.SetColor(cur_addr, CIC_ITEM, 0x2020c0)
                        self.or_ins = self.cur_ins
                        self.cur_ins = cur_addr
                        ir_list.append(one_ir)
                        mark_num = mark_num + 1
                        break
            else:
                if mark_num >= 1:
                    ir_list.append(one_ir)

        if mark_num == 0:
            self.browser.append('bp address is not taint')
        else:
            for one_ir in ir_list:
                self.browser.append(one_ir)
Beispiel #28
0
 def view_dblclick(self, viewer, point):
     widget_type = ida_kernwin.get_widget_type(viewer)
     if not (widget_type == 48 or widget_type == 28):
         return
     # Decompiler or Structures window
     func_cand_name = None
     place, x, y = ida_kernwin.get_custom_viewer_place(viewer, False)
     if place.name() == "structplace_t":  # Structure window:
         structplace = ida_kernwin.place_t_as_structplace_t(place)
         if structplace is not None:
             s = ida_struct.get_struc(ida_struct.get_struc_by_idx(structplace.idx))
             if s:
                 member = ida_struct.get_member(s, structplace.offset)
                 if member:
                     func_cand_name = ida_struct.get_member_name(member.id)
     if func_cand_name is None:
         line = utils.get_curline_striped_from_viewer(viewer)
         func_cand_name = cpp_utils.find_valid_cppname_in_line(line, x)
     if func_cand_name is not None:
         func_cand_ea = ida_name.get_name_ea(BADADDR, func_cand_name)
         if func_cand_ea is not None and utils.is_func_start(func_cand_ea):
             idc.jumpto(func_cand_ea)
Beispiel #29
0
def goto_rva():
    rva = 0
    txt = clip_text()
    if txt.isdigit():
        try:
            rva = int(txt, 10)
        except:
            pass
    elif txt.isalnum():
        try:
            rva = int(txt, 16)
        except:
            pass
    rva = ida_kernwin.ask_addr(rva, "Enter the RVA to jump to")
    if rva is None:
        return 0

    base = ida_nalt.get_imagebase()
    ea = base + rva
    plg_print("RVA = 0x%X -> EA = 0x%X" % (rva, ea))
    idc.jumpto(ea)
    return 1
Beispiel #30
0
def unkret(ea, end_ea=None, ui=True, hexOut=True):
    """
    Thhs finds the next return based on the next.ret function, that is not already defined within a function.
    This counts red code, unknown bytes, and returns hidden within data.
    :param ea: ea to start searching from
    :param end_ea: the last address to look for
    :param ui: if True, jump to address automatically
    :param hexOut: output hex formatted ea instead
    :return: ea of next unknown return
    """
    ea = ret(ea, end_ea, ui=False, hexOut=False)
    output = idaapi.BADADDR
    if not end_ea: end_ea = end_ea
    while ea < end_ea:
        d = Data.Data(ea)
        if not Function.isFunction(d.ea):
            output = ea
            break
        ea = ret(ea, end_ea, ui=False, hexOut=False)
    if ui: idc.jumpto(output)
    if hexOut: return '%07X' % output
    return output
Beispiel #31
0
 def OnSelectLine(self, n):
     idc.jumpto(self.items[n][2])
     return (Choose.NOTHING_CHANGED, )
Beispiel #32
0
def main():
    eh = flare_emu.EmuHelper()

    # dictionary that stores data used across emulation runs, function emulation specific data is set below
    userData = {
        # found stackstrings in stack memory
        "stackstrings": [],
        # found stackstrings in global memory (globalstrings)
        "globalstrings": []
    }

    cnt_functions = 0
    cnt_analyzed = 0
    cnt_found_ss = 0
    cnt_commented_ss = 0
    errors = []

    start = time.time()
    print("Started ironstrings stackstring deobfuscation")
    print_header()

    if ANALYZE_SINGLE_FUNC:
        fvas = [idc.get_func_attr(idc.here(), idc.FUNCATTR_START)]
    else:
        fvas = idautils.Functions()

    for fva in fvas:
        logging.debug("running on 0x%X", fva)
        if JUMP_TO_FUNC:
            idc.jumpto(fva)

        if fva == idaapi.BADADDR:
            logging.debug("skipping invalid function address")
            continue
        if idc.get_func_flags(fva) & (idc.FUNC_LIB | idc.FUNC_THUNK):
            logging.debug("skipping library or thunk function 0x%X", fva)
            continue

        # function start address
        userData["funcStart"] = fva

        # list of addresses of last instruction for all basic blocks in function
        userData["bb_ends"] = get_bb_ends(fva)

        # memory writes in current function
        userData["mem_writes"] = {}

        # start and end addresses of all memory writes in function
        userData["writelog"] = set()

        # memory write count in current basic block
        userData["mem_write_count"] = 0

        # cache previous address to count instructions that are executed multiple times, e.g. rep prefixed
        userData["prevAddress"] = 0

        # number same instruction has been executed in a row
        userData["repCount"] = 0

        cnt_functions += 1
        try:
            # emulate various paths through function via flare-emu, use hooks to reconstruct strings
            eh.iterateAllPaths(fva, noop, hookData=userData, callHook=call_hook, instructionHook=instr_hook,
                               memAccessHook=hook_mem_write, hookApis=False, maxPaths=MAX_CODE_PATHS)
        except unicorn.UcError as e:
            errors.append("Error analyzing function 0x{:X}: {}".format(fva, str(e)))
        else:
            cnt_analyzed += 1

            # print stackstrings found in this function
            f_ss = filter(lambda s: s.fva == fva, userData["stackstrings"])
            cnt_found_ss += len(f_ss)
            for ss in sorted(f_ss, key=lambda s: s.written_at):
                print_string(ss.fva, ss.written_at, ss.offset, ss.s)
                # IMPROVEMENT adjust stack frame member size in IDA view

            # print globalstrings found in this function
            f_gs = filter(lambda g: g.fva == fva, userData["globalstrings"])
            cnt_found_ss += len(f_gs)
            for gs in sorted(f_gs, key=lambda g: g.written_at):
                print_string(gs.fva, gs.written_at, gs.offset, gs.s)

            if COMMENT_STACKSTRINGS:
                for ss in f_ss:
                    if not ss.written_at:
                        errors.append("Can't get location where '{}' was written in 0x{:X}.".format(ss.s, ss.fva))
                        continue
                    ss_cmt = format_comment(ss.s)
                    if append_comment(ss.written_at, ss_cmt):
                        cnt_commented_ss += 1
                    else:
                        errors.append("Failed to set comment at 0x{:X}: {}".format(ss.written_at, ss_cmt))

                for gs in f_gs:
                    if COMMENT_STACKSTRING_GLOBAL_REPEATABLE:
                        repeatable = True
                        cmt_va = gs.offset
                    else:
                        repeatable = False
                        cmt_va = gs.written_at

                    if not cmt_va:
                        errors.append("Can't get location where '{}' was written in 0x{:X}.".format(gs.s, gs.fva))
                        continue
                    gs_cmt = format_comment(gs.s)
                    if append_comment(cmt_va, gs_cmt, repeatable):
                        cnt_commented_ss += 1
                    else:
                        errors.append("Failed to set comment at 0x{:X}: {}".format(cmt_va, gs_cmt))

        # update IDA view
        idc.refresh_idaview_anyway()

        # clean up memory after each function
        eh.resetEmulatorHeapAndStack()

    print_summary(cnt_functions, cnt_analyzed, cnt_found_ss, cnt_commented_ss, errors)

    if PRINT_PLAIN_SUMMARY:
        print_plain_summary(userData["stackstrings"] + userData["globalstrings"])

    print("\nFinished ironstrings stackstring deobfuscation after {:.2f} seconds".format(time.time() - start))
def jumpto(ea):
    if is_hexrays_v7():
        idc.jumpto(ea)
    else:
        idaapi.jumpto(ea)