def bySlug(slug, path):
        session = db.getSession()

        ret = session.query(TargetConfig).filter(
            TargetConfig.target_slug == slug).first()
        if ret is None:
            ret = TargetConfig(slug, path)
            session.add(ret)
            session.commit()

        return ret
Beispiel #2
0
    def export(self, export_cb=None):
        crashes = self.get_crashes()

        csvPath = os.path.join(self.exportDir, "triage.csv")
        with open(csvPath, "w") as f:
            csvWriter = csv.writer(f, lineterminator="\n")
            checksec_no_gs = self.checksec_cols.copy()
            checksec_no_gs[checksec_no_gs.index("gs")] = "guardStack"
            csvWriter.writerow(checksec_no_gs + self.crash_cols +
                               ["tracer.formatted"])
            session = db.getSession()
            target = session.query(TargetConfig).filter(
                TargetConfig.target_slug == self.slug).first()
            if not target:
                print("[!] Could not retrieve target config!")
            checksec = session.query(Checksec).filter(
                Checksec.hash == target.hash).first()
            if not checksec:
                print("[!} Could not retrieve Checksec results!")
            for crash in crashes:
                tracer = session.query(Tracer).filter(
                    Tracer.runid == crash.runid).first()
                if not tracer:
                    print("[!] Could not retrive Tracer results!")
                row = []
                for col in self.checksec_cols:
                    row.append(getattr(checksec, col, None))
                for col in self.crash_cols:
                    row.append(getattr(crash, col, None))
                row.append(tracer.formatted)
                csvWriter.writerow(row)

        for idx, crash in enumerate(crashes):
            try:
                if export_cb:
                    export_cb(idx)
                dstdir = os.path.join(
                    self.exportDir,
                    sanitizeString(crash.exploitability),
                    sanitizeString(crash.crashReason),
                    sanitizeString(crash.crashash),
                    crash.runid,
                )
                # os.makedirs( dstdir, exist_ok=True )
                srcdir = os.path.dirname(crash.minidumpPath)
                print("%s -> %s" % (srcdir, dstdir))
                shutil.copytree(srcdir,
                                dstdir,
                                ignore=ignore_patterns("mem*.dmp"))
            except FileExistsError as x:
                print("File already exists for crash ", crash.minidumpPath, x)
Beispiel #3
0
    def factory(runid, formatted=None, raw=None):
        runid = str(runid)
        session = db.getSession()
        ret = session.query(Tracer).filter(Tracer.runid == runid).first()
        if ret:
            return ret

        if not formatted and not raw:
            print("Could not find tracer for runid ", runid)
            return None

        ret = Tracer(runid, formatted, raw)

        session.add(ret)
        session.commit()
    def _handle_completion(self):
        session = db.getSession()

        record = RunBlock(
            self.target_slug,
            self.started,
            self.runs_counted,
            self.crash_counter,
            self.run_dict["bkt"],
            self.run_dict["scr"],
            self.run_dict["rem"],
        )

        session.add(record)
        session.commit()
Beispiel #5
0
    def incrementPath(pathhash, target_slug):
        session = db.getSession()
        session.expire_on_commit = False

        ret = session.query(PathRecord).filter(
            PathRecord.hash == pathhash).first()
        if ret:
            ret.count = ret.count + 1
            ret.last_seen = datetime.datetime.utcnow()
        else:
            ret = PathRecord(pathhash, target_slug)
            session.add(ret)

        session.commit()
        session.close()
Beispiel #6
0
    def factory(key, value=None):
        session = db.getSession()

        ret = session.query(Conf).filter(Conf.key == key).first()
        if ret:
            return ret

        if not value:
            return None

        conf = Conf(key, value)
        session.add(conf)
        session.commit()

        return conf
Beispiel #7
0
    def factory(runid, slug=None, targetPath=None):
        cfg = config
        session = db.getSession()
        runid = str(runid)
        ret = session.query(Crash).filter(Crash.runid == runid).first()
        if ret:
            return ret

        dmpPath = db.utilz.runidToDumpPath(runid)

        if not dmpPath:
            print("Unable to find dumpfile for runid %s" % runid)
            return None

        # Runs triager, which will give us exploitability info
        # using 2 engines: Google's breakpad and an reimplementation of Microsofts
        # !exploitable
        cmd = [cfg.config["triager_path"], dmpPath]
        out = subprocess.check_output(cmd, shell=False)
        # TODO: sorry didn't have time to clean this up before leave
        dirname = os.path.dirname(dmpPath)
        path = os.path.join(dirname, "triage.txt")
        with open(path, "wb", newline=None) as f:
            f.write(out)

        out = out.decode("utf8")
        j = None
        for line in out.splitlines():
            line = line.strip()
            if re.match(r"{.*}", line):
                j = json.loads(line)
                j["output"] = out

        if not j:
            return None
        try:
            ret = Crash(j, slug, runid, targetPath)
        except:  # noqa: E722
            print("Unable to process crash json")
            return None

        ret.mergeTracer()
        ret.reconstructor()
        session.add(ret)
        session.commit()
        return ret
Beispiel #8
0
def plot_run_rate(target_slug):
    session = db.getSession()
    target_runs = session.query(RunBlock).filter(RunBlock.target_config_slug == target_slug).all()

    rates = []
    for block in target_runs:
        elapsed = block.ended - block.started
        rate = block.runs / elapsed.total_seconds()
        rates.append(rate)

    stddev = statistics.stdev(rates)
    mean = statistics.mean(rates)

    no_outliers = list(filter(lambda x: abs(x[0] - mean) < 4 * stddev, zip(rates, target_runs)))

    plt.plot(get_fuzzing_time(k[1] for k in no_outliers), [k[0] for k in no_outliers], marker="o")
    plt.xlabel("Seconds spent fuzzing")
    plt.ylabel("Runs/Second (single threaded)")
    return plt
Beispiel #9
0
    def update(self):
        # create a query for the current target
        session = getSession()
        basequery = session.query(Crash).filter(
            Crash.target_config_slug == self.target_slug)

        # Set default values
        self.crashes = basequery.all()
        self.crashesCnt = len(self.crashes)
        self.exploitabilityCnts = {
            "High": 0,
            "Medium": 0,
            "Low": 0,
            "Unknown": 0,
            "None": 0
        }

        self.uniquesCnt = 0
        self.dupesCount = 0
        self.ranksMean = 0
        self.ranksMedian = 0

        # if there are crashes, update the rest of the counters
        if self.crashesCnt > 0:
            self.uniquesCnt = basequery.distinct(Crash.crashash).group_by(
                Crash.crashash).count()
            self.dupesCount = self.crashesCnt - self.uniquesCnt
            self.ranks = [_.rank for _ in self.crashes]
            self.ranksMean = statistics.mean(self.ranks)
            self.ranksMedian = statistics.median(self.ranks)
            self.exploitabilityCnts["High"] = basequery.filter(
                Crash.rank == 4).count()
            self.exploitabilityCnts["Medium"] = basequery.filter(
                Crash.rank == 3).count()
            self.exploitabilityCnts["Low"] = basequery.filter(
                Crash.rank == 2).count()
            self.exploitabilityCnts["Unknown"] = basequery.filter(
                Crash.rank == 1).count()
            self.exploitabilityCnts["None"] = basequery.filter(
                Crash.rank == 0).count()

        html = self.toHTML()
        self.web.setText(html)
Beispiel #10
0
def plot_discovered_paths(target_slug):
    session = db.getSession()
    target_runs = session.query(RunBlock).filter(RunBlock.target_config_slug == target_slug).all()

    figure, count = plt.subplots()

    # Plot the number of paths over time
    count.plot(get_fuzzing_time(target_runs), [block.num_paths for block in target_runs], marker=".", color="black")
    count.set_xlabel("Seconds spent fuzzing")
    count.set_ylabel("Unique Paths Encountered")
    count.legend(["Unique Paths"])

    # Plot the estimated percentage of all paths over time
    percentage = count.twinx()
    percentage.plot(
        get_fuzzing_time(target_runs), [(block.path_coverage * 100) for block in target_runs], marker=",", color="r"
    )
    percentage.legend(["Estimated Completion"])
    percentage.set_ylabel("Estimated path completion percentage")

    plt.title("Code Paths Over Time")
    figure.tight_layout()
    return plt
Beispiel #11
0
    def estimate_current_path_coverage(target_slug):
        session = db.getSession()
        target_query = session.query(PathRecord).filter(
            PathRecord.target_config_slug == target_slug)
        num_paths = target_query.count()
        num_singletons = target_query.filter(PathRecord.count == 1).count()
        num_doubletons = target_query.filter(PathRecord.count == 2).count()
        num_runs = sum(x.count for x in target_query.all())

        session.close()
        # TODO - is it fair to calculate assuming at least one doubleton here?
        c = num_paths / (num_paths + ((num_runs - 1) / num_runs) *
                         ((num_singletons**2) / (2 * max(num_doubletons, 1))))
        print(
            "Total Paths:",
            num_paths,
            # "Singletons:", num_singletons,
            # "Doubletons:", num_doubletons,
            "Total Runs:",
            num_runs,
            "Estimated Path Fraction:",
            c,
        )
        return num_paths, c
Beispiel #12
0
    def byExecutable(path):
        cfg = config
        session = db.getSession()
        session.expire_on_commit = False

        ret = session.query(Checksec).filter(
            Checksec.hash == hash_file(path)).first()
        if ret:
            session.close()
            return ret
        checker = cfg.config["checksec_path"]
        cmd = [checker, "-j", path]

        try:
            out = subprocess.check_output(cmd)
            ret = json.loads(out)
            ret = Checksec(ret)
            session.add(ret)
            session.commit()
            session.close()
        except subprocess.CalledProcessError as x:
            print("Exception", x)

        return ret
Beispiel #13
0
def generate_report(dest=None, browser=True):
    # Create the template environment
    env = Environment(loader=PackageLoader("sl2", "reporting/templates"))
    env.filters["comma_ify"] = comma_ify  # Pass in the comma_ify filter so we can use it when rendering
    template = env.get_template("index.html")

    # Look for any existing reports and increment the revision number if necessary
    target_dir = get_target_dir(sl2.harness.config.config)
    found = [
        int(f.split("Report_v")[1].replace(".html", "")) for f in glob.glob(os.path.join(target_dir, "Report_v*.html"))
    ]
    revision = 0 if len(found) == 0 else max(found) + 1

    # Render the graph of the estimated path coverage and base64 encode it
    slug = get_target_slug(sl2.harness.config.config)
    coverage_img = io.BytesIO()
    plt = plot_discovered_paths(slug)
    plt.savefig(coverage_img, format="png", dpi=200)
    coverage_graph = b64encode(coverage_img.getvalue()).decode("utf-8")

    # Get a current estimate of the path coverage
    num_paths, coverage_estimate = PathRecord.estimate_current_path_coverage(slug)

    # Grab the run blocks and crashes from the database
    session = db.getSession()
    run_blocks = session.query(RunBlock).filter(RunBlock.target_config_slug == slug).all()
    crash_base = session.query(Crash).filter(Crash.target_config_slug == slug)

    # create a big dict with all the environment variables for the template to render
    vars = {
        # Get the css framework and custom styles
        "normalize_css": env.get_template("css/normalize.css").render(),
        "skeleton_css": env.get_template("css/skeleton.css").render(),
        "custom_css": env.get_template("css/sl2.css").render(),
        # Get the base64 encoded logo
        "logo": env.get_template("images/logo.png.b64").render(),
        # Get app metadata
        "app_name": sl2.harness.config.profile,
        "revision": revision,
        "generated": datetime.datetime.now().isoformat(timespec="minutes"),
        "version": pkg_resources.require("sl2")[0].version,
        # Get the count of unique, total, and severe crashes from the database
        "uniq_crash_count": crash_base.distinct(Crash.crashash).group_by(Crash.crashash).count(),
        "total_crash_count": crash_base.count(),
        "severe_crash_count": crash_base.filter(
            Crash.exploitability != "None", Crash.exploitability != "Unknown", Crash.exploitability != "Low"
        )
        .group_by(Crash.crashash)
        .count(),
        # Get the number of runs and time spent
        "run_count": sum(x.runs for x in run_blocks),
        "cpu_time": sum(((block.ended - block.started).total_seconds()) for block in run_blocks),
        # Get the number of paths and coverage
        "path_count": num_paths,
        "coverage_estimate": coverage_estimate * 100,
        "coverage_graph": coverage_graph,
        # Generate a list of the unique crashes
        "crashes": sorted(
            session.query(Crash).filter(Crash.target_config_slug == slug).group_by(Crash.crashash).all(),
            key=lambda crash: crash.int_exploitability,
        ),
    }

    # Write the report to the disk
    fname = os.path.join(target_dir, "Report_v{}.html".format(revision))
    with open(fname, "w") as outfile:
        outfile.write(template.render(**vars))

    # Copy the report to the user-selected output folder (if given)
    if dest is not None:
        if ".html" not in dest:
            dest = os.path.join(dest, "Report_v{}.html".format(revision))
        copyfile(fname, dest)
        if browser:
            os.startfile(dest)
    else:
        print("Written to", fname)
        if browser:
            os.startfile(fname)
Beispiel #14
0
 def get_crashes(self):
     return db.getSession().query(Crash).filter(
         Crash.target_config_slug == self.slug).all()
Beispiel #15
0
 def getAll():
     session = db.getSession()
     return session.query(Crash).all()
Beispiel #16
0
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.crashes = []
        self.thread_holder = []
        self.paused_fuzzer_threads = []
        self.start_time = None

        # Select config profile before starting
        self.cfg = ConfigWindow()
        if self.cfg.exec() == QtWidgets.QDialog.Rejected:
            sys.exit(1)

        # Set up basic window
        self.setWindowTitle("Sienna Locomotive 2")
        self.setMinimumSize(QSize(1800, 1300))

        _central_widget = QtWidgets.QWidget(self)
        self.setCentralWidget(_central_widget)
        self._layout = QtWidgets.QVBoxLayout(_central_widget)
        _central_widget.setLayout(self._layout)

        # Set up Checksec, Wizard and Server threads so we don't block the UI
        # when they're running
        self.checksec_thread = ChecksecThread(
            config.config["target_application_path"])
        self.wizard_thread = WizardThread(config.config)
        self.server_thread = ServerThread(close_on_exit=True)

        # CREATE WIDGETS #

        # Menu bar
        self.menu_bar = self.menuBar()
        self.file_menu = self.menu_bar.addMenu("&File")
        self.change_profile_action = self.file_menu.addAction("Change Profile")
        self.open_report_in_browser = QtWidgets.QAction(
            "Open exported report in browser", self, checkable=True)
        self.file_menu.addAction(self.open_report_in_browser)
        self.open_report_in_browser.setChecked(True)

        # Target info
        self.target_status = QtWidgets.QStatusBar()
        self.target_label = QtWidgets.QLabel()
        self.target_status.addWidget(self.target_label)
        self._layout.addWidget(self.target_status)
        self.checksec_thread.start()
        self.checksec_thread.result_ready.connect(self.checksec_finished)

        # Create wizard button
        self.wizard_button = QtWidgets.QPushButton("Run Wizard")
        self._layout.addWidget(self.wizard_button)

        # Set up function tree display
        self._func_tree = CheckboxTreeWidget()
        self._layout.addWidget(self._func_tree)

        # Set up underlying model for exposing function data
        self.target_data = get_target(config.config)
        self.model = CheckboxTreeModel()
        self.func_proxy_model = CheckboxTreeSortFilterProxyModel()
        self.func_proxy_model.setSourceModel(self.model)
        self.func_proxy_model.setFilterKeyColumn(0)
        self.file_proxy_model = CheckboxTreeSortFilterProxyModel()
        self.file_proxy_model.setSourceModel(self.func_proxy_model)
        self.file_proxy_model.setFilterKeyColumn(1)
        self.module_proxy_model = CheckboxTreeSortFilterProxyModel()
        self.module_proxy_model.setSourceModel(self.file_proxy_model)
        self.module_proxy_model.setFilterKeyColumn(4)
        self.build_func_tree()
        self._func_tree.setModel(self.module_proxy_model)
        self._func_tree.setItemDelegate(
            ComboboxTreeItemDelegate(self.target_data))

        # These need to happen after we set the model
        self._func_tree.expandAll()
        self._func_tree.resizeColumnToContents(0)
        self._func_tree.resizeColumnToContents(1)
        self._func_tree.resizeColumnToContents(2)
        self._func_tree.resizeColumnToContents(3)

        # Create menu items for the context menu
        self.expand_action = QtWidgets.QAction("Expand All")
        self.collapse_action = QtWidgets.QAction("Collapse All")
        self.check_action = QtWidgets.QAction("Check All")
        self.uncheck_action = QtWidgets.QAction("Uncheck All")

        # Build layout for function filter text boxes
        self.filter_layout = QtWidgets.QHBoxLayout()
        self.filter_layout.addWidget(QtWidgets.QLabel("Filter Function: "))
        self.func_filter_box = QtWidgets.QLineEdit()
        self.filter_layout.addWidget(self.func_filter_box)
        self.filter_layout.addWidget(QtWidgets.QLabel("Filter Files: "))
        self.file_filter_box = QtWidgets.QLineEdit()
        self.filter_layout.addWidget(self.file_filter_box)
        self.filter_layout.addWidget(QtWidgets.QLabel("Filter Modules: "))
        self.module_filter_box = QtWidgets.QLineEdit()
        self.filter_layout.addWidget(self.module_filter_box)

        # Set up fuzzer button
        self.fuzzer_button = QtWidgets.QPushButton("Fuzz selected targets")
        if not self.target_data.target_list:
            self.fuzzer_button.setEnabled(False)

        # Create checkboxes for continuous mode
        self.continuous_mode_cbox = QtWidgets.QCheckBox("Continuous")
        self.pause_mode_cbox = QtWidgets.QCheckBox("Pause on crash")
        if config.config["continuous"]:
            self.continuous_mode_cbox.setChecked(True)
        if config.config["exit_early"]:
            self.pause_mode_cbox.setChecked(True)

        # Set up spinboxes for setting timeout values
        self.fuzz_timeout_box = QtWidgets.QSpinBox()
        self.fuzz_timeout_box.setSuffix(" seconds")
        self.fuzz_timeout_box.setMaximum(1200)
        if "fuzz_timeout" in config.config:
            self.fuzz_timeout_box.setValue(config.config["fuzz_timeout"])
        self.fuzz_timeout_box.setSpecialValueText("None")
        self.tracer_timeout_box = QtWidgets.QSpinBox()
        self.tracer_timeout_box.setSuffix(" seconds")
        self.tracer_timeout_box.setMaximum(2400)
        if "tracer_timeout" in config.config:
            self.tracer_timeout_box.setValue(config.config["tracer_timeout"])
        self.tracer_timeout_box.setSpecialValueText("None")
        self.tracer_timeout_box.setSingleStep(10)
        self.verbose_cbox = QtWidgets.QCheckBox()
        self.verbose_cbox.clicked.connect(self.toggle_verbose_state)

        # Create spinbox for controlling simultaneous fuzzing instances
        self.thread_count = QtWidgets.QSpinBox()
        self.thread_count.setSuffix(" threads")
        self.thread_count.setRange(1, 2 * cpu_count())
        if "simultaneous" in config.config:
            self.thread_count.setValue(config.config["simultaneous"])

        # Create button for hiding and showing the extended controls
        self.expand_button = QtWidgets.QToolButton()
        self.expand_button.setArrowType(Qt.DownArrow)

        # Create nested widget to hold the expanded fuzzing controls
        self.extension_widget = QtWidgets.QWidget()
        self.extension_layout = QtWidgets.QGridLayout()
        self.extension_widget.setLayout(self.extension_layout)

        # Create layouts for fuzzing controls
        self.fuzz_controls_outer_layout = QtWidgets.QHBoxLayout()
        self.fuzz_controls_inner_left = QtWidgets.QVBoxLayout()
        self.fuzz_controls_inner_right = QtWidgets.QVBoxLayout()

        # Add widgets to left, right, and expanded layouts
        self.fuzz_controls_inner_left.addLayout(self.filter_layout)
        self.fuzz_controls_inner_left.addWidget(self.extension_widget)
        self.extension_widget.hide()
        self.fuzz_controls_inner_left.addWidget(self.fuzzer_button)
        self.extension_layout.addWidget(self.continuous_mode_cbox, 0, 0)
        self.extension_layout.addWidget(self.pause_mode_cbox, 1, 0)
        self.extension_layout.addWidget(QtWidgets.QLabel("Fuzz timeout:"), 0,
                                        1, 1, 1, Qt.AlignRight)
        self.extension_layout.addWidget(self.fuzz_timeout_box, 0, 2, 1, 1,
                                        Qt.AlignLeft)
        self.extension_layout.addWidget(QtWidgets.QLabel("Triage Timeout:"), 1,
                                        1, 1, 1, Qt.AlignRight)
        self.extension_layout.addWidget(self.tracer_timeout_box, 1, 2, 1, 1,
                                        Qt.AlignLeft)
        self.extension_layout.addWidget(
            QtWidgets.QLabel("Simultaneous fuzzing threads:"), 0, 3, 1, 1,
            Qt.AlignRight)
        self.extension_layout.addWidget(self.thread_count, 0, 4, 1, 1,
                                        Qt.AlignLeft)

        self.extension_layout.addWidget(QtWidgets.QLabel("Verbose:"), 1, 3, 1,
                                        1, Qt.AlignRight)
        self.extension_layout.addWidget(self.verbose_cbox, 1, 4, 1, 1,
                                        Qt.AlignLeft)

        self.fuzz_controls_inner_right.addWidget(self.expand_button)

        # Compose layouts
        self.fuzz_controls_outer_layout.addLayout(
            self.fuzz_controls_inner_left)
        self.fuzz_controls_outer_layout.addLayout(
            self.fuzz_controls_inner_right)
        self._layout.addLayout(self.fuzz_controls_outer_layout)

        # Crashes table
        session = db.getSession()
        self.crashes_model = sqlalchemy_model.SqlalchemyModel(
            session,
            db.Crash,
            [
                ("Time", db.Crash.timestamp, "timestamp", {}),
                ("RunID", db.Crash.runid, "runid", {}),
                ("Reason", db.Crash.crashReason, "crashReason", {}),
                ("Exploitability", db.Crash.exploitability, "exploitability",
                 {}),
                ("Ranks", db.Crash.ranksString, "ranksString", {}),
                ("Crashash", db.Crash.crashash, "crashash", {}),
                ("Crash Address", db.Crash.crashAddressString,
                 "crashAddressString", {}),
                ("RIP", db.Crash.instructionPointerString,
                 "instructionPointerString", {}),
                ("RSP", db.Crash.stackPointerString, "stackPointerString", {}),
                ("RDI", db.Crash.rdi, "rdi", {}),
                ("RSI", db.Crash.rsi, "rsi", {}),
                ("RBP", db.Crash.rdx, "rbp", {}),
                ("RAX", db.Crash.rax, "rax", {}),
                ("RBX", db.Crash.rbx, "rbx", {}),
                ("RCX", db.Crash.rcx, "rcx", {}),
                ("RDX", db.Crash.rdx, "rdx", {}),
            ],
            orderBy=desc(db.Crash.timestamp),
            filters={"target_config_slug": get_target_slug(config.config)},
        )
        self.crashes_table = QtWidgets.QTableView()
        self.crashes_table.setFont(
            QFontDatabase.systemFont(QFontDatabase.FixedFont))
        self.crashes_table.setModel(self.crashes_model)
        self._layout.addWidget(self.crashes_table)
        self.crashes_table.horizontalHeader().setStretchLastSection(True)
        self.crashes_table.resizeColumnsToContents()
        self.crashes_table.show()
        self.crashes_table.clicked.connect(self.crash_clicked)

        # Crash Browser, details about a crash
        self.crash_browser = QtWidgets.QTextBrowser()
        self.crash_browser.setText("<NO CRASH SELECTED>")
        self.crash_browser.setFont(
            QFontDatabase.systemFont(QFontDatabase.FixedFont))
        self._layout.addWidget(self.crash_browser)

        self.stats_widget = stats.StatsWidget(get_target_slug(config.config))
        self._layout.addWidget(self.stats_widget)

        # Set up stop button (and hide it)
        self.stop_button = QtWidgets.QPushButton("Stop Fuzzing")
        self.stop_button.hide()
        self._layout.addWidget(self.stop_button)

        self.export_triage_button = QtWidgets.QPushButton("Export Triage")
        self._layout.addWidget(self.export_triage_button)

        # Set up status bar
        self.status_bar = QtWidgets.QStatusBar()
        self._layout.addWidget(self.status_bar)

        # Create helper variables for storing counters with signals attached
        self.runs, self.crash_counter = QIntVariable(0), QIntVariable(0)
        self.throughput = QFloatVariable(0.0)
        self.run_adapter = QTextAdapter("Fuzzing Runs: {0.value} ", self.runs)
        self.throughput_adapter = QTextAdapter(" {0.value:.3f} Runs/s ",
                                               self.throughput)
        self.crash_adapter = QTextAdapter(" Crashes Found: {0.value} ",
                                          self.crash_counter)

        # Create the busy label
        self.busy_label = QtWidgets.QLabel()
        busy_gif = QMovie("gui/busy.gif")
        self.busy_label.setMovie(busy_gif)
        busy_gif.start()
        self.busy_label.hide()

        # Set up labels for the status bar
        self.fuzz_count = QtWidgets.QLabel()
        self.throughput_label = QtWidgets.QLabel()
        self.crash_count = QtWidgets.QLabel()

        # Add all the labels to the status bar
        self.status_bar.addPermanentWidget(self.busy_label)
        self.status_bar.addWidget(self.fuzz_count)
        self.status_bar.addWidget(self.throughput_label)
        self.status_bar.addWidget(self.crash_count)

        # CONNECT SIGNALS #
        self.change_profile_action.triggered.connect(self.change_profile)

        # Update the text of the status bar adapters whenever the underlying variables change
        self.runs.valueChanged.connect(self.run_adapter.update)
        self.throughput.valueChanged.connect(self.throughput_adapter.update)
        self.crash_counter.valueChanged.connect(self.crash_adapter.update)

        self.run_adapter.updated.connect(self.fuzz_count.setText)
        self.throughput_adapter.updated.connect(self.throughput_label.setText)
        self.crash_adapter.updated.connect(self.crash_count.setText)

        # Start the wizard when we click the button and update the tree when we're done
        self.wizard_button.clicked.connect(self.wizard_thread.start)
        self.wizard_thread.started.connect(
            partial(self.setCursor, Qt.WaitCursor))
        self.wizard_thread.finished.connect(self.unsetCursor)
        self.wizard_thread.result_ready.connect(self.wizard_finished)

        # Connect the context menu buttons
        self.expand_action.triggered.connect(self._func_tree.expandAll)
        self.collapse_action.triggered.connect(self._func_tree.collapseAll)
        self.check_action.triggered.connect(self.check_all)
        self.uncheck_action.triggered.connect(self.uncheck_all)

        # Filter the list of functions displayed when we type things into the boxes
        self.func_filter_box.textChanged.connect(
            self.func_proxy_model.setFilterFixedString)
        self.file_filter_box.textChanged.connect(
            self.file_proxy_model.setFilterFixedString)
        self.module_filter_box.textChanged.connect(
            self.module_proxy_model.setFilterFixedString)

        # Handle checks/unchecks in the target tree
        self._func_tree.itemCheckedStateChanged.connect(self.tree_changed)

        self.export_triage_button.clicked.connect(self.export_triage)

        # Fuzzer control buttons for showing the panel and starting a run
        self.expand_button.clicked.connect(self.toggle_expansion)
        self.fuzzer_button.clicked.connect(self.server_thread.start)
        self.server_thread.finished.connect(self.start_all_threads)

        # If the user changes the continuous or pause mode, then we make sure the
        # two are consistent.
        self.pause_mode_cbox.stateChanged.connect(self.unify_pause_state)
        self.continuous_mode_cbox.stateChanged.connect(
            self.unify_continuous_state)

        # Connect the stop button to the thread so we can pause it
        self.stop_button.clicked.connect(self.pause_all_threads)

        # Connect the thread counter to the thread pool
        self.thread_count.valueChanged.connect(self.change_thread_count)
        self.change_thread_count(self.thread_count.value())
Beispiel #17
0
 def occurrences(self):
     session = db.getSession()
     return session.query(Crash).filter(
         Crash.crashash == self.crashash).count()