diff options
-rw-r--r-- | frida_mode/DEBUGGING.md | 160 | ||||
-rw-r--r-- | frida_mode/README.md | 3 | ||||
-rw-r--r-- | frida_mode/src/cmplog/cmplog.c | 4 | ||||
-rw-r--r-- | frida_mode/src/entry.c | 2 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument.c | 4 |
5 files changed, 169 insertions, 4 deletions
diff --git a/frida_mode/DEBUGGING.md b/frida_mode/DEBUGGING.md new file mode 100644 index 00000000..f8d91f2f --- /dev/null +++ b/frida_mode/DEBUGGING.md @@ -0,0 +1,160 @@ +If you are using FRIDA mode and have hit some problems, then this guide may help +you to diagnose any problems you are encountering. This assumes you have +followed the [osx-lib](#test/osx-lib) example to start fuzzing your target. + +It should be noted that attempting to debug code using gdb which has been +instrumented in FRIDA is unlikely to be successful since the debugger will be +inserting breakpoints by patching the code in memory. FRIDA works by reading +this code and generating an instrumented copy to execute. In any case, unless +you are very familiar with the implementation of Stalker, the instrumented code +generated by FRIDA is likely to be very difficult to follow. For this reason, +the following debugging strategies are outlined below. + +Byte convention below all files should be provided with their path (they are +omitted for readability) and all items in `<braces>` are placeholders and should +be replaced accordingly. + +# Select your version +Test with both the `dev` and `stable` branches of AFL++. The `dev` branch should +have the very latest version containing any fixes for identified issues. The +`stable` branch is updated less frequently, but equally might avoid a problem if +a regression has been introduced into the `dev` branch. + +# Enable Diagnostic Information +- Run your target specifying the `AFL_DEBUG_CHILD=1` environment variable. This + will print a lot more diagnostic information to the screen when the target + starts up. If you have a simple configuration issue then you will likely see a + warning or error message in the output. + +# Check your Test Harness +If any of the following steps fail, then there is a problem with your test +harness, or your target library. Since this is running without FRIDA mode or +`afl-fuzz` that greatly reduces the search area for your defect. This is why it +is *VERY* important to carry out these basic steps first before taking on the +additional complexity of debugging with FRIDA mode or `afl-fuzz`. + +- Run your harness outside of the fuzzer, passing it a representative seed as + it's input `./harness <input>`. +- Pass you harness multiple seeds to check that it is stable when running + multiple tests as it will when running in fork server mode `./harness <input1> + <intput2>`. +- Build your test harness with `CFLAGS=-fsanitize=address` and + `LDFLAGS=-fsanitize=address`. Then run it again with multiple inputs to check + for errors (note that when fuzzing your harness should not be built with any + sanitizer options). + +# Check the Samples +FRIDA mode contains a number of different sample targets in the `test` folder. +Have a look throught these and find one which is similar to your real target. +Check whether you have any issues running the sample target and make sure you +compare the command line used to launch the sample with that you are using to +launch your real target very carefully to check for any differences. If possible +start with one of these samples and gradually make changes one at a time +re-testing as you go until you have migrated it to run your own target. + +# FRIDA Mode +## Basic +First just try running your target with `LD_PRELOAD=afl-frida-trace.so ./harness + <input>`. An error here means that your defect occurs when running with just + FRIDA mode and isn't related to `afl-fuzz`. + +Now you can try commenting out the implementation of `LLVMFuzzerTestOneInput` so +that the harness doesn't actually run your target library. This may also aid in +narrowing down the problem. +```c +int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size){ + // fpn_crashme(data, size); + return 0; +} + +``` + +## Persistent Mode +If your target is ok running in basic mode, you can try running it in persistent +mode (if that is the configuration you are having issues with) as follows (again +outside of afl-fuzz). This time you will want to run it inside a debugger so +that you can use the debugger to send the `SIGCONT` signals (by continuing) +usually sent by `afl-fuzz` on each iteration. + +```bash +gdb \ + --ex 'set environment __AFL_PERSISTENT=1' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_CNT=3' \ + --ex 'set environment LD_PRELOAD=afl-frida-trace.so' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=<entry_address>' \ + --args ./harness <input> +``` +Note we have to manually set the `__AFL_PERSISTENT` environment variable which +is usually passed by `afl-fuzz`. + +Note that setting breakpoints etc is likely to interfere with FRIDA and cause +spurious errors. + +If this is successful, you can try additionally loading the hook library: +```bash +gdb \ + --ex 'set environment __AFL_PERSISTENT=1' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_CNT=3' \ + --ex 'set environment LD_PRELOAD=afl-frida-trace.so' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=<entry_address>' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_HOOK=frida_hook.so' + --args ./harness <input> +``` +Note that the format of the hook used for FRIDA mode is subtly different to that +used when running in QEMU mode as shown below. Thus the DSO used for the hook is +not interchangeable. + +```c +void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, + uint32_t input_buf_len); + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len); +``` + +## ASAN +It is also possible to enalbe ASAN (if that is the configuration you are having +issues with) without having to use `afl-fuzz` this can be done as follows (note +that the name of the asan DSO may need to be changed depending on your +platform). Note that the asan DSO must appear first in the `LD_PRELOAD` +environment variable: + +```bash +LD_PRELOAD=libclang_rt.asan-x86_64.so:afl-frida-trace.so \ +ASAN_OPTIONS=detect_leaks=false,halt_on_error=0 \ +AFL_USE_FASAN=1 \ + ./harness <input> +``` + +Note that care should be taken to ensure that if you set `AFL_INST_LIBS=1`, you +use `AFL_FRIDA_INST_RANGES` or `AFL_FRIDA_EXCLUDE_RANGES` to exclude the ASAN +DSO from coverage. Failure to do so will result in ASAN attempting to sanitize +itself and as a result detecting failures when it attempts to update the shadow +maps. + +# Printf +If you have an idea of where things are going wrong for you, then don't be +scared to add `printf` statements to either AFL++ or FRIDA mode itself to show +more diagnostic information. Just be sure to set `AFL_DEBUG=1` and +`AFL_DEBUG_CHILD=1` when you are testing it. + +# Core Dumps +Lastly, if your defect only occurs when using `afl-fuzz` (e.g. when using +`CMPLOG` which cannot be tested outside of `afl-fuzz` due to it's need for a +shared memory mapping being created for it to record its data), it is possible +to enable the creation of a core dump for post-mortem analysis. + +Firstly check your `/proc/sys/kernel/core_pattern` configuration is simply set +to a filename (AFL++ encourages you to set it to the value 'core' in any case +since it doesn't want any handler applications getting in the way). Next set +`ulimit -c unlimited` to remove any size limitations for core files. Lastly, +when you `afl-fuzz` set the environment variable `AFL_DEBUG=1` to enable the +creation of the `core` file. The file should be created in the working directory +of the target application. If there is an existing `core` file aleady there, +then it may not be overwritten. + +# Reach out +Get in touch on discord and ask for help. The groups are pretty active so +someone may well be able to offer some advice. Better still, if you are able to +create a minimal reproducer for your problem it will make it easier to diagnose +the issue. diff --git a/frida_mode/README.md b/frida_mode/README.md index 63959af6..83612210 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -311,6 +311,9 @@ of `main`, since this is the point that FRIDA mode is initialized. Otherwise, it will not be possible to configure coverage for the test library using `AFL_FRIDA_INST_RANGES` or similar. +# Debugging +Please refer to the [debugging](#debugging) guide for assistant should you +encounter problems with FRIDA mode. ## TODO diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c index a2609c8e..ae3116eb 100644 --- a/frida_mode/src/cmplog/cmplog.c +++ b/frida_mode/src/cmplog/cmplog.c @@ -56,7 +56,9 @@ void cmplog_config(void) { void cmplog_init(void) { - if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); } + OKF("CMPLOG - Enabled [%c]", __afl_cmp_map == NULL ? ' ' : 'X'); + + if (__afl_cmp_map == NULL) { return; } cmplog_get_ranges(); diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c index a0ffd028..0b5f61ec 100644 --- a/frida_mode/src/entry.c +++ b/frida_mode/src/entry.c @@ -21,6 +21,7 @@ static void entry_launch(void) { __afl_manual_init(); /* Child here */ + entry_reached = TRUE; instrument_on_fork(); stats_on_fork(); @@ -59,7 +60,6 @@ void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) { if (persistent_start == 0) { - entry_reached = TRUE; ranges_exclude(); stalker_trust(); diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 67aafa5a..fddff19a 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -116,8 +116,8 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, } - instrument_previous_pc = - ((current_pc & (MAP_SIZE - 1) >> 1)) | ((current_pc & 0x1) << 15); + instrument_previous_pc = ((current_pc & (MAP_SIZE - 1) >> 1)) | + ((current_pc & 0x1) << (MAP_SIZE_POW2 - 1)); } |