about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xafl-wine-trace55
-rw-r--r--docs/ChangeLog1
-rw-r--r--docs/binaryonly_fuzzing.txt4
-rw-r--r--include/afl-fuzz.h3
-rw-r--r--include/common.h5
-rw-r--r--src/afl-analyze.c88
-rw-r--r--src/afl-common.c175
-rw-r--r--src/afl-fuzz-globals.c2
-rw-r--r--src/afl-fuzz-init.c77
-rw-r--r--src/afl-fuzz.c26
-rw-r--r--src/afl-showmap.c86
-rw-r--r--src/afl-tmin.c88
12 files changed, 330 insertions, 280 deletions
diff --git a/afl-wine-trace b/afl-wine-trace
new file mode 100755
index 00000000..fa552051
--- /dev/null
+++ b/afl-wine-trace
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+import pefile
+import shutil
+
+if len(sys.argv) < 2:
+    print("[afl-wine-trace] usage: wine-cov binary [args...]\n")
+    exit(1)
+
+if os.getenv("AFL_PATH"):
+    my_dir = os.getenv("AFL_PATH")
+else:
+    my_dir = os.path.dirname(os.path.abspath(__file__))
+
+os.environ["WINELOADERNOEXEC"] = "1"
+
+pe = pefile.PE(sys.argv[1])
+
+os.environ["AFL_ENTRYPOINT"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.AddressOfEntryPoint)
+if not os.getenv("AFL_INST_LIBS"):
+    if "AFL_CODE_START" not in os.environ:
+        os.environ["AFL_CODE_START"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode)
+    if "AFL_CODE_END" not in os.environ:
+        os.environ["AFL_CODE_END"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode + pe.OPTIONAL_HEADER.SizeOfCode)
+
+if os.getenv("WINECOV_QEMU_PATH"):
+    qemu_path = os.getenv("WINECOV_QEMU_PATH")
+elif os.path.exists(os.path.join(my_dir, "afl-qemu-trace")):
+    qemu_path = os.path.join(my_dir, "afl-qemu-trace")
+else:
+    qemu_path = "qemu-"
+    if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
+        qemu_path += "x86_64"
+    elif pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_I386"]:
+        qemu_path += "i386"
+    else:
+        print ("[afl-wine-trace] unsupported architecture\n")
+        exit(1)
+    qemu_path = shutil.which(qemu_path)
+
+if os.getenv("WINECOV_WINE_PATH"):
+    wine_path = os.getenv("WINECOV_WINE_PATH")
+else:
+    wine_path = "/usr/lib/wine/wine"
+    if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
+        wine_path += "64"
+    elif pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_I386"]:
+        pass
+    else:
+        print ("[wine-cov] unsuppoted architecture\n")
+        exit(1)
+
+os.execve(qemu_path, [qemu_path, wine_path] + sys.argv[1:], os.environ)
diff --git a/docs/ChangeLog b/docs/ChangeLog
index c1b401c9..4ea4e4b2 100644
--- a/docs/ChangeLog
+++ b/docs/ChangeLog
@@ -27,6 +27,7 @@ Version ++2.54d (dev):
   - removed compile warnings from python internal stuff
   - added man page for afl-clang-fast[++]
   - updated documentation
+  - Wine mode to run Win32 binaries with the QEMU instrumentation (-W)
 
 
 --------------------------
diff --git a/docs/binaryonly_fuzzing.txt b/docs/binaryonly_fuzzing.txt
index 53361f5f..239fb4b0 100644
--- a/docs/binaryonly_fuzzing.txt
+++ b/docs/binaryonly_fuzzing.txt
@@ -26,6 +26,10 @@ It is the easiest to use alternative and even works for cross-platform binaries.
 
 As it is included in afl++ this needs no URL.
 
+WINE+QEMU
+---------
+Wine mode can run Win32 PE with the QEMU instrumentation.
+It needs Wine, python3 and the pefile python package installed.
 
 UNICORN
 -------
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index f6874785..9536e06a 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -241,7 +241,6 @@ extern u8 *in_dir,                      /* Input directory with test cases  */
     *file_extension,                    /* File extension                   */
     *orig_cmdline,                      /* Original command line            */
     *doc_path,                          /* Path to documentation dir        */
-    *target_path,                       /* Path to target binary            */
     *out_file;                          /* File to fuzz, if any             */
 
 extern u32 exec_tmout;                  /* Configurable exec timeout (ms)   */
@@ -294,6 +293,7 @@ extern u8 skip_deterministic,           /* Skip deterministic stages?       */
     bitmap_changed,                     /* Time to update bitmap?           */
     qemu_mode,                          /* Running in QEMU mode?            */
     unicorn_mode,                       /* Running in Unicorn mode?         */
+    use_wine,                           /* Use WINE with QEMU mode          */
     skip_requested,                     /* Skip request, via SIGUSR1        */
     run_over10m,                        /* Run time over 10 minutes?        */
     persistent_mode,                    /* Running in persistent mode?      */
@@ -612,6 +612,7 @@ void   fix_up_banner(u8*);
 void   check_if_tty(void);
 void   setup_signal_handlers(void);
 char** get_qemu_argv(u8*, char**, int);
+char** get_wine_argv(u8*, char**, int);
 void   save_cmdline(u32, char**);
 
 /**** Inline routines ****/
diff --git a/include/common.h b/include/common.h
index 905830b5..c370044e 100644
--- a/include/common.h
+++ b/include/common.h
@@ -27,6 +27,11 @@
 #define __AFLCOMMON_H
 #include "types.h"
 
+extern u8  *target_path;                 /* Path to target binary            */
+
 void detect_file_args(char **argv, u8 *prog_in);
+
+char** get_qemu_argv(u8* own_loc, char** argv, int argc);
+char** get_wine_argv(u8* own_loc, char** argv, int argc);
 #endif
 
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 4b157973..3e15ca35 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -61,7 +61,6 @@ u8* trace_bits;                        /* SHM with instrumentation bitmap   */
 
 static u8 *in_file,                    /* Analyzer input test case          */
     *prog_in,                          /* Targeted program input file       */
-    *target_path,                      /* Path to target binary             */
     *doc_path;                         /* Path to docs                      */
 
 static u8* in_data;                    /* Input data for analysis           */
@@ -760,7 +759,8 @@ static void usage(u8* argv0) {
       "  -t msec       - timeout for each run (%d ms)\n"
       "  -m megs       - memory limit for child process (%d MB)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
-      "  -U            - use unicorn-based instrumentation (Unicorn mode)\n\n"
+      "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
+      "  -W            - use qemu-based instrumentation with Wine (Wine mode)\n\n"
 
       "Analysis settings:\n\n"
 
@@ -829,78 +829,19 @@ static void find_binary(u8* fname) {
 
 }
 
-/* Fix up argv for QEMU. */
-
-static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
-
-  char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
-  u8 *   tmp, *cp, *rsl, *own_copy;
-
-  memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
-
-  /* Now we need to actually find qemu for argv[0]. */
-
-  new_argv[2] = target_path;
-  new_argv[1] = "--";
-
-  tmp = getenv("AFL_PATH");
-
-  if (tmp) {
-
-    cp = alloc_printf("%s/afl-qemu-trace", tmp);
-
-    if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
-
-    target_path = new_argv[0] = cp;
-    return new_argv;
-
-  }
-
-  own_copy = ck_strdup(own_loc);
-  rsl = strrchr(own_copy, '/');
-
-  if (rsl) {
-
-    *rsl = 0;
-
-    cp = alloc_printf("%s/afl-qemu-trace", own_copy);
-    ck_free(own_copy);
-
-    if (!access(cp, X_OK)) {
-
-      target_path = new_argv[0] = cp;
-      return new_argv;
-
-    }
-
-  } else
-
-    ck_free(own_copy);
-
-  if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
-
-    target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace";
-    return new_argv;
-
-  }
-
-  FATAL("Unable to find 'afl-qemu-trace'.");
-
-}
-
 /* Main entry point */
 
 int main(int argc, char** argv) {
 
   s32 opt;
-  u8  mem_limit_given = 0, timeout_given = 0, qemu_mode = 0, unicorn_mode = 0;
+  u8  mem_limit_given = 0, timeout_given = 0, qemu_mode = 0, unicorn_mode = 0, use_wine = 0;
   char** use_argv;
 
   doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
 
   SAYF(cCYA "afl-analyze" VERSION cRST " by <lcamtuf@google.com>\n");
 
-  while ((opt = getopt(argc, argv, "+i:f:m:t:eQUh")) > 0)
+  while ((opt = getopt(argc, argv, "+i:f:m:t:eQUWh")) > 0)
 
     switch (opt) {
 
@@ -989,6 +930,16 @@ int main(int argc, char** argv) {
         unicorn_mode = 1;
         break;
 
+      case 'W':                                             /* Wine+QEMU mode */
+
+        if (use_wine) FATAL("Multiple -W options not supported");
+        qemu_mode = 1;
+        use_wine = 1;
+
+        if (!mem_limit_given) mem_limit = 0;
+
+        break;
+
       case 'h':
         usage(argv[0]);
         return -1;
@@ -1011,9 +962,14 @@ int main(int argc, char** argv) {
   find_binary(argv[optind]);
   detect_file_args(argv + optind, prog_in);
 
-  if (qemu_mode)
-    use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
-  else
+  if (qemu_mode) {
+  
+    if (use_wine)
+      use_argv = get_wine_argv(argv[0], argv + optind, argc - optind);
+    else
+      use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
+  
+  } else
     use_argv = argv + optind;
 
   SAYF("\n");
diff --git a/src/afl-common.c b/src/afl-common.c
index 62722cb9..0d690831 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -35,6 +35,8 @@
 #include <unistd.h>
 #endif
 
+u8  *target_path;                       /* Path to target binary            */
+
 void detect_file_args(char** argv, u8* prog_in) {
 
   u32 i = 0;
@@ -95,3 +97,176 @@ void detect_file_args(char** argv, u8* prog_in) {
 
 }
 
+
+/* Rewrite argv for QEMU. */
+
+char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
+
+  char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
+  u8 *   tmp, *cp, *rsl, *own_copy;
+
+  memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
+
+  new_argv[2] = target_path;
+  new_argv[1] = "--";
+
+  /* Now we need to actually find the QEMU binary to put in argv[0]. */
+
+  tmp = getenv("AFL_PATH");
+
+  if (tmp) {
+
+    cp = alloc_printf("%s/afl-qemu-trace", tmp);
+
+    if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
+
+    target_path = new_argv[0] = cp;
+    return new_argv;
+
+  }
+
+  own_copy = ck_strdup(own_loc);
+  rsl = strrchr(own_copy, '/');
+
+  if (rsl) {
+
+    *rsl = 0;
+
+    cp = alloc_printf("%s/afl-qemu-trace", own_copy);
+    ck_free(own_copy);
+
+    if (!access(cp, X_OK)) {
+
+      target_path = new_argv[0] = cp;
+      return new_argv;
+
+    }
+
+  } else
+
+    ck_free(own_copy);
+
+  if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
+
+    target_path = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace");
+    return new_argv;
+
+  }
+
+  SAYF("\n" cLRD "[-] " cRST
+       "Oops, unable to find the 'afl-qemu-trace' binary. The binary must be "
+       "built\n"
+       "    separately by following the instructions in qemu_mode/README.qemu. "
+       "If you\n"
+       "    already have the binary installed, you may need to specify "
+       "AFL_PATH in the\n"
+       "    environment.\n\n"
+
+       "    Of course, even without QEMU, afl-fuzz can still work with "
+       "binaries that are\n"
+       "    instrumented at compile time with afl-gcc. It is also possible to "
+       "use it as a\n"
+       "    traditional \"dumb\" fuzzer by specifying '-n' in the command "
+       "line.\n");
+
+  FATAL("Failed to locate 'afl-qemu-trace'.");
+
+}
+
+/* Rewrite argv for Wine+QEMU. */
+
+char** get_wine_argv(u8* own_loc, char** argv, int argc) {
+
+  char** new_argv = ck_alloc(sizeof(char*) * (argc + 3));
+  u8 *   tmp, *cp, *rsl, *own_copy;
+
+  memcpy(new_argv + 2, argv + 1, sizeof(char*) * argc);
+
+  new_argv[1] = target_path;
+
+  /* Now we need to actually find the QEMU binary to put in argv[0]. */
+
+  tmp = getenv("AFL_PATH");
+
+  if (tmp) {
+
+    cp = alloc_printf("%s/afl-qemu-trace", tmp);
+
+    if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
+    
+    ck_free(cp);
+    
+    cp = alloc_printf("%s/afl-wine-trace", tmp);
+
+    if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
+
+    target_path = new_argv[0] = cp;
+    return new_argv;
+
+  }
+
+  own_copy = ck_strdup(own_loc);
+  rsl = strrchr(own_copy, '/');
+
+  if (rsl) {
+
+    *rsl = 0;
+
+    cp = alloc_printf("%s/afl-qemu-trace", own_copy);
+    ck_free(own_copy);
+
+    if (!access(cp, X_OK)) {
+
+      ck_free(cp);
+      
+      cp = alloc_printf("%s/afl-wine-trace", own_copy);
+      
+      if (!access(cp, X_OK)) {
+
+        target_path = new_argv[0] = cp;
+        return new_argv;
+        
+      }
+
+    }
+
+  } else
+
+    ck_free(own_copy);
+
+  u8 *ncp = BIN_PATH "/afl-qemu-trace";
+
+  if (!access(ncp, X_OK)) {
+  
+    ncp = BIN_PATH "/afl-wine-trace";
+    
+    if (!access(ncp, X_OK)) {
+
+      target_path = new_argv[0] = ck_strdup(ncp);
+      return new_argv;
+      
+    }
+
+  }
+
+  SAYF("\n" cLRD "[-] " cRST
+       "Oops, unable to find the '%s' binary. The binary must be "
+       "built\n"
+       "    separately by following the instructions in qemu_mode/README.qemu. "
+       "If you\n"
+       "    already have the binary installed, you may need to specify "
+       "AFL_PATH in the\n"
+       "    environment.\n\n"
+
+       "    Of course, even without QEMU, afl-fuzz can still work with "
+       "binaries that are\n"
+       "    instrumented at compile time with afl-gcc. It is also possible to "
+       "use it as a\n"
+       "    traditional \"dumb\" fuzzer by specifying '-n' in the command "
+       "line.\n", ncp);
+
+  FATAL("Failed to locate '%s'.", ncp);
+
+}
+
+
diff --git a/src/afl-fuzz-globals.c b/src/afl-fuzz-globals.c
index d457d28c..1358a1fb 100644
--- a/src/afl-fuzz-globals.c
+++ b/src/afl-fuzz-globals.c
@@ -74,7 +74,6 @@ u8 *in_dir,                             /* Input directory with test cases  */
     *file_extension,                    /* File extension                   */
     *orig_cmdline;                      /* Original command line            */
 u8 *doc_path,                           /* Path to documentation dir        */
-    *target_path,                       /* Path to target binary            */
     *out_file;                          /* File to fuzz, if any             */
 
 u32 exec_tmout = EXEC_TIMEOUT;          /* Configurable exec timeout (ms)   */
@@ -115,6 +114,7 @@ u8 skip_deterministic,                  /* Skip deterministic stages?       */
     bitmap_changed = 1,                 /* Time to update bitmap?           */
     qemu_mode,                          /* Running in QEMU mode?            */
     unicorn_mode,                       /* Running in Unicorn mode?         */
+    use_wine,                           /* Use WINE with QEMU mode          */
     skip_requested,                     /* Skip request, via SIGUSR1        */
     run_over10m,                        /* Run time over 10 minutes?        */
     persistent_mode,                    /* Running in persistent mode?      */
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 55464a36..e791fdde 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -1728,7 +1728,7 @@ void check_binary(u8* fname) {
 
   }
 
-  if (getenv("AFL_SKIP_BIN_CHECK")) return;
+  if (getenv("AFL_SKIP_BIN_CHECK") || use_wine) return;
 
   /* Check for blatant user errors. */
 
@@ -1963,81 +1963,6 @@ void setup_signal_handlers(void) {
 
 }
 
-/* Rewrite argv for QEMU. */
-
-char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
-
-  char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
-  u8 *   tmp, *cp, *rsl, *own_copy;
-
-  memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
-
-  new_argv[2] = target_path;
-  new_argv[1] = "--";
-
-  /* Now we need to actually find the QEMU binary to put in argv[0]. */
-
-  tmp = getenv("AFL_PATH");
-
-  if (tmp) {
-
-    cp = alloc_printf("%s/afl-qemu-trace", tmp);
-
-    if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
-
-    target_path = new_argv[0] = cp;
-    return new_argv;
-
-  }
-
-  own_copy = ck_strdup(own_loc);
-  rsl = strrchr(own_copy, '/');
-
-  if (rsl) {
-
-    *rsl = 0;
-
-    cp = alloc_printf("%s/afl-qemu-trace", own_copy);
-    ck_free(own_copy);
-
-    if (!access(cp, X_OK)) {
-
-      target_path = new_argv[0] = cp;
-      return new_argv;
-
-    }
-
-  } else
-
-    ck_free(own_copy);
-
-  if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
-
-    target_path = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace");
-    return new_argv;
-
-  }
-
-  SAYF("\n" cLRD "[-] " cRST
-       "Oops, unable to find the 'afl-qemu-trace' binary. The binary must be "
-       "built\n"
-       "    separately by following the instructions in qemu_mode/README.qemu. "
-       "If you\n"
-       "    already have the binary installed, you may need to specify "
-       "AFL_PATH in the\n"
-       "    environment.\n\n"
-
-       "    Of course, even without QEMU, afl-fuzz can still work with "
-       "binaries that are\n"
-       "    instrumented at compile time with afl-gcc. It is also possible to "
-       "use it as a\n"
-       "    traditional \"dumb\" fuzzer by specifying '-n' in the command "
-       "line.\n");
-
-  FATAL("Failed to locate 'afl-qemu-trace'.");
-
-}
-
 /* Make a copy of the current command line. */
 
 void save_cmdline(u32 argc, char** argv) {
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index c2e18477..a2e3c873 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -53,7 +53,8 @@ static void usage(u8* argv0) {
       "  -t msec       - timeout for each run (auto-scaled, 50-%d ms)\n"
       "  -m megs       - memory limit for child process (%d MB)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
-      "  -U            - use Unicorn-based instrumentation (Unicorn mode)\n\n"
+      "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
+      "  -W            - use qemu-based instrumentation with Wine (Wine mode)\n"
       "  -L minutes    - use MOpt(imize) mode and set the limit time for "
       "entering the\n"
       "                  pacemaker mode (minutes of no new paths, 0 = "
@@ -131,7 +132,7 @@ int main(int argc, char** argv) {
   gettimeofday(&tv, &tz);
   init_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
 
-  while ((opt = getopt(argc, argv, "+i:o:f:m:t:T:dnCB:S:M:x:QUe:p:s:V:E:L:h")) >
+  while ((opt = getopt(argc, argv, "+i:o:f:m:t:T:dnCB:S:M:x:QUWe:p:s:V:E:L:h")) >
          0)
 
     switch (opt) {
@@ -369,6 +370,16 @@ int main(int argc, char** argv) {
         if (!mem_limit_given) mem_limit = MEM_LIMIT_UNICORN;
 
         break;
+      
+      case 'W':                                             /* Wine+QEMU mode */
+
+        if (use_wine) FATAL("Multiple -W options not supported");
+        qemu_mode = 1;
+        use_wine = 1;
+
+        if (!mem_limit_given) mem_limit = 0;
+
+        break;
 
       case 'V': {
 
@@ -709,9 +720,14 @@ int main(int argc, char** argv) {
 
   start_time = get_cur_time();
 
-  if (qemu_mode)
-    use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
-  else
+  if (qemu_mode) {
+  
+    if (use_wine)
+      use_argv = get_wine_argv(argv[0], argv + optind, argc - optind);
+    else
+      use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
+  
+  } else
     use_argv = argv + optind;
 
   perform_dry_run(use_argv);
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index bf9306d5..0720a234 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -64,7 +64,6 @@ u8* trace_bits;                        /* SHM with instrumentation bitmap   */
 
 static u8 *out_file,                   /* Trace output file                 */
     *doc_path,                         /* Path to docs                      */
-    *target_path,                      /* Path to target binary             */
     *at_file;                          /* Substitution string for @@        */
 
 static u32 exec_tmout;                 /* Exec timeout (ms)                 */
@@ -419,6 +418,7 @@ static void usage(u8* argv0) {
       "  -m megs       - memory limit for child process (%d MB)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
       "  -U            - use Unicorn-based instrumentation (Unicorn mode)\n"
+      "  -W            - use qemu-based instrumentation with Wine (Wine mode)\n"
       "                  (Not necessary, here for consistency with other afl-* "
       "tools)\n\n"
 
@@ -493,77 +493,18 @@ static void find_binary(u8* fname) {
 
 }
 
-/* Fix up argv for QEMU. */
-
-static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
-
-  char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
-  u8 *   tmp, *cp, *rsl, *own_copy;
-
-  memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
-
-  new_argv[2] = target_path;
-  new_argv[1] = "--";
-
-  /* Now we need to actually find qemu for argv[0]. */
-
-  tmp = getenv("AFL_PATH");
-
-  if (tmp) {
-
-    cp = alloc_printf("%s/afl-qemu-trace", tmp);
-
-    if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
-
-    target_path = new_argv[0] = cp;
-    return new_argv;
-
-  }
-
-  own_copy = ck_strdup(own_loc);
-  rsl = strrchr(own_copy, '/');
-
-  if (rsl) {
-
-    *rsl = 0;
-
-    cp = alloc_printf("%s/afl-qemu-trace", own_copy);
-    ck_free(own_copy);
-
-    if (!access(cp, X_OK)) {
-
-      target_path = new_argv[0] = cp;
-      return new_argv;
-
-    }
-
-  } else
-
-    ck_free(own_copy);
-
-  if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
-
-    target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace";
-    return new_argv;
-
-  }
-
-  FATAL("Unable to find 'afl-qemu-trace'.");
-
-}
-
 /* Main entry point */
 
 int main(int argc, char** argv) {
 
   s32 opt;
-  u8  mem_limit_given = 0, timeout_given = 0, qemu_mode = 0, unicorn_mode = 0;
+  u8  mem_limit_given = 0, timeout_given = 0, qemu_mode = 0, unicorn_mode = 0, use_wine = 0;
   u32 tcnt = 0;
   char** use_argv;
 
   doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
 
-  while ((opt = getopt(argc, argv, "+o:m:t:A:eqZQUbcrh")) > 0)
+  while ((opt = getopt(argc, argv, "+o:m:t:A:eqZQUWbcrh")) > 0)
 
     switch (opt) {
 
@@ -671,6 +612,16 @@ int main(int argc, char** argv) {
         unicorn_mode = 1;
         break;
 
+      case 'W':                                             /* Wine+QEMU mode */
+
+        if (use_wine) FATAL("Multiple -W options not supported");
+        qemu_mode = 1;
+        use_wine = 1;
+
+        if (!mem_limit_given) mem_limit = 0;
+
+        break;
+
       case 'b':
 
         /* Secret undocumented mode. Writes output in raw binary format
@@ -719,9 +670,14 @@ int main(int argc, char** argv) {
 
   detect_file_args(argv + optind, at_file);
 
-  if (qemu_mode)
-    use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
-  else
+  if (qemu_mode) {
+  
+    if (use_wine)
+      use_argv = get_wine_argv(argv[0], argv + optind, argc - optind);
+    else
+      use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
+  
+  } else
     use_argv = argv + optind;
 
   run_target(use_argv);
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 8308d98d..fa9769b1 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -70,7 +70,6 @@ static u8* mask_bitmap;                /* Mask for trace bits (-B)          */
 u8 *in_file,                           /* Minimizer input test case         */
     *output_file,                      /* Minimizer output file             */
     *out_file,                         /* Targeted program input file       */
-    *target_path,                      /* Path to target binary             */
     *doc_path;                         /* Path to docs                      */
 
 s32 out_fd;                           /* Persistent fd for out_file         */
@@ -934,7 +933,8 @@ static void usage(u8* argv0) {
       "  -t msec       - timeout for each run (%d ms)\n"
       "  -m megs       - memory limit for child process (%d MB)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
-      "  -U            - use Unicorn-based instrumentation (Unicorn mode)\n\n"
+      "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
+      "  -W            - use qemu-based instrumentation with Wine (Wine mode)\n\n"
       "                  (Not necessary, here for consistency with other afl-* "
       "tools)\n\n"
 
@@ -1006,65 +1006,6 @@ static void find_binary(u8* fname) {
 
 }
 
-/* Fix up argv for QEMU. */
-
-static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
-
-  char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
-  u8 *   tmp, *cp, *rsl, *own_copy;
-
-  memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
-
-  /* Now we need to actually find qemu for argv[0]. */
-
-  new_argv[2] = target_path;
-  new_argv[1] = "--";
-
-  tmp = getenv("AFL_PATH");
-
-  if (tmp) {
-
-    cp = alloc_printf("%s/afl-qemu-trace", tmp);
-
-    if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
-
-    target_path = new_argv[0] = cp;
-    return new_argv;
-
-  }
-
-  own_copy = ck_strdup(own_loc);
-  rsl = strrchr(own_copy, '/');
-
-  if (rsl) {
-
-    *rsl = 0;
-
-    cp = alloc_printf("%s/afl-qemu-trace", own_copy);
-    ck_free(own_copy);
-
-    if (!access(cp, X_OK)) {
-
-      target_path = new_argv[0] = cp;
-      return new_argv;
-
-    }
-
-  } else
-
-    ck_free(own_copy);
-
-  if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
-
-    target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace";
-    return new_argv;
-
-  }
-
-  FATAL("Unable to find 'afl-qemu-trace'.");
-
-}
-
 /* Read mask bitmap from file. This is for the -B option. */
 
 static void read_bitmap(u8* fname) {
@@ -1084,14 +1025,14 @@ static void read_bitmap(u8* fname) {
 int main(int argc, char** argv) {
 
   s32 opt;
-  u8  mem_limit_given = 0, timeout_given = 0, qemu_mode = 0, unicorn_mode = 0;
+  u8  mem_limit_given = 0, timeout_given = 0, qemu_mode = 0, unicorn_mode = 0, use_wine = 0;
   char** use_argv;
 
   doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
 
   SAYF(cCYA "afl-tmin" VERSION cRST " by <lcamtuf@google.com>\n");
 
-  while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeQUh")) > 0)
+  while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeQUWh")) > 0)
 
     switch (opt) {
 
@@ -1192,6 +1133,16 @@ int main(int argc, char** argv) {
         unicorn_mode = 1;
         break;
 
+      case 'W':                                             /* Wine+QEMU mode */
+
+        if (use_wine) FATAL("Multiple -W options not supported");
+        qemu_mode = 1;
+        use_wine = 1;
+
+        if (!mem_limit_given) mem_limit = 0;
+
+        break;
+
       case 'B':                                              /* load bitmap */
 
         /* This is a secret undocumented option! It is speculated to be useful
@@ -1232,9 +1183,14 @@ int main(int argc, char** argv) {
   find_binary(argv[optind]);
   detect_file_args(argv + optind, out_file);
 
-  if (qemu_mode)
-    use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
-  else
+  if (qemu_mode) {
+  
+    if (use_wine)
+      use_argv = get_wine_argv(argv[0], argv + optind, argc - optind);
+    else
+      use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
+  
+  } else
     use_argv = argv + optind;
 
   exact_mode = !!getenv("AFL_TMIN_EXACT");