about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2021-08-07 12:03:29 +0200
committerGitHub <noreply@github.com>2021-08-07 12:03:29 +0200
commit6b06d4c74d0d8d82ddbe75c81e35ed423e735314 (patch)
tree12ba5226e92ab43c7cc5c70925a58cfe0513773b
parent8ad6e7c1404be214ea25692cbd9093aad3dff9ae (diff)
parentfda210aabd9d5493d72f36eaaefe7bdff34c241c (diff)
downloadafl++-6b06d4c74d0d8d82ddbe75c81e35ed423e735314.tar.gz
Merge pull request #1053 from DMaroo/gtk-dev
Added a minimal working/functional GTK UI for analyzing fuzzing stats
-rw-r--r--.gitignore1
-rw-r--r--GNUmakefile5
-rw-r--r--README.md12
-rwxr-xr-xafl-plot173
-rw-r--r--utils/README.md3
-rw-r--r--utils/plot_ui/Makefile10
-rw-r--r--utils/plot_ui/README.md5
-rw-r--r--utils/plot_ui/afl-plot-ui.c166
8 files changed, 357 insertions, 18 deletions
diff --git a/.gitignore b/.gitignore
index 8c420b5e..5627d8ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -85,4 +85,5 @@ gmon.out
 afl-frida-trace.so
 utils/afl_network_proxy/afl-network-client
 utils/afl_network_proxy/afl-network-server
+utils/plot_ui/afl-plot-ui
 *.o.tmp
diff --git a/GNUmakefile b/GNUmakefile
index 6ae361e0..66fc0f07 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -572,6 +572,7 @@ clean:
 	$(MAKE) -C utils/afl_network_proxy clean
 	$(MAKE) -C utils/socket_fuzzing clean
 	$(MAKE) -C utils/argv_fuzzing clean
+	-$(MAKE) -C utils/plot_ui clean
 	$(MAKE) -C qemu_mode/unsigaction clean
 	$(MAKE) -C qemu_mode/libcompcov clean
 	$(MAKE) -C qemu_mode/libqasan clean
@@ -605,6 +606,7 @@ endif
 	$(MAKE) -C utils/afl_network_proxy
 	$(MAKE) -C utils/socket_fuzzing
 	$(MAKE) -C utils/argv_fuzzing
+	# -$(MAKE) -C utils/plot_ui
 	-$(MAKE) -C frida_mode
 ifneq "$(SYS)" "Darwin"
 	-cd qemu_mode && sh ./build_qemu_support.sh
@@ -618,6 +620,7 @@ binary-only: test_shm test_python ready $(PROGS)
 	$(MAKE) -C utils/afl_network_proxy
 	$(MAKE) -C utils/socket_fuzzing
 	$(MAKE) -C utils/argv_fuzzing
+	# -$(MAKE) -C utils/plot_ui
 	-$(MAKE) -C frida_mode
 ifneq "$(SYS)" "Darwin"
 	-cd qemu_mode && sh ./build_qemu_support.sh
@@ -632,6 +635,7 @@ ifneq "$(SYS)" "Darwin"
 endif
 	$(MAKE) -C utils/libdislocator
 	$(MAKE) -C utils/libtokencap
+	# -$(MAKE) -C utils/plot_ui
 
 %.8:	%
 	@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
@@ -660,6 +664,7 @@ install: all $(MANPAGES)
 	@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
 	install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
 	@if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
+	@if [ -f utils/plot_ui/afl-plot-ui ]; then install -m 755 utils/plot_ui/afl-plot-ui $${DESTDIR}$(BIN_PATH); fi
 	@if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
 	@if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
 	@if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
diff --git a/README.md b/README.md
index c5e396c5..92b6071c 100644
--- a/README.md
+++ b/README.md
@@ -1181,6 +1181,18 @@ If you have gnuplot installed, you can also generate some pretty graphs for any
 active fuzzing task using afl-plot. For an example of how this looks like,
 see [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/).
 
+You can also manually build and install afl-plot-ui, which is a helper utility
+for showing the graphs generated by afl-plot in a graphical window using GTK.
+You can build and install it as follows
+
+```shell
+sudo apt install libgtk-3-0 libgtk-3-dev pkg-config
+cd utils/plot_ui
+make
+cd ../../
+sudo make install
+```
+
 ## Help: Crash triage
 
 The coverage-based grouping of crashes usually produces a small data set that
diff --git a/afl-plot b/afl-plot
index 662c0907..87b9caae 100755
--- a/afl-plot
+++ b/afl-plot
@@ -22,16 +22,28 @@ get_abs_path() {
 echo "progress plotting utility for afl-fuzz by Michal Zalewski"
 echo
 
-if [ ! "$#" = "2" ]; then
+GRAPHICAL="0"
+
+if [ "$1"  = "-g" ] || [ "$1" = "--graphical" ]; then
+GRAPHICAL="1"
+shift
+fi
+
+if [ "$#" != "2" ]; then
 
   cat 1>&2 <<_EOF_
-$0 afl_state_dir graph_output_dir
+$0 [ -g | --graphical ] afl_state_dir graph_output_dir
 
-This program generates gnuplot images from afl-fuzz output data. Usage:
+This program generates gnuplot images from afl-fuzz output data.
 
-The afl_state_dir parameter should point to an existing state directory for any
-active or stopped instance of afl-fuzz; while graph_output_dir should point to
-an empty directory where this tool can write the resulting plots to.
+Usage:
+
+    afl_state_dir       should point to an existing state directory for any
+                        active or stopped instance of afl-fuzz
+    graph_output_dir    should point to an empty directory where this
+                        tool can write the resulting plots to
+    -g, --graphical     (optional) display the plots in a graphical window
+                        (you should have built afl-plot-ui to use this option)
 
 The program will put index.html and three PNG images in the output directory;
 you should be able to view it with any web browser of your choice.
@@ -102,18 +114,10 @@ fi
 rm -f "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png"
 mv -f "$outputdir/index.html" "$outputdir/index.html.orig" 2>/dev/null
 
-echo "[*] Generating plots..."
-
-(
-
-cat <<_EOF_
-set terminal png truecolor enhanced size 1000,300 butt
-
-set output '$outputdir/high_freq.png'
-
+GNUPLOT_SETUP="
 #set xdata time
 #set timefmt '%s'
-#set format x "%b %d\n%H:%M"
+#set format x \"%b %d\n%H:%M\"
 set tics font 'small'
 unset mxtics
 unset mytics
@@ -127,36 +131,169 @@ set key outside
 set autoscale xfixmin
 set autoscale xfixmax
 
-set xlabel "relative time in seconds" font "small"
+set xlabel \"relative time in seconds\" font \"small\"
+"
+
+PLOT_HF="
+set terminal png truecolor enhanced size 1000,300 butt
+set output '$outputdir/high_freq.png'
+
+$GNUPLOT_SETUP
 
 plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
      '' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
      '' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\
      '' using 1:6 with lines title 'pending favs' linecolor rgb '#c00080' linewidth 3, \\
      '' using 1:2 with lines title 'cycles done' linecolor rgb '#c000f0' linewidth 3
+"
 
+PLOT_LF="
 set terminal png truecolor enhanced size 1000,200 butt
 set output '$outputdir/low_freq.png'
 
+$GNUPLOT_SETUP
+
 plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
      '' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\
      '' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\
      '' using 1:10 with lines title 'levels' linecolor rgb '#0090ff' linewidth 3
+"
 
+PLOT_ES="
 set terminal png truecolor enhanced size 1000,200 butt
 set output '$outputdir/exec_speed.png'
 
+$GNUPLOT_SETUP
+
 plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
      '$inputdir/plot_data' using 1:11 with lines title '    execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
+"
 
+PLOT_EG="
 set terminal png truecolor enhanced size 1000,300 butt
 set output '$outputdir/edges.png'
 
+$GNUPLOT_SETUP
+
 plot '$inputdir/plot_data' using 1:13 with lines title '        edges' linecolor rgb '#0090ff' linewidth 3
+"
+
+if [ "$#" = "2" ] && [ "$GRAPHICAL" = "1" ]; then
+
+afl-plot-ui -h > /dev/null 2>&1
+
+if [ "$?" != "0" ]; then
+
+cat 1>&2 <<_EOF_
+You do not seem to have the afl-plot-ui utility installed. If you have installed afl-plot-ui, make sure the afl-plot-ui executable is in your PATH.
+If you are still facing any problems, please open an issue at https://github.com/AFLplusplus/AFLplusplus/issues.
+
+No plots have been generated. Please rerun without the "-g" or "--graphical" flag to generate the plots.
+_EOF_
+
+exit 1
+
+fi
+
+mkdir -p "$outputdir/tmp"
+afl-plot-ui > "$outputdir/tmp/win_ids" &
+
+sleep 0.5
+
+W_ID1=$(cat $outputdir/tmp/win_ids | head -1)
+W_ID2=$(cat $outputdir/tmp/win_ids | head -2 | tail -1)
+W_ID3=$(cat $outputdir/tmp/win_ids | head -3 | tail -1)
+W_ID4=$(cat $outputdir/tmp/win_ids | tail -1)
+
+echo "[*] Generating plots..."
+
+(
+
+cat << _EOF_
+
+$PLOT_HF
+set term x11 window "$W_ID3"
+set output
+replot
+pause mouse close
+
+_EOF_
+
+) | gnuplot 2> /dev/null &
+
+(
+
+cat << _EOF_
+
+$PLOT_LF
+set term x11 window "$W_ID4"
+set output
+replot
+pause mouse close
+
+_EOF_
+
+) | gnuplot 2> /dev/null &
+
+(
+
+cat << _EOF_
+
+$PLOT_ES
+set term x11 window "$W_ID2"
+set output
+replot
+pause mouse close
+
+_EOF_
+
+) | gnuplot 2> /dev/null &
+
+(
+
+cat << _EOF_
+
+$PLOT_EG
+set term x11 window "$W_ID1"
+set output
+replot
+pause mouse close
 
 _EOF_
 
-) | gnuplot 
+) | gnuplot 2> /dev/null &
+
+sleep 1
+
+rm "$outputdir/tmp/win_ids"
+
+if [ -z "$(ls -A $outputdir/tmp)" ]; then
+	rm -r "$outputdir/tmp"
+fi
+
+else
+
+echo "[*] Generating plots..."
+
+(
+
+cat << _EOF_
+
+$PLOT_HF
+
+$PLOT_LF
+
+$PLOT_ES
+
+$PLOT_EG
+
+_EOF_
+
+) | gnuplot
+
+echo "[?] You can also use -g flag to view the plots in an GUI window, and interact with the plots (if you have built afl-plot-ui). Run \"afl-plot-h\" to know more."
+
+fi
 
 if [ ! -s "$outputdir/exec_speed.png" ]; then
 
diff --git a/utils/README.md b/utils/README.md
index eb2e36b7..7fd6177a 100644
--- a/utils/README.md
+++ b/utils/README.md
@@ -8,6 +8,9 @@ Here's a quick overview of the stuff you can find in this directory:
   - afl_network_proxy    - fuzz a target over the network: afl-fuzz on
                            a host, target on an embedded system.
 
+  - plot_ui              - simple UI window utility to display the
+                           plots generated by afl-plot
+
   - afl_proxy            - skeleton file example to show how to fuzz
                            something where you gather coverage data via
                            different means, e.g. hw debugger
diff --git a/utils/plot_ui/Makefile b/utils/plot_ui/Makefile
new file mode 100644
index 00000000..7ade8a40
--- /dev/null
+++ b/utils/plot_ui/Makefile
@@ -0,0 +1,10 @@
+CFLAGS=`pkg-config --cflags gtk+-3.0`
+LDFLAGS=`pkg-config --libs gtk+-3.0`
+
+all:  afl-plot-ui
+
+afl-plot-ui:	afl-plot-ui.c
+	$(CC) $(CFLAGS) -o afl-plot-ui afl-plot-ui.c $(LDFLAGS)
+
+clean:
+	rm -f afl-plot-ui
\ No newline at end of file
diff --git a/utils/plot_ui/README.md b/utils/plot_ui/README.md
new file mode 100644
index 00000000..d8afa09f
--- /dev/null
+++ b/utils/plot_ui/README.md
@@ -0,0 +1,5 @@
+# afl-plot-ui
+
+`afl-plot-ui` is a helper utility for rendering the GNUplot graphs in a GTK window. This allows to real time resizing, scrolling, and cursor positioning features while viewing the graph. This utility also provides options to hide graphs using check buttons.
+
+*NOTE:* This utility is not meant to be used standalone. Never run this utility directly. Always run [`afl-plot`](../../afl-plot), which will, in turn, invoke this utility (when run using `-g` or `--graphical` flag).
\ No newline at end of file
diff --git a/utils/plot_ui/afl-plot-ui.c b/utils/plot_ui/afl-plot-ui.c
new file mode 100644
index 00000000..856bf082
--- /dev/null
+++ b/utils/plot_ui/afl-plot-ui.c
@@ -0,0 +1,166 @@
+#include <gtk/gtk.h>
+#include <gtk/gtkx.h>
+#include <stdio.h>
+#include <string.h>
+
+#define WIDTH 400
+#define HEIGHT 640
+
+char USAGE[] =
+    "is a helper utility for rendering the GNUplot graphs in a GTK window. This allows to real time resizing, scrolling, and cursor positioning features while viewing the graph. This utility also provides options to hide graphs using check buttons.\n \
+\n \
+Usage:\n \
+    -h, --help      Show this help menu\n \
+\n \
+NOTE: This utility is not meant to be used standalone. Never run this utility directly. Always run afl-plot, which will, in turn, invoke this utility (when run using `-g` or `--graphical` flag).\n \
+";
+
+static void plot_toggled(GtkWidget *caller, gpointer data);
+
+int main(int argc, char **argv) {
+
+  if (argc == 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help"))) {
+
+    printf("%s %s", argv[0], USAGE);
+    return EXIT_SUCCESS;
+
+  }
+
+  GtkWidget *window;
+  GtkWidget *main_vbox;
+
+  GtkWidget *cbuttons_frame;
+  GtkWidget *cbuttons_hbox;
+
+  GtkWidget *separator_maj, *separator_min1, *separator_min2, *separator_min3;
+
+  GtkWidget *plots_vbox;
+  GtkWidget *plot_edges_frame, *plot_exec_speed_frame, *plot_high_freq_frame,
+      *plot_low_freq_frame;
+  GtkWidget *plot_edges, *plot_exec_speed, *plot_high_freq, *plot_low_freq;
+
+  gtk_init(&argc, &argv);
+
+  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_default_size(GTK_WINDOW(window), WIDTH, HEIGHT);
+  gtk_window_set_title(GTK_WINDOW(window), "Graph drawing");
+  gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+  main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+
+  cbuttons_frame = gtk_frame_new("Select the plots");
+  gtk_container_set_border_width(GTK_CONTAINER(cbuttons_frame), 5);
+
+  cbuttons_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1);
+
+  GtkWidget *cbutton_edges, *cbutton_exec_speed, *cbutton_high_freq,
+      *cbutton_low_freq;
+
+  cbutton_edges = gtk_check_button_new_with_label("Edges");
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_edges), TRUE);
+  g_signal_connect(cbutton_edges, "toggled", G_CALLBACK(plot_toggled),
+                   &plot_edges_frame);
+
+  cbutton_exec_speed = gtk_check_button_new_with_label("Execution Speed");
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_exec_speed), TRUE);
+  g_signal_connect(cbutton_exec_speed, "toggled", G_CALLBACK(plot_toggled),
+                   &plot_exec_speed_frame);
+
+  cbutton_high_freq = gtk_check_button_new_with_label("High Frequency");
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_high_freq), TRUE);
+  g_signal_connect(cbutton_high_freq, "toggled", G_CALLBACK(plot_toggled),
+                   &plot_high_freq_frame);
+
+  cbutton_low_freq = gtk_check_button_new_with_label("Low Frequency");
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_low_freq), TRUE);
+  g_signal_connect(cbutton_low_freq, "toggled", G_CALLBACK(plot_toggled),
+                   &plot_low_freq_frame);
+
+  gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_edges, TRUE, TRUE, 1);
+  gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_exec_speed, TRUE, TRUE, 1);
+  gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_high_freq, TRUE, TRUE, 1);
+  gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_low_freq, TRUE, TRUE, 1);
+
+  gtk_container_add(GTK_CONTAINER(cbuttons_frame), cbuttons_hbox);
+  gtk_box_pack_start(GTK_BOX(main_vbox), cbuttons_frame, FALSE, TRUE, 1);
+
+  separator_maj = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
+  gtk_box_pack_start(GTK_BOX(main_vbox), separator_maj, FALSE, TRUE, 1);
+
+  plots_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
+
+  plot_edges_frame = gtk_frame_new("Edges");
+  gtk_container_set_border_width(GTK_CONTAINER(plot_edges_frame), 5);
+  plot_edges = gtk_socket_new();
+  gtk_container_add(GTK_CONTAINER(plot_edges_frame), plot_edges);
+
+  plot_exec_speed_frame = gtk_frame_new("Exec Speed");
+  gtk_container_set_border_width(GTK_CONTAINER(plot_exec_speed_frame), 5);
+  plot_exec_speed = gtk_socket_new();
+  gtk_container_add(GTK_CONTAINER(plot_exec_speed_frame), plot_exec_speed);
+
+  plot_high_freq_frame = gtk_frame_new("High Frequency");
+  gtk_container_set_border_width(GTK_CONTAINER(plot_high_freq_frame), 5);
+  plot_high_freq = gtk_socket_new();
+  gtk_container_add(GTK_CONTAINER(plot_high_freq_frame), plot_high_freq);
+
+  plot_low_freq_frame = gtk_frame_new("Low Frequency");
+  gtk_container_set_border_width(GTK_CONTAINER(plot_low_freq_frame), 5);
+  plot_low_freq = gtk_socket_new();
+  gtk_container_add(GTK_CONTAINER(plot_low_freq_frame), plot_low_freq);
+
+  separator_min1 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
+  separator_min2 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
+  separator_min3 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
+
+  gtk_box_pack_start(GTK_BOX(plots_vbox), plot_edges_frame, TRUE, TRUE, 1);
+  gtk_box_pack_start(GTK_BOX(plots_vbox), separator_min1, FALSE, TRUE, 1);
+
+  gtk_box_pack_start(GTK_BOX(plots_vbox), plot_exec_speed_frame, TRUE, TRUE, 1);
+  gtk_box_pack_start(GTK_BOX(plots_vbox), separator_min2, FALSE, TRUE, 1);
+
+  gtk_box_pack_start(GTK_BOX(plots_vbox), plot_high_freq_frame, TRUE, TRUE, 1);
+  gtk_box_pack_start(GTK_BOX(plots_vbox), separator_min3, FALSE, TRUE, 1);
+
+  gtk_box_pack_start(GTK_BOX(plots_vbox), plot_low_freq_frame, TRUE, TRUE, 1);
+
+  gtk_box_pack_start(GTK_BOX(main_vbox), plots_vbox, TRUE, TRUE, 1);
+
+  gtk_container_add(GTK_CONTAINER(window), main_vbox);
+
+  guint id_edges = gtk_socket_get_id(GTK_SOCKET(plot_edges));
+  guint id_exec_speed = gtk_socket_get_id(GTK_SOCKET(plot_exec_speed));
+  guint id_high_freq = gtk_socket_get_id(GTK_SOCKET(plot_high_freq));
+  guint id_low_freq = gtk_socket_get_id(GTK_SOCKET(plot_low_freq));
+
+  printf("%x\n%x\n%x\n%x\n", id_edges, id_exec_speed, id_high_freq,
+         id_low_freq);
+
+  fclose(stdout);
+
+  g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit),
+                   NULL);
+  gtk_widget_show_all(window);
+  gtk_main();
+
+  return EXIT_SUCCESS;
+
+}
+
+static void plot_toggled(GtkWidget *caller, gpointer data) {
+
+  gboolean state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(caller));
+
+  GtkWidget *widget = *(GtkWidget **)data;
+
+  if (state) {
+
+    gtk_widget_show(widget);
+
+  } else {
+
+    gtk_widget_hide(widget);
+
+  }
+
+}