def trackArgOrigin(vw, fva, argidx):
    """
    Return an input tree (visgraph path tree) of the trackable inputs
    to the specified function.

    Each node in the list will be a leaf node for a path leading
    down toward a call to the target function.  Each node will have
    the following path node properties:

    fva    - The function
    argidx - The index of the argument input with this call
    cva    - The address of the call (to our next) (None on root node)
    argv   - A list of (<val>,<magic>) tuples for the call args (None on root node)
    """

    rootpath = vg_path.newPathNode(fva=fva,
                                   cva=None,
                                   trackidx=argidx,
                                   argidx=None,
                                   argv=None)

    todo = [
        rootpath,
    ]

    while len(todo):

        path = todo.pop()

        fva = vg_path.getNodeProp(path, 'fva')
        trackidx = vg_path.getNodeProp(path, 'trackidx')

        # Get all of our callers and their arguments to us
        for callva, argv in trackFunctionInputs(vw, fva):

            newfva = vw.getFunction(callva)
            pargs = dict(parent=path,
                         fva=newfva,
                         cva=callva,
                         argidx=trackidx,
                         argv=argv)
            newpath = vg_path.newPathNode(**pargs)

            aval, amagic = argv[trackidx]
            if isinstance(amagic, viv_magic.StackArg) and newfva:
                vg_path.setNodeProp(newpath, 'trackidx', amagic.index)
                todo.append(newpath)

    return vg_path.getLeafNodes(rootpath)
Example #2
0
def getCodePathsTo(fgraph, tocbva, loopcnt=0, maxpath=None):
    '''
    Yields all the paths through the hierarchical graph starting at the 
    "root nodes" and ending at tocbva.  Specify a loopcnt to allow loop 
    paths to be generated with the given "loop iteration count"

    Example:
        for path in getCodePathsTo(fgraph, tocbva):
            for node,edge in path:
                ...etc...
    '''
    pathcnt = 0
    looptrack = []
    pnode = vg_pathcore.newPathNode(nid=tocbva, eid=None)

    #rootnodes = fgraph.getHierRootNodes()
    cbnode = fgraph.getNode(tocbva)
    todo = [
        (cbnode, pnode),
    ]

    while todo:

        node, cpath = todo.pop()

        refsto = fgraph.getRefsTo(node)

        # Is this is the root node?
        if node[1].get('rootnode'):
            path = vg_pathcore.getPathToNode(cpath)
            path.reverse()
            yield [_nodeedge(n) for n in path]
            vg_pathcore.trimPath(cpath)

            pathcnt += 1
            if maxpath and pathcnt >= maxpath:
                return

        for eid, n1, n2, einfo in refsto:
            # Skip loops if they are "deeper" than we are allowed
            loops = vg_pathcore.getPathLoopCount(cpath, 'nid', n1)
            if loops > loopcnt:
                continue

            vg_pathcore.setNodeProp(cpath, 'eid', eid)
            npath = vg_pathcore.newPathNode(parent=cpath, nid=n1, eid=None)
            node1 = fgraph.getNode(n1)
            todo.append((node1, npath))
Example #3
0
def getCodePathsTo(fgraph, tocbva, loopcnt=0, maxpath=None):
    '''
    Yields all the paths through the hierarchical graph starting at the 
    "root nodes" and ending at tocbva.  Specify a loopcnt to allow loop 
    paths to be generated with the given "loop iteration count"

    Example:
        for path in getCodePathsTo(fgraph, tocbva):
            for node,edge in path:
                ...etc...
    '''
    pathcnt = 0
    looptrack = []
    pnode = vg_pathcore.newPathNode(nid=tocbva, eid=None)

    #rootnodes = fgraph.getHierRootNodes()
    cbnode = fgraph.getNode(tocbva)
    todo = [(cbnode,pnode), ]

    while todo:

        node,cpath = todo.pop()

        refsto = fgraph.getRefsTo(node)

        # Is this is the root node?
        if node[1].get('rootnode'):
            path = vg_pathcore.getPathToNode(cpath)
            path.reverse()
            yield [ _nodeedge(n) for n in path ]
            vg_pathcore.trimPath(cpath)

            pathcnt += 1
            if maxpath and pathcnt >= maxpath:
                return

        for eid, n1, n2, einfo in refsto:
            # Skip loops if they are "deeper" than we are allowed
            loops = vg_pathcore.getPathLoopCount(cpath, 'nid', n1)
            if loops > loopcnt:
                continue

            vg_pathcore.setNodeProp(cpath, 'eid', eid)
            npath = vg_pathcore.newPathNode(parent=cpath, nid=n1, eid=None)
            node1 = fgraph.getNode(n1)
            todo.append((node1,npath))
Example #4
0
def trackArgOrigin(vw, fva, argidx):
    """
    Return an input tree (visgraph path tree) of the trackable inputs
    to the specified function.

    Each node in the list will be a leaf node for a path leading
    down toward a call to the target function.  Each node will have
    the following path node properties:

    fva    - The function
    argidx - The index of the argument input with this call
    cva    - The address of the call (to our next) (None on root node)
    argv   - A list of (<val>,<magic>) tuples for the call args (None on root node)
    """

    rootpath = vg_path.newPathNode(fva=fva, cva=None, trackidx=argidx, argidx=None, argv=None)

    todo = [rootpath, ]

    while len(todo):

        path = todo.pop()

        fva = vg_path.getNodeProp(path, 'fva')
        trackidx = vg_path.getNodeProp(path, 'trackidx')

        # Get all of our callers and their arguments to us
        for callva, argv in trackFunctionInputs(vw, fva):

            newfva = vw.getFunction(callva)
            pargs = dict(parent=path, fva=newfva, cva=callva, argidx=trackidx, argv=argv)
            newpath = vg_path.newPathNode(**pargs)

            aval, amagic = argv[trackidx]
            if isinstance(amagic, viv_magic.StackArg) and newfva:
                vg_path.setNodeProp(newpath, 'trackidx', amagic.index)
                todo.append(newpath)

    return vg_path.getLeafNodes(rootpath)
Example #5
0
        def codewalker(ppath, edge, path):
            # first, test for the "entry" case
            if ppath is None and edge is None:
                emu = self.getFuncEmu(fva)
                for fname, funccb in self.funccb.items():
                    emu.addFunctionCallback(fname, funccb)

                patheffs = emu.applyEffects(self.preeffects)
                pathcons = emu.applyEffects(self.preconstraints)

                node = graph.getNode(fva)
                effects = node[1].get('symbolik_effects',())
                patheffs.extend(emu.applyEffects(effects))

                vg_pathcore.setNodeProp(path, 'pathemu', emu)
                vg_pathcore.setNodeProp(path, 'pathcons', pathcons)
                vg_pathcore.setNodeProp(path, 'patheffs', patheffs)
                return True

            # we are now in the "walking" case
            emu = self.getFuncEmu(fva)
            pemu = vg_pathcore.getNodeProp(ppath, 'pathemu')

            emu.setSymSnapshot( pemu.getSymSnapshot() )
            patheffs = list( vg_pathcore.getNodeProp(ppath, 'patheffs') )
            pathcons = list( vg_pathcore.getNodeProp(ppath, 'pathcons') )

            vg_pathcore.setNodeProp(path,'pathemu',emu)
            vg_pathcore.setNodeProp(path,'patheffs',patheffs)
            vg_pathcore.setNodeProp(path,'pathcons',pathcons)

            # pick up the edge constraints
            newcons = graph.getEdgeProps(edge[0]).get('symbolik_constraints', ())
            newcons = emu.applyEffects(newcons)

            [ c.reduce(emu=emu) for c in newcons ]
            for coneff in newcons:
                # bail if the constraint is dorked
                if coneff.cons.isDiscrete():
                    if not coneff.cons._solve():
                        print('TRIM: %s' % (str(coneff.cons),))
                        return False
                    continue

                # bail if the constraint is mutex
                # FIXME
                #if any([ oldconeff.isMutualExclusion( coneff ) for oldconeff in pathcons ]):
                    #return False
                # TODO: collective failed constraints 
                #   (previous constraint "var > 3" and this constraint "var == 2")

                patheffs.append( coneff )
                pathcons.append( coneff )

            # We have survived constraints!
            node2 = graph.getNode(edge[2])
            neweffs = node2[1].get('symbolik_effects',())
            neweffs = emu.applyEffects(neweffs)
            patheffs.extend(neweffs)
            return True
Example #6
0
    def getFuncCbRoutedPaths_genback(self, fromva, tova, loopcnt=0, maxpath=None, maxsec=None):
        '''
        Yields all the paths through the hierarchical graph starting at the 
        "root nodes" and ending at tocbva.  Specify a loopcnt to allow loop 
        paths to be generated with the given "loop iteration count"

        Example:
            for path in getCodePathsTo(fgraph, tocbva):
                for node,edge in path:
                    ...etc...
        '''
        fgraph = self.graph
        self.__update = 0
        self.__go__ = True
        pathcnt = 0
        tocbva = getGraphNodeByVa(fgraph, tova)
        frcbva = getGraphNodeByVa(fgraph, fromva)

        preRouteGraph(fgraph, fromva, tova)
        
        pnode = vg_pathcore.newPathNode(nid=tocbva, eid=None)

        todo = [(tocbva,pnode), ]

        if maxsec:
            self.watchdog(maxsec)

        while todo:
            if not self.__go__:
                raise PathForceQuitException()

            nodeid,cpath = todo.pop()

            refsto = fgraph.getRefsTo((nodeid, None))

            # This is the root node!
            if nodeid == frcbva:
                path = vg_pathcore.getPathToNode(cpath)
                path.reverse()
                self.__steplock.acquire()
                yield [ viv_graph._nodeedge(n) for n in path ]
                vg_pathcore.trimPath(cpath)

                pathcnt += 1
                self.__update = 1
                self.__steplock.release()
                if maxpath and pathcnt >= maxpath:
                    return

            for eid, fromid, toid, einfo in refsto:
                if fgraph.getNodeProps(fromid).get('up') != True:
                    # TODO: drop the bad edges from graph in preprocessing? instead of "if" here
                    vg_pathcore.trimPath(cpath)
                    continue

                # Skip loops if they are "deeper" than we are allowed
                loops = vg_pathcore.getPathLoopCount(cpath, 'nid', fromid)
                if loops > loopcnt:
                    continue

                vg_pathcore.setNodeProp(cpath, 'eid', eid)
                npath = vg_pathcore.newPathNode(parent=cpath, nid=fromid, eid=None)
                todo.append((fromid,npath))
Example #7
0
        def codewalker(ppath, edge, path):
            # first, test for the "entry" case
            if ppath == None and edge == None:
                emu = self.getFuncEmu(fva)
                for fname, funccb in self.funccb.items():
                    emu.addFunctionCallback(fname, funccb)

                patheffs = emu.applyEffects(self.preeffects)
                pathcons = emu.applyEffects(self.preconstraints)

                node = graph.getNode(fva)
                effects = node[1].get('symbolik_effects',())
                patheffs.extend(emu.applyEffects(effects))

                vg_pathcore.setNodeProp(path, 'pathemu', emu)
                vg_pathcore.setNodeProp(path, 'pathcons', pathcons )
                vg_pathcore.setNodeProp(path, 'patheffs', patheffs )
                return True

            # we are now in the "walking" case
            emu = self.getFuncEmu(fva)
            pemu = vg_pathcore.getNodeProp(ppath, 'pathemu')

            emu.setSymSnapshot( pemu.getSymSnapshot() )
            patheffs = list( vg_pathcore.getNodeProp(ppath, 'patheffs') )
            pathcons = list( vg_pathcore.getNodeProp(ppath, 'pathcons') )

            vg_pathcore.setNodeProp(path,'pathemu',emu)
            vg_pathcore.setNodeProp(path,'patheffs',patheffs)
            vg_pathcore.setNodeProp(path,'pathcons',pathcons)

            # pick up the edge constraints
            newcons = graph.getEdgeProps(edge[0]).get('symbolik_constraints', ())
            newcons = emu.applyEffects(newcons)

            [ c.reduce(emu=emu) for c in newcons ]
            for coneff in newcons:
                # bail if the constraint is dorked
                if coneff.cons.isDiscrete():
                    if not coneff.cons.prove():
                        print('TRIM: %s' % (str(coneff.cons),))
                        return False
                    continue
                    
                # bail if the constraint is mutex
                # FIXME
                #if any([ oldconeff.isMutualExclusion( coneff ) for oldconeff in pathcons ]):
                    #return False
                # TODO: collective failed constraints 
                #   (previous constraint "var > 3" and this constraint "var == 2")

                patheffs.append( coneff )
                pathcons.append( coneff )

            # We have survived constraints!
            node2 = graph.getNode(edge[2])
            neweffs = node2[1].get('symbolik_effects',())
            neweffs = emu.applyEffects(neweffs)
            patheffs.extend(neweffs)
            return True
Example #8
0
    def runFunction(self,
                    funcva,
                    stopva=None,
                    maxhit=None,
                    maxloop=None,
                    tmode=None):
        """
        This is a utility function specific to WorkspaceEmulation (and impemu) that
        will emulate, but only inside the given function.  You may specify a stopva
        to return once that location is hit.
        """
        logger.debug(
            '=== emu.runFunction(0x%x, stopva=%r, maxhit=%r, maxloop=%r, tmode=%r)',
            funcva, stopva, maxhit, maxloop, tmode)
        funcva = self._prep(funcva, tmode)

        # Let the current (should be base also) path know where we are starting
        vg_path.setNodeProp(self.curpath, 'bva', funcva)

        hits = {}
        todo = [(funcva, self.getEmuSnap(), self.path)]
        vw = self.vw  # Save a dereference many many times

        while len(todo):

            va, esnap, self.curpath = todo.pop()

            self.setEmuSnap(esnap)

            self.setProgramCounter(va)
            tmode = self.getFlag(PSR_T_bit)

            # Check if we are beyond our loop max...
            if maxloop is not None:
                lcount = vg_path.getPathLoopCount(self.curpath, 'bva', va)
                if lcount > maxloop:
                    continue

            while True:

                starteip = self.getProgramCounter()

                if not vw.isValidPointer(starteip):
                    break

                if starteip == stopva:
                    return

                # Check straight hit count...
                if maxhit is not None:
                    h = hits.get(starteip, 0)
                    h += 1
                    if h > maxhit:
                        break
                    hits[starteip] = h

                # If we ran out of path (branches that went
                # somewhere that we couldn't follow)?
                if self.curpath is None:
                    break

                try:
                    # FIXME unify with stepi code...
                    op = self.parseOpcode(starteip | tmode)

                    self.op = op
                    if self.emumon:
                        try:
                            self.emumon.prehook(self, op, starteip)
                        except v_exc.BadOpBytes as e:
                            logger.debug(str(e))
                            break
                        except v_exc.BadOutInstruction:
                            pass
                        except Exception as e:
                            logger.log(
                                self._log_level,
                                "funcva: 0x%x opva: 0x%x:  %r   (%r) (in emumon prehook: %r)",
                                funcva, starteip, op, e, self.emumon)

                        if self.emustop:
                            return

                    # Execute the opcode
                    self.executeOpcode(op)
                    vg_path.getNodeProp(self.curpath,
                                        'valist').append(starteip)

                    endeip = self.getProgramCounter()

                    if self.emumon:
                        try:
                            self.emumon.posthook(self, op, endeip)
                        except v_exc.BadOpBytes as e:
                            logger.debug(str(e))
                            break
                        except v_exc.BadOutInstruction:
                            pass
                        except Exception as e:
                            logger.log(
                                self._log_level,
                                "funcva: 0x%x opva: 0x%x:  %r   (%r) (in emumon posthook: %r)",
                                funcva, starteip, op, e, self.emumon)

                        if self.emustop:
                            return

                    iscall = self.checkCall(starteip, endeip, op)
                    if self.emustop:
                        return

                    # If it wasn't a call, check for branches, if so, add them to
                    # the todo list and go around again...
                    if not iscall:
                        blist = self.checkBranches(starteip, endeip, op)
                        if len(blist):
                            # pc in the snap will be wrong, but over-ridden at restore
                            esnap = self.getEmuSnap()
                            for bva, bpath in blist:
                                todo.append((bva, esnap, bpath))
                            break

                    else:
                        # check if we've blx'd to a different thumb state.  if so,
                        # be sure to return to the original tmode before continuing emulation pass
                        newtmode = self.getFlag(PSR_T_bit)
                        if newtmode != tmode:
                            self.setFlag(PSR_T_bit, tmode)

                    # If we enounter a procedure exit, it doesn't
                    # matter what EIP is, we're done here.
                    if op.iflags & envi.IF_RET:
                        vg_path.setNodeProp(self.curpath, 'cleanret', True)
                        break

                    # TODO: hook things like error(...) when they have a param that indicates to
                    # exit. Might be a bit hairy since we'll possibly have to fix up codeblocks
                    # Make sure we can at least get past the first instruction in certain functions
                    if self.vw.isNoReturnVa(op.va) and op.va != funcva:
                        vg_path.setNodeProp(self.curpath, 'cleanret', False)
                        break

                except envi.BadOpcode:
                    break
                except envi.UnsupportedInstruction as e:
                    if self.strictops:
                        logger.debug(
                            'runFunction breaking after unsupported instruction: 0x%08x %s',
                            e.op.va, e.op.mnem)
                        raise e
                    else:
                        logger.debug(
                            'runFunction continuing after unsupported instruction: 0x%08x %s',
                            e.op.va, e.op.mnem)
                        self.setProgramCounter(e.op.va + e.op.size)
                except v_exc.BadOutInstruction:
                    break
                except Exception as e:
                    if self.emumon is not None and not isinstance(
                            e, e_exc.BreakpointHit):
                        self.emumon.logAnomaly(self, starteip, str(e))
                    logger.debug(
                        'runFunction breaking after exception (fva: 0x%x): %s',
                        funcva, e)
                    break  # If we exc during execution, this branch is dead.
Example #9
0
    def runFunction(self, funcva, stopva=None, maxhit=None, maxloop=None):
        """
        This is a utility function specific to WorkspaceEmulation (and impemu) that
        will emulate, but only inside the given function.  You may specify a stopva
        to return once that location is hit.
        """

        self.funcva = funcva

        # Let the current (should be base also) path know where we are starting
        vg_path.setNodeProp(self.curpath, 'bva', funcva)
        hits = {}
        todo = [(funcva, self.getEmuSnap(), self.path)]
        vw = self.vw  # Save a dereference many many times

        while len(todo):

            va, esnap, self.curpath = todo.pop()

            self.setEmuSnap(esnap)

            self.setProgramCounter(va)

            # Check if we are beyond our loop max...
            if maxloop is not None:
                lcount = vg_path.getPathLoopCount(self.curpath, 'bva', va)
                if lcount > maxloop:
                    continue

            while True:

                starteip = self.getProgramCounter()

                if not vw.isValidPointer(starteip):
                    break

                if starteip == stopva:
                    return

                # Check straight hit count...
                if maxhit is not None:
                    h = hits.get(starteip, 0)
                    h += 1
                    if h > maxhit:
                        break
                    hits[starteip] = h

                # If we ran out of path (branches that went
                # somewhere that we couldn't follow)?
                if self.curpath is None:
                    break

                try:

                    # FIXME unify with stepi code...
                    op = self.parseOpcode(starteip)
                    self.op = op
                    if self.emumon:
                        try:
                            self.emumon.prehook(self, op, starteip)
                        except Exception as e:
                            if not self.getMeta('silent'):
                                logger.warn(
                                    "funcva: 0x%x opva: 0x%x:  %r   (%r) (in emumon prehook)",
                                    funcva, starteip, op, e)

                        if self.emustop:
                            return
                    # Execute the opcode
                    self.executeOpcode(op)
                    vg_path.getNodeProp(self.curpath,
                                        'valist').append(starteip)

                    endeip = self.getProgramCounter()

                    if self.emumon:
                        try:
                            self.emumon.posthook(self, op, endeip)
                        except Exception as e:
                            if not self.getMeta('silent'):
                                logger.warn(
                                    "funcva: 0x%x opva: 0x%x:  %r   (%r) (in emumon posthook)",
                                    funcva, starteip, op, e)

                        if self.emustop:
                            return

                    iscall = self.checkCall(starteip, endeip, op)
                    if self.emustop:
                        return

                    # If it wasn't a call, check for branches, if so, add them to
                    # the todo list and go around again...
                    if not iscall:
                        blist = self.checkBranches(starteip, endeip, op)
                        if len(blist):
                            # pc in the snap will be wrong, but over-ridden at restore
                            esnap = self.getEmuSnap()
                            for bva, bpath in blist:
                                todo.append((bva, esnap, bpath))
                            break

                    # If we enounter a procedure exit, it doesn't
                    # matter what EIP is, we're done here.
                    if op.iflags & envi.IF_RET:
                        vg_path.setNodeProp(self.curpath, 'cleanret', True)
                        break
                except envi.UnsupportedInstruction as e:
                    if self.strictops:
                        logger.debug(
                            'runFunction failed: unsupported instruction: 0x%08x %s',
                            e.op.va, e.op.mnem)
                        break
                    else:
                        logger.debug(
                            'runFunction continuing after unsupported instruction: 0x%08x %s',
                            e.op.va, e.op.mnem)
                        self.setProgramCounter(e.op.va + e.op.size)
                except Exception as e:
                    if self.emumon is not None and not isinstance(
                            e, e_exc.BreakpointHit):
                        self.emumon.logAnomaly(self, starteip, str(e))

                    break  # If we exc during execution, this branch is dead.
Example #10
0
 def setPathProp(self, key, value):
     """
     Set a named value which is only relevant for the current code path.
     """
     return vg_path.setNodeProp(self.curpath, key, value)
Example #11
0
    def getFuncCbRoutedPaths_genback(self,
                                     fromva,
                                     tova,
                                     loopcnt=0,
                                     maxpath=None,
                                     timeout=None):
        '''
        Yields all the paths through the hierarchical graph starting at the 
        "root nodes" and ending at tocbva.  Specify a loopcnt to allow loop 
        paths to be generated with the given "loop iteration count"

        Example:
            for path in getCodePathsTo(fgraph, tocbva):
                for node,edge in path:
                    ...etc...
        '''
        fgraph = self.graph
        self.__update = 0
        self.__go__ = True
        pathcnt = 0
        tocbva = getGraphNodeByVa(fgraph, tova)
        frcbva = getGraphNodeByVa(fgraph, fromva)

        preRouteGraph(fgraph, fromva, tova)

        pnode = vg_pathcore.newPathNode(nid=tocbva, eid=None)

        todo = [
            (tocbva, pnode),
        ]

        maxtime = None
        if timeout:
            maxtime = time.time() + timeout

        while todo:
            if maxtime and time.time() > maxtime:
                raise PathForceQuitException()

            if not self.__go__:
                raise PathForceQuitException()

            nodeid, cpath = todo.pop()

            refsto = fgraph.getRefsTo((nodeid, None))

            # This is the root node!
            if nodeid == frcbva:
                path = vg_pathcore.getPathToNode(cpath)
                path.reverse()
                self.__steplock.acquire()
                yield [viv_graph._nodeedge(n) for n in path]
                vg_pathcore.trimPath(cpath)

                pathcnt += 1
                self.__update = 1
                self.__steplock.release()
                if maxpath and pathcnt >= maxpath:
                    return

            for eid, fromid, toid, einfo in refsto:
                if fgraph.getNodeProps(fromid).get('up') != True:
                    # TODO: drop the bad edges from graph in preprocessing? instead of "if" here
                    vg_pathcore.trimPath(cpath)
                    continue

                # Skip loops if they are "deeper" than we are allowed
                loops = vg_pathcore.getPathLoopCount(cpath, 'nid', fromid)
                if loops > loopcnt:
                    continue

                vg_pathcore.setNodeProp(cpath, 'eid', eid)
                npath = vg_pathcore.newPathNode(parent=cpath,
                                                nid=fromid,
                                                eid=None)
                todo.append((fromid, npath))

        self.__go__ = False
Example #12
0
    def runFunction(self, funcva, stopva=None, maxhit=None, maxloop=None):
        """
        This is a utility function specific to WorkspaceEmulation (and impemu) that
        will emulate, but only inside the given function.  You may specify a stopva
        to return once that location is hit.
        """

        self.funcva = funcva

        # Let the current (should be base also) path know where we are starting
        vg_path.setNodeProp(self.curpath, 'bva', funcva)

        hits = {}
        todo = [(funcva,self.getEmuSnap(),self.path),]
        vw = self.vw # Save a dereference many many times

        while len(todo):

            va,esnap,self.curpath = todo.pop()

            self.setEmuSnap(esnap)

            self.setProgramCounter(va)

            # Check if we are beyond our loop max...
            if maxloop != None:
                lcount = vg_path.getPathLoopCount(self.curpath, 'bva', va)
                if lcount > maxloop:
                    continue

            while True:

                starteip = self.getProgramCounter()

                if not vw.isValidPointer(starteip):
                    break

                if starteip == stopva:
                    return

                # Check straight hit count...
                if maxhit != None:
                    h = hits.get(starteip, 0)
                    h += 1
                    if h > maxhit:
                        break
                    hits[starteip] = h

                # If we ran out of path (branches that went
                # somewhere that we couldn't follow?
                if self.curpath == None:
                    break

                try:

                    # FIXME unify with stepi code...
                    op = self.parseOpcode(starteip)
                    self.op = op
                    if self.emumon:
                        self.emumon.prehook(self, op, starteip)

                        if self.emustop:
                            return 

                    # Execute the opcode
                    self.executeOpcode(op)
                    vg_path.getNodeProp(self.curpath, 'valist').append(starteip)

                    endeip = self.getProgramCounter()

                    if self.emumon:
                        self.emumon.posthook(self, op, endeip)
                        if self.emustop:
                            return 

                    iscall = self.checkCall(starteip, endeip, op)
                    if self.emustop:
                        return

                    # If it wasn't a call, check for branches, if so, add them to
                    # the todo list and go around again...
                    if not iscall:
                        blist = self.checkBranches(starteip, endeip, op)
                        if len(blist):
                            # pc in the snap will be wrong, but over-ridden at restore
                            esnap = self.getEmuSnap()
                            for bva,bpath in blist:
                                todo.append((bva, esnap, bpath))
                            break

                    # If we enounter a procedure exit, it doesn't
                    # matter what EIP is, we're done here.
                    if op.iflags & envi.IF_RET:
                        vg_path.setNodeProp(self.curpath, 'cleanret', True)
                        break
                except envi.UnsupportedInstruction, e:
                    if self.strictops:
                        break
                    else:
                        print 'runFunction continuing after unsupported instruction: 0x%08x %s' % (e.op.va, e.op.mnem)
                        self.setProgramCounter(e.op.va+ e.op.size)
                except Exception, e:
                    #traceback.print_exc()
                    if self.emumon != None:
                        self.emumon.logAnomaly(self, starteip, str(e))

                    break # If we exc during execution, this branch is dead.
Example #13
0
 def setPathProp(self, key, value):
     """
     Set a named value which is only relevant for the current code path.
     """
     return vg_path.setNodeProp(self.curpath, key, value)
Example #14
0
    def _runFunction(self, funcva, stopva=None, maxhit=None, maxloop=None, maxrep=None, strictops=True, func_only=True):
        """
        :param func_only: is this emulator meant to stay in one function scope?
        :param strictops: should we bail on emulation if unsupported instruction encountered
        """
        vg_path.setNodeProp(self.curpath, 'bva', funcva)

        hits = {}
        rephits = {}
        todo = [(funcva, self.getEmuSnap(), self.path), ]
        emu = self._emu
        vw = self._emu.vw # Save a dereference many many times
        depth = 0
        op = None

        while len(todo) > 0:
            va, esnap, self.curpath = todo.pop()
            self.setEmuSnap(esnap)
            emu.setProgramCounter(va)

            # Check if we are beyond our loop max...
            if maxloop != None:
                lcount = vg_path.getPathLoopCount(self.curpath, 'bva', va)
                if lcount > maxloop:
                    continue

            while True:
                startpc = emu.getProgramCounter()

                if not vw.isValidPointer(startpc):
                    break

                if startpc == stopva:
                    return

                # If we ran out of path (branches that went
                # somewhere that we couldn't follow?
                if self.curpath == None:
                    break

                try:
                    op = emu.parseOpcode(startpc)

                    if op.prefixes & PREFIX_REP and maxrep != None:
                        # execute same instruction with `rep` prefix up to maxrep times
                        h = rephits.get(startpc, 0)
                        h += 1
                        if h > maxrep:
                            break
                        rephits[startpc] = h
                    elif maxhit != None:
                        # Check straight hit count for all other instructions...
                        h = hits.get(startpc, 0)
                        h += 1
                        if h > maxhit:
                            break
                        hits[startpc] = h

                    nextpc = startpc + len(op)
                    self.op = op

                    for mon in self._monitors:
                        mon.prehook(emu, op, startpc)

                    iscall = bool(op.iflags & v_envi.IF_CALL)
                    if iscall:
                        wentInto = self.handleCall(startpc, op, avoid_calls=func_only)
                        if wentInto:
                            depth += 1
                    else:
                        emu.executeOpcode(op)

                    vg_path.getNodeProp(self.curpath, 'valist').append(startpc)
                    endpc = emu.getProgramCounter()

                    for mon in self._monitors:
                        mon.posthook(emu, op, endpc)

                    if not iscall:
                        # If it wasn't a call, check for branches, if so, add them to
                        # the todo list and go around again...
                        blist = emu.checkBranches(startpc, endpc, op)
                        if len(blist) > 0:
                            # pc in the snap will be wrong, but over-ridden at restore
                            esnap = self.getEmuSnap()
                            for bva, bpath in blist:
                                todo.append((bva, esnap, bpath))
                            break

                    if op.iflags & v_envi.IF_RET:
                        vg_path.setNodeProp(self.curpath, 'cleanret', True)
                        if depth == 0:
                            break
                        else:
                            depth -= 1

                # If we enounter a procedure exit, it doesn't
                # matter what PC is, we're done here.
                except v_envi.UnsupportedInstruction as e:
                    if strictops:
                        break
                    else:
                        self._logger.debug('runFunction continuing after unsupported instruction: 0x%08x %s',
                               e.op.va, e.op.mnem)
                        emu.setProgramCounter(e.op.va + e.op.size)
                except Exception as e:
                    self._logger.warning("error during emulation of function: %s", e)#, exc_info=True)
                    for mon in self._monitors:
                        mon.logAnomaly(emu, startpc, str(e))
                    break # If we exc during execution, this branch is dead.
Example #15
0
    def _runFunction(self,
                     funcva,
                     stopva=None,
                     maxhit=None,
                     maxloop=None,
                     maxrep=None,
                     strictops=True,
                     func_only=True):
        """
        :param func_only: is this emulator meant to stay in one function scope?
        :param strictops: should we bail on emulation if unsupported instruction encountered
        """
        vg_path.setNodeProp(self.curpath, 'bva', funcva)

        hits = {}
        rephits = {}
        todo = [
            (funcva, self.getEmuSnap(), self.path),
        ]
        emu = self._emu
        vw = self._emu.vw  # Save a dereference many many times
        depth = 0
        op = None

        while len(todo) > 0:
            va, esnap, self.curpath = todo.pop()
            self.setEmuSnap(esnap)
            emu.setProgramCounter(va)

            # Check if we are beyond our loop max...
            if maxloop != None:
                lcount = vg_path.getPathLoopCount(self.curpath, 'bva', va)
                if lcount > maxloop:
                    continue

            while True:
                startpc = emu.getProgramCounter()

                if not vw.isValidPointer(startpc):
                    break

                if startpc == stopva:
                    return

                # If we ran out of path (branches that went
                # somewhere that we couldn't follow?
                if self.curpath == None:
                    break

                try:
                    op = emu.parseOpcode(startpc)

                    if op.prefixes & PREFIX_REP and maxrep != None:
                        # execute same instruction with `rep` prefix up to maxrep times
                        h = rephits.get(startpc, 0)
                        h += 1
                        if h > maxrep:
                            break
                        rephits[startpc] = h
                    elif maxhit != None:
                        # Check straight hit count for all other instructions...
                        h = hits.get(startpc, 0)
                        h += 1
                        if h > maxhit:
                            break
                        hits[startpc] = h

                    nextpc = startpc + len(op)
                    self.op = op

                    for mon in self._monitors:
                        mon.prehook(emu, op, startpc)

                    iscall = bool(op.iflags & v_envi.IF_CALL)
                    if iscall:
                        wentInto = self.handleCall(startpc,
                                                   op,
                                                   avoid_calls=func_only)
                        if wentInto:
                            depth += 1
                    else:
                        emu.executeOpcode(op)

                    vg_path.getNodeProp(self.curpath, 'valist').append(startpc)
                    endpc = emu.getProgramCounter()

                    for mon in self._monitors:
                        mon.posthook(emu, op, endpc)

                    if not iscall:
                        # If it wasn't a call, check for branches, if so, add them to
                        # the todo list and go around again...
                        blist = emu.checkBranches(startpc, endpc, op)
                        if len(blist) > 0:
                            # pc in the snap will be wrong, but over-ridden at restore
                            esnap = self.getEmuSnap()
                            for bva, bpath in blist:
                                todo.append((bva, esnap, bpath))
                            break

                    if op.iflags & v_envi.IF_RET:
                        vg_path.setNodeProp(self.curpath, 'cleanret', True)
                        if depth == 0:
                            break
                        else:
                            depth -= 1

                # If we enounter a procedure exit, it doesn't
                # matter what PC is, we're done here.
                except v_envi.UnsupportedInstruction as e:
                    if strictops:
                        break
                    else:
                        self._logger.debug(
                            'runFunction continuing after unsupported instruction: 0x%08x %s',
                            e.op.va, e.op.mnem)
                        emu.setProgramCounter(e.op.va + e.op.size)
                except Exception as e:
                    self._logger.warning(
                        "error during emulation of function: %s",
                        e)  #, exc_info=True)
                    for mon in self._monitors:
                        mon.logAnomaly(emu, startpc, str(e))
                    break  # If we exc during execution, this branch is dead.