Beispiel #1
0
def getEmuAtVa(vw, va, maxhit=None):
    """
    Build and run an emulator to the given virtual address
    from the function entry point.

    (most useful for state analysis.  kinda heavy though...)
    """
    fva = vw.getFunction(va)
    if fva == None:
        return None

    cbva,cbsize,cbfva = vw.getCodeBlock(va)
    fgraph = v_graphutil.buildFunctionGraph(vw, fva)

    # Just take the first one off the iterator...
    for path in v_graphutil.getCodePathsTo(fgraph, cbva):

        emu = vw.getEmulator()
        opcodes = v_graphutil.getOpsFromPath(vw, fgraph, path)
        for op in opcodes:
            if op.va == va:
                break

            emu.executeOpcode(op)

        return emu
Beispiel #2
0
    def _hotkey_paintUp(self, va=None):
        """
        Paint the VA's from the selected basic block up to all possible 
        non-looping starting points.
        """
        graph = viv_graphutil.buildFunctionGraph(self.vw, self.fva, revloop=True)
        startva = self.mem_canvas._canv_curva
        if startva == None:
            return

        viv_graphutil.preRouteGraphUp(graph, startva, mark="hit")

        count = 0
        colormap = {}
        for node in graph.getNodesByProp("hit"):
            count += 1
            off = 0
            cbsize = node[1].get("cbsize")
            if cbsize == None:
                raise Exception("node has no cbsize: %s" % repr(node))

            # step through opcode for a node
            while off < cbsize:
                op = self.vw.parseOpcode(node[0] + off)
                colormap[op.va] = "orange"
                off += len(op)

        self.vw.vprint("Colored Blocks: %d" % count)
        vqtevent("viv:colormap", colormap)
        return colormap
Beispiel #3
0
    def _hotkey_paintMerge(self, va=None):
        """
        same as paintdown but only until the graph remerges
        """

        graph = viv_graphutil.buildFunctionGraph(self.vw, self.fva, revloop=True)
        startva = self.mem_canvas._canv_curva
        if startva == None:
            return

        viv_graphutil.findRemergeDown(graph, startva)

        count = 0
        colormap = {}
        for node in graph.getNodesByProp("hit"):
            count += 1
            off = 0
            cbsize = node[1].get("cbsize")
            if cbsize == None:
                raise Exception("node has no cbsize: %s" % repr(node))

            # step through opcode for a node
            while off < cbsize:
                op = self.vw.parseOpcode(node[0] + off)
                colormap[op.va] = "brown"
                off += len(op)

        self.vw.vprint("Colored Blocks: %d" % count)
        vqtevent("viv:colormap", colormap)
        return colormap
Beispiel #4
0
    def _hotkey_paintDown(self, va=None):
        """
        Paint the VA's from the selected basic block down to all possible 
        non-looping blocks.  This is valuable for determining what code can 
        execute from any starting basic block, without a loop.
        """
        # TODO: make overlapping colors available for multiple paintings

        graph = viv_graphutil.buildFunctionGraph(self.vw, self.fva, revloop=True)
        startva = self.mem_canvas._canv_curva
        if startva == None:
            return

        viv_graphutil.preRouteGraphDown(graph, startva, mark="hit")

        count = 0
        colormap = {}
        for node in graph.getNodesByProp("hit"):
            count += 1
            off = 0
            cbsize = node[1].get("cbsize")
            if cbsize == None:
                raise Exception("node has no cbsize: %s" % repr(node))

            # step through opcode for a node
            while off < cbsize:
                op = self.vw.parseOpcode(node[0] + off)
                colormap[op.va] = "brown"
                off += len(op)

        self.vw.vprint("Colored Blocks: %d" % count)
        vqtevent("viv:colormap", colormap)
        return colormap
Beispiel #5
0
	def graphSearch(self):
		"""
			Do a graph search in the code for leaf nodes

			TODO: check if detected instruction is a jump!
		"""
		# search for EIP and loop on all of them
		for eip in self.vw.getEntryPoints():
			if self.debug:
				print("FOUND ENTRY POINT 0x%08x\n" % eip)

			# build a code graph starting at EIP
			graph = viv_cgh.buildFunctionGraph(self.vw, eip)
			visited = []

			for node in graph.getNodes():
				if(node in visited):
					if self.debug:
						print("LOOP DETECTED in CODE -- ignoring path!")
					break
				else:
					visited.append(node)
				if graph.isLeafNode(node):
					# TODO print the surrounding code block
					if self.isJumpFar(node[0]):
						print("TIP: Set BP at: 0x%08x (%s)" % (node[0], self.vw.reprVa(node[0])))
						refby = self.vw.getXrefsTo(node[0])
						for ref in refby:
							print("    REFERENCED at:  0x%08x (%s)" % (ref[0], self.vw.reprVa(ref[0])))
							self.getFunctionCode(ref[0])
						self.bininfo.breakpoints.append(node[0])
		return
Beispiel #6
0
def getFunctionEdgeList(vw, fva):
    '''
    Return a list of b1mnems|b2mnems strings where b*mnems is a list
    of the instruction mnemonics for each block.  This creates a list of
    "edges" rather than a list of blocks which makes false positive matches
    on similar blocks less likely.
    '''

    g = viv_graphutil.buildFunctionGraph(vw, fva)

    # A variant on the function hash graph stuff which allows
    # similarity comparison...

    for nid,ninfo in g.getNodes():

        # Just the mnemonics... (may allow block comparison *inside* funcions with diffs)
        mnems = getBlockMnems(vw, ninfo['cbva'], ninfo['cbsize'])
        ninfo['diff_node'] = mnems

    # Similar to get function hash but the data in the block relationship *must*
    # be more stable across changes to identify the totally new blocks
    edgediff = []
    for eid, fromid, toid, einfo in g.getEdges():
        fromdiff = g.getNodeInfo(fromid, 'diff_node')
        todiff   = g.getNodeInfo(toid, 'diff_node')
        edgediff.append('%s|%s' % (fromdiff, todiff))

    return edgediff
Beispiel #7
0
    def renderFunctionGraph(self, fva):

        self.fva = fva
        #self.graph = self.vw.getFunctionGraph(fva)
        self.graph = viv_graphutil.buildFunctionGraph(self.vw, fva, revloop=True)

        # Go through each of the nodes and render them so we know sizes
        for node in self.graph.getNodes():
            #cbva,cbsize = self.graph.getCodeBlockBounds(node)
            cbva = node[1].get('cbva')
            cbsize = node[1].get('cbsize')
            self.mem_canvas.renderMemory(cbva, cbsize)

        # Let the renders complete...
        eatevents()

        frame = self.mem_canvas.page().mainFrame()
        frame.evaluateJavaScript(funcgraph_js)

        for nid,nprops in self.graph.getNodes():
            cbva = nprops.get('cbva')

            cbname = 'codeblock_%.8x' % cbva
            girth, ok = frame.evaluateJavaScript('document.getElementById("%s").offsetWidth;' % cbname).toInt()
            height, ok = frame.evaluateJavaScript('document.getElementById("%s").offsetHeight;' % cbname).toInt()
            self.graph.setNodeProp((nid,nprops), "size", (girth, height))

        self.dylayout = vg_dynadag.DynadagLayout(self.graph)
        self.dylayout._barry_count = 20
        self.dylayout.layoutGraph()

        width, height = self.dylayout.getLayoutSize()

        svgid = 'funcgraph_%.8x' % fva
        frame.evaluateJavaScript('svgwoot("vbody", "%s", %d, %d);' % (svgid, width+18, height))

        for nid,nprops in self.graph.getNodes():

            cbva = nprops.get('cbva')
            if cbva == None:
                continue

            xpos, ypos = nprops.get('position')
            girth, height = nprops.get('size')

            foid = 'fo_cb_%.8x' % cbva
            cbid = 'codeblock_%.8x' % cbva

            frame.evaluateJavaScript('addSvgForeignObject("%s", "%s", %d, %d);' % (svgid, foid, girth+16, height))
            frame.evaluateJavaScript('addSvgForeignHtmlElement("%s", "%s");' % (foid, cbid))
            frame.evaluateJavaScript('moveSvgElement("%s", %d, %d);' % (foid, xpos, ypos))

        # Draw in some edge lines!
        for eid, n1, n2, einfo in self.graph.getEdges():
            points = einfo.get('edge_points')
            pointstr = ' '.join(['%d,%d' % (x,y) for (x,y) in points ])

            frame.evaluateJavaScript('drawSvgLine("%s", "edge_%.8s", "%s");' % (svgid, eid, pointstr))

        self.updateWindowTitle()
Beispiel #8
0
    def checkGetCodePathsTo(self, vw, fva, cbva):
        graph = viv_graph.buildFunctionGraph(vw, fva )
        paths = [ path for path in viv_graph.getCodePathsTo(graph, cbva) ]
        self.codepathsto = paths
        self.assertGreater(len(self.codepaths), len(self.codepathsto))

        paths = [ path for path in graph.getHierPathsTo((cbva,)) ]
        self.hierpathsto = paths
        self.assertGreater(len(self.codepaths), len(self.hierpathsto))
Beispiel #9
0
    def getFunctionHash(self, vw, fva):

        rowpos = {}

        g = viv_graphutil.buildFunctionGraph(vw, fva)
        weights = g.getNodeWeights()

        #print '0x%.8x: %d' % (fva, len(g.getNodes()))

        # Here, we assume that the calculation of "node order" is consistant
        # because it is dependant on the graphutil code following branches in
        # a consistant way.

        # NOTE: This is a good way to identify totally identical functions, but
        # a terrible way to tell *what* changed due to all subsequant nodes being
        # bumped and moved around...

        for nid,ninfo in g.getNodes():
            # Set each node's "node identifier" info
            # ( which is currently, nodeid:depth:rowpos
            weight = weights.get(nid, -1)
            row = rowpos.get(weight)
            if row == None:
                row = []
                rowpos[weight] = row

            # Just ID information and graph layout... (may allow matching
            # even in the presence of compiler optimization
            #ninfo['diff_node'] = '%d:%d:%d' % (nid, weight, len(row))

            # Mnemonics and graph layouts.  Probably the most twitchy match...
            #mnems = getBlockMnems(vw, ninfo['cbva'], ninfo['cbsize'])
            #ninfo['diff_node'] = '%s:%d:%d' % (mnems, weight, len(row))

            # FIXME this could also do hash's of above/below to do block compare...

            # Just the mnemonics... (may allow block comparison *inside* funcions with diffs)
            mnems = getBlockMnems(vw, ninfo['cbva'], ninfo['cbsize'])
            ninfo['diff_node'] = mnems

            #print nid,ninfo['diff_node']
            row.append(nid)


        # The *actual* data we use to unique the function is the *relationship*
        # between nodes rather than the nodes themselves.  Each node's 'diff_node'
        # identifier is assumed to be non-unique, but grouping.  The relationship
        # between nodes is used to feed a sha1 hash...
        edgediff = []
        for eid, fromid, toid, einfo in g.getEdges():
            fromdiff = g.getNodeInfo(fromid, 'diff_node')
            todiff   = g.getNodeInfo(toid, 'diff_node')
            edgediff.append('%s|%s' % (fromdiff, todiff))

        edgediff.sort()

        return hashlib.sha1(','.join(edgediff)).hexdigest()
Beispiel #10
0
    def getSymbolikGraph(self, fva, fgraph=None):
        '''
        Instantiate a standard vivisect function graph (visgraph
        hierarchical graph) and translate all the opcodes in each block
        to un-applied symbolik effects.  The list of effects for each node
        is stored in 'symbolik_effects' list in the node properties.
        '''
        xlate = self.getTranslator()
        graph = SymbolikFunctionGraph()

        if fgraph == None:
            fgraph = viv_graph.buildFunctionGraph(self.vw, fva)

        for nodeva,ninfo in fgraph.getNodes():

            cbva = ninfo.get('cbva')
            cbsize = ninfo.get('cbsize')

            cbmax = cbva + cbsize
            oplist = []
            while cbva < cbmax:
                op = self.vw.parseOpcode(cbva)
                oplist.append(op)
                cbva += len(op)

            for op in oplist:
                xlate.translateOpcode(op)

            efflist = xlate.getEffects() # we needn't copy
            conlist = xlate.getConstraints()
            xlate.clearEffects()
            # Put constraints into a dictionary lookup by target address
            con_lookup = {}
            for coneff in conlist:
                addrva = coneff.addrsym.solve()
                clist = con_lookup.get(addrva)
                if clist == None:
                    clist = []
                    con_lookup[addrva] = clist
                clist.append(coneff)

            # Save these off in node info for later
            ninfo['opcodes'] = oplist
            ninfo['symbolik_effects'] = efflist

            # Add the constraints to the edges
            for eid,fromid,toid,einfo in fgraph.getRefsFromByNid(nodeva):
                clist = con_lookup.pop(toid, None)
                if clist == None:
                    continue
                einfo['symbolik_constraints'] = clist

            #if len(con_lookup):
                #raise Exception('FIXME: We ditched a constraint! %s' % repr(con_lookup))

        return fgraph
Beispiel #11
0
    def getSymbolikGraph(self, fva, fgraph=None):
        '''
        Instantiate a standard vivisect function graph (visgraph
        hierarchical graph) and translate all the opcodes in each block
        to un-applied symbolik effects.  The list of effects for each node
        is stored in 'symbolik_effects' list in the node properties.
        '''
        xlate = self.getTranslator()

        if fgraph is None:
            fgraph = viv_graph.buildFunctionGraph(self.vw, fva)

        for nodeva, ninfo in fgraph.getNodes():

            cbva = ninfo.get('cbva')
            cbsize = ninfo.get('cbsize')

            cbmax = cbva + cbsize
            oplist = []
            while cbva < cbmax:
                op = self.vw.parseOpcode(cbva)
                oplist.append(op)
                cbva += len(op)

            for op in oplist:
                xlate.translateOpcode(op)

            efflist = xlate.getEffects()  # we needn't copy
            conlist = xlate.getConstraints()
            xlate.clearEffects()
            # Put constraints into a dictionary lookup by target address
            con_lookup = {}
            for coneff in conlist:
                addrva = coneff.addrsym.solve()
                clist = con_lookup.get(addrva)
                if clist is None:
                    clist = []
                    con_lookup[addrva] = clist
                clist.append(coneff)

            # Save these off in node info for later
            ninfo['opcodes'] = oplist
            ninfo['symbolik_effects'] = efflist

            # Add the constraints to the edges
            for eid, fromid, toid, einfo in fgraph.getRefsFromByNid(nodeva):
                clist = con_lookup.pop(toid, None)
                if clist is None:
                    continue
                einfo['symbolik_constraints'] = clist

            #if len(con_lookup):
                #raise Exception('FIXME: We ditched a constraint! %s' % repr(con_lookup))

        return fgraph
Beispiel #12
0
 def test_graphutil_longpath(self):
     '''
     order matters
     '''
     vw = self.firefox_vw
     g = v_t_graphutil.buildFunctionGraph(vw, 0x1400037c0)
     longpath = []
     longpath = [0x1400037c0, 0x14000382d, 0x1400038a4, 0x140003964, 0x140003994, 0x1400039cc, 0x1400039f6, 0x140003a29, 0x140003a59, 0x140003a83, 0x140003ab3, 0x140003b3b, 0x140003b3e, 0x140003ccd, 0x140003c3c, 0x140003c3f, 0x140003c4c, 0x140003c52, 0x140003c5f, 0x140003c65, 0x140003c72, 0x140003c78, 0x140003c85, 0x140003c8b, 0x140003c98, 0x140003c9e, 0x140003cab, 0x140003cb1, 0x140003cc2, 0x1400038fd, 0x14000390a, 0x140003910, 0x14000392b, 0x140003938, 0x14000393e]
     path = next(v_t_graphutil.getLongPath(g))
     path = [k[0] for k in path]
     self.assertEqual(path, longpath)
Beispiel #13
0
    def renderFunctionGraph(self, fva, graph=None):

        self.fva = fva
        #self.graph = self.vw.getFunctionGraph(fva)
        if graph == None:
            try:
                graph = viv_graphutil.buildFunctionGraph(self.vw, fva, revloop=True)
            except Exception, e:
                import sys
                sys.excepthook(*sys.exc_info())
                return
Beispiel #14
0
    def do_searchopcodes(self, line):
        '''
        search opcodes/function for a pattern

        searchopcodes [-f <funcva>] [options] <pattern>
        -f [fva]   - focus on one function
        -c         - search comments
        -o         - search operands
        -t         - search text
        -M <color> - mark opcodes (default = orange)
        -R         - pattern is REGEX (otherwise just text)

        '''
        parser = e_cli.VOptionParser()
        parser.add_option('-f', action='store', dest='funcva', type='long')
        parser.add_option('-c', action='store_true', dest='searchComments')
        parser.add_option('-o', action='store_true', dest='searchOperands')
        parser.add_option('-t', action='store_true', dest='searchText')
        parser.add_option('-M',
                          action='store',
                          dest='markColor',
                          default='orange')
        parser.add_option('-R', action='store_true', dest='is_regex')

        argv = shlex.split(line)
        try:
            options, args = parser.parse_args(argv)
        except Exception as e:
            self.vprint(repr(e))
            return self.do_help('searchopcodes')

        pattern = ' '.join(args)
        if len(pattern) == 0:
            self.vprint('you must specify a pattern')
            return self.do_help('searchopcodes')

        # generate our interesting va list
        valist = []
        if options.funcva:
            # setup valist from function data
            try:
                fva = int(args[0], 0)
                graph = viv_graph.buildFunctionGraph(self, fva)
            except Exception, e:
                self.vprint(repr(e))
                return

            for nva, node in graph.getNodes():
                va = nva
                endva = va + node.get('cbsize')
                while va < endva:
                    lva, lsz, ltype, ltinfo = self.getLocation(va)
                    valist.append(va)
                    va += lsz
Beispiel #15
0
    def renderFunctionGraph(self, fva, graph=None):

        self.fva = fva
        #self.graph = self.vw.getFunctionGraph(fva)
        if graph == None:
            try:
                graph = viv_graphutil.buildFunctionGraph(self.vw,
                                                         fva,
                                                         revloop=True)
            except Exception, e:
                import sys
                sys.excepthook(*sys.exc_info())
                return
Beispiel #16
0
    def checkTestWorkspace(self, vw, ans):
        self.assertEqual(vw.getMeta('Platform'), ans.getMeta('Platform'))
        self.assertEqual(vw.getMeta('Architecture'), ans.getMeta('Architecture'))

        self.assertEqual(sorted(vw.getFunctions()), sorted(ans.getFunctions()))
        self.assertEqual(sorted(vw.getLibraryDependancies()), sorted(ans.getLibraryDependancies()))
        self.assertEqual(sorted(vw.getRelocations()), sorted(ans.getRelocations()))
        self.assertEqual(sorted(vw.getImports()), sorted(ans.getImports()))
        self.assertEqual(sorted(vw.getExports()), sorted(ans.getExports()))
        self.assertEqual(sorted(vw.getSegments()), sorted(ans.getSegments()))
        # self.assertEqual( sorted( vw.getCodeBlocks() ), sorted( ans.getCodeBlocks() ) )
        # self.assertEqual( sorted( vw.getLocations() ), sorted( ans.getLocations() ) )
        # self.assertEqual( sorted( vw.getNames() ), sorted( ans.getNames() ) )
        self.assertEqual(sorted(vw.getFiles()), sorted(ans.getFiles()))

        for fva in ans.getFunctions():
            self.assertEqual(vw.getFunction(fva), ans.getFunction(fva))
            vwfgraph = viv_graph.buildFunctionGraph(vw, fva)
            ansfgraph = viv_graph.buildFunctionGraph(ans, fva)
            vwnodes = list(vwfgraph.nodes.keys())
            ansnodes = list(ansfgraph.nodes.keys())
            self.assertEqual(sorted(vwnodes), sorted(ansnodes))
Beispiel #17
0
    def checkTestWorkspace(self, vw, ans):
        self.assertEqual( vw.getMeta('Platform'), ans.getMeta('Platform') )
        self.assertEqual( vw.getMeta('Architecture'), ans.getMeta('Architecture') )

        self.assertEqual( sorted( vw.getFunctions() ), sorted( ans.getFunctions() ) )
        self.assertEqual( sorted( vw.getLibraryDependancies() ), sorted( ans.getLibraryDependancies() ) )
        self.assertEqual( sorted( vw.getRelocations() ), sorted( ans.getRelocations() ) )
        self.assertEqual( sorted( vw.getImports() ), sorted( ans.getImports() ) )
        self.assertEqual( sorted( vw.getExports() ), sorted( ans.getExports() ) )
        self.assertEqual( sorted( vw.getSegments() ), sorted( ans.getSegments() ) )
        #self.assertEqual( sorted( vw.getCodeBlocks() ), sorted( ans.getCodeBlocks() ) )
        #self.assertEqual( sorted( vw.getLocations() ), sorted( ans.getLocations() ) )
        #self.assertEqual( sorted( vw.getNames() ), sorted( ans.getNames() ) )
        self.assertEqual( sorted( vw.getFiles() ), sorted( ans.getFiles() ) )

        for fva in ans.getFunctions():
            self.assertEqual(vw.getFunction(fva), ans.getFunction(fva))
            vwfgraph = viv_graph.buildFunctionGraph(vw, fva)
            ansfgraph = viv_graph.buildFunctionGraph(ans, fva)
            vwnodes = vwfgraph.nodes.keys()
            ansnodes = ansfgraph.nodes.keys()
            self.assertEqual( sorted( vwnodes ), sorted( ansnodes ) )
Beispiel #18
0
    def do_searchopcodes(self, line):
        '''
        search opcodes/function for a pattern

        searchopcodes [-f <funcva>] [options] <pattern>
        -f [fva]   - focus on one function
        -c         - search comments
        -o         - search operands
        -t         - search text
        -M <color> - mark opcodes (default = orange)
        -R         - pattern is REGEX (otherwise just text)

        '''
        parser = e_cli.VOptionParser()
        parser.add_option('-f', action='store', dest='funcva', type='long')
        parser.add_option('-c', action='store_true', dest='searchComments')
        parser.add_option('-o', action='store_true', dest='searchOperands')
        parser.add_option('-t', action='store_true', dest='searchText')
        parser.add_option('-M', action='store', dest='markColor', default='orange')
        parser.add_option('-R', action='store_true', dest='is_regex')

        argv = shlex.split(line)
        try:
            options, args = parser.parse_args(argv)
        except Exception as e:
            self.vprint(repr(e))
            return self.do_help('searchopcodes')

        pattern = ' '.join(args)
        if len(pattern) == 0:
            self.vprint('you must specify a pattern')
            return self.do_help('searchopcodes')

        # generate our interesting va list
        valist = []
        if options.funcva:
            # setup valist from function data
            try:
                fva = int(args[0], 0)
                graph = viv_graph.buildFunctionGraph(self, fva)
            except Exception, e:
                self.vprint(repr(e))
                return

            for nva, node in graph.getNodes():
                va = nva
                endva = va + node.get('cbsize')
                while va < endva:
                    lva, lsz, ltype, ltinfo = self.getLocation(va)
                    valist.append(va)
                    va += lsz
Beispiel #19
0
    def test_graphutil_longpath(self):
        '''
        order matters
        '''
        vw = self.gcc_vw
        # TODO: symbolik switchcase
        # g = v_t_graphutil.buildFunctionGraph(vw, 0x445db6)
        # longpath = [0x445db6, 0x445dc3, 0x445dd7, 0x445deb, 0x445dfc, 0x445e01, 0x445e0b, 0x445ddc, 0x445e11, 0x445e20, 0x445e2c, 0x445e30, 0x445e4b, 0x445e5b, 0x445e72, 0x445e85, 0x445e85, 0x445ea1, 0x445ea3, 0x445eae, 0x445ebb, 0x445df5, 0x445ec2]
        # path = next(v_t_graphutil.getLongPath(g))
        # self.assertEqual(longpath, map(lambda k: k[0], path))

        g = v_t_graphutil.buildFunctionGraph(vw, 0x405c10)
        longpath=[0x405c10, 0x405c48, 0x405ca6, 0x405cb0, 0x405cc3, 0x405c4e, 0x405c57, 0x405c5c, 0x405c6b, 0x405cd4, 0x405ce4, 0x405c80, 0x405c8c, 0x405cf6, 0x405c92]
        path = next(v_t_graphutil.getLongPath(g))
        path = map(lambda k: k[0], path)
        self.assertEqual(path, longpath)
Beispiel #20
0
    def do_pathcount(self, line):
        '''
        Mostly for testing the graph stuff... this will likely be removed.

        (does not count paths with loops currently...)

        Usage: pathcount <func_expr>
        '''
        fva = self.parseExpression(line)
        if not self.isFunction(fva):
            self.vprint('Not a function!')
            return

        g = v_t_graph.buildFunctionGraph(self, fva)
        pathcnt = 0
        for path in v_t_graph.getCodePaths(g):
            self.vprint('Path through 0x%.8x: %s' %
                        (fva, [hex(p[0]) for p in path]))
            pathcnt += 1
        self.vprint('Total Paths: %d' % pathcnt)
Beispiel #21
0
    def renderFunctionGraph(self, fva=None, graph=None):
        if fva is not None:
            self.fva = fva

        if graph is None:
            try:
                graph = viv_graphutil.buildFunctionGraph(self.vw, fva, revloop=True)
            except Exception as e:
                self.vw.vprint(f'Error building function graph for {fva} ({str(e)}')
                self.vw.vprint(traceback.format_exc())
                return

        self.graph = graph

        # Go through each of the nodes and render them so we know sizes
        self.nodes = self.graph.getNodes()
        if len(self.nodes):
            node = self.nodes.pop(0)
            cbva = node[1].get('cbva')
            cbsize = node[1].get('cbsize')
            self.mem_canvas.renderMemory(cbva, cbsize, self._renderCodeBlock)
Beispiel #22
0
    def test_graphutil_getopsfrompath(self):
        vw = self.firefox_vw
        g = v_t_graphutil.buildFunctionGraph(vw, 0x140048b84)
        path = next(v_t_graphutil.getLongPath(g))

        ops = [
            'push rbx', 'push rsi', 'push rdi', 'sub rsp,64', 'mov rbx,rcx',
            'call qword [rip + 36451]', 'mov rsi,qword [rbx + 248]',
            'xor edi,edi', 'xor r8d,r8d', 'lea rdx,qword [rsp + 96]',
            'mov rcx,rsi', 'call qword [rip + 36505]', 'test rax,rax',
            'jz 0x140048bed', 'and qword [rsp + 56],0',
            'lea rcx,qword [rsp + 104]', 'mov rdx,qword [rsp + 96]',
            'mov r9,rax', 'mov qword [rsp + 48],rcx', 'mov r8,rsi',
            'lea rcx,qword [rsp + 112]', 'mov qword [rsp + 40],rcx',
            'xor ecx,ecx', 'mov qword [rsp + 32],rbx',
            'call qword [rip + 36514]', 'inc edi', 'cmp edi,2',
            'jl 0x140048b9e', 'add rsp,64', 'pop rdi', 'pop rsi', 'pop rbx',
            'ret '
        ]
        self.assertEqual(
            ops, [str(op) for op in v_t_graphutil.getOpsFromPath(vw, g, path)])
Beispiel #23
0
    def renderFunctionGraph(self, fva=None, graph=None):
        '''
        Begins the process of drawing the function graph to the canvas.

        So, this is a bit of complicated mess due to how PyQt5's runJavaScript method works.
        runJavaScript is asynchronous, but not like actual python async, but Qt's async variant
        with their event loop. The only way to get some level of a guarantee that the
        javascript ran (which we need for getting the size of codeblocks and line layouts) is
        via the secondary parameter, which is a callback that gets run when the javascript
        completes. That being said, technically according to their docs, the callback is guaranteed
        to be run, but it might be during page destruction. In practice it's somewhat responsive.
        runJavascript also doesn't check if the DOM has been created. So...yea. In practice
        that doesn't matter too much, but something to keep in mind.

        So the general method is to build up a bunch of javascript that we need to run in order
        to render the codeblocks to get their sizes, layout the graph lines, realign everything
        nicely, etc. And it's all callbacks, all the way down.
        '''
        if fva is not None:
            self.fva = fva

        if graph is None:
            try:
                graph = viv_graphutil.buildFunctionGraph(self.vw, fva, revloop=True)
            except Exception as e:
                self.vw.vprint(f'Error building function graph for {fva} ({str(e)}')
                self.vw.vprint(traceback.format_exc())
                return

        self.graph = graph

        # Go through each of the nodes and render them so we know sizes
        self.nodes = self.graph.getNodes()
        if len(self.nodes):
            node = self.nodes.pop(0)
            cbva = node[1].get('cbva')
            cbsize = node[1].get('cbsize')
            self.mem_canvas.renderMemory(cbva, cbsize, self._renderCodeBlock)
Beispiel #24
0
    def do_pathcount(self, line):
        '''
        Mostly for testing the graph stuff... this will likely be removed.

        (does not count paths with loops currently...)

        Usage: pathcount <func_expr>
        '''
        fva = self.parseExpression(line)
        if not self.isFunction(fva):
            self.vprint('Not a function!')
            return

        g = v_t_graph.buildFunctionGraph(self, fva)
        # Lets find the "bottom" nodes...
        endblocks = []
        for nid,ninfo in g.getNodes():
            if len(g.getRefsFrom(nid)) == 0:
                endblocks.append((nid,ninfo))

        for nid,ninfo in endblocks:
            paths = list(g.pathSearch(0, toid=nid))
            self.vprint('paths to 0x%.8x: %d' % (ninfo.get('cbva'), len(paths)))
Beispiel #25
0
    def test_graphutil_getopsfrompath(self):
        vw = self.gcc_vw
        g = v_t_graphutil.buildFunctionGraph(vw, 0x414a2a)
        path = next(v_t_graphutil.getLongPath(g))

        ops = [
            'push r14', 'push r13', 'mov r13,rdx', 'push r12', 'push rbp',
            'mov r12,rsi', 'push rbx', 'mov rbx,rdi', 'sar r12,3',
            'mov rbp,rsi', 'mov edx,r12d', 'mov r14d,ecx', 'sub rsp,16',
            'mov rdi,qword [rdi + 48]', 'mov qword [rsp + 8],rsi',
            'lea rsi,qword [rsp + 8]', 'call 0x00414962', 'cmp qword [rax],0',
            'jz 0x00414abc', 'mov rdx,qword [rax + 8]', 'mov rax,qword [rdx]',
            'cmp r13,rax', 'jbe 0x00414a85', 'mov edx,0x004d76b0',
            'mov esi,151', 'mov edi,0x004d7534', 'call 0x0041806c',
            'sub rax,r13', 'test r14l,r14l', 'mov qword [rdx],rax',
            'jz 0x00414abc', 'mov rbx,qword [rbx + 48]',
            'lea rsi,qword [rsp + 8]', 'xor ecx,ecx', 'mov edx,r12d',
            'mov qword [rsp + 8],rbp', 'mov rdi,rbx', 'call 0x004154ec',
            'cmp qword [rax],0', 'jz 0x00414abc', 'mov qword [rax],1',
            'inc qword [rbx + 24]', 'add rsp,16', 'pop rbx', 'pop rbp',
            'pop r12', 'pop r13', 'pop r14', 'ret '
        ]
        self.assertEqual(ops,
                         map(str, v_t_graphutil.getOpsFromPath(vw, g, path)))
Beispiel #26
0
    def do_searchopcodes(self, line):
        '''
        search opcodes/function for a pattern

        searchopcodes [-f <funcva>] [options] <pattern>
        -f [fva]   - focus on one function
        -c         - search comments
        -o         - search operands
        -t         - search text
        -M <color> - mark opcodes (default = orange)
        -R         - pattern is REGEX (otherwise just text)

        '''
        parser = e_cli.VOptionParser()
        parser.add_option('-f', action='store', dest='funcva', type='int')
        parser.add_option('-c', action='store_true', dest='searchComments')
        parser.add_option('-o', action='store_true', dest='searchOperands')
        parser.add_option('-t', action='store_true', dest='searchText')
        parser.add_option('-M',
                          action='store',
                          dest='markColor',
                          default='orange')
        parser.add_option('-R', action='store_true', dest='is_regex')

        argv = shlex.split(line)
        try:
            options, args = parser.parse_args(argv)
        except Exception as e:
            self.vprint(repr(e))
            return self.do_help('searchopcodes')

        pattern = ' '.join(args)
        if len(pattern) == 0:
            self.vprint('you must specify a pattern')
            return self.do_help('searchopcodes')

        # generate our interesting va list
        valist = []
        if options.funcva:
            # setup valist from function data
            try:
                fva = options.funcva
                graph = viv_graph.buildFunctionGraph(self, fva)
            except Exception as e:
                self.vprint(repr(e))
                return

            for nva, node in graph.getNodes():
                va = nva
                endva = va + node.get('cbsize')
                while va < endva:
                    lva, lsz, ltype, ltinfo = self.getLocation(va)
                    valist.append(va)
                    va += lsz

        else:
            # the whole workspace is our oyster
            valist = [
                va for va, lvsz, ltype, ltinfo in self.getLocations(LOC_OP)
            ]

        res = []
        canv = e_canvas.StringMemoryCanvas(self)

        defaultSearchAll = True
        for va in valist:
            try:
                addthis = False
                op = self.parseOpcode(va)

                # search comment
                if options.searchComments:
                    defaultSearchAll = False
                    cmt = self.getComment(va)
                    if cmt is not None:

                        if options.is_regex:
                            if len(re.findall(pattern, cmt)):
                                addthis = True

                        else:
                            if pattern in cmt:
                                addthis = True

                # search operands
                if options.searchOperands:
                    defaultSearchAll = False
                    for opidx, oper in enumerate(op.opers):
                        # we're writing to a temp canvas, so clear it before each test
                        canv.clearCanvas()
                        oper = op.opers[opidx]
                        oper.render(canv, op, opidx)
                        operepr = canv.strval

                        if options.is_regex:
                            if len(re.findall(pattern, operepr)):
                                addthis = True

                        else:
                            if pattern in operepr:
                                addthis = True

                            # if we're doing non-regex, let's test against real numbers
                            # (instead of converting to hex and back)
                            numpattrn = pattern
                            try:
                                numpattrn = int(numpattrn, 0)
                            except:
                                pass

                            if numpattrn in vars(oper).values():
                                addthis = True

                # search full text
                if options.searchText or defaultSearchAll:
                    # search through the rendering of the opcode, as well as the comment
                    canv.clearCanvas()
                    op.render(canv)
                    oprepr = canv.strval
                    cmt = self.getComment(va)
                    if cmt is not None:
                        oprepr += "  ; " + cmt

                    if options.is_regex:
                        if len(re.findall(pattern, oprepr)):
                            addthis = True

                    else:
                        if pattern in oprepr:
                            addthis = True
                # only want one listing of each va, no matter how many times it matches
                if addthis:
                    res.append(va)
            except:
                self.vprint(''.join(
                    traceback.format_exception(*sys.exc_info())))

        if len(res) == 0:
            self.vprint('pattern not found: %s (%s)' %
                        (pattern.encode('utf-8').hex(), repr(pattern)))
            return

        # set the color for each finding
        color = options.markColor
        colormap = {va: color for va in res}
        if self._viv_gui is not None:
            from vqt.main import vqtevent
            vqtevent('viv:colormap', colormap)

        self.vprint('matches for: %s (%s)' %
                    (pattern.encode('utf-8').hex(), repr(pattern)))
        for va in res:
            mbase, msize, mperm, mfile = self.memobj.getMemoryMap(va)
            pname = e_memory.reprPerms(mperm)
            sname = self.reprPointer(va)

            op = self.parseOpcode(va)
            self.canvas.renderMemory(va, len(op))
            cmt = self.getComment(va)
            if cmt is not None:
                self.canvas.addText('\t\t; %s (Perms: %s, Smartname: %s)' %
                                    (cmt, pname, sname))

            self.canvas.addText('\n')

        self.vprint('done (%d results).' % len(res))
Beispiel #27
0
    def test_graphutil_getcodepaths(self):
        '''
        In this function, order doesn't matter
        '''
        vw = self.firefox_vw
        g = v_t_graphutil.buildFunctionGraph(vw, 0x140010e60)
        paths = [
            set([
                5368778336, 5368778350, 5368778362, 5368778366, 5368778394,
                5368778400
            ]),
            set([
                5368778336, 5368778350, 5368778362, 5368778366, 5368778498,
                5368778515, 5368778394, 5368778400
            ]),
            set([
                5368778336, 5368778350, 5368778362, 5368778366, 5368778498,
                5368778520, 5368778544, 5368778549
            ]),
            set([
                5368778336, 5368778350, 5368778362, 5368778366, 5368778498,
                5368778520, 5368778544, 5368778601, 5368778603
            ]),
            set([
                5368778336, 5368778350, 5368778362, 5368778366, 5368778498,
                5368778520, 5368778560, 5368778603
            ]),
            set([
                5368778336, 5368778350, 5368778482, 5368778366, 5368778394,
                5368778400
            ]),
            set([
                5368778336, 5368778350, 5368778482, 5368778366, 5368778498,
                5368778515, 5368778394, 5368778400
            ]),
            set([
                5368778336, 5368778350, 5368778482, 5368778366, 5368778498,
                5368778520, 5368778544, 5368778549
            ]),
            set([
                5368778336, 5368778350, 5368778482, 5368778366, 5368778498,
                5368778520, 5368778544, 5368778601, 5368778603
            ]),
            set([
                5368778336, 5368778350, 5368778482, 5368778366, 5368778498,
                5368778520, 5368778560, 5368778603
            ]),
            set([5368778336, 5368778400]),
        ]

        pathcount = 0
        genr = v_t_graphutil.getCodePaths(g, loopcnt=0, maxpath=None)
        for path in genr:
            p = set([k[0] for k in path])
            self.assertIn(p, paths)
            pathcount += 1

        self.assertEqual(11, pathcount)

        g = v_t_graphutil.buildFunctionGraph(vw, vw.getFunction(0x1400110a0))
        thruCnt = glen(v_t_graphutil.getCodePathsThru(g, 0x1400110a0))
        self.assertEqual(23, thruCnt)
        thruCnt = glen(
            v_t_graphutil.getCodePathsThru(g, 0x1400110a0, maxpath=2))
        self.assertEqual(2, thruCnt)

        g = v_t_graphutil.buildFunctionGraph(vw, vw.getFunction(0x14001ead0))
        toCnt = glen(v_t_graphutil.getCodePathsTo(g, 0x14001ec2a))
        self.assertEqual(2, toCnt)
        toCnt = glen(v_t_graphutil.getCodePathsTo(g, 0x14001ec2a, maxpath=99))
        self.assertEqual(2, toCnt)

        g = v_t_graphutil.buildFunctionGraph(vw, vw.getFunction(0x1400019ab))
        fromCnt = glen(v_t_graphutil.getCodePathsFrom(g, 0x1400019ab))
        self.assertEqual(2, fromCnt)
        fromCnt = glen(
            v_t_graphutil.getCodePathsFrom(g, 0x1400019ab, maxpath=1))
        self.assertEqual(1, fromCnt)
Beispiel #28
0
 def checkCoveragePaths(self, vw, fva):
     graph = viv_graph.buildFunctionGraph(vw, fva)
     paths = [ path for path in viv_graph.getCoveragePaths(graph, 150) ]
     self.codepaths = paths
     self.assertEqual(len(self.codepaths), 22)
Beispiel #29
0
 def checkGetLongPath(self, vw, fva):
     graph = viv_graph.buildFunctionGraph(vw, fva)
     paths = [ path for path in viv_graph.getLongPath(graph) ]
     self.codepaths = paths
     self.assertGreater(len(self.codepaths), 150)
Beispiel #30
0
 def checkPathGenGetCodePaths(self, vw, fva):
     graph = viv_graph.buildFunctionGraph(vw, fva)
     paths = [ path for path in viv_graph.getCodePathsThru(graph) ]
     self.codepaths = paths
     self.assertGreater(len(self.codepaths), 150)
Beispiel #31
0
    def test_graphutil_getcodepaths(self):
        '''
        In this function, order doesn't matter
        '''
        vw = self.firefox_vw
        g = v_t_graphutil.buildFunctionGraph(vw, 0x140010e60)
        paths = [
            set([
                0x140010e60, 0x140010e6e, 0x140010e7a, 0x140010e7e,
                0x140010e9a, 0x140010ea0
            ]),
            set([
                0x140010e60, 0x140010e6e, 0x140010e7a, 0x140010e7e,
                0x140010e9a, 0x140010ea0, 0x140010f02, 0x140010f13
            ]),
            set([
                0x140010e60, 0x140010e6e, 0x140010e7a, 0x140010e7e,
                0x140010f02, 0x140010f18
            ]),
            set([
                0x140010e60, 0x140010e6e, 0x140010e7e, 0x140010e9a,
                0x140010ea0, 0x140010ef2
            ]),
            set([
                0x140010e60, 0x140010e6e, 0x140010e7e, 0x140010e9a,
                0x140010ea0, 0x140010ef2, 0x140010f02, 0x140010f13
            ]),
            set([
                0x140010e60, 0x140010e6e, 0x140010e7e, 0x140010ef2,
                0x140010f02, 0x140010f18
            ]),
            set([0x140010e60, 0x140010ea0]),
        ]

        pathcount = 0
        genr = v_t_graphutil.getCodePaths(g, loopcnt=0, maxpath=None)
        for path in genr:
            p = set([k[0] for k in path])
            self.assertIn(p, paths)
            pathcount += 1

        self.assertEqual(7, pathcount)

        g = v_t_graphutil.buildFunctionGraph(vw, vw.getFunction(0x1400110a0))
        thruCnt = glen(v_t_graphutil.getCodePathsThru(g, 0x1400110a0))
        self.assertEqual(21, thruCnt)
        thruCnt = glen(
            v_t_graphutil.getCodePathsThru(g, 0x1400110a0, maxpath=2))
        self.assertEqual(2, thruCnt)

        g = v_t_graphutil.buildFunctionGraph(vw, vw.getFunction(0x14001ead0))
        toCnt = glen(v_t_graphutil.getCodePathsTo(g, 0x14001ec2a))
        self.assertEqual(2, toCnt)
        toCnt = glen(v_t_graphutil.getCodePathsTo(g, 0x14001ec2a, maxpath=99))
        self.assertEqual(2, toCnt)

        g = v_t_graphutil.buildFunctionGraph(vw, vw.getFunction(0x1400019ab))
        fromCnt = glen(v_t_graphutil.getCodePathsFrom(g, 0x1400019ab))
        self.assertEqual(2, fromCnt)
        fromCnt = glen(
            v_t_graphutil.getCodePathsFrom(g, 0x1400019ab, maxpath=1))
        self.assertEqual(1, fromCnt)
Beispiel #32
0
    def renderFunctionGraph(self, fva, graph=None):

        self.fva = fva
        #self.graph = self.vw.getFunctionGraph(fva)
        if graph == None:
            graph = viv_graphutil.buildFunctionGraph(self.vw,
                                                     fva,
                                                     revloop=True)

        self.graph = graph

        # Go through each of the nodes and render them so we know sizes
        for node in self.graph.getNodes():
            #cbva,cbsize = self.graph.getCodeBlockBounds(node)
            cbva = node[1].get('cbva')
            cbsize = node[1].get('cbsize')
            self.mem_canvas.renderMemory(cbva, cbsize)

        # Let the renders complete...
        eatevents()

        frame = self.mem_canvas.page().mainFrame()
        frame.evaluateJavaScript(funcgraph_js)

        for nid, nprops in self.graph.getNodes():
            cbva = nprops.get('cbva')

            cbname = 'codeblock_%.8x' % cbva
            girth, ok = frame.evaluateJavaScript(
                'document.getElementById("%s").offsetWidth;' % cbname).toInt()
            height, ok = frame.evaluateJavaScript(
                'document.getElementById("%s").offsetHeight;' %
                cbname).toInt()
            self.graph.setNodeProp((nid, nprops), "size", (girth, height))

        self.dylayout = vg_dynadag.DynadagLayout(self.graph)
        self.dylayout._barry_count = 20
        self.dylayout.layoutGraph()

        width, height = self.dylayout.getLayoutSize()

        svgid = 'funcgraph_%.8x' % fva
        frame.evaluateJavaScript('svgwoot("vbody", "%s", %d, %d);' %
                                 (svgid, width + 18, height))

        for nid, nprops in self.graph.getNodes():

            cbva = nprops.get('cbva')
            if cbva == None:
                continue

            xpos, ypos = nprops.get('position')
            girth, height = nprops.get('size')

            foid = 'fo_cb_%.8x' % cbva
            cbid = 'codeblock_%.8x' % cbva

            frame.evaluateJavaScript(
                'addSvgForeignObject("%s", "%s", %d, %d);' %
                (svgid, foid, girth + 16, height))
            frame.evaluateJavaScript('addSvgForeignHtmlElement("%s", "%s");' %
                                     (foid, cbid))
            frame.evaluateJavaScript('moveSvgElement("%s", %d, %d);' %
                                     (foid, xpos, ypos))

        # Draw in some edge lines!
        for eid, n1, n2, einfo in self.graph.getEdges():
            points = einfo.get('edge_points')
            pointstr = ' '.join(['%d,%d' % (x, y) for (x, y) in points])

            frame.evaluateJavaScript('drawSvgLine("%s", "edge_%.8s", "%s");' %
                                     (svgid, eid, pointstr))

        self.updateWindowTitle()
Beispiel #33
0
 def checkCoveragePaths(self, vw, fva):
     graph = viv_graph.buildFunctionGraph(vw, fva)
     paths = [path for path in viv_graph.getCoveragePaths(graph, 150)]
     self.codepaths = paths
     self.assertEqual(len(self.codepaths), 22)
Beispiel #34
0
 def checkGetLongPath(self, vw, fva):
     graph = viv_graph.buildFunctionGraph(vw, fva)
     paths = [path for path in viv_graph.getLongPath(graph)]
     self.codepaths = paths
     self.assertGreater(len(self.codepaths), 150)
Beispiel #35
0
else:
	vw.loadFromFile(malbin, None)
	vw.analyze() # binary analysis"
	vw.saveWorkspace() # save work

# Test -- ! need to find correctly the "main" function
for eip in vw.getEntryPoints():
	print("FOUND ENTRY POINT 0x%08x\n" % eip)
eip = vw.getEntryPoints()[0] # to replace by a call to a function for each iteration of loop
# add threading

# call the code block graph
#graph = viv_cg.CodeBlockGraph(vw)
print "GRAPH SEARCH"
#graph = vw.getFunctionGraph(eip)
graph = viv_cgh.buildFunctionGraph(vw, eip)
#graph = vw.getCallGraph()
visited = []

print("NUMBER OF NODES: %d" % len(graph.getNodes()))
for node in graph.getNodes():
	if(node in visited):
		print("LOOP DETECTED!")
		break
	else:
		visited.append(node)
	if graph.isLeafNode(node):
		print "LEAF NODE FOUND:"
		print("Set BP at: 0x%08x" % node[0])

print "THIS IS THE END :-D or :'("
Beispiel #36
0
 def checkPathGenGetCodePaths(self, vw, fva):
     graph = viv_graph.buildFunctionGraph(vw, fva)
     paths = [path for path in viv_graph.getCodePathsThru(graph)]
     self.codepaths = paths
     self.assertGreater(len(self.codepaths), 150)
Beispiel #37
0
    def test_graphutil_getcodepaths(self):
        '''
        In this function, order doesn't matter
        '''
        vw = self.gcc_vw
        g = v_t_graphutil.buildFunctionGraph(vw, 0x456190)
        paths = [
            set([
                0x456190, 0x4561ba, 0x456202, 0x456216, 0x45621c, 0x456240,
                0x4561fa, 0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x456216, 0x45621c, 0x40aa97,
                0x4561ea, 0x4561ef, 0x4561fa, 0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x456216, 0x45621c, 0x40aa97,
                0x4561ea, 0x4561fa, 0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x456216, 0x4561c2, 0x4561d0,
                0x4561ea, 0x4561ef, 0x4561fa, 0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x456216, 0x4561c2, 0x4561d0,
                0x4561ea, 0x4561fa, 0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x456216, 0x4561c2, 0x40aa85,
                0x40aa8d, 0x4561d0, 0x4561ea, 0x4561ef, 0x4561fa, 0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x456216, 0x4561c2, 0x40aa85,
                0x40aa8d, 0x4561d0, 0x4561ea, 0x4561fa, 0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x456216, 0x4561c2, 0x40aa85,
                0x40aab9, 0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x45621c, 0x456240, 0x4561fa,
                0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x45621c, 0x40aa97, 0x4561ea,
                0x4561ef, 0x4561fa, 0x456242
            ]),
            set([
                0x456190, 0x4561ba, 0x456202, 0x45621c, 0x40aa97, 0x4561ea,
                0x4561fa, 0x456242
            ]),
            set([0x456190, 0x456242]),
        ]

        pathcount = 0
        genr = v_t_graphutil.getCodePaths(g, loopcnt=0, maxpath=None)
        for path in genr:
            p = set(map(lambda k: k[0], path))
            self.assertIn(p, paths)
            pathcount += 1

        self.assertEqual(12, pathcount)

        g = v_t_graphutil.buildFunctionGraph(vw, vw.getFunction(0x0041a766))
        thruCnt = glen(v_t_graphutil.getCodePathsThru(g, 0x0041a766))
        self.assertEqual(2, thruCnt)
        thruCnt = glen(v_t_graphutil.getCodePathsThru(g, 0x0041a766,
                                                      maxpath=1))
        self.assertEqual(1, thruCnt)

        # this will not be true for all examples, but for this function it is
        g = v_t_graphutil.buildFunctionGraph(vw, vw.getFunction(0x0041a77d))
        toCnt = glen(v_t_graphutil.getCodePathsTo(g, 0x0041a77d))
        self.assertEqual(2, toCnt)
        toCnt = glen(v_t_graphutil.getCodePathsTo(g, 0x0041a77d, maxpath=99))
        self.assertEqual(2, toCnt)

        g = v_t_graphutil.buildFunctionGraph(vw, vw.getFunction(0x004042eb))
        fromCnt = glen(v_t_graphutil.getCodePathsFrom(g, 0x004042eb))
        self.assertEqual(8, fromCnt)
        fromCnt = glen(v_t_graphutil.getCodePathsFrom(g, 0x004042eb,
                                                      maxpath=3))
        self.assertEqual(3, fromCnt)