コード例 #1
0
def nameDispatch(address):
    '''Name the dispatch function at the specified address in quicktime.qts'''
    try:
        start, end = function.getRange(address)

    except ValueError:
        print '%x making a function' % address
        function.make(address)
        start, end = function.getRange(address)

    try:
        ea = FindLastAssignment(address, 'eax')
        code = getDispatchCode(ea)
    except ValueError:
        print '%08x - Unable to find dispatch code' % address
        return

    function.setName(start, 'dispatch_%08x' % code)
    function.tag(start, 'code', code)
    function.tag(start, 'group', 'dispatch')
    try:
        function.tag(start, 'realname', __quicktime.qt_fv_list[code])
    except KeyError:
        pass

    try:
        function.tag(start,
                     'address',
                     resolveDispatcher(code),
                     repeatable=True)
    except:
        pass
コード例 #2
0
ファイル: quicktime.py プロジェクト: IDA-RE-things/toolbag
def nameDispatch(address):
    '''Name the dispatch function at the specified address in quicktime.qts'''
    try:
        start, end = function.getRange(address)

    except ValueError:
        print '%x making a function'% address
        function.make(address)
        start, end = function.getRange(address)

    try:
        ea = FindLastAssignment(address, 'eax')
        code = getDispatchCode(ea)
    except ValueError:
        print '%08x - Unable to find dispatch code'% address
        return

    function.setName(start, 'dispatch_%08x'% code)
    function.tag(start, 'code', code)
    function.tag(start, 'group', 'dispatch')
    try:
        function.tag(start, 'realname', __quicktime.qt_fv_list[code])
    except KeyError:
        pass

    try:
        function.tag(start, 'address', resolveDispatcher(code), repeatable=True)
    except:
        pass
コード例 #3
0
ファイル: callgraph.py プロジェクト: IDA-RE-things/revtools
    def tag_popularity(self, context=None):
        import function
        import idautils
        import idc
        import symath.graph.algorithms as algorithms
        funcs = set(idautils.Functions())
        rv = {}

        for fa in funcs:
            f = idc.GetTrueName(fa)
            p = algorithms.popularity(self, node=f, context=context)
            function.tag(fa, 'popularity', p)
            rv[fa] = p

        return rv
コード例 #4
0
def search_func(addr, funcname, curr_addr_list=None):
    """
    Given an address and function name, recursively look from the given address
    for calls to the given function name. Modifies the 'calls' function tag with
    the function name and True or False depending if the function contains the wanted
    function or not.
    """
    if curr_addr_list == None:
        curr_addr_list = [addr]

    print("Addr: {}".format(addr))
    curr_calls = fn.tag(addr).get('calls', {})
    for ea in fn.iterate(addr):
        if funcname in db.disasm(ea):
            curr_calls[funcname] = True
            fn.tag(addr, 'calls', curr_calls)
            return True

        if not ins.isCall(ea):
            continue

        call = ins.op_value(ea, 0)

        # Don't cycle ourselves
        if call == addr:
            print("Ignoring recursive loop on function: {}".format(hex(addr)))
            continue

        # Try to know if the call operand is a valid address
        # Bail if not..
        try:
            print(hex(call))
        except:
            continue

        # Check if this function has been analyzed already
        # and return the result
        # Cannot return False, because that will exit the loop and not
        # continue to iterate over the rest of the instrutions in the function
        call_cache = fn.tag(call).get('calls', {})
        print("Call cache: {}".format(call_cache))
        if funcname in call_cache:
            if call_cache[funcname]:
                curr_calls[funcname] = call_cache[funcname]
                fn.tag(addr, 'calls', curr_calls)
                return True

        # Don't call functions we are currently looking into
        if call in curr_addr_list:
            continue

        # Only now ca
        curr_addr_list.append(call)
        search_func(call, funcname=funcname, curr_addr_list=curr_addr_list)

    curr_calls[funcname] = False
    fn.tag(addr, 'calls', curr_calls)
    return False
コード例 #5
0
 def __select(q):
     for x in functions():
         x = function.top(x)
         if q.has(function.tag(x)):
             yield x
         continue
     return
コード例 #6
0
    def select(*tags, **boolean):
        '''Fetch all the functions containing the specified tags within it's declaration'''
        boolean = dict((k, set(v) if type(v) is tuple else set((v, )))
                       for k, v in boolean.viewitems())
        if tags:
            boolean.setdefault(
                'And',
                set(boolean.get(
                    'And',
                    set())).union(set(tags) if len(tags) > 1 else set(tags, )))

        if not boolean:
            for ea in functions():
                res = tag(ea)
                if res: yield ea, res
            return

        for ea in functions():
            res, d = {}, function.tag(ea)

            Or = boolean.get('Or', set())
            res.update((k, v) for k, v in d.iteritems() if k in Or)

            And = boolean.get('And', set())
            if And:
                if And.intersection(d.viewkeys()) == And:
                    res.update((k, v) for k, v in d.iteritems() if k in And)
                else:
                    continue
            if res: yield ea, res
        return
コード例 #7
0
ファイル: database.py プロジェクト: nihilus/idascripts-2
    def select(*tags, **boolean):
        '''Fetch all the functions containing the specified tags within it's declaration'''
        boolean = dict((k,set(v) if type(v) is tuple else set((v,))) for k,v in boolean.viewitems())
        if tags:
            boolean.setdefault('And', set(boolean.get('And',set())).union(set(tags) if len(tags) > 1 else set(tags,)))

        if not boolean:
            for ea in functions():
                res = tag(ea)
                if res: yield ea, res
            return

        for ea in functions():
            res,d = {},function.tag(ea)

            Or = boolean.get('Or', set())
            res.update((k,v) for k,v in d.iteritems() if k in Or)

            And = boolean.get('And', set())
            if And:
                if And.intersection(d.viewkeys()) == And:
                    res.update((k,v) for k,v in d.iteritems() if k in And)
                else: continue
            if res: yield ea,res
        return
コード例 #8
0
ファイル: database.py プロジェクト: corelanc0d3r/toolbag
def __select(q):
    for x in functions():
        x = function.top(x)
        if q.has(function.tag(x)):
            yield x
        continue
    return
コード例 #9
0
ファイル: hooks.py プロジェクト: 5l1v3r1/ida-minsc
def del_func(pfn):
    global State
    if State != state.ready: return

    # convert all contents into globals
    for l, r in function.chunks(pfn):
        for ea in database.address.iterate(l, r):
            for k in database.tag(ea):
                internal.comment.contents.dec(
                    ea, k, target=interface.range.start(pfn))
                internal.comment.globals.inc(ea, k)
                logging.debug(
                    u"{:s}.del_func({:#x}) : Exchanging (increasing) refcount for global tag {!s} and (decreasing) refcount for contents tag {!s}."
                    .format(__name__, interface.range.start(pfn),
                            utils.string.repr(k), utils.string.repr(k)))
            continue
        continue

    # remove all function tags
    for k in function.tag(interface.range.start(pfn)):
        internal.comment.globals.dec(interface.range.start(pfn), k)
        logging.debug(
            u"{:s}.del_func({:#x}) : Removing (global) tag {!s} from function."
            .format(__name__, interface.range.start(pfn),
                    utils.string.repr(k)))
    return
コード例 #10
0
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
コード例 #11
0
ファイル: helper.py プロジェクト: IDA-RE-things/idascripts
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
コード例 #12
0
ファイル: functiongraph.py プロジェクト: bniemczyk/revtools
    def tag_signed():
        import function
        import idc
        import idautils

        fns = set(idautils.Functions())
        rv = {}
        
        for f in fns:
            fg = FunctionGraph(f)
            for n in fg.nodes:
                m = idc.GetMnem(n).lower()
                if m in ('jl', 'jle', 'jg', 'jge', 'js'):
                    function.tag(f, 'signed arithmetic', True)
                    rv[f] = True
                    break

        return rv
コード例 #13
0
ファイル: prioritize.py プロジェクト: IDA-RE-things/revtools
def prioritize(ruleset=DEFAULT_RULESET, context=None):
    ruleset = list(ruleset)

    # make all weights explicit
    for i in range(len(ruleset)):
        if type(ruleset[i]) != type((1,1)):
            print 'using default weight of 1.0 for %s' % (ruleset[i],)
            ruleset[i] = (ruleset[i], 1.0)

    numerator = {}
    denominator = {}
    zeros = {}

    fns = set(idautils.Functions())
    for f in fns:
        numerator[f] = 0.0
        denominator[f] = 0.0
        zeros[f] = False

    for (rule,weight) in ruleset:
        d = rule(context)
        for f in fns:
            if f not in d:
                continue
            if d[f] == 0:
                zeros[f] = True
            else:
              try:
                numerator[f] += symath.desymbolic(weight) * math.log(symath.desymbolic(d[f]))
                denominator[f] += symath.desymbolic(weight)
              except:
                print "could not float/parse either %s or %s" % (weight, d[f])
                raise

    for f in fns:
        if denominator[f] != 0.0 and not zeros[f]:
            numerator[f] = math.exp(numerator[f] / denominator[f])
        else:
            numerator[f] = 0.0

        function.tag(f, 'priority', numerator[f])

    return numerator
コード例 #14
0
ファイル: functiongraph.py プロジェクト: bniemczyk/revtools
    def tag_cyclomatic_complexity():
        import function
        import idc
        import idautils
        import symath.graph.signatures as sigs

        fns = set(idautils.Functions())
        rv = {}

        for f in fns:
            fg = FunctionGraph(f)
            #c = fg.cyclomatic_complexity()
            c = sigs.complexity(fg)[1]
            if c < 0:
                c = 0
            function.tag(fg.start_addr, 'cyclomatic complexity', c)
            rv[f] = c

        return rv
コード例 #15
0
ファイル: tagfix.py プロジェクト: k273811702/idascripts
def do_functions():
    addr, tags = {}, {}
    t = len(list(db.functions()))
    for i, ea in enumerate(db.functions()):
        print "{:x} : fetching function {:d} of {:d}".format(ea, i, t)
        res = fn.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
    return addr, tags
コード例 #16
0
ファイル: callgraph.py プロジェクト: IDA-RE-things/revtools
    def tag_recursive(self):
        import function
        import idautils
        import idc
        funcs = set(idautils.Functions())
        rv = {}

        for fa in funcs:

            f = idc.GetTrueName(fa)
            tags = []
            for stack in self.stackwalk(f):
                if self.connectedQ(stack[-1], f):
                    tags.append(stack)
            
            
            if len(tags) > 0:
                function.tag(idc.LocByName(f), 'recursive', tags)
                rv[fa] = len(tags)

        return rv
コード例 #17
0
ファイル: callgraph.py プロジェクト: IDA-RE-things/revtools
    def tag_distance(self, function_name, direction='incoming'):
        import function
        import idc
        import idautils
        f = idc.LocByName(function_name)
        rv = {}
        fns = set(idautils.Functions())

        for (n,l) in self.walk(function_name, direction=direction):
            if l == 0:
                continue

            loc = idc.LocByName(n)
            if loc in fns:
                function.tag(loc, '%s distance %s' % (direction, function_name), l)
                rv[loc] = l

        for fn in fns:
            if fn not in rv:
                rv[fn] = 0.0

        return rv
コード例 #18
0
def globals():
    '''Yields all the global tags.'''
    ea, sentinel = db.range()
    while ea < sentinel:
        f = idaapi.get_func(ea)
        if f:
            t = fn.tag(ea)
            if t: yield ea, t
            ea = f.endEA
            continue
        t = db.tag(ea)
        if t: yield ea, t
        ea = db.a.next(ea)
    return
コード例 #19
0
ファイル: functiongraph.py プロジェクト: bniemczyk/revtools
    def tag_aggregate_complexity():
        import function
        import idc
        import idautils
        import callgraph
        import symath.graph.signatures as sigs

        cg = callgraph.CallGraph(includeImports=False)

        graphs = {}
        _reversed = {}
        rv = {}

        fns = set(idautils.Functions())
        cc = {}

        for f in fns:
            graphs[f] = FunctionGraph(f)
            _reversed[f] = FunctionGraph._tag_val(f, 'reversed') != None
            if _reversed[f]:
                cg.strip_edges_to(idc.GetTrueName(f))

        for i in fns:
            ac = symbolic(0)
            for j,l in cg.walk(idc.GetTrueName(i), direction='outgoing'):
                loc = idc.LocByName(j)
                if loc not in graphs:
                  continue
                if loc not in cc:
                    cc[loc] = sigs.complexity(graphs[loc])[1]
                ac += cc[loc] if cc[loc] > 0 else 0

            ac = ac.simplify()
            function.tag(i, 'aggregate complexity', ac)
            rv[i] = ac

        return rv
コード例 #20
0
ファイル: tools.py プロジェクト: perfectswpuboy1/ida-minsc
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
コード例 #21
0
ファイル: tools.py プロジェクト: arizvisa/idascripts
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
コード例 #22
0
ファイル: functiongraph.py プロジェクト: bniemczyk/revtools
    def tag_xors():
        import function
        import idc
        import idautils

        fns = set(idautils.Functions())
        rv = {}

        for f in fns:
            #print 'analyzing %x for xor loops' % (f)
            fg = FunctionGraph(f)
            rv[f] = False
            for n in fg.nodes:
                m = idc.GetMnem(n)
                if m != 'xor':
                    continue
                op0 = idc.GetOpnd(n,0)
                op1 = idc.GetOpnd(n,1)
                if op0 != op1 and n in algorithms.find_cylic_nodes(fg,f):
                    function.tag(f, 'xor in loop', True)
                    rv[f] = True
                    break

        return rv
コード例 #23
0
def del_func(pfn):
    global State
    if State != state.ready: return
    # convert all contents into globals
    for (l,r) in function.chunks(pfn):
        for ea in database.iterate(l, r):
            for k in database.tag(ea):
                internal.comment.contents.dec(ea, k, target=pfn.startEA)
                internal.comment.globals.inc(ea, k)
            continue
        continue

    # remove all function tags
    for k in function.tag(pfn.startEA):
        internal.comment.globals.dec(pfn.startEA, k)
    return
コード例 #24
0
ファイル: objects.py プロジェクト: IDA-RE-things/revtools
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
コード例 #25
0
ファイル: hooks.py プロジェクト: heruix/ida-minsc
def del_func(pfn):
    global State
    if State != state.ready: return
    # convert all contents into globals
    for l, r in function.chunks(pfn):
        for ea in database.address.iterate(l, r):
            for k in database.tag(ea):
                internal.comment.contents.dec(ea, k, target=pfn.startEA)
                internal.comment.globals.inc(ea, k)
                logging.debug("{:s}.del_func({:#x}) : Decreasing refcount for contents tag {!r} and increasing refcount for globals tag {!r}".format(__name__, pfn.startEA, k, k))
            continue
        continue

    # remove all function tags
    for k in function.tag(pfn.startEA):
        internal.comment.globals.dec(pfn.startEA, k)
        logging.debug("{:s}.del_func({:#x}) : Removing function (global) tag {!r}".format(__name__, pfn.startEA, k))
    return
コード例 #26
0
ファイル: tagfix.py プロジェクト: arizvisa/idascripts
def fetch_globals_functions():
    """Fetch the reference count for the global tags (function) in the database.

    Returns the tuple `(address, tags)` where the `address` and `tags`
    fields are both dictionaries containing the reference count for
    the addresses and tag names.
    """
    addr, tags = {}, {}
    t = len(list(db.functions()))
    for i, ea in enumerate(db.functions()):
        ui.navigation.auto(ea)
        six.print_(u"globals: fetching tag from function {:#x} : {:d} of {:d}".format(ea, i, t), file=output)
        res = func.tag(ea)
        #res.pop('name', None)
        for k, v in six.iteritems(res):
            addr[ea] = addr.get(ea, 0) + 1
            tags[k] = tags.get(k, 0) + 1
        continue
    return addr, tags
コード例 #27
0
def fetch_globals_functions():
    """Fetch the reference count for the global tags (function) in the database.

    Returns the tuple `(address, tags)` where the `address` and `tags`
    fields are both dictionaries containing the reference count for
    the addresses and tag names.
    """
    addr, tags = {}, {}
    t = len(list(db.functions()))
    for i, ea in enumerate(db.functions()):
        ui.navigation.auto(ea)
        print >> output, "globals: fetching tag from function {:#x} : {:d} of {:d}".format(
            ea, i, t)
        res = func.tag(ea)
        #res.pop('name', None)
        for k, v in six.iteritems(res):
            addr[ea] = addr.get(ea, 0) + 1
            tags[k] = tags.get(k, 0) + 1
        continue
    return addr, tags
コード例 #28
0
ファイル: main.py プロジェクト: HomuraNoKen/amai-chan
async def rand_tag(ctx, *, arg):
    embed = tag(arg)
    msg = await ctx.send(embed=embed)
    await msg.add_reaction('👍')
    await msg.add_reaction('👎')
    await msg.add_reaction('❌')
コード例 #29
0
def search_malloc(addr, funcname='malloc', curr_addr_list=None):
    # print(hex(addr), curr_addr_list)
    if curr_addr_list == None:
        curr_addr_list = [addr]

    print("Addr: {}".format(addr))
    curr_calls = fn.tag(addr).get('calls', {})
    for ea in fn.iterate(addr):
        if not ins.isCall(ea):
            continue

        if ins.op_type(0) == 'reg':
            """
            Handle this case - malloc(100)
            mov ebp, ds:malloc
            push 100
            call ebp
            """

        if funcname in db.disasm(ea):
            # Push before malloc "should" be within 20 instructions
            """
            Handle this case - malloc(100)
            push 100
            mov eax, 10
            mov ebx, 20
            call malloc
            """
            search_addr = db.prev(ea)
            for _ in range(20):
                if ins.mnem(search_addr) == 'push':
                    break
                search_addr = db.prev(search_addr)

            print("FOUND PUSH FOR MALLOC: {}".format(hex(search_addr)))
            malloc_value = ins.op_value(search_addr, 0)
            if isinstance(malloc_value, (int, long)):
                curr_calls[funcname] = malloc_value
            else:
                curr_calls[funcname] = 'variable'

            fn.tag(addr, 'calls', curr_calls)
            return True

        call = ins.op_value(ea, 0)

        # Don't cycle ourselves
        if call == addr:
            print("Ignoring recursive loop on function: {}".format(hex(addr)))
            continue

        # Try to know if the call operand is a valid address
        # Bail if not..
        try:
            print(hex(call))
        except:
            continue

        # Check if this function has been analyzed already
        # and return the result
        # Cannot return False, because that will exit the loop and not
        # continue to iterate over the rest of the instrutions in the function
        call_cache = fn.tag(call).get('calls', {})
        print("Call cache: {}".format(call_cache))
        if funcname in call_cache:
            if call_cache[funcname]:
                curr_calls[funcname] = call_cache[funcname]
                fn.tag(addr, 'calls', curr_calls)
                return True

        # Don't call functions we are currently looking into
        if call in curr_addr_list:
            continue

        # Only now ca
        curr_addr_list.append(call)
        search_malloc(call, funcname=funcname, curr_addr_list=curr_addr_list)

    curr_calls[funcname] = False
    fn.tag(addr, 'calls', curr_calls)
    return False
コード例 #30
0
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')
コード例 #31
0
ファイル: functiongraph.py プロジェクト: bniemczyk/revtools
 def _tag_val(addr, tagname, default=None):
     import function
     try:
         return function.tag(addr, tagname)
     except:
         return default
コード例 #32
0
 def has(ea):
     d = function.tag(ea)
     for k, v in where.iteritems():
         if k not in d or (v is not None and v != d[k]):
             return False
     return True