Ejemplo n.º 1
0
    def __init__(self,remote,db_name,exclude_pattern=None):
        # Keep remote address:
        self._remote = remote

        # Keep remote db name:
        self._db_name = db_name

        # A thread executor. Allows only one task to be run every time.
        self._te = ThreadExecutor()

        # A regexp pattern that identifies functions that are not named, and
        # should be ignored.
        self._exclude_pattern = exclude_pattern

        
        # A thread safe print function. I am not sure if this is rquired. It is
        # done to be one the safe side:
        self._print = print
Ejemplo n.º 2
0
    def __init__(self,remote,db_name,exclude_pattern=None):
        # Keep remote address:
        self._remote = remote

        # Keep remote db name:
        self._db_name = db_name

        # A thread executor. Allows only one task to be run every time.
        self._te = ThreadExecutor()

        # A regexp pattern that identifies functions that are not named, and
        # should be ignored.
        self._exclude_pattern = exclude_pattern

        
        # A thread safe print function. I am not sure if this is rquired. It is
        # done to be one the safe side:
        self._print = print
Ejemplo n.º 3
0
    def calculate(self, wait=False):
        _debug("Calculating")

        self.__freeze_changes()

        parent = None
        have_error = False

        executor = None

        for chunk in self.iterate_chunks():
            if isinstance(chunk, StatementChunk):
                changed = False

                if chunk.needs_compile or chunk.needs_execute:
                    if not executor:
                        executor = ThreadExecutor(parent)

                if executor:
                    statement = chunk.get_statement(self)
                    executor.add_statement(statement)

                parent = chunk.statement

        if executor:
            if wait:
                loop = gobject.MainLoop()

            def on_statement_execution_state_changed(executor, statement):
                if (statement.state == Statement.COMPILE_ERROR or
                    statement.state == Statement.EXECUTE_ERROR or
                    statement.state == Statement.INTERRUPTED):
                    self.__executor_error = True

                statement.chunk.update_statement()

                if self.__freeze_changes_count == 0:
                    self.__freeze_changes()
                    self.__chunk_changed(statement.chunk)
                    self.__thaw_changes()
                else:
                    self.__chunk_changed(statement.chunk)

            def on_complete(executor):
                self.__executor = None
                self.__set_state(NotebookFile.ERROR if self.__executor_error else NotebookFile.EXECUTE_SUCCESS)
                if wait:
                    loop.quit()

            self.__executor = executor
            self.__executor_error = False
            self.__set_state(NotebookFile.EXECUTING)
            executor.connect('statement-executing', on_statement_execution_state_changed)
            executor.connect('statement-complete', on_statement_execution_state_changed)
            executor.connect('complete', on_complete)

            if executor.compile():
                executor.execute()
                if wait:
                    loop.run()
        else:
            # Nothing to execute, we could have been in a non-success state if statements were deleted
            # at the end of the file.
            self.__set_state(NotebookFile.EXECUTE_SUCCESS)

        self.__thaw_changes()
Ejemplo n.º 4
0
class FCatalogClient(object):
    def __init__(self,remote,db_name,exclude_pattern=None):
        # Keep remote address:
        self._remote = remote

        # Keep remote db name:
        self._db_name = db_name

        # A thread executor. Allows only one task to be run every time.
        self._te = ThreadExecutor()

        # A regexp pattern that identifies functions that are not named, and
        # should be ignored.
        self._exclude_pattern = exclude_pattern

        
        # A thread safe print function. I am not sure if this is rquired. It is
        # done to be one the safe side:
        self._print = print

    def _is_func_named(self,func_addr):
        """
        Check if a function was ever named by the user.
        """
        logger.debug('_is_func_named {}'.format(func_addr))
        func_name = GetFunctionName(func_addr)

        # Avoid functions like sub_409f498:
        if func_name.startswith('sub_'):
            return False

        # If exclude_pattern was provided, make sure that the function
        # name does not match it:
        if self._exclude_pattern is not None:
            mt = re.match(self._exclude_pattern,func_name)
            if mt is not None:
                return False

        # Avoid reindexing FCATALOG functions:
        if is_func_fcatalog(func_addr):
            return False

        return True

    def _is_func_commit_candidate(self,func_addr):
        """
        Is this function a candidate for committing?
        """
        # Don't commit if chunked:
        if is_func_chunked(func_addr):
            return False

        if not self._is_func_named(func_addr):
            return False

        if not is_func_long_enough(func_addr):
            return False

        return True

    def _is_func_find_candidate(self,func_addr):
        """
        Is this function a candidate for finding from database (Finding similars
        for this function?)
        """
        if is_func_chunked(func_addr):
            return False

        if self._is_func_named(func_addr):
            return False

        if not is_func_long_enough(func_addr):
            return False

        return True


    def _iter_func_find_candidates(self):
        """
        Iterate over all functions that are candidates for finding similars from
        the remote database.
        This function is IDA read thread safe.
        """
        for func_addr in Functions():
            if self._is_func_find_candidate(func_addr):
                yield func_addr


    def _commit_funcs_thread(self):
        """
        Commit all the named functions from this idb to the server.
        This is an IDA read thread safe function.
        """
        self._print('Commiting functions...')
        # Set up a connection to remote db:
        frame_endpoint = TCPFrameClient(self._remote)
        fdb = DBEndpoint(frame_endpoint,self._db_name)


        for func_addr in Functions():
            logger.debug('Iterating over func_addr: {}'.format(func_addr))
            if not self._is_func_commit_candidate(func_addr):
                continue

            func_name = GetFunctionName(func_addr)
            func_comment = strip_comment_fcatalog(get_func_comment(func_addr))
            func_data = get_func_data(func_addr)

            # If we had problems reading the function data, we skip it.
            if func_data is None:
                self._print('!> Skipping {}'.format(func_name))
                continue

            fdb.add_function(func_name,func_comment,func_data)
            self._print(func_name)

        # Close db:
        fdb.close()
        self._print('Done commiting functions.')

    def commit_funcs(self):
        """
        Commit all functions from this IDB to the server.
        """
        try:
            t = self._te.execute(self._commit_funcs_thread)
        except ThreadExecutorError:
            print('Another operation is currently running. Please wait.')


    def _batch_similars(self,fdb,l_func_addr):
        """
        Given a list of function addresses, request similars for each of those
        functions. Then wait for all the responses, and return a list of tuples
        of the form: (func_addr,similars)
        This function is IDA read thread safe.
        """
        # Send requests for similars for every function in l_func_addr list:
        for func_addr in l_func_addr:
            func_data = get_func_data(func_addr)
            fdb.request_similars(func_data,1)

        # Collect responses from remote server:
        lres = []
        for func_addr in l_func_addr:
            similars = fdb.response_similars()
            lres.append((func_addr,similars))

        return lres


    def _find_similars_thread(self,similarity_cut,batch_size):
        """
        For each unnamed function in this database find a similar functions
        from the fcatalog remote db, and rename appropriately.
        This thread is IDA write thread safe.
        """
        self._print('Finding similars...')

        # Set up a connection to remote db:
        frame_endpoint = TCPFrameClient(self._remote)
        fdb = DBEndpoint(frame_endpoint,self._db_name)

        # Iterate over blocks of candidate functions addresses:
        for l_func_addr in blockify(self._iter_func_find_candidates(),\
                batch_size):
            # Send block to remote server and get results:
            bsimilars = self._batch_similars(fdb,l_func_addr)
            # Iterate over functions and results:
            for func_addr,similars in bsimilars:

                if len(similars) == 0:
                    # No similars found.
                    continue

                # Get the first entry (Highest similarity):
                fsim = similars[0]

                # Discard if doesn't pass the similarity cut:
                if fsim.sim_grade < similarity_cut:
                    continue

                old_name = GetFunctionName(func_addr)

                # Generate new name:
                new_name = make_fcatalog_name(fsim.name,fsim.sim_grade,func_addr)

                # If name matches old name, skip:
                if new_name == old_name:
                    continue

                # Set function to have the new name:
                make_name(func_addr,new_name)

                # Add the comments from the fcatalog entry:
                func_comment = get_func_comment(func_addr)
                func_comment_new = \
                        add_comment_fcatalog(func_comment,fsim.comment)
                set_func_comment(func_addr,func_comment_new)

                self._print('{} --> {}'.format(old_name,new_name))

        # Close db:
        fdb.close()

        self._print('Done finding similars.')

    def find_similars(self,similarity_cut,batch_size=GET_SIMILARS_BATCH_SIZE):
        """
        For each unnamed function in this database find a similar functions
        from the fcatalog remote db, and rename appropriately.
        """
        try:
            t = self._te.execute(self._find_similars_thread,\
                    similarity_cut,batch_size)
        except ThreadExecutorError:
            print('Another operation is currently running. Please wait.')
Ejemplo n.º 5
0
    def calculate(self, wait=False, end_line=None):
        _debug("Calculating")

        self.__freeze_changes()

        parent = None
        have_error = False

        executor = None

        for chunk in self.iterate_chunks(end_line=end_line):
            if isinstance(chunk, StatementChunk):
                if chunk.needs_compile or chunk.needs_execute:
                    if not executor:
                        executor = ThreadExecutor(parent)

                if executor:
                    statement = chunk.get_clean_statement(self)
                    executor.add_statement(statement)

                parent = chunk.statement

        # See if there are any more statements after the ones we are executing
        more_statements = (end_line is not None) and \
            any(isinstance(chunk, StatementChunk) for chunk in self.iterate_chunks(start_line=end_line))

        if executor:
            if wait:
                loop = executor.event_loop

            def on_statement_execution_state_changed(executor, statement):
                if (statement.state == Statement.COMPILE_ERROR or
                    statement.state == Statement.EXECUTE_ERROR or
                    statement.state == Statement.INTERRUPTED):
                    self.__executor_error = True

                statement.chunk.update_statement()

                if self.__freeze_changes_count == 0:
                    self.__freeze_changes()
                    self.__chunk_changed(statement.chunk)
                    self.__thaw_changes()
                else:
                    self.__chunk_changed(statement.chunk)

            def on_complete(executor):
                self.__executor.destroy()
                self.__executor = None
                if self.__executor_error:
                    self.__set_state(NotebookFile.ERROR)
                elif more_statements:
                    self.__set_state(NotebookFile.NEEDS_EXECUTE)
                else:
                    self.__set_state(NotebookFile.EXECUTE_SUCCESS)
                if wait:
                    loop.quit()

            self.__executor = executor
            self.__executor_error = False
            self.__set_state(NotebookFile.EXECUTING)
            executor.sig_statement_executing.connect(on_statement_execution_state_changed)
            executor.sig_statement_complete.connect(on_statement_execution_state_changed)
            executor.sig_complete.connect(on_complete)

            if executor.compile():
                executor.execute()
                if wait:
                    loop.run()
        else:
            # Nothing to execute, we could have been in a non-success state if statements were deleted
            # at the end of the file.
            if not more_statements:
                self.__set_state(NotebookFile.EXECUTE_SUCCESS)

        self.__thaw_changes()
Ejemplo n.º 6
0
class FCatalogClient(object):
    def __init__(self,remote,db_name,exclude_pattern=None):
        # Keep remote address:
        self._remote = remote

        # Keep remote db name:
        self._db_name = db_name

        # A thread executor. Allows only one task to be run every time.
        self._te = ThreadExecutor()

        # A regexp pattern that identifies functions that are not named, and
        # should be ignored.
        self._exclude_pattern = exclude_pattern

        
        # A thread safe print function. I am not sure if this is rquired. It is
        # done to be one the safe side:
        self._print = print

    def _is_func_named(self,func_addr):
        """
        Check if a function was ever named by the user.
        """
        logger.debug('_is_func_named {}'.format(func_addr))
        func_name = GetFunctionName(func_addr)

        # Avoid functions like sub_409f498:
        if func_name.startswith('sub_'):
            return False

        # If exclude_pattern was provided, make sure that the function
        # name does not match it:
        if self._exclude_pattern is not None:
            mt = re.match(self._exclude_pattern,func_name)
            if mt is not None:
                return False

        # Avoid reindexing FCATALOG functions:
        if is_func_fcatalog(func_addr):
            return False

        return True

    def _is_func_commit_candidate(self,func_addr):
        """
        Is this function a candidate for committing?
        """
        # Don't commit if chunked:
        if is_func_chunked(func_addr):
            return False

        if not self._is_func_named(func_addr):
            return False

        if not is_func_long_enough(func_addr):
            return False

        return True

    def _is_func_find_candidate(self,func_addr):
        """
        Is this function a candidate for finding from database (Finding similars
        for this function?)
        """
        if is_func_chunked(func_addr):
            return False

        if self._is_func_named(func_addr):
            return False

        if not is_func_long_enough(func_addr):
            return False

        return True


    def _iter_func_find_candidates(self):
        """
        Iterate over all functions that are candidates for finding similars from
        the remote database.
        This function is IDA read thread safe.
        """
        for func_addr in Functions():
            if self._is_func_find_candidate(func_addr):
                yield func_addr


    def _commit_funcs_thread(self):
        """
        Commit all the named functions from this idb to the server.
        This is an IDA read thread safe function.
        """
        self._print('Commiting functions...')
        # Set up a connection to remote db:
        frame_endpoint = TCPFrameClient(self._remote)
        fdb = DBEndpoint(frame_endpoint,self._db_name)


        for func_addr in Functions():
            logger.debug('Iterating over func_addr: {}'.format(func_addr))
            if not self._is_func_commit_candidate(func_addr):
                continue

            func_name = GetFunctionName(func_addr)
            func_comment = strip_comment_fcatalog(get_func_comment(func_addr))
            func_data = get_func_data(func_addr)

            # If we had problems reading the function data, we skip it.
            if func_data is None:
                self._print('!> Skipping {}'.format(func_name))
                continue

            fdb.add_function(func_name,func_comment,func_data)
            self._print(func_name)

        # Close db:
        fdb.close()
        self._print('Done commiting functions.')

    def commit_funcs(self):
        """
        Commit all functions from this IDB to the server.
        """
        try:
            t = self._te.execute(self._commit_funcs_thread)
        except ThreadExecutorError:
            print('Another operation is currently running. Please wait.')


    def _batch_similars(self,fdb,l_func_addr):
        """
        Given a list of function addresses, request similars for each of those
        functions. Then wait for all the responses, and return a list of tuples
        of the form: (func_addr,similars)
        This function is IDA read thread safe.
        """
        # Send requests for similars for every function in l_func_addr list:
        for func_addr in l_func_addr:
            func_data = get_func_data(func_addr)
            fdb.request_similars(func_data,1)

        # Collect responses from remote server:
        lres = []
        for func_addr in l_func_addr:
            similars = fdb.response_similars()
            lres.append((func_addr,similars))

        return lres


    def _find_similars_thread(self,similarity_cut,batch_size):
        """
        For each unnamed function in this database find a similar functions
        from the fcatalog remote db, and rename appropriately.
        This thread is IDA write thread safe.
        """
        self._print('Finding similars...')

        # Set up a connection to remote db:
        frame_endpoint = TCPFrameClient(self._remote)
        fdb = DBEndpoint(frame_endpoint,self._db_name)

        # Iterate over blocks of candidate functions addresses:
        for l_func_addr in blockify(self._iter_func_find_candidates(),\
                batch_size):
            # Send block to remote server and get results:
            bsimilars = self._batch_similars(fdb,l_func_addr)
            # Iterate over functions and results:
            for func_addr,similars in bsimilars:

                if len(similars) == 0:
                    # No similars found.
                    continue

                # Get the first entry (Highest similarity):
                fsim = similars[0]

                # Discard if doesn't pass the similarity cut:
                if fsim.sim_grade < similarity_cut:
                    continue

                old_name = GetFunctionName(func_addr)

                # Generate new name:
                new_name = make_fcatalog_name(fsim.name,fsim.sim_grade,func_addr)

                # If name matches old name, skip:
                if new_name == old_name:
                    continue

                # Set function to have the new name:
                make_name(func_addr,new_name)

                # Add the comments from the fcatalog entry:
                func_comment = get_func_comment(func_addr)
                func_comment_new = \
                        add_comment_fcatalog(func_comment,fsim.comment)
                set_func_comment(func_addr,func_comment_new)

                self._print('{} --> {}'.format(old_name,new_name))

        # Close db:
        fdb.close()

        self._print('Done finding similars.')

    def find_similars(self,similarity_cut,batch_size=GET_SIMILARS_BATCH_SIZE):
        """
        For each unnamed function in this database find a similar functions
        from the fcatalog remote db, and rename appropriately.
        """
        try:
            t = self._te.execute(self._find_similars_thread,\
                    similarity_cut,batch_size)
        except ThreadExecutorError:
            print('Another operation is currently running. Please wait.')
Ejemplo n.º 7
0
    def calculate(self, wait=False, end_line=None):
        _debug("Calculating")

        self.__freeze_changes()

        parent = None
        have_error = False

        executor = None

        for chunk in self.iterate_chunks(end_line=end_line):
            if isinstance(chunk, StatementChunk):
                if chunk.needs_compile or chunk.needs_execute:
                    if not executor:
                        executor = ThreadExecutor(parent)

                if executor:
                    statement = chunk.get_clean_statement(self)
                    executor.add_statement(statement)

                parent = chunk.statement

        # See if there are any more statements after the ones we are executing
        more_statements = (end_line is not None) and \
            any(isinstance(chunk, StatementChunk) for chunk in self.iterate_chunks(start_line=end_line))

        if executor:
            if wait:
                loop = executor.event_loop

            def on_statement_execution_state_changed(executor, statement):
                if (statement.state == Statement.COMPILE_ERROR
                        or statement.state == Statement.EXECUTE_ERROR
                        or statement.state == Statement.INTERRUPTED):
                    self.__executor_error = True

                statement.chunk.update_statement()

                if self.__freeze_changes_count == 0:
                    self.__freeze_changes()
                    self.__chunk_changed(statement.chunk)
                    self.__thaw_changes()
                else:
                    self.__chunk_changed(statement.chunk)

            def on_complete(executor):
                self.__executor.destroy()
                self.__executor = None
                if self.__executor_error:
                    self.__set_state(NotebookFile.ERROR)
                elif more_statements:
                    self.__set_state(NotebookFile.NEEDS_EXECUTE)
                else:
                    self.__set_state(NotebookFile.EXECUTE_SUCCESS)
                if wait:
                    loop.quit()

            self.__executor = executor
            self.__executor_error = False
            self.__set_state(NotebookFile.EXECUTING)
            executor.sig_statement_executing.connect(
                on_statement_execution_state_changed)
            executor.sig_statement_complete.connect(
                on_statement_execution_state_changed)
            executor.sig_complete.connect(on_complete)

            if executor.compile():
                executor.execute()
                if wait:
                    loop.run()
        else:
            # Nothing to execute, we could have been in a non-success state if statements were deleted
            # at the end of the file.
            if not more_statements:
                self.__set_state(NotebookFile.EXECUTE_SUCCESS)

        self.__thaw_changes()