diff options
Diffstat (limited to 'qemu_mode')
-rw-r--r-- | qemu_mode/README.md | 228 | ||||
-rw-r--r-- | qemu_mode/README.persistent.md | 141 | ||||
-rw-r--r-- | qemu_mode/README.wine.md | 30 |
3 files changed, 206 insertions, 193 deletions
diff --git a/qemu_mode/README.md b/qemu_mode/README.md index c62309a2..b4b5e7bf 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -1,184 +1,194 @@ # High-performance binary-only instrumentation for afl-fuzz - (See ../README.md for the general instruction manual.) +For the general instruction manual, see [README.md](../README.md). ## 1) Introduction The code in this directory allows you to build a standalone feature that leverages the QEMU "user emulation" mode and allows callers to obtain -instrumentation output for black-box, closed-source binaries. This mechanism -can be then used by afl-fuzz to stress-test targets that couldn't be built -with afl-gcc. +instrumentation output for black-box, closed-source binaries. This mechanism can +be then used by afl-fuzz to stress-test targets that couldn't be built with +afl-cc. -The usual performance cost is 2-5x, which is considerably better than -seen so far in experiments with tools such as DynamoRIO and PIN. +The usual performance cost is 2-5x, which is considerably better than seen so +far in experiments with tools such as DynamoRIO and PIN. -The idea and much of the initial implementation comes from Andrew Griffiths. -The actual implementation on current QEMU (shipped as qemuafl) is from -Andrea Fioraldi. Special thanks to abiondo that re-enabled TCG chaining. +The idea and much of the initial implementation comes from Andrew Griffiths. The +actual implementation on current QEMU (shipped as qemuafl) is from Andrea +Fioraldi. Special thanks to abiondo that re-enabled TCG chaining. -## 2) How to use qemu_mode +## 2) How to use QEMU mode -The feature is implemented with a patched QEMU. The simplest way -to build it is to run ./build_qemu_support.sh. The script will download, -configure, and compile the QEMU binary for you. +The feature is implemented with a patched QEMU. The simplest way to build it is +to run ./build_qemu_support.sh. The script will download, configure, and compile +the QEMU binary for you. -QEMU is a big project, so this will take a while, and you may have to -resolve a couple of dependencies (most notably, you will definitely need -libtool and glib2-devel). +QEMU is a big project, so this will take a while, and you may have to resolve a +couple of dependencies (most notably, you will definitely need libtool and +glib2-devel). Once the binaries are compiled, you can leverage the QEMU tool by calling -afl-fuzz and all the related utilities with -Q in the command line. +afl-fuzz and all the related utilities with `-Q` in the command line. -Note that QEMU requires a generous memory limit to run; somewhere around -200 MB is a good starting point, but considerably more may be needed for -more complex programs. The default -m limit will be automatically bumped up -to 200 MB when specifying -Q to afl-fuzz; be careful when overriding this. +Note that QEMU requires a generous memory limit to run; somewhere around 200 MB +is a good starting point, but considerably more may be needed for more complex +programs. The default `-m` limit will be automatically bumped up to 200 MB when +specifying `-Q` to afl-fuzz; be careful when overriding this. -In principle, if you set CPU_TARGET before calling ./build_qemu_support.sh, -you should get a build capable of running non-native binaries (say, you -can try CPU_TARGET=arm). This is also necessary for running 32-bit binaries -on a 64-bit system (CPU_TARGET=i386). If you're trying to run QEMU on a -different architecture you can also set HOST to the cross-compiler prefix -to use (for example HOST=arm-linux-gnueabi to use arm-linux-gnueabi-gcc). +In principle, if you set `CPU_TARGET` before calling ./build_qemu_support.sh, +you should get a build capable of running non-native binaries (say, you can try +`CPU_TARGET=arm`). This is also necessary for running 32-bit binaries on a +64-bit system (`CPU_TARGET=i386`). If you're trying to run QEMU on a different +architecture, you can also set `HOST` to the cross-compiler prefix to use (for +example `HOST=arm-linux-gnueabi` to use arm-linux-gnueabi-gcc). -You can also compile statically-linked binaries by setting STATIC=1. This -can be useful when compiling QEMU on a different system than the one you're -planning to run the fuzzer on and is most often used with the HOST variable. +You can also compile statically-linked binaries by setting `STATIC=1`. This can +be useful when compiling QEMU on a different system than the one you're planning +to run the fuzzer on and is most often used with the `HOST` variable. -Note: when targetting the i386 architecture, on some binaries the forkserver -handshake may fail due to the lack of reserved memory. Fix it with +Note: when targeting the i386 architecture, on some binaries the forkserver +handshake may fail due to the lack of reserved memory. Fix it with: +``` export QEMU_RESERVED_VA=0x1000000 +``` -Note: if you want the QEMU helper to be installed on your system for all -users, you need to build it before issuing 'make install' in the parent -directory. +Note: if you want the QEMU helper to be installed on your system for all users, +you need to build it before issuing `make install` in the parent directory. -If you want to specify a different path for libraries (e.g. to run an arm64 -binary on x86_64) use QEMU_LD_PREFIX. +If you want to specify a different path for libraries (e.g., to run an arm64 +binary on x86_64) use `QEMU_LD_PREFIX`. ## 3) Deferred initialization -As for LLVM mode (refer to its README.md for mode details) QEMU mode supports -the deferred initialization. +As for LLVM mode (refer to +[instrumentation/README.llvm.md](../instrumentation/README.llvm.md) for mode +details), QEMU mode supports the deferred initialization. -This can be enabled setting the environment variable AFL_ENTRYPOINT which allows -to move the forkserver to a different part, e.g. just before the file is -opened (e.g. way after command line parsing and config file loading, etc.) +This can be enabled by setting the environment variable `AFL_ENTRYPOINT` which +allows to move the forkserver to a different part, e.g., just before the file is +opened (e.g., way after command line parsing and config file loading, etc.) which can be a huge speed improvement. ## 4) Persistent mode -AFL++'s QEMU mode now supports also persistent mode for x86, x86_64, arm -and aarch64 targets. -This increases the speed by several factors, however it is a bit of work to set -up - but worth the effort. +AFL++'s QEMU mode now supports also persistent mode for x86, x86_64, arm, and +aarch64 targets. This increases the speed by several factors, however, it is a +bit of work to set up - but worth the effort. -Please see the extra documentation for it: [README.persistent.md](README.persistent.md) +For more information, see [README.persistent.md](README.persistent.md). ## 5) Snapshot mode As an extension to persistent mode, qemuafl can snapshot and restore the memory -state and brk(). Details are in the persistent mode readme. +state and brk(). For details, see [README.persistent.md](README.persistent.md). -The env var that enables the ready to use snapshot mode is AFL_QEMU_SNAPSHOT and -takes a hex address as a value that is the snapshot entrypoint. +The env var that enables the ready to use snapshot mode is `AFL_QEMU_SNAPSHOT` +and takes a hex address as a value that is the snapshot entry point. -Snapshot mode can work restoring all the writeable pages, that is typically slower than -fork() mode but, on the other hand, it can scale better with multicore. -If the AFL++ Snapshot kernel module is loaded, qemuafl will use it and, in this -case, the speed is better than fork() and also the scaling capabilities. +Snapshot mode can work restoring all the writeable pages, that is typically +slower than fork() mode but, on the other hand, it can scale better with +multicore. If the AFL++ snapshot kernel module is loaded, qemuafl will use it +and, in this case, the speed is better than fork() and also the scaling +capabilities. ## 6) Partial instrumentation You can tell QEMU to instrument only a part of the address space. -Just set AFL_QEMU_INST_RANGES=A,B,C... +Just set `AFL_QEMU_INST_RANGES=A,B,C...`. -The format of the items in the list is either a range of addresses like 0x123-0x321 -or a module name like module.so (that is matched in the mapped object filename). +The format of the items in the list is either a range of addresses like +0x123-0x321 or a module name like module.so (that is matched in the mapped +object filename). -Alternatively you can tell QEMU to ignore part of an address space for instrumentation. +Alternatively, you can tell QEMU to ignore part of an address space for +instrumentation. -Just set AFL_QEMU_EXCLUDE_RANGES=A,B,C... +Just set `AFL_QEMU_EXCLUDE_RANGES=A,B,C...`. -The format of the items on the list is the same as for AFL_QEMU_INST_RANGES, and excluding ranges -takes priority over any included ranges or AFL_INST_LIBS. +The format of the items on the list is the same as for `AFL_QEMU_INST_RANGES` +and excluding ranges takes priority over any included ranges or `AFL_INST_LIBS`. ## 7) CompareCoverage CompareCoverage is a sub-instrumentation with effects similar to laf-intel. -You have to set `AFL_PRELOAD=/path/to/libcompcov.so` together with -setting the AFL_COMPCOV_LEVEL you want to enable it. +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=1` is to instrument comparisons with only immediate +values/read-only memory. -AFL_COMPCOV_LEVEL=2 instruments all comparison instructions and 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 +`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. +Integer comparison instructions are currently instrumented only on the x86, +x86_64, arm, and aarch64 targets. Recommended, but not as good as CMPLOG mode (see below). ## 8) CMPLOG mode -Another new feature is CMPLOG, which is based on the redqueen project. -Here all immediates in CMP instructions are learned and put into a dynamic -dictionary and applied to all locations in the input that reached that -CMP, trying to solve and pass it. -This is a very effective feature and it is available for x86, x86_64, arm -and aarch64. +Another new feature is CMPLOG, which is based on the redqueen project. Here all +immediates in CMP instructions are learned and put into a dynamic dictionary and +applied to all locations in the input that reached that CMP, trying to solve and +pass it. This is a very effective feature and it is available for x86, x86_64, +arm, and aarch64. -To enable it you must pass on the command line of afl-fuzz: - -c /path/to/your/target +To enable it, you must pass on the command line of afl-fuzz: + +``` +-c /path/to/your/target +``` ## 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. +Note that some binaries require user interaction with the GUI and must be +patched. -For examples look [here](https://github.com/andreafioraldi/WineAFLplusplusDEMO). +For examples, look +[here](https://github.com/andreafioraldi/WineAFLplusplusDEMO). ## 10) Notes on linking -The feature is supported only on Linux. Supporting BSD may amount to porting -the changes made to linux-user/elfload.c and applying them to -bsd-user/elfload.c, but I have not looked into this yet. +The feature is supported only on Linux. Supporting BSD may amount to porting the +changes made to linux-user/elfload.c and applying them to bsd-user/elfload.c, +but I have not looked into this yet. The instrumentation follows only the .text section of the first ELF binary encountered in the linking process. It does not trace shared libraries. In practice, this means two things: - - Any libraries you want to analyze *must* be linked statically into the - executed ELF file (this will usually be the case for closed-source - apps). +- Any libraries you want to analyze *must* be linked statically into the + executed ELF file (this will usually be the case for closed-source apps). - - Standard C libraries and other stuff that is wasteful to instrument - should be linked dynamically - otherwise, AFL will have no way to avoid - peeking into them. +- Standard C libraries and other stuff that is wasteful to instrument should be + linked dynamically - otherwise, AFL++ will have no way to avoid peeking into + them. -Setting AFL_INST_LIBS=1 can be used to circumvent the .text detection logic +Setting `AFL_INST_LIBS=1` can be used to circumvent the .text detection logic and instrument every basic block encountered. ## 11) Benchmarking If you want to compare the performance of the QEMU instrumentation with that of -afl-gcc compiled code against the same target, you need to build the +afl-clang-fast compiled code against the same target, you need to build the non-instrumented binary with the same optimization flags that are normally -injected by afl-gcc, and make sure that the bits to be tested are statically -linked into the binary. A common way to do this would be: +injected by afl-clang-fast, and make sure that the bits to be tested are +statically linked into the binary. A common way to do this would be: +``` CFLAGS="-O3 -funroll-loops" ./configure --disable-shared make clean all +``` Comparative measurements of execution speed or instrumentation coverage will be fairly meaningless if the optimization levels or instrumentation scopes don't @@ -186,37 +196,37 @@ match. ## 12) Other features -With `AFL_QEMU_FORCE_DFL` you force QEMU to ignore the registered signal +With `AFL_QEMU_FORCE_DFL`, you force QEMU to ignore the registered signal handlers of the target. ## 13) Gotchas, feedback, bugs 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. +`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 -run out of memory. +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 run out of +memory. Compared to fully-fledged virtualization, the user emulation mode is *NOT* a security boundary. The binaries can freely interact with the host OS. If you somehow need to fuzz an untrusted binary, put everything in a sandbox first. -QEMU does not necessarily support all CPU or hardware features that your -target program may be utilizing. In particular, it does not appear to have -full support for AVX2 / FMA3. Using binaries for older CPUs, or recompiling them -with -march=core2, can help. +QEMU does not necessarily support all CPU or hardware features that your target +program may be utilizing. In particular, it does not appear to have full support +for AVX2/FMA3. Using binaries for older CPUs or recompiling them with +`-march=core2`, can help. Beyond that, this is an early-stage mechanism, so fields reports are welcome. You can send them to <afl-users@googlegroups.com>. ## 14) Alternatives: static rewriting -Statically rewriting binaries just once, instead of attempting to translate -them at run time, can be a faster alternative. That said, static rewriting is -fraught with peril, because it depends on being able to properly and fully model -program control flow without actually executing each and every code path. +Statically rewriting binaries just once, instead of attempting to translate them +at run time, can be a faster alternative. That said, static rewriting is fraught +with peril, because it depends on being able to properly and fully model program +control flow without actually executing each and every code path. -Check out -[docs/fuzzing_binary-only_targets.md](../docs/fuzzing_binary-only_targets.md) -for more information and hints. +For more information and hints, check out +[docs/fuzzing_binary-only_targets.md](../docs/fuzzing_binary-only_targets.md). \ No newline at end of file diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md index 2ca5c873..7210a8cc 100644 --- a/qemu_mode/README.persistent.md +++ b/qemu_mode/README.persistent.md @@ -2,118 +2,118 @@ ## 1) Introduction -Persistent mode lets you fuzz your target persistently between two -addresses - without forking for every fuzzing attempt. -This increases the speed by a factor between x2 and x5, hence it is -very, very valuable. +Persistent mode lets you fuzz your target persistently between two addresses - +without forking for every fuzzing attempt. This increases the speed by a factor +between x2 and x5, hence it is very, very valuable. -The persistent mode is currently only available for x86/x86_64, arm -and aarch64 targets. +The persistent mode is currently only available for x86/x86_64, arm, and aarch64 +targets. ## 2) How use the persistent mode ### 2.1) The START address -The start of the persistent loop has to be set with env var AFL_QEMU_PERSISTENT_ADDR. +The start of the persistent loop has to be set with environment variable +`AFL_QEMU_PERSISTENT_ADDR`. -This address can be the address of whatever instruction. -Setting this address to the start of a function makes the usage simple. -If the address is however within a function, either RET, OFFSET or EXITS -(see below in 2.2, 2.3, 2.6) have to be set. -This address (as well as the RET address, see below) has to be defined in +This address can be the address of whatever instruction. Setting this address to +the start of a function makes the usage simple. If the address is however within +a function, either RET, OFFSET, or EXITS (see below in 2.2, 2.3, 2.6) have to be +set. This address (as well as the RET address, see below) has to be defined in hexadecimal with the 0x prefix or as a decimal value. If both RET and EXITS are not set, QEMU will assume that START points to a -function and will patch the return address (on stack or in the link register) -to return to START (like WinAFL). +function and will patch the return address (on stack or in the link register) to +return to START (like WinAFL). -*Note:* If the target is compiled with position independant code (PIE/PIC) -qemu loads these to a specific base address. -For 64 bit you have to add 0x4000000000 (9 zeroes) and for 32 bit 0x40000000 -(7 zeroes) to the address. -On strange setups the base address set by QEMU for PIE executable may change, -you can check it printing the process map using -`AFL_QEMU_DEBUG_MAPS=1 afl-qemu-trace TARGET-BINARY` +*Note:* If the target is compiled with position independent code (PIE/PIC) qemu +loads these to a specific base address. For 64 bit you have to add 0x4000000000 +(9 zeroes) and for 32 bit 0x40000000 (7 zeroes) to the address. On strange +setups the base address set by QEMU for PIE executable may change. You can check +it printing the process map using `AFL_QEMU_DEBUG_MAPS=1 afl-qemu-trace +TARGET-BINARY`. If this address is not valid, afl-fuzz will error during startup with the message that the forkserver was not found. ### 2.2) The RET address -The RET address is the last instruction of the persistent loop. -The emulator will emit a jump to START when translating the instruction at RET. -It is optional, and only needed if the return should not be -at the end of the function to which the START address points into, but earlier. +The RET address is the last instruction of the persistent loop. The emulator +will emit a jump to START when translating the instruction at RET. It is +optional and only needed if the return should not be at the end of the function +to which the START address points into, but earlier. -It is defined by setting AFL_QEMU_PERSISTENT_RET, and too 0x4000000000 has to -be set if the target is position independant. +It is defined by setting `AFL_QEMU_PERSISTENT_RET`, and too 0x4000000000 has to +be set if the target is position independent. ### 2.3) The OFFSET This option is valid only for x86/x86_64 only, arm/aarch64 do not save the return address on stack. -If the START address is *not* the beginning of a function, and *no* RET has -been set (so the end of the loop will be at the end of the function but START -will not be at the beginning of it), we need an offset from the ESP pointer -to locate the return address to patch. +If the START address is *not* the beginning of a function, and *no* RET has been +set (so the end of the loop will be at the end of the function but START will +not be at the beginning of it), we need an offset from the ESP pointer to locate +the return address to patch. The value by which the ESP pointer has to be corrected has to be set in the -variable AFL_QEMU_PERSISTENT_RETADDR_OFFSET. +variable `AFL_QEMU_PERSISTENT_RETADDR_OFFSET`. Now to get this value right here is some help: -1. use gdb on the target -2. set a breakpoint to "main" (this is required for PIE/PIC binaries so the - addresses are set up) -3. "run" the target with a valid commandline -4. set a breakpoint to the function in which START is contained -5. set a breakpoint to your START address -6. "continue" to the function start breakpoint -6. print the ESP value with `print $esp` and take note of it -7. "continue" the target until the second breakpoint -8. again print the ESP value -9. calculate the difference between the two values - and this is the offset +1. Use gdb on the target. +2. Set a breakpoint to "main" (this is required for PIE/PIC binaries so the + addresses are set up). +3. "run" the target with a valid commandline. +4. Set a breakpoint to the function in which START is contained. +5. Set a breakpoint to your START address. +6. "continue" to the function start breakpoint. +7. Print the ESP value with `print $esp` and take note of it. +8. "continue" the target until the second breakpoint. +9. Again print the ESP value. +10. Calculate the difference between the two values - and this is the offset. ### 2.4) Resetting the register state It is very, very likely you need to restore the general purpose registers state when starting a new loop. Because of this 99% of the time you should set +``` AFL_QEMU_PERSISTENT_GPR=1 +``` -An example is when you want to use main() as persistent START: +An example is when you want to use `main()` as persistent START: ```c int main(int argc, char **argv) { if (argc < 2) return 1; - + // do stuff } ``` -If you don't save and restore the registers in x86_64, the parameter `argc` -will be lost at the second execution of the loop. +If you don't save and restore the registers in x86_64, the parameter `argc` will +be lost at the second execution of the loop. ### 2.5) Resetting the memory state This option restores the memory state using the AFL++ Snapshot LKM if loaded. Otherwise, all the writeable pages are restored. -To enable this option, set AFL_QEMU_PERSISTENT_MEM=1. +To enable this option, set `AFL_QEMU_PERSISTENT_MEM=1`. ### 2.6) Reset on exit() The user can force QEMU to set the program counter to START instead of executing the exit_group syscall and exit the program. -The env variable is AFL_QEMU_PERSISTENT_EXITS. +The environment variable is `AFL_QEMU_PERSISTENT_EXITS`. ### 2.7) Snapshot -AFL_QEMU_SNAPSHOT=address is just a "syntactical sugar" env variable that is equivalent to -the following set of variables: +`AFL_QEMU_SNAPSHOT=address` is just a "syntactical sugar" environment variable +that is equivalent to the following set of variables: ``` AFL_QEMU_PERSISTENT_ADDR=address @@ -127,26 +127,27 @@ AFL_QEMU_PERSISTENT_EXITS=1 ### 3.1) Loop counter value The more stable your loop in the target, the longer you can run it, the more -unstable it is the lower the loop count should be. A low value would be 100, -the maximum value should be 10000. The default is 1000. -This value can be set with AFL_QEMU_PERSISTENT_CNT +unstable it is the lower the loop count should be. A low value would be 100, the +maximum value should be 10000. The default is 1000. This value can be set with +`AFL_QEMU_PERSISTENT_CNT`. -This is the same concept as in the llvm_mode persistent mode with __AFL_LOOP(). +This is the same concept as in the llvm_mode persistent mode with +`__AFL_LOOP()`. ### 3.2) A hook for in-memory fuzzing -You can increase the speed of the persistent mode even more by bypassing all -the reading of the fuzzing input via a file by reading directly into the -memory address space of the target process. +You can increase the speed of the persistent mode even more by bypassing all the +reading of the fuzzing input via a file by reading directly into the memory +address space of the target process. All this needs is that the START address has a register that can reach the -memory buffer or that the memory buffer is at a known location. You probably need -the value of the size of the buffer (maybe it is in a register when START is -hit). +memory buffer or that the memory buffer is at a known location. You probably +need the value of the size of the buffer (maybe it is in a register when START +is hit). -The persistent hook will execute a function on every persistent iteration -(at the start START) defined in a shared object specified with -AFL_QEMU_PERSISTENT_HOOK=/path/to/hook.so. +The persistent hook will execute a function on every persistent iteration (at +the start START) defined in a shared object specified with +`AFL_QEMU_PERSISTENT_HOOK=/path/to/hook.so`. The signature is: @@ -157,8 +158,8 @@ void afl_persistent_hook(struct ARCH_regs *regs, uint32_t input_buf_len); ``` -Where ARCH is one of x86, x86_64, arm or arm64. -You have to include `path/to/qemuafl/qemuafl/api.h`. +Where ARCH is one of x86, x86_64, arm or arm64. You have to include +`path/to/qemuafl/qemuafl/api.h`. In this hook, you can inspect and change the saved GPR state at START. @@ -168,8 +169,8 @@ with: `int afl_persistent_hook_init(void);` If this routine returns true, the shared mem fuzzing feature of AFL++ is used -and so the input_buf variables of the hook becomes meaningful. Otherwise, -you have to read the input from a file like stdin. +and so the input_buf variables of the hook becomes meaningful. Otherwise, you +have to read the input from a file like stdin. -An example that you can use with little modification for your target can -be found here: [utils/qemu_persistent_hook](../utils/qemu_persistent_hook) +An example that you can use with little modification for your target can be +found here: [utils/qemu_persistent_hook](../utils/qemu_persistent_hook) \ No newline at end of file diff --git a/qemu_mode/README.wine.md b/qemu_mode/README.wine.md index 567901cd..ee1ef58a 100644 --- a/qemu_mode/README.wine.md +++ b/qemu_mode/README.wine.md @@ -1,21 +1,23 @@ # 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`. + +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. +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 +Alternatively, 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 |