def name(ea, string=None): '''Returns the name at the specified address. (local than global)''' if string is not None: SN_NOCHECK = 0x00 SN_NOLIST = 0x80 SN_LOCAL = 0x200 SN_PUBLIC = 0x02 n = name(ea) flags = SN_NOCHECK try: function.top(ea) flags |= SN_LOCAL except ValueError: flags |= 0 idc.MakeNameEx(ea, string, flags) tag(ea, '__name__', string) return n try: return tag(ea, '__name__') except KeyError: pass return None
def function(ea): '''Iterate through all addresses in the function ``ea`` and it's tagcache with any found tags.''' try: fn.top(ea) except LookupError: return {}, {} f, addr, tags = fetch_function(ea) for k in set(tags.keys()): if k in ('__tags__', '__address__'): if f in addr: addr[f] -= 1 if addr[f] == 0: addr.pop(f) if k in tags: tags[k] -= 1 if tags[k] == 0: tags.pop(k) continue for k, v in tags.iteritems(): internal.comment.contents.set_name(f, k, v) for k, v in addr.iteritems(): if not fn.within(k): continue internal.comment.contents.set_address(k, v) return addr, tags
def name(ea, string=None): '''Returns the name at the specified address. (local than global)''' if string is not None: SN_NOCHECK = 0x00 SN_NOLIST = 0x80 SN_LOCAL = 0x200 SN_PUBLIC = 0x02 n = name(ea) flags = SN_NOCHECK try: function.top(ea) flags |= SN_LOCAL except ValueError: flags |= 0 res = idaapi.set_name(ea, string, flags) tag(ea, 'name', string) return n try: return tag(ea, 'name') except KeyError: pass return None
def below(ea, includeSegment=False): '''Return all of the function names and their offset that are called by the function at `ea`.''' tryhard = lambda ea: "{:s}{:+x}".format(func.name(func.top( ea)), ea - func.top(ea)) if func.within(ea) else "{:+x}".format( ea) if func.name(ea) is None else func.name(ea) return '\n'.join(':'.join( [segment.name(ea), tryhard(ea)] if includeSegment else [tryhard(ea)]) for ea in func.down(ea))
def above(ea, includeSegment=False): '''Return all of the function names and their offset that calls the function at `ea`.''' tryhard = lambda ea: "{:s}{:+x}".format(func.name(func.top( ea)), ea - func.top(ea)) if func.within(ea) else "{:+x}".format( ea) if func.name(ea) is None else func.name(ea) return '\n'.join( ':'.join((segment.name(ea), tryhard(ea)) if includeSegment else (tryhard(ea), )) for ea in func.up(ea))
def below(ea, includeSegment=False): '''Display all the functions that the function at /ea/ can call''' tryhard = lambda ea: "{:s}+{:x}".format(database.name(function.top( ea)), ea - function.top(ea)) if function.within( ea) else "+{:x}".format(ea) if database.name( ea) is None else database.name(ea) return '\n'.join( ':'.join((segment.name(ea), tryhard(ea)) if includeSegment else (tryhard(ea), )) for ea in function.down(ea))
def analyze_vtables(): vtables = set(locate_vtables()) fns = set(idautils.Functions()) for vt in vtables: # create a new class sname = "class_%x" % (vt) sid = idc.AddStruc(-1, sname) if sid == idc.BADADDR: sid = idc.GetStrucIdByName(sname) # create a struc for the vtable vname = "vtable_%x" % (vt) vid = idc.AddStruc(-1, vname) vfuncs = set() if vid == idc.BADADDR: vid = idc.GetStrucIdByName(vname) for i in range(0xffffff): target = idc.Dword(vt + (4 * i)) if target not in fns: break if i > 0: # if there is a data ref, then it's probably the start of a new vtable xrefs = set(idautils.DataRefsTo(vt + (4 * i))) if len(xrefs) > 0: continue idc.AddStrucMember(vid, 'vfunc_%x' % (i), -1, idc.FF_DWRD, -1, 4) # setup the target function function.tag(target, 'virtual table', hex(vt)) vfuncs.add(target) # add a vtable to the new class idc.AddStrucMember(sid, 'vtable', 0, idc.FF_DWRD, -1, 4) # tag functions that reference the vtable as either a constructor or destructor # in order to do decide which, take advantage of a C++ thing, destructors will be # virtual, and constructors will not xrefs = idautils.DataRefsTo(vt) for r in xrefs: try: if xrefs in vfuncs: function.tag(function.top(r), 'destructor', 'guessed from vtable (%x) analysis' % (vt)) else: function.tag(function.top(r), 'constructor', 'guessed from vtable (%x) analysis' % (vt)) except: pass
def checkmarks(): '''Output all functions (sys.stdout) containing more than 1 mark.''' res = [] for a, m in database.marks(): try: res.append((function.top(a), a, m)) except ValueError: pass continue d = list(res) d.sort(lambda a, b: cmp(a[0], b[0])) flookup = {} for fn, a, m in d: try: flookup[fn].append((a, m)) except: flookup[fn] = [(a, m)] continue functions = [(k, v) for k, v in flookup.items() if len(v) > 1] if not functions: logging.warning( 'There are no functions available containing multiple marks.') return for k, v in functions: print >> sys.stdout, "{:x} : in function {:s}".format( k, function.name(function.byAddress(k))) print >> sys.stdout, '\n'.join( ("- {:x} : {:s}".format(a, m) for a, m in sorted(v))) return
def tag(address, *args, **kwds): '''tag(address, key?, value?) -> fetches/stores a tag from specified address''' try: context = function.top(address) except ValueError: context = None if len(args) == 0 and len(kwds) == 0: # result = __datastore.content.select(context, query.address(address)) result = datastore.address(context).select(query.address(address)) try: result = result[address] except: result = {} return result elif len(args) == 1: key, = args # result = __datastore.content.select(context, query.address(address), query.attribute(key)) result = datastore.address(context).select(query.address(address), query.attribute(key)) try: result = result[address][key] except: raise KeyError( (hex(address),key) ) result = None return result if len(args) > 0: key,value = args kwds.update({key:value}) return datastore.address(context).address(address).set(**kwds)
def __select(q): for x in functions(): x = function.top(x) if q.has(function.tag(x)): yield x continue return
def collectcall(ea, sentinel=set()): """Collect all of the function calls starting at function `ea` and recurse until a terminating function is encountered. If the set `sentinel` is specified, then its addresses are used as sentinel functions and collection will terminate when one of those functions are reached. """ if isinstance(sentinel, list): sentinel = set(sentinel) if not isinstance(sentinel, set): raise AssertionError("{:s}.collectcall({:#x}, {!r}) : Sentinel is not a set.".format(__name__, ea, sentinel)) def _collectcall(addr, result): process = set() for f in func.down(addr): if any(f in coll for coll in (result, sentinel)): continue if not func.within(f): logging.warn("{:s}.collectcall({:#x}, {!r}) : Adding non-function address {:#x} ({:s}).".format(__name__, ea, sentinel, f, database.name(f))) result.add(f) continue process.add(f) for addr in process: result |= _collectcall(addr, result | process) return result addr = func.top(ea) return _collectcall(addr, set([addr]))
def checkmarks(): """Emit all functions that contain more than 1 mark within them. As an example, if marks are used to keep track of backtraces then this tool will emit where those backtraces intersect. """ res = [] for a, m in database.marks(): try: res.append((func.top(a), a, m)) except internal.exceptions.FunctionNotFoundError: pass continue d = list(res) d.sort( lambda a, b: cmp(a[0], b[0]) ) flookup = {} for fn, a, m in d: try: flookup[fn].append((a, m)) except: flookup[fn] = [(a, m)] continue functions = [ (k, v) for k, v in flookup.items() if len(v) > 1 ] if not functions: logging.warning('There are no functions available containing multiple marks.') return for k, v in functions: print >>sys.stdout, "{:#x} : in function {:s}".format(k, func.name(func.byAddress(k))) print >>sys.stdout, '\n'.join( ("- {:#x} : {:s}".format(a, m) for a, m in sorted(v)) ) return
def checkmarks(): '''Output all functions (sys.stdout) containing more than 1 mark.''' res = [] for a,m in database.marks(): try: res.append((function.top(a), a, m)) except ValueError: pass continue d = list(res) d.sort( lambda a,b: cmp(a[0], b[0]) ) flookup = {} for fn,a,m in d: try: flookup[fn].append((a,m)) except: flookup[fn] = [(a,m)] continue functions = [ (k,v) for k,v in flookup.items() if len(v) > 1 ] if not functions: logging.warning('There are no functions available containing multiple marks.') return for k,v in functions: print >>sys.stdout, '%x : in function %s'% (k,function.name(function.byAddress(k))) print >>sys.stdout, '\n'.join( ('- %x : %s'%(a,m) for a,m in sorted(v)) ) return
def apply_dyn_calls(dyn_calls, delete=False): hex = '{:x}'.format for dyn_call in dyn_calls: print(dyn_call) for i, p in enumerate(dyn_call.parents): print(i, hex(p)) top = func.top(p) if 'dynamic_call' not in func.tag(top): fn.tag(top, 'dynamic_call', set()) if delete: fn.tag(top, 'dynamic_call', None) continue curr_tag = fn.tag(top, 'dynamic_call') print(type(curr_tag), hex(top)) try: curr_tag.add(dyn_call.parents[i + 1]) except IndexError: curr_tag.add(dyn_call.call) fn.tag(top, 'dynamic_call', curr_tag) # Be sure to tag the actual function containing the dynamic call top = fn.top(dyn_call.call) if delete: if 'dynamic_call' in fn.tag(top): fn.tag(top, 'dynamic_call', None) if 'dynamic_call' in fn.tag(dyn_call.call): fn.tag(dyn_call.call, 'dynamic_call', None) continue if 'dynamic_call' not in fn.tag(top): fn.tag(top, 'dynamic_call', set()) curr_tag = fn.tag(top, 'dynamic_call') curr_tag.add(dyn_call.call) fn.tag(top, 'dynamic_call', curr_tag) db.tag(dyn_call.call, 'dynamic_call', 'here')
def checkmarks(): """Emit all functions that contain more than 1 mark within them. As an example, if marks are used to keep track of backtraces then this tool will emit where those backtraces intersect. """ listable = [] for a, m in database.marks(): try: listable.append((func.top(a), a, m)) except internal.exceptions.FunctionNotFoundError: pass continue d = listable[:] d.sort(key=lambda item: item[0]) flookup = {} for fn, a, m in d: try: flookup[fn].append((a, m)) except: flookup[fn] = [(a, m)] continue functions = [ (k, v) for k, v in flookup.items() if len(v) > 1 ] if not functions: logging.warning('There are no functions available containing multiple marks.') return for k, v in functions: six.print_("{:#x} : in function {:s}".format(k, func.name(func.by_address(k))), file=sys.stdout) six.print_('\n'.join(("- {:#x} : {:s}".format(a, m) for a, m in sorted(v))), file=sys.stdout) return
def collectcall(ea, sentinel=set()): """Collect all of the function calls starting at function `ea` and recurse until a terminating function is encountered. If the set `sentinel` is specified, then its addresses are used as sentinel functions and collection will terminate when one of those functions are reached. """ if isinstance(sentinel, list): sentinel = set(sentinel) if not isinstance(sentinel, set): raise AssertionError( "{:s}.collectcall({:#x}, {!r}) : Sentinel is not a set.".format( __name__, ea, sentinel)) def _collectcall(addr, result): process = set() for f in func.down(addr): if any(f in coll for coll in (result, sentinel)): continue if not func.within(f): logging.warn( "{:s}.collectcall({:#x}, {!r}) : Adding non-function address {:#x} ({:s})." .format(__name__, ea, sentinel, f, database.name(f))) result.add(f) continue process.add(f) for addr in process: result |= _collectcall(addr, result | process) return result addr = func.top(ea) return _collectcall(addr, set([addr]))
def tag(ea, *args, **kwds): '''tag(ea, key?, value?) -> fetches/stores a tag from specified address''' try: context = function.top(ea) except ValueError: context = None if len(args) == 0 and len(kwds) == 0: result = datastore.address(context).select(query.address(ea)) try: result = result[address] except: result = {} return result elif len(args) == 1: key, = args result = datastore.address(context).select(query.address(ea), query.attribute(key)) try: result = result[address][key] except: raise KeyError((hex(ea), key)) return result if len(args) > 0: key, value = args kwds.update({key: value}) return datastore.address(context).address(ea).set(**kwds)
def addEdge(self, src, dst): func_top = function.top(src) context = self.store.c(func_top) content = context.address(src) x = dst content.edge((x,x)) self.commit() return True
def iterate(self, pc, options): if self.provider.segStart(pc) == 0xFFFFFFFF: raise ValueError('F*****g IDA') # if its a call, get the xrefs from it # XXX: removed ia32 from public release #if ia32.isCall(insn): proc = self.provider.getArch() if proc == "pc": call_mnem = "call" elif proc == "arm" or proc == "ppc": call_mnem = "bl" elif proc == "mips": call_mnem = "jalr" # XXX gotta add support for jmps that go outside a function if call_mnem in self.provider.getMnem(pc).lower(): xrefs_from = database.cxdown(pc) func_top = function.top(pc) for x in xrefs_from: if self.provider.isCode(self.provider.getFlags(x)): xref_top = function.top(x) context = options['database'].c(func_top) content = context.address(pc) content.edge((x, x)) try: endEA = self.provider.funcEnd(pc) except: return if endEA == pc: return # removed as we aren't in private release # hlt instruction #if insn[1] == "\xf4": # return return
def addressToLocation(ea, chunks=None): """Convert the address `ea` to a `(function, id, offset)`. The fields `id` and `offset` represent the chunk index and the offset into the chunk for the function at `ea`. If the list `chunks` is specified as a parameter, then use it as a tuple of ranges in order to calculate the correct address. """ F, chunks = func.by(ea), chunks or [ch for ch in func.chunks(ea)] cid, base = next((i, l) for i, (l, r) in enumerate(chunks) if l <= ea < r) return func.top(F), cid, ea - base
def enter(self, pc, options): options['database'].address(pc)['name'] = database.name(pc) xrefs_to = database.cxup(pc) func_top = pc for x in xrefs_to: xref_top = function.top(x) context = options['database'].c(xref_top) context.address(x).edge((func_top, func_top)) return
def fetch_function(f): addr, tags = {}, {} for ea in fn.iterate(f): res = db.tag(ea) #res.pop('name', None) for k, v in res.iteritems(): addr[ea] = addr.get(ea, 0) + 1 tags[k] = tags.get(k, 0) + 1 continue ea = f return fn.top(ea), addr, tags
def name(ea, string=None): '''Returns the name at the specified address. (local than global)''' if string is not None: SN_NOCHECK = 0x00 SN_NOLIST = 0x80 SN_LOCAL = 0x200 SN_PUBLIC = 0x02 n = name(ea) flags = SN_NOCHECK try: function.top(ea) flags |= SN_LOCAL except ValueError: flags |= 0 idc.MakeNameEx(ea, string, flags) #tag(ea, '__name__', string) return n return None
def color_block(ea=None, color=0x55ff7f): """http://reverseengineering.stackexchange.com/questions/10662/change-block-node-color-with-idapython and WanderingGlitch for the tip of refresh_idaview_anyway()""" func_top = fn.top() f = idaapi.get_func(ea) g = idaapi.FlowChart(f, flags=idaapi.FC_PREDS) bb_id = get_bb_id(g, ea) p = idaapi.node_info_t() p.bg_color = color idaapi.set_node_info2(func_top, bb_id, p, idaapi.NIF_BG_COLOR | idaapi.NIF_FRAME_COLOR) idaapi.refresh_idaview_anyway()
def dump_breaks(func=None, tagname='break', stdout=True): if func is None: for func, _ in db.selectcontents(tagname): dump_breaks(func, tagname=tagname) return Escape = lambda s: s.replace('"', '\\"') entry, exit = fn.top(func), fn.bottom(func) funcname = fn.name(func) #[(entry,{tagname:'.printf "Entering {:s} %x,%x\\n",poi(@esp),@esp'.format(funcname)})], [(x,{tagname:'.printf "Exiting {:s} %x,%x\\n",poi(@esp),@esp'.format(funcname)}) for x in exit], select = itertools.chain(fn.select(func, And=(tagname, ), Or=('', ))) res = {} for ea, t in select: h = res.setdefault(ea, {}) for k in t.keys(): if k == tagname: h.setdefault(k, []).extend(t[k].split(';')) else: assert k not in h h[k] = t[k] continue output = [] for ea, t in res.iteritems(): ofs = db.offset(ea) commands = [] label = Template('.printf "$label -- $note\\n"' if t. has_key('') else '.printf "$label\\n"') commands.append( label.safe_substitute(label=eaToLabel(ea), note=t.get('', ''))) commands.extend(t.get(tagname, ['g'])) commands = map(windbgescape, commands) breakpoint = 'bp {:s} "{:s}"'.format(eaToReference(ea), Escape(';'.join(commands))) if stdout: print(breakpoint) output.append(breakpoint) if len(output) == 1: return output[0] + '\n' return '\n'.join(output)
def getText(self, addy): #print "Fetching text for %08x" % addy color = idaapi.SCOLOR_STRING if addy == function.top(addy): name = idc.NameEx(addy, addy) try: name = idc.Demangle(name, idc.GetLongPrm(idc.INF_SHORT_DN)) except: pass else: name = idc.NameEx(addy, addy) if name: return idaapi.COLSTR(" %s " % name, color) else: return idaapi.COLSTR(" 0x%08x " % addy, color)
def colormarks(color=0x7f007f): '''Iterate through all database marks and tag+color their address''' # tag and color f = set() for ea, m in database.marks(): database.tag(ea, 'mark', m) database.color(ea, color) try: f.add(function.top(ea)) except (LookupError, ValueError): pass # tag the functions too for ea in list(f): m = function.marks(ea) function.tag(ea, 'marks', [ea for ea, _ in m]) return
def colormarks(color=0x7f007f): '''Iterate through all database marks and tag+color their address''' # tag and color f = set() for ea,m in database.marks(): database.tag(ea, 'mark', m) database.color(ea, color) try: f.add(function.top(ea)) except ValueError: pass continue # tag the functions too for ea in list(f): m = function.marks(ea) function.tag(ea, 'marks', [ea for ea,_ in m]) return
def colormarks(color=0x7f007f): """Walk through the current list of marks whilst coloring them with the specified `color`. Each mark's address is tagged with its description, and if the address belongs to a function, the function is also tagged with the address of the marks that it contains. """ # tag and color f = set() for ea, m in database.marks(): database.tag(ea, 'mark', m) if database.color(ea) is None: database.color(ea, color) try: f.add(func.top(ea)) except internal.exceptions.FunctionNotFoundError: pass continue # tag the functions too for ea in list(f): m = func.marks(ea) func.tag(ea, 'marks', [ea for ea, _ in m]) return
def top(ea=None): return function.top(ea is not None and ea or database.h())
def below(ea): '''Display all the functions that the function at /ea/ can call''' tryhard = lambda x: '%s+%x'%(database.name(function.top(x)),x-function.top(x)) if function.within(x) else hex(x) if database.name(x) is None else database.name(x) return '\n'.join(map(tryhard,function.down(ea)))
def above(ea): '''Display all the callers of the function at /ea/''' tryhard = lambda x: '%s+%x'%(database.name(function.top(x)),x-function.top(x)) if function.within(x) else hex(x) if database.name(x) is None else database.name(x) return '\n'.join(map(tryhard,function.up(ea)))
def top(): import function # ida's usage of python sucks. return function.top(db.h())
def below(ea): '''Display all the functions that the function at /ea/ can call''' tryhard = lambda x: '%s+%x' % (database.name(function.top( x)), x - function.top(x)) if function.within(x) else hex( x) if database.name(x) is None else database.name(x) return '\n'.join(map(tryhard, function.down(ea)))
def __init__(self, options, create=True, existing=None): self.provider = ida.IDA() if create: # create the DB print "[*] db.py: Creating a new DB file" db = store.sqlite3.connect(options['full_file_name']) #db.isolation_level = self.db_obj = db store.driver.sqlite.Deploy(db).create() # mutes the pesky sqlite messages tmp = sys.stderr sys.stderr = StringIO() session = store.driver.sqlite.Session(db,0) my_store = store.Store(session) sys.stderr = tmp all_funcs = database.functions() opt = {} opt['database'] = my_store self.store = my_store proc = self.provider.getArch() if proc == "pc": # XXX: hackish way to fix a crap ton of stuff... start = self.provider.segByBase(self.provider.segByName(".text")) end = self.provider.segEnd(self.provider.segByBase(self.provider.segByName(".text"))) succeeded = 0 for instr in self.provider.iterInstructions(start, end): disasm = self.provider.getDisasm(instr) tokens = disasm.split(" ") res = [] for t in tokens: if len(t) != 0: res.append(t) prologues = [['mov', 'edi,', 'edi'], ['push', 'ebp'], ['push', 'rbp']] if res in prologues and instr not in all_funcs: try: prev_ea = self.provider.prevItem(instr, instr-0x20) if prev_ea not in all_funcs: if options['verbosity'] > 2: print "[!] Attempting to create a function at 0x%08x" % instr ret = self.provider.makeFunc(instr) else: continue if ret: if options['verbosity'] > 2: print "[*] Successfully made new function at 0x%08x" % instr succeeded += 1 except Exception as detail: print detail pass elif "dup(90h)" in disasm: if options['verbosity'] > 2: print "Found dup at 0x%08x" % instr try: next_ea = self.provider.nextItem(instr, instr+0x20) if next_ea not in all_funcs: ret = self.provider.nextItem(next_ea, 0xFFFFFFFF) else: continue if not ret and (next_ea in database.functions()) : if options['verbosity'] > 2: print "[*] Successfully made new function at 0x%08x" % next_ea succeeded += 1 except: pass if succeeded != 0: print "[*] Successfully created %d new functions" % succeeded print "[*] There are %d funtions to process" % len(all_funcs) failed = 0 succeeded = 0 for i in xrange(0, len(all_funcs)): i_actual = i+1 ea = all_funcs[i] if ((i_actual % 250 == 0) or (i == len(all_funcs)-1)): print "[*] db.py: Processing 0x%08x (%d of %d)" % (ea, i_actual, len(all_funcs)) analyza = analyze_xrefs(opt) collecta = collector(analyza, opt) try: collecta.go(ea) succeeded += 1 except ValueError as detail: failed += 1 if options['verbosity'] > 2: print "0x%08x - failed to process node, %s" % (ea, detail) opt['database'].commit() print "[*] Failed to process %d functions" % failed print "[*] Successfully processed %d functions" % succeeded # now loop imports segs = list(self.provider.getSegments()) if proc in ["arm", "ppc", "mips"]: idata = "extern" elif proc == "pc": idata = ".idata" for s in segs: if self.provider.segName(s) == idata: start = s end = self.provider.segEnd(s) for head in self.provider.iterData(start, end): opt['database'].address(head)['name'] = self.provider.getName(head) xrefs_to = database.cxup(head) for x in xrefs_to: try: xref_top = function.top(x) except ValueError: continue context = opt['database'].c(xref_top) context.address(x).edge((head, head)) self.commit() else: db = store.sqlite3.connect(options['full_file_name']) self.db_obj = db # mutes the pesky sqlite messages tmp = sys.stderr sys.stderr = StringIO() session = store.driver.sqlite.Session(db,0) sys.stderr = tmp my_store = store.Store(session) self.store = my_store
def nextstack(cls, ea, delta): fn, sp = function.top(ea), function.getSpDelta(ea) return cls.walk(ea, cls.next, lambda n: abs(function.getSpDelta(n) - sp) < delta)
def below(ea, includeSegment=False): '''Return all of the function names and their offset that are called by the function at `ea`.''' tryhard = lambda ea: "{:s}{:+x}".format(func.name(func.top(ea)), ea - func.top(ea)) if func.within(ea) else "{:+x}".format(ea) if func.name(ea) is None else func.name(ea) return '\n'.join(':'.join((segment.name(ea), tryhard(ea)) if includeSegment else (tryhard(ea),)) for ea in func.down(ea))
def top(): return function.top(database.h())
def above(ea): '''Display all the callers of the function at /ea/''' tryhard = lambda x: '%s+%x' % (database.name(function.top( x)), x - function.top(x)) if function.within(x) else hex( x) if database.name(x) is None else database.name(x) return '\n'.join(map(tryhard, function.up(ea)))
def name(ea=None, *args, **kwds): """name(ea), name(ea, string) First syntax returns the name at the given address. Second syntax changes the name at the given address. """ if len(args) > 1: raise TypeError, "{:s}() takes exactly {!r} arguments ({:d} given)".format( 'name', (1, 2), len(args) + 1 + len(kwds)) if kwds and tuple(kwds.keys()) != ('string', ): raise TypeError, "{:s}() got an unexpected keyword argument '{:s}'".format( 'name', filter(lambda n: n != 'string', kwds.keys())[0]) ea = ui.current.address() if ea is None else ea if len(args) == 1 or kwds.has_key('string'): string = kwds.get('string', args[0]) assert idaapi.SN_NOCHECK == 0, '%s.name : idaapi.SN_NOCHECK != 0' % __name__ SN_NOLIST = idaapi.SN_NOLIST SN_LOCAL = idaapi.SN_LOCAL SN_NON_PUBLIC = idaapi.SN_NON_PUBLIC if idaapi.has_any_name(idaapi.getFlags(ea)): pass flags = idaapi.SN_NON_AUTO flags |= 0 if idaapi.is_in_nlist(ea) else idaapi.SN_NOLIST flags |= idaapi.SN_WEAK if idaapi.is_weak_name( ea) else idaapi.SN_NON_WEAK flags |= idaapi.SN_PUBLIC if idaapi.is_public_name( ea) else idaapi.SN_NON_PUBLIC try: function.top(ea) flags |= idaapi.SN_LOCAL except Exception: flags &= ~idaapi.SN_LOCAL try: # check if we're a label of some kind f = idaapi.getFlags(ea) if idaapi.has_dummy_name(f) or idaapi.has_user_name(f): # that is referenced by an array with a correctly sized pointer inside it (r, sidata), = ((r, type.array(r)) for r in xref.data_up(ea)) if config.bits() == sidata.itemsize * 8 and ea in sidata: # which we check to see if it's a switch_info_t si, = (idaapi.get_switch_info_ex(r) for r in xref.data_up(r)) if si is not None: # because it's name has it's local flag cleared flags ^= idaapi.SN_LOCAL except: pass res, ok = name(ea), idaapi.set_name(ea, string or "", flags) tag(ea, 'name', string) assert ok, '%s.name : unable to call idaapi.set_name(%x, %r, %x)' % ( __name__, ea, string, flags) return res try: return tag(ea, 'name') except KeyError: pass return None