about summary refs log tree commit diff
path: root/qemu_mode
diff options
context:
space:
mode:
Diffstat (limited to 'qemu_mode')
-rw-r--r--qemu_mode/QEMUAFL_VERSION2
-rw-r--r--qemu_mode/README.md27
-rw-r--r--qemu_mode/README.wine.md21
-rwxr-xr-xqemu_mode/build_qemu_support.sh7
-rw-r--r--qemu_mode/libcompcov/compcovtest.cc163
-rw-r--r--qemu_mode/libqasan/hooks.c10
-rw-r--r--qemu_mode/libqasan/libqasan.c12
m---------qemu_mode/qemuafl0
8 files changed, 152 insertions, 90 deletions
diff --git a/qemu_mode/QEMUAFL_VERSION b/qemu_mode/QEMUAFL_VERSION
index 8d95c359..0fb33ae2 100644
--- a/qemu_mode/QEMUAFL_VERSION
+++ b/qemu_mode/QEMUAFL_VERSION
@@ -1 +1 @@
-ddc4a9748d
+d73b0336b4
diff --git a/qemu_mode/README.md b/qemu_mode/README.md
index a14cbe64..d28479d9 100644
--- a/qemu_mode/README.md
+++ b/qemu_mode/README.md
@@ -110,22 +110,23 @@ takes priority over any included ranges or AFL_INST_LIBS.
 
 CompareCoverage is a sub-instrumentation with effects similar to laf-intel.
 
-The environment variable that enables QEMU CompareCoverage is AFL_COMPCOV_LEVEL.
-There is also ./libcompcov/ which implements CompareCoverage for *cmp functions
-(splitting memcmp, strncmp, etc. to make these conditions easier solvable by
-afl-fuzz).
+You have to set `AFL_PRELOAD=/path/to/libcompcov.so` together with
+setting the AFL_COMPCOV_LEVEL you want to enable it.
 
 AFL_COMPCOV_LEVEL=1 is to instrument comparisons with only immediate
-values / read-only memory. AFL_COMPCOV_LEVEL=2 instruments all
-comparison instructions and memory comparison functions when libcompcov
-is preloaded.
-AFL_COMPCOV_LEVEL=3 has the same effects of AFL_COMPCOV_LEVEL=2 but enables also
-the instrumentation of the floating-point comparisons on x86 and x86_64 (experimental).
+values / read-only memory.
+
+AFL_COMPCOV_LEVEL=2 instruments all comparison instructions and memory
+comparison functions when libcompcov is preloaded.
+
+AFL_COMPCOV_LEVEL=3 has the same effects of AFL_COMPCOV_LEVEL=2 but enables
+also the instrumentation of the floating-point comparisons on x86 and x86_64
+(experimental).
 
 Integer comparison instructions are currently instrumented only
 on the x86, x86_64, arm and aarch64 targets.
 
-Highly recommended.
+Recommended, but not as good as CMPLOG mode (see below).
 
 ## 8) CMPLOG mode
 
@@ -141,7 +142,7 @@ To enable it you must pass on the command line of afl-fuzz:
 
 ## 9) Wine mode
 
-AFL++ QEMU can use Wine to fuzz WIn32 PE binaries. Use the -W flag of afl-fuzz.
+AFL++ QEMU can use Wine to fuzz Win32 PE binaries. Use the -W flag of afl-fuzz.
 
 Note that some binaries require user interaction with the GUI and must be patched.
 
@@ -190,8 +191,8 @@ handlers of the target.
 
 ## 13) Gotchas, feedback, bugs
 
-If you need to fix up checksums or do other cleanup on mutated test cases, see
-utils/custom_mutators/ for a viable solution.
+If you need to fix up checksums or do other cleanups on mutated test cases, see
+`afl_custom_post_process` in custom_mutators/examples/example.c for a viable solution.
 
 Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate
 the "shadow VM" trick employed by the sanitizers and will probably just
diff --git a/qemu_mode/README.wine.md b/qemu_mode/README.wine.md
new file mode 100644
index 00000000..567901cd
--- /dev/null
+++ b/qemu_mode/README.wine.md
@@ -0,0 +1,21 @@
+# How to troubleshoot AFL++'s wine mode
+
+## 1) Debugging
+To turn on wine debugging use the `WINEDEBUG` environment variable, 
+e.g. `WINEDEBUG=+timestamp,+tid,+loaddll`. 
+
+## 2) LoadLibraryA workaround
+The forked process fails to load libraries loaded via `LoadLibrary` 
+if the load happens after the entry point (error code: 87). To resolve 
+this issue, one needs to load any external libraries before the fork happens.
+
+An early DLL load can be achieved by adding the DLL name into the `Import Directory`
+in the PE file. Such an entry can be added manually in any PE editor. 
+
+Alternativly, one can generate a `.lib` file from the DLL exports and link 
+them together with the harness to create an entry in the `Import Directory`. 
+Use `dumpbin /exports <filename>.dll` to extract the exports and paste the 
+exported function names into a `.def` file. Use `lib /def:<deffile> /OUT:<libfile>`
+to generate a `.lib` and add the library to the linker options. Once the usage of 
+an export is detected (`__declspec(dllimport)`), the
+linker adds the early DLL load.
\ No newline at end of file
diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh
index 38085389..84f144be 100755
--- a/qemu_mode/build_qemu_support.sh
+++ b/qemu_mode/build_qemu_support.sh
@@ -9,7 +9,7 @@
 # TCG instrumentation and block chaining support by Andrea Biondo
 #                                    <andrea.biondo965@gmail.com>
 #
-# QEMU 3.1.1 port, TCG thread-safety, CompareCoverage and NeverZero
+# QEMU 5+ port, TCG thread-safety, CompareCoverage and NeverZero
 # counters by Andrea Fioraldi <andreafioraldi@gmail.com>
 #
 # Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
@@ -211,8 +211,9 @@ if [ "$STATIC" = "1" ]; then
 
   echo Building STATIC binary
 
+  # static PIE causes https://github.com/AFLplusplus/AFLplusplus/issues/892
   QEMU_CONF_FLAGS="$QEMU_CONF_FLAGS \
-    --static \
+    --static --disable-pie \
     --extra-cflags=-DAFL_QEMU_STATIC_BUILD=1 \
     "
 
@@ -360,6 +361,8 @@ if ! command -v "$CROSS" > /dev/null ; then
     make -C unsigaction && echo "[+] unsigaction ready"
     echo "[+] Building libqasan ..."
     make -C libqasan && echo "[+] unsigaction ready"
+    echo "[+] Building qemu libfuzzer helpers ..."
+    make -C ../utils/aflpp_driver
   else
     echo "[!] Cross compiler $CROSS could not be found, cannot compile libcompcov libqasan and unsigaction"
   fi
diff --git a/qemu_mode/libcompcov/compcovtest.cc b/qemu_mode/libcompcov/compcovtest.cc
index d70bba91..3c975e15 100644
--- a/qemu_mode/libcompcov/compcovtest.cc
+++ b/qemu_mode/libcompcov/compcovtest.cc
@@ -1,67 +1,98 @@
-/////////////////////////////////////////////////////////////////////////

-//

-// Author: Mateusz Jurczyk (mjurczyk@google.com)

-//

-// Copyright 2019-2020 Google LLC

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-// https://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-//

-

-// solution: echo -ne 'The quick brown fox jumps over the lazy

-// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest

-

-#include <cstdint>

-#include <cstdio>

-#include <cstdlib>

-#include <cstring>

-

-int main() {

-
-  char buffer[44] = {/* zero padding */};

-  fread(buffer, 1, sizeof(buffer) - 1, stdin);

-

-  if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 ||

-      strncmp(&buffer[20], "jumps over ", 11) != 0 ||

-      strcmp(&buffer[31], "the lazy dog") != 0) {

-
-    return 1;

-
-  }

-

-  uint64_t x = 0;

-  fread(&x, sizeof(x), 1, stdin);

-  if (x != 0xCAFEBABECAFEBABE) { return 2; }

-

-  uint32_t y = 0;

-  fread(&y, sizeof(y), 1, stdin);

-  if (y != 0xDEADC0DE) { return 3; }

-

-  uint16_t z = 0;

-  fread(&z, sizeof(z), 1, stdin);

-

-  switch (z) {

-
-    case 0xBEEF:

-      break;

-

-    default:

-      return 4;

-
-  }

-

-  printf("Puzzle solved, congrats!\n");

-  abort();

-  return 0;

-
-}

+/////////////////////////////////////////////////////////////////////////
+//
+// Author: Mateusz Jurczyk (mjurczyk@google.com)
+//
+// Copyright 2019-2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// solution: echo -ne 'The quick brown fox jumps over the lazy
+// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest
+
+#include "../../include/config.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+int main(int argc, char **argv) {
+
+  char buffer[44] = {/* zero padding */};
+
+  FILE *file = stdin;
+
+  if (argc > 1) {
+
+    if ((file = fopen(argv[1], "r")) == NULL) {
+
+      perror(argv[1]);
+      exit(-1);
+
+    }
+
+  }
+
+  fread(buffer, 1, sizeof(buffer) - 1, file);
+
+  if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 ||
+      strncmp(&buffer[20], "jumps over ", 11) != 0 ||
+      strcmp(&buffer[31], "the lazy dog") != 0) {
+
+    if (argc > 1) { fclose(file); }
+    return 1;
+
+  }
+
+  uint64_t x = 0;
+  fread(&x, sizeof(x), 1, file);
+  if (x != 0xCAFEBABECAFEBABE) {
+
+    if (argc > 1) { fclose(file); }
+    return 2;
+
+  }
+
+  uint32_t y = 0;
+  fread(&y, sizeof(y), 1, file);
+  if (y != 0xDEADC0DE) {
+
+    if (argc > 1) { fclose(file); }
+    return 3;
+
+  }
+
+  uint16_t z = 0;
+  fread(&z, sizeof(z), 1, file);
+
+  switch (z) {
+
+    case 0xBEEF:
+      break;
+
+    default:
+      if (argc > 1) { fclose(file); }
+      return 4;
+
+  }
+
+  printf("Puzzle solved, congrats!\n");
+  abort();
+
+  if (argc > 1) { fclose(file); }
+
+  return 0;
+
+}
 
diff --git a/qemu_mode/libqasan/hooks.c b/qemu_mode/libqasan/hooks.c
index 0e6c3e08..c542521c 100644
--- a/qemu_mode/libqasan/hooks.c
+++ b/qemu_mode/libqasan/hooks.c
@@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "libqasan.h"
 #include "map_macro.h"
+#include <unistd.h>
+#include <sys/syscall.h>
 
-ssize_t (*__lq_libc_write)(int, const void *, size_t);
-ssize_t (*__lq_libc_read)(int, void *, size_t);
 char *(*__lq_libc_fgets)(char *, int, FILE *);
 int (*__lq_libc_atoi)(const char *);
 long (*__lq_libc_atol)(const char *);
@@ -37,8 +37,6 @@ void __libqasan_init_hooks(void) {
 
   __libqasan_init_malloc();
 
-  __lq_libc_write = ASSERT_DLSYM(write);
-  __lq_libc_read = ASSERT_DLSYM(read);
   __lq_libc_fgets = ASSERT_DLSYM(fgets);
   __lq_libc_atoi = ASSERT_DLSYM(atoi);
   __lq_libc_atol = ASSERT_DLSYM(atol);
@@ -52,7 +50,7 @@ ssize_t write(int fd, const void *buf, size_t count) {
 
   QASAN_DEBUG("%14p: write(%d, %p, %zu)\n", rtv, fd, buf, count);
   QASAN_LOAD(buf, count);
-  ssize_t r = __lq_libc_write(fd, buf, count);
+  ssize_t r = syscall(SYS_write, fd, buf, count);
   QASAN_DEBUG("\t\t = %zd\n", r);
 
   return r;
@@ -65,7 +63,7 @@ ssize_t read(int fd, void *buf, size_t count) {
 
   QASAN_DEBUG("%14p: read(%d, %p, %zu)\n", rtv, fd, buf, count);
   QASAN_STORE(buf, count);
-  ssize_t r = __lq_libc_read(fd, buf, count);
+  ssize_t r = syscall(SYS_read, fd, buf, count);
   QASAN_DEBUG("\t\t = %zd\n", r);
 
   return r;
diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c
index 9fc4ef7a..6ea24f08 100644
--- a/qemu_mode/libqasan/libqasan.c
+++ b/qemu_mode/libqasan/libqasan.c
@@ -61,10 +61,19 @@ void __libqasan_print_maps(void) {
 
 }
 
-/*__attribute__((constructor))*/ void __libqasan_init() {
+int __libqasan_is_initialized = 0;
+
+__attribute__((constructor)) void __libqasan_init() {
+
+  if (__libqasan_is_initialized) return;
+  __libqasan_is_initialized = 1;
 
   __libqasan_init_hooks();
 
+  if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch();
+
+  if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch();
+
 #ifdef DEBUG
   __qasan_debug = getenv("QASAN_DEBUG") != NULL;
 #endif
@@ -86,7 +95,6 @@ int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv,
   typeof(&__libc_start_main) orig = dlsym(RTLD_NEXT, "__libc_start_main");
 
   __libqasan_init();
-  if (getenv("AFL_INST_LIBS")) __libqasan_hotpatch();
 
   return orig(main, argc, argv, init, fini, rtld_fini, stack_end);
 
diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl
-Subproject 0fb212daab492411b3e323bc18a3074c1aecfd3
+Subproject d73b0336b451fd034e5f469089fb7ee96c80adf