Compare commits

...

635 Commits

Author SHA1 Message Date
16cc444ae5 Merge pull request #2460 from AFLplusplus/dev
update frida
2025-05-30 18:14:52 +02:00
a9900f02cb Merge pull request #2459 from WorksButNotTested/update-frida
Update FRIDA again
2025-05-29 22:36:07 +02:00
e82de006a7 Update FRIDA again 2025-05-29 17:33:39 +01:00
4a923e59fd Update FRIDA (#2458) 2025-05-28 22:52:27 +02:00
20348a63bd Merge pull request #2455 from AFLplusplus/dev
enable llvm 21
2025-05-27 15:11:16 +02:00
cafcb343b1 enable llvm 21 2025-05-27 13:35:04 +02:00
588dda3e84 Merge pull request #2453 from AFLplusplus/dev
push to stable
2025-05-26 11:20:25 +02:00
a17d1daab8 deepwiki 2025-05-26 11:19:04 +02:00
affe7cf5b4 set errno=0 when no afl-fuzz present 2025-05-25 11:38:05 +02:00
fa1ac051eb Merge pull request #2451 from kcwu/revise-map-resize
Revise map resize
2025-05-25 11:08:05 +02:00
f21cc2da58 nit 2025-05-25 11:05:01 +02:00
8c1ab19ebe add libaflppdesock 2025-05-25 11:04:00 +02:00
2e7f191f3b extract function to resize map buffers 2025-05-25 09:33:34 +08:00
8090c82c63 fix resize afl->top_rated 2025-05-24 23:36:54 +08:00
f610f53838 remove redundent code
these field are already copied in afl_fsrv_init_dup
2025-05-24 22:28:26 +08:00
0012f710d8 Merge pull request #2450 from AFLplusplus/dev
push to stable
2025-05-24 13:24:03 +02:00
be00ea9f00 Merge pull request #2446 from kcwu/fix-save_if_interesting
fix save_if_interesting
2025-05-24 12:43:26 +02:00
d0df78f07a use functions instead of macros 2025-05-24 16:39:31 +08:00
7e1dc85450 nit 2025-05-23 09:19:42 +02:00
8152def40e changelog 2025-05-23 09:18:55 +02:00
e6ed31d550 Merge pull request #2449 from AFLplusplus/hidden
instrument all hidden edges
2025-05-23 09:16:17 +02:00
77758a1343 nits in calibrate_case 2025-05-23 08:50:37 +02:00
ea1fbb75b3 Merge pull request #2448 from kcwu/setup-ld-preload
Refactor and simplify handling of AFL_PRELOAD
2025-05-23 08:22:03 +02:00
d62a885f0f simplify code 2025-05-23 10:48:56 +08:00
55d534cd6d extract function afl_fsrv_setup_preload 2025-05-23 10:39:03 +08:00
cee764689c fix save_if_interesting
The value of `classified`, `bits_new`, and `cksum`, were not always
correctly maintained.
 1. In the past, `afl->queue_top->exec_cksum` was always assigned when
    `add_to_queue`, however it became conditional since cd57641705.
    This doesn't change correctness because calibrate_case() will
    calculate the checksum. However, this mean one calibration run is
    wasted.

 2. Sometimes `classified` is set incorrectly.
    For example, this code snippet
    ```
    new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
    classified = 1;
    ```
    should be changed to
    ```
    new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
    if (new_bits) classified = 1;
    ```

This commit fixed above issues and use macros to make the code easier to
understand. This should prevent to forget to set classified in the
future (like the bug fixed by 30c93d1321).

The macros also defers the calculations to where the values are really
needed. This could save cpu if the code returns earlier. For example,
if a case is timeout first and not timeout the second time, the current
code does classify_counts, which is not always needed.
2025-05-22 23:14:40 +08:00
d02390e62e add desock option 2025-05-22 17:08:12 +02:00
1f878f1b7c Merge pull request #2438 from AFLplusplus/dev
push to stable
2025-05-22 12:00:37 +02:00
ff1e0580b0 changelog 2025-05-22 12:00:10 +02:00
4730fa4226 Merge pull request #2444 from AFLplusplus/better_sync
Better sync
2025-05-22 11:55:53 +02:00
50fb923691 nit 2025-05-22 11:55:39 +02:00
300fc1f002 fix startup check 2025-05-21 11:52:57 +02:00
4ff40ee6fd add comment 2025-05-20 17:09:52 +02:00
c3d5f3f471 skip entried synced from us if we have not restarted 2025-05-20 17:07:30 +02:00
45a7d65207 Merge pull request #2433 from kcwu/not-sync-known-case
skip known case if the file is actually coming from us
2025-05-20 16:09:14 +02:00
b8d1f16979 Merge pull request #2441 from abhisen7/fix/afl-cmin
Execute ASan targets without leak checks to read AFL_MAP_SIZE
2025-05-19 14:11:00 +02:00
c699aa252d reduce overhead 2025-05-19 18:53:22 +08:00
7c27fc7cfe skip known case if the file is actually coming from us
Assume we have one main node and N secondary nodes in a parallel
fuzzing campaign. Every time the main node found a new case, the case
will be synced to all secondary nodes. Later when the main node sync,
the main node need to run the file again to see if the file is
interesting because they are "new" cases on the secondary nodes.

In other words, for one new case, the main node has to run the redundent
test N times. This is wasteful and slowed down the progress of main
node.

The wasteful issue on secondary nodes is acceptable because we can run
more secondary nodes to mitigate the inefficiency. OTOH, increasing the
number of secondary nodes slow down the main node further.
2025-05-19 18:50:22 +08:00
46b9efbf7d Execute ASan targets without leak checks to read AFL_MAP_SIZE 2025-05-19 11:52:40 +02:00
92d1a60096 print deubg on before missed instrumented instructions 2025-05-19 10:23:22 +02:00
f90fafc07a Merge pull request #2440 from AFLplusplus/dev
push to hidden
2025-05-19 10:02:12 +02:00
59c2198532 Merge pull request #2437 from AFLplusplus/fixsync
Fix sync for restarted instances
2025-05-18 17:30:30 +02:00
c7654c028d nit 2025-05-18 17:26:57 +02:00
ccc7ab5944 use goto and free glob 2025-05-18 17:23:53 +02:00
06afa48e02 code format 2025-05-18 14:07:03 +02:00
816334000a Merge branch 'stable' into dev 2025-05-18 14:06:09 +02:00
2573ccb66e flush stdout for AFL_DUMP_MAP_SIZE 2025-05-18 14:02:58 +02:00
767b990af6 fix syncing to restarted instances 2025-05-18 11:03:40 +02:00
1631e5988f nit 2025-05-17 13:57:24 +02:00
3ee3b5c384 code format 2025-05-17 00:05:31 +02:00
7f7d5ff29b Merge pull request #2427 from kcwu/dev
avoid duplicated code
2025-05-16 18:05:48 +02:00
6dcd0aa089 Add env variable SHM_FUZZ_MAP_SIZE (#2430)
* Add env variable SHM_FUZZ_PAGE_SIZE to tell the forkserver about the max shm input size

* fix

* PAGE_SIZE->MAP_SIZE

* fix more nits

* More cleanup
2025-05-16 12:14:58 +02:00
c47221db7c Fix aflpp_driver compilation on MacOS (#2431) (#2432)
* Fix aflpp_driver compilation on MacOS

* less newline
2025-05-15 19:43:30 +02:00
d6bb210410 Fix aflpp_driver compilation on MacOS (#2431)
* Fix aflpp_driver compilation on MacOS

* less newline
2025-05-15 19:05:20 +02:00
c2a026f68f Merge pull request #2428 from AFLplusplus/dev
push to stable
2025-05-15 14:12:44 +02:00
2a97350754 Merge pull request #2426 from AFLplusplus/fix_resume
Fix resume for syncing
2025-05-15 14:09:09 +02:00
9004be20b8 update changelog 2025-05-15 14:08:49 +02:00
dffd6537ae avoid duplicated code 2025-05-15 18:44:25 +08:00
25d7d65216 workaround for compiler asan+lto issues 2025-05-15 11:46:39 +02:00
7a32331c99 better solution 2025-05-15 11:05:02 +02:00
b27e861a51 fix resume for syncing 2025-05-15 10:47:36 +02:00
875c3902f0 Merge pull request #2425 from AFLplusplus/dev
push to stable
2025-05-15 10:20:25 +02:00
bedb38e216 fix UAF in -F 2025-05-14 21:05:38 +02:00
ef0c236427 update fuzzing_in_depth 2025-05-14 16:45:23 +02:00
b6d1247e7d fix incorrect allocation size for top_rated_candidates (#2424) 2025-05-14 10:31:31 +02:00
62e63d1125 Merge pull request #2423 from kcwu/more-stats-sync-foreign
show stats more frequently when sync foreign
2025-05-13 10:54:44 +02:00
9e4449bad2 code format 2025-05-13 10:51:56 +02:00
6d4a56e481 Merge pull request #2421 from wtdcode/rename-afl-san-no-inst
Rename `AFL_SAN_NO_INST` to `AFL_FSRV_ONLY`
2025-05-13 10:51:08 +02:00
221439fc7a fix foreign sync naming 2025-05-13 10:42:26 +02:00
mio
fca39a6ec3 implement AFL_GCC_ONLY_FSRV 2025-05-13 16:15:11 +08:00
mio
9476204da0 rename to AFL_LLVM_ONLY_FSRV 2025-05-13 15:45:33 +08:00
919108ee57 show stats more frequently when sync foreign
otherwise, the stats might have no updates for hours for large foreign directory
2025-05-13 15:22:50 +08:00
mio
8204bf6915 Allow afl-cmin.py for pre-3.12 by backport from more-itertools 2025-05-13 00:12:18 +08:00
b9e361df46 cmplog: ignore loop icmp 2025-05-12 12:24:52 +02:00
mio
19fc27a3f7 update docs 2025-05-12 14:55:20 +08:00
mio
2357daebe0 update SAND docs accordingly 2025-05-12 14:46:29 +08:00
mio
f3995d5225 rename AFL_SAN_NO_INST to AFL_FSRV_ONLY 2025-05-12 14:43:08 +08:00
ea6d182b4a print skipped bb 2025-05-11 19:52:55 +02:00
adeaa714ce do not instrument icmp/fcmp if result is used in select 2025-05-11 19:27:23 +02:00
231a4b1937 fix fcmp 2025-05-09 17:14:44 +02:00
977e08cda1 fix fcmp + icmp for vectors 2025-05-09 17:07:54 +02:00
6b1d6a9055 Merge pull request #2418 from Evian-Zhang/memmem-no-nul
Do not include NUL when memmem
2025-05-09 09:22:24 +02:00
4d9d8aaf16 afl-cmin.py nits 2025-05-09 09:12:37 +02:00
c150d8e17d Merge pull request #2413 from kcwu/afm-cmin
add afl-cmin.py
2025-05-09 09:09:08 +02:00
61e97a8ceb Do not match NUL when memmem 2025-05-09 09:46:05 +08:00
3f2e03aaf9 call afl-cmin.py if it can be executed successfully 2025-05-08 21:52:12 +08:00
406e4880c7 remove phi instrumentation 2025-05-08 09:36:05 +02:00
22b7d370bc try different intrumentation strategy 2025-05-07 19:01:51 +02:00
ec27e96486 reformat by black 2025-05-06 23:45:42 +08:00
fcca917f4f better variable following 2025-05-06 17:22:10 +02:00
5bf01afd6b fix 2025-05-06 14:40:08 +02:00
0a9916deab instrument hidden selects 2025-05-06 14:16:50 +02:00
b1730d99b6 new LLVM defaults! 2025-05-05 17:46:01 +02:00
6d45b286f8 nits 2025-05-05 14:35:52 +02:00
673463ff1c Merge pull request #2412 from alexandredoyen29/environment_forkserver
Environment variable to discriminate the target and the forkserver
2025-05-05 14:30:40 +02:00
f580fefc5f Doc 2025-05-05 11:12:51 +02:00
320d4b7ef8 Requested changes 2025-05-05 11:03:26 +02:00
19bd2984d5 Writing style mistaske 2025-05-05 10:52:27 +02:00
7d29418db5 Auxiliary variable for afl-forkserver.c too 2025-05-05 10:50:13 +02:00
4d984d6e2b getenv() call at the beginning of __afl_start_forkserver() 2025-05-05 10:44:34 +02:00
421b6492d3 Merge pull request #2414 from kcwu/refactor
Minor refactor and clean up
2025-05-05 10:42:03 +02:00
062f883160 add splice_optout_py prototype 2025-05-05 16:16:42 +08:00
a76ff5e798 Specific environment variable to choose if we want to be able to discriminate or not forkserver in preloaded libraries 2025-05-05 09:54:53 +02:00
e9f49527e9 We check before if the AFL_PRELOAD env variable is set 2025-05-05 09:49:56 +02:00
6f4767ea81 AFL_I_AM_THE_FORKSERVER becomes AFL_FORKSERVER_PARENT 2025-05-05 09:42:33 +02:00
d28b1418a2 Merge pull request #2410 from jwpconsulting/test-persistent-exit
Add test case for AFL_QEMU_PERSISTENT_EXITS
2025-05-05 09:37:53 +02:00
d10b85421d update qemuafl 2025-05-05 09:36:23 +02:00
6876ab7901 remove dead prototype 2025-05-05 08:46:49 +08:00
b1649f2fdb nyx nit 2025-05-05 08:44:26 +08:00
701299eefd remove dead code; we no longer use murmurhash 2025-05-05 08:44:26 +08:00
90e929ea17 only reinit shm map when make sense 2025-05-05 08:44:26 +08:00
24dc7b569c nit: simplify code
"!target_hash" already cover "afl->fsrv.nyx_mode && target_hash == 0"
2025-05-05 08:44:26 +08:00
7cb8ccc960 mention afl-cmin.py in afl-cmin 2025-05-04 19:35:55 +08:00
0c4f8934c7 add afl-cmin.py 2025-05-04 19:06:55 +08:00
cd0cb1e731 Setting the AFL_I_AM_THE_FORKSERVER environment variable in the begining of the forkserver child process, and unsetting it when the target is launched 2025-05-04 11:36:01 +02:00
52631d925d Merge pull request #2411 from Scott-Guest/gcc-sand
Disable GCC instrumentation for AFL_SAN_NO_INST
2025-05-03 09:38:39 +02:00
d40f935b4e Disable GCC instrumentation for AFL_SAN_NO_INST 2025-05-02 17:25:16 -07:00
b418a87340 Add test case for AFL_QEMU_PERSISTENT_EXITS
Add a test case to `test/test-qemu-mode.sh` and make sure that
AFL_QEMU_PERSISTENT_EXITS loops correctly.

This works only on platforms for which `afl-qemu-trace` detects exit
signals and resets the program counter.

This commit updates `test-instr.c` to optionally call `exit(n)` instead of
returning n to the operating system. This option can be activated using
the `EXIT_AT_END` flag. This way, we can test the
QEMU persistent exit mode without having to add a new test file.

You can compile and run `test-instr.c` with the exit mode like so:

```bash
gcc -o exit -DEXIT_AT_END test-instr.c
AFL_QEMU_DEBUG_MAPS= \
    AFL_DEBUG= \
    AFL_QEMU_PERSISTENT_ADDR=$(readelf -a exit | grep 'main$' | awk '{ printf "0x%s", $2 }') \
    AFL_QEMU_PERSISTENT_GPR=1 \
    AFL_QEMU_PERSISTENT_EXITS=1 \
    ./afl-qemu-trace exit
```

Press enter repeatedly and you will see an output like this:

```
...
Debug: Sending status 0xc201ffff

test-instr:

Neither one or zero? How quaint!

test-instr:

Neither one or zero? How quaint!

test-instr:

Neither one or zero? How quaint!

test-instr:

Neither one or zero? How quaint!

test-instr:

Neither one or zero? How quaint!
```

To make sure that persistent exits are detected correctly on x86_64, I've made
the following changes to qemuafl:

```
 linux-user/i386/cpu_loop.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
index 4509f46b95..46bdbaf94a 100644
--- a/linux-user/i386/cpu_loop.c
+++ b/linux-user/i386/cpu_loop.c
@@ -235,7 +235,7 @@ void cpu_loop(CPUX86State *env)
 #ifndef TARGET_ABI32
         case EXCP_SYSCALL:
             /* linux syscall from syscall instruction */
-            if (afl_fork_child && persistent_exits &&
+            if (persistent_exits &&
                 env->regs[R_EAX] == TARGET_NR_exit_group) {
               env->eip = afl_persistent_addr;
               continue;
```
2025-05-02 15:13:08 +09:00
04f2a2dd09 ignore unnecessary warnings for tools 2025-04-29 15:55:14 +02:00
aa1c58a077 Merge pull request #2408 from smoelius/color-no-ui-output
Color `AFL_NO_UI` output
2025-04-29 10:38:52 +02:00
cca5538747 Merge pull request #2409 from Scott-Guest/libdislocator-cflags
Add missing override directive for CFLAGS+= in libdislocator
2025-04-29 10:37:41 +02:00
c4be2ec32f utils/libdislocator/Makefile: Add missing override directive to CFLAGS+= 2025-04-28 20:52:15 -07:00
83a2a8aa14 Color AFL_NO_UI output 2025-04-28 20:29:10 -04:00
6c70d68783 update make flags 2025-04-28 22:09:58 +02:00
6d5784e955 lower values for fuzzing state assessment 2025-04-28 19:30:07 +02:00
5f7009d6e9 code format 2025-04-28 14:23:17 +02:00
48bce88050 Merge pull request #2406 from maribu/config/64-bit
Define WORD_SIZE_64 for more 64-bit arches
2025-04-28 14:22:53 +02:00
f43116d9e0 more classified count fixes 2025-04-28 14:22:37 +02:00
876a528156 Merge pull request #2403 from kcwu/fix-aflfast
fix power schedules
2025-04-28 14:12:22 +02:00
8a0e9c8915 minimum llvm 14 in docs 2025-04-28 14:03:12 +02:00
b083016304 Define WORD_SIZE_64 for more 64-bit arches
This enables 64-bit detection for the following additional systems:

- [PowerPC64 (little endian)](https://en.wikipedia.org/wiki/Ppc64)
- [S390x](https://en.wikipedia.org/wiki/S390x)
- [LoongArch64](https://en.wikipedia.org/wiki/LoongArch64)
2025-04-28 07:58:09 +02:00
30c93d1321 fix power schedules
AFLFast power schedules regressed since v4.31c
2025-04-27 00:07:06 +08:00
e30a17be91 v4.33a init 2025-04-26 15:57:30 +02:00
c340a022e2 Merge pull request #2401 from AFLplusplus/dev
v4.32c release
2025-04-26 15:36:45 +02:00
06219b4d56 v4.32c 2025-04-26 15:35:47 +02:00
c5b8f4250e code format 2025-04-26 15:30:56 +02:00
779cb5d942 Merge pull request #2400 from AFLplusplus/dev
push to stable
2025-04-26 15:30:18 +02:00
fb1a41f5af fix 2025-04-26 13:24:21 +02:00
8352f0a89f fix LLVM 20 pass pipeline insertion 2025-04-26 13:20:51 +02:00
9935190c7b drop llvm 13 AFL++ plugin support 2025-04-25 18:37:19 +02:00
e3ee26262f fix AFL_OLD_FORKSERVER 2025-04-25 13:42:19 +02:00
737c13b460 Merge pull request #2386 from 5angjun/dev
Add someone else to the "list of contributors" :)
2025-04-25 10:03:37 +02:00
9836598d65 Merge pull request #2398 from kcwu/fix-minor
Minor fixes
2025-04-25 10:03:23 +02:00
63509fb696 fix afl-cmin message output 2025-04-25 11:51:34 +08:00
d1c44e12a8 remove dead comment 2025-04-25 11:51:20 +08:00
f78ed6eabc remove redundent code 2025-04-25 11:51:08 +08:00
64c942d0c9 fix printf format 2025-04-25 11:50:50 +08:00
50e343a0d0 Merge branch 'dev' into dev 2025-04-25 11:23:33 +09:00
55719ab23b Resolve merge conflict in README.md 2025-04-25 11:19:52 +09:00
d12c5edd59 Merge pull request #2395 from ryberger-nvidia/fix-infinite-loop
fix infinite loop when custom mutator rejects smallest_favored
2025-04-24 16:04:41 +02:00
1b82d6b904 fix for nit in afl-tmin 2025-04-24 14:42:32 +02:00
61201fbbb8 fix infinite loop when custom mutator rejects smallest_favored
When running with custom mutators, afl-fuzz delegates the responsibility of queuing to` afl_custom_queue_get`
implemented by the mutator. If any mutator cannot process the input, then it is rejected. After an input is rejected
then a new suitable item to queue must be found. Before this PR, that would be `smallest_favored`. However,
if `smallest_favored` were rejected, it would not be cleared from its position as  `smallest_favored` meaning it
would be attempted to be queued again catching afl-fuzz in an infinite loop.

To fix it, we simply return that we skipped the entry, along with using a `goto abandon_entry` to clean the entry up so that
the fuzzer never considers the input again
2025-04-23 14:47:55 -07:00
b9458e72e7 nit 2025-04-23 16:42:49 +02:00
5045f9e615 code format 2025-04-21 11:45:33 +02:00
6cd8a0168f Merge pull request #2391 from kcwu/fix-__AFL_COVERAGE
fix __AFL_COVERAGE: multiple definition of `__afl_selective_coverage`
2025-04-21 11:45:05 +02:00
448c6c212d fix __AFL_COVERAGE: multiple definition of __afl_selective_coverage
fix #2390
2025-04-21 09:02:23 +00:00
05f4762894 nits 2025-04-21 10:59:59 +02:00
0a06e36788 Merge pull request #2336 from gitToki/stable
Enhancement: Custom Python trimming support to afl-tmin
2025-04-19 15:50:42 +02:00
9b1f80c277 Merge pull request #2388 from kcwu/fix-changelog
fix 4.31c change log
2025-04-19 15:36:42 +02:00
787a332a73 fix 4.31c change log
the splicing auto enable is removed by b2a01936c3
2025-04-19 12:13:36 +00:00
7d85047fd9 update bitmap api 2025-04-17 15:28:31 +02:00
fa8dc2028f Merge branch 'AFLplusplus:stable' into stable 2025-04-17 15:20:31 +02:00
619aa70414 Add someone else to the "list of contributors" :) 2025-04-17 16:28:35 +09:00
247e8241b4 Merge pull request #2360 from AFLplusplus/dev
push to stable
2025-04-16 18:14:35 +02:00
0bb64e4bc9 Merge pull request #2384 from fanquake/ubuntu_20_04_removed
Ubuntu 20.04 removed by GitHub
2025-04-16 17:52:30 +02:00
7b84ec97e2 Merge pull request #2383 from fanquake/fix_lld_version
build: improve lld version parsing
2025-04-16 15:18:09 +02:00
20a6cdabad ci: drop usage of ubuntu:20.04
Support for this has been removed by GitHub:
https://github.com/actions/runner-images/issues/11101.
2025-04-16 14:03:36 +01:00
0d286c9e19 build: improve lld version parsing
Currently, if LLD is in a weird location and has a version string like:
```bash
Ubuntu LLD 18.1.3 (compatible with GNU linkers)
```
or
```bash
Homebrew LLD 20.1.2 (compatible with GNU linkers)
```

The version comparison will fail:
```bash
GNUmakefile.llvm:247: ld.lld found in a weird location (/opt/homebrew/bin/ld.lld) and its of a different version than LLMV (LLD vs. 20.1.2) - cannot enable LTO mode
```

Fix that by replacing the usage of awk, with the same sed command used
to retrieve the version of Clang, which fixes the issue:
```bash
GNUmakefile.llvm:245: ld.lld found in a weird location (/opt/homebrew/bin/ld.lld), but its the same version as LLVM so we will allow it
```
2025-04-16 13:37:15 +01:00
db94ec9cad Merge pull request #2382 from kcwu/fix-performance-unit
fix build for "make PERFORMANCE=1 unit"
2025-04-16 10:14:43 +02:00
05dfb70787 fix build for "make PERFORMANCE=1 unit" 2025-04-16 00:48:30 +00:00
7f2becba72 build fix for asan+performance 2025-04-14 13:57:45 +02:00
13b27bb59e Merge pull request #2375 from kcwu/format-cache
code-format cache
2025-04-14 10:11:50 +02:00
ecdbdc3164 Merge pull request #2377 from kcwu/fix-custom-format
fix in_define in .custom-format.py
2025-04-14 10:10:38 +02:00
788e70a01a Merge pull request #2379 from r3sting/patch-1
Fix linker error
2025-04-14 10:09:43 +02:00
938ed60ea9 Merge pull request #2380 from kcwu/fix-memory-leak
Fix memory leak
2025-04-14 10:09:03 +02:00
5b9d2cc38b code-format cache
This change reduces "make code-format" from 3 minutes to 3 seconds if
large files are not changed.
2025-04-13 08:26:18 +00:00
e305bc15d3 fix memory leaks 2025-04-13 06:46:46 +00:00
0b12c7e0cc Fix linker error 2025-04-12 16:20:33 -06:00
4bd492f212 fix memory leak in check_main_node_exists 2025-04-12 16:56:14 +00:00
be8393f201 fix in_define in .custom-format.py
avoid the extra \ before #define line
2025-04-12 15:56:36 +00:00
aec90c7227 Merge pull request #2376 from kcwu/minor-changes
Minor changes
2025-04-12 16:01:34 +02:00
1960352310 add custom mutator support for afl tmin 2025-04-12 14:55:30 +02:00
03169b2b67 print the file name with variable behavior
Because queue/.state/variable_behavior was removed, print file name in
case some users still want the information.
2025-04-12 11:16:11 +00:00
dee51213a7 update build dependency rule in GNUmakefile 2025-04-12 11:16:11 +00:00
1d2de1cb6d remove dead code in comment 2025-04-12 11:15:25 +00:00
5ed187b517 fix for cycle_schedule change 2025-04-12 12:57:37 +02:00
a845852b98 Merge pull request #2374 from kcwu/fix-memory-leaks
Fix memory leaks
2025-04-12 12:16:16 +02:00
9513397336 free memory when shutdown
With this fix, ASAN_BUILD won't report leaks if ctrl-c (in a short run).
2025-04-12 09:49:24 +00:00
57fa87ce5e only allocate SAND memory if enabled 2025-04-12 09:49:19 +00:00
c6a2cf88bf Merge pull request #2370 from kcwu/dev
code cleanup
2025-04-10 16:57:05 +02:00
8461f860eb code format 2025-04-10 16:28:03 +02:00
7395223512 Merge pull request #2368 from w1redch4d/qbdi_fix
fixed qbdi mode to work out of the box
2025-04-10 16:26:48 +02:00
1121af301b Merge pull request #2369 from 5angjun/dev
add cleanup for top_rated_candidates in afl_state_deinit()
2025-04-10 16:25:18 +02:00
b9c1536283 added safe_length option for portability and clarity 2025-04-10 19:44:54 +05:30
6691ce943a remove unused variable 2025-04-10 21:54:54 +08:00
1dba3a276f remove unused variable 2025-04-10 21:54:54 +08:00
3c8016e071 fixed qbdi mode to work out of the box 2025-04-10 19:21:14 +05:30
b64dd0a1ec add cleanup for top_rated_candidates in afl_state_deinit() 2025-04-10 22:50:42 +09:00
55f758a168 Merge pull request #2366 from 5angjun/dev
fix: correct rescoring logic with minimal executions
2025-04-10 14:01:49 +02:00
bd631c73a2 Enable conditional allocation for cycle schedules 2025-04-10 18:41:32 +09:00
6cbe58ff55 code format 2025-04-10 09:30:18 +02:00
c71d487a4c Merge pull request #2367 from wtdcode/sand-fix
Fix missing classified accidentally removed by 4ff2673
2025-04-10 08:37:06 +02:00
mio
939171952d Fix missing classified accidentally removed by 4ff2673 2025-04-10 12:35:31 +08:00
161905c2fc fix: correct rescoring logic with minimal executions
Previous scoring logic did not correctly rescore all queue entries.

This patch ensures rescoring works under the updated scheduling logic,
while minimizing executions per feedback from PR #2363.

Based on feedback from: https://github.com/AFLplusplus/AFLplusplus/pull/2363
2025-04-09 23:37:16 +09:00
5ff21c9aad Merge pull request #2365 from wtdcode/sand-fix
Fix sand due to default schedule change
2025-04-09 15:58:21 +02:00
mio
112d90656b rebase against dev 2025-04-09 21:34:33 +08:00
mio
bc11bd7661 Fix comments 2025-04-09 21:34:20 +08:00
mio
6b71ca7809 Also remove declaration 2025-04-09 21:34:19 +08:00
mio
eb0b8b2c5c No longer need classify_counts_mem 2025-04-09 21:34:19 +08:00
mio
6223ddf6d2 Changes not saved =( 2025-04-09 21:34:18 +08:00
mio
920c7fe71a Fix sand due to default schedule change 2025-04-09 21:34:18 +08:00
4ff2673895 fix update_bitmap_score when no current trace is present 2025-04-09 14:21:42 +02:00
891b7f48f0 nits 2025-04-09 10:48:34 +02:00
5df3cdbc0b effeciency fix for SAND 2025-04-08 17:43:26 +02:00
57466909e4 remove outdated doc 2025-04-08 11:33:05 +02:00
55c9c4ff19 deprecate some queue/.state files 2025-04-08 11:32:08 +02:00
fe202b5fee Merge pull request #2361 from kcwu/patch-1
Update FAQ.md
2025-04-08 10:18:17 +02:00
c5e511302f Update FAQ.md
the default schedule was changed to EXPLORE since 4.10a
2025-04-08 09:37:20 +08:00
7c349b6cde increase fast resume version 2025-04-07 10:13:13 +02:00
fc38904e25 fix 2025-04-07 10:08:34 +02:00
eee2521eb4 Merge pull request #2358 from kcwu/fix-buffer-overflow
fix potential q->trace_mini off by 1 overflow
2025-04-07 10:08:16 +02:00
192d4817e0 Merge pull request #2357 from wtdcode/fix-sand-comments
Fix comments in for SAND
2025-04-06 13:59:37 +02:00
mio
58e4070573 Update comments 2025-04-06 12:18:49 +08:00
mio
2ecf28440f Fix comments in for SAND 2025-04-06 12:16:34 +08:00
757184e611 adjustment 2025-04-06 01:37:15 +02:00
27b18e6267 refactor/ Use functions from other files instead of creating new ones 2025-04-05 21:08:08 +02:00
f1ee7bc9cd Merge pull request #2354 from kcwu/reduce-skipdet_e-memory-usage
reduce skipdet_e memory usage
2025-04-05 13:03:44 +02:00
969541b54f fix potential q->trace_mini off by 1 overflow
Be careful this change is incompatible with old version of fastresume.bin
2025-04-05 03:06:15 +00:00
ec07f531f8 reduce skipdet_e memory usage
By using bitmaps, the memory requirement for
`q->skipdet_e->skip_eff_map` and `done_inf_map`, which previously scaled
with the corpus size, is reduced to one-eighth of its original size.
2025-04-05 01:49:27 +00:00
56b5983b61 Merge pull request #2353 from 20urc3/patch-2
Patch 2
2025-04-03 18:10:05 +02:00
f17ea60a30 Update afl-cmin
removed `-a ! -path \"*/.state\"`
2025-04-03 16:49:43 +01:00
68634964ef Update afl-cmin 2025-04-03 16:28:31 +01:00
d21804bdd1 Update afl-cmin
Fix patch 1
2025-04-03 15:30:45 +01:00
5a527046a5 Merge pull request #2352 from AFLplusplus/dev
push to stable
2025-04-03 15:27:31 +02:00
b2a8765b1f Merge pull request #2348 from Xeonacid/riscv
Define WORD_SIZE_64 for riscv64
2025-04-03 15:25:44 +02:00
106309492c Merge pull request #2351 from kcwu/fix-double-free
fix double free bug introduced by 73ab495b5d1a99722f4a2c2b1b9507daa73…
2025-04-03 15:20:27 +02:00
58c5e2b96c fix double free bug introduced by 73ab495b5d 2025-04-03 11:09:32 +00:00
5842ba87e5 Define WORD_SIZE_64 for riscv64 2025-04-03 04:17:37 -04:00
5069551778 update changelog 2025-04-03 08:43:14 +02:00
0606d95f86 Merge pull request #2347 from AFLplusplus/dev
push to stable
2025-04-03 08:42:27 +02:00
0e35e56cc9 update changelog 2025-04-03 08:25:21 +02:00
fc860872d6 Merge pull request #2344 from kcwu/fix-sync-foreign
avoid import already imported foreign corpus
2025-04-03 08:25:05 +02:00
735d647e48 Merge pull request #2345 from kcwu/fix-leak-foreign
fix memory leak in read_foreign_testcases
2025-04-03 08:20:30 +02:00
73ab495b5d Merge pull request #2346 from kcwu/fix-memory-leak
fix memory leaks
2025-04-03 08:19:48 +02:00
d1cab470bb fix memory leaks 2025-04-03 04:17:12 +00:00
992349e48a fix memory leak in read_foreign_testcases 2025-04-02 12:48:05 +00:00
950b90abcd avoid import already imported foreign corpus
If no new foreign cases, mtime_max is 0 and this incorrectly reset last
import mtime.
2025-04-02 12:45:47 +00:00
f3b15d6340 fmt 2025-04-01 17:59:59 +02:00
0134a23046 impl normal custom mutators 2025-04-01 17:55:43 +02:00
7c296f099f Merge pull request #2337 from 5angjun/stable
Bug Fix: Crash when using INTROSPECTION=1 with -z (skip deterministic)
2025-03-31 16:15:48 +02:00
919e6226d3 Merge pull request #2338 from r3sting/fix-frida-mode-macos
Fix frida-mode compliation error for MacOS
2025-03-31 14:49:46 +02:00
a85f0c0ef9 Add skip routine before writing det_plot_file 2025-03-30 10:14:02 +09:00
6457e2ea30 Fix frida-mode compliation error for MacOS 2025-03-29 16:12:29 -07:00
542233e1ce custom python mutators in afl-tmin 2025-03-28 00:36:12 +01:00
8e4823e7ed add python flag to gnumakefile 2025-03-27 22:20:13 +01:00
f27c504f29 update afl-*-config 2025-03-25 20:57:32 +01:00
9776e402c3 Merge pull request #2334 from andy-knowles/exit-code
Better handling of exit codes used by sanitzers
2025-03-25 09:28:40 +01:00
4cabb81996 Better handling of exit codes used by sanitzers 2025-03-24 16:30:05 +01:00
42465480ef Merge pull request #2328 from 0xXA/fix-doc
fix(afl-fuzz-init): ensure proper permissions for setting CPU governor
2025-03-11 11:24:16 +01:00
f27f109880 fix(afl-fuzz-init): ensure proper permissions for setting CPU governor
The previous command used tee without sudo, which could fail due to insufficient permissions.

Signed-off-by: Yuvraj Saxena <ysaxenax@gmail.com>
2025-03-10 17:43:18 +05:30
fa9e256e09 Merge pull request #2325 from Evian-Zhang/dev
Add notes about cpu bind in docker
2025-03-06 14:18:07 +01:00
78952e8440 ensure constants are kept for LLVMFuzzerTestOneInput 2025-03-06 14:15:53 +01:00
8b543df04c Add notes about cpu bind in docker 2025-03-05 18:51:37 +08:00
e64c3f8653 code format 2025-03-03 18:03:59 +01:00
f590973387 Merge pull request #2320 from AFLplusplus/dev
push to stable
2025-03-03 13:52:45 +01:00
36338ad08b Merge pull request #2319 from smoelius/add-fflush-before-abort
Add `fflush(stdout);` before `abort` call
2025-03-03 13:29:29 +01:00
73a36ffda3 Add fflush(stdout); before abort call
Fixes #2318
2025-03-03 05:24:36 -05:00
cdf93f4d1f Merge pull request #2317 from AFLplusplus/dev
push to stable
2025-02-28 10:58:59 +01:00
a0d996558b fix doc 2025-02-28 10:57:44 +01:00
21e75d73a6 unicornafl example: fix incorrect comment (#2315) 2025-02-27 14:29:41 +01:00
cc1d41f59d Merge pull request #2313 from vnc0/ios
Add support for iOS builds
2025-02-27 11:46:32 +01:00
9530b4c9d4 fix We need at least one valid input seed that does not crash when fast restart 2025-02-27 09:50:40 +01:00
f1998bb53b Update INSTALL.md 2025-02-26 18:08:36 +01:00
0e3c82e2ea Merge branch 'dev' into ios 2025-02-26 17:59:07 +01:00
c22b06a27d Merge branch 'ios-cross' into ios 2025-02-26 17:51:07 +01:00
1d1aa3edec Add iOS installation instructions 2025-02-26 17:50:20 +01:00
50f6b38530 Add iOS cross-compilation support
- Updated CFLAGS and LDFLAGS.
- Disabled signing of bin2c during cross-compilation.
2025-02-26 16:46:49 +01:00
0cd932c4b5 Add support for iOS builds
- Define IS_IOS variable and add conditional compilation flags for iOS
- Enable binary signing with ldid for iOS builds
2025-02-25 11:58:06 +01:00
a635aa8cba potential macos fix 2025-02-23 13:22:44 +01:00
00577bb32d Merge pull request #2312 from stock1218/stable
Small change to LTO documentation
2025-02-21 20:35:01 +01:00
6aaba974b6 Update LTO documentation to reference LLVM 19 in all examples 2025-02-21 12:06:14 -05:00
6459707f24 Merge pull request #2310 from devnexen/llvm20
preparing for LLVM 20 with new sanitizer.
2025-02-20 16:38:57 +01:00
870e22246a preparing for LLVM 20 with new sanitizer.
note: no real valuable option atm.
2025-02-20 11:22:22 +00:00
66c2bb3994 Merge pull request #2309 from AFLplusplus/dev
push to stable
2025-02-19 10:00:13 +01:00
a482b817af Merge pull request #2307 from intrigus-lgtm/feat/arm-in-ci
feat: use GH hosted ARM runners.
2025-02-19 09:59:37 +01:00
6f433b5d73 feat: re-enable arm64 docker containers. Use GH arm runners 2025-02-18 21:06:51 +00:00
2843b7eb02 feat: enable arm runners in CI 2025-02-18 21:06:51 +00:00
6ed9b6d631 Merge pull request #2308 from AFLplusplus/delete_initial_run
Delete initial call to LLVMFuzzerTestOneInput in aflpp driver
2025-02-18 14:52:15 +01:00
6f018b3d80 del 2025-02-18 14:09:43 +01:00
1318636ae7 Merge pull request #2305 from kdsjZh/dev
add doc for the new default deterministic mode (followup for PR #1972)
2025-02-17 15:10:05 +01:00
29f48ab3e7 update 2025-02-17 09:43:59 +01:00
2c2a0471cd fix 2025-02-17 09:42:56 +01:00
68f5c4811e move to feature 2025-02-17 09:40:58 +01:00
fe6d3990ce Merge pull request #2306 from AFLplusplus/dev
push to stable
2025-02-17 09:37:34 +01:00
2b143688a6 disable arm64 image due workflow problems 2025-02-17 09:01:01 +01:00
f37f0b4ee4 easier LTO CTX activation 2025-02-17 08:40:57 +01:00
bd5ccc6977 add doc for deterministic mode 2025-02-17 08:30:57 +01:00
e0b23dd53d Merge pull request #2304 from wtdcode/c++-alt
Also set /usr/bin/c++ or this fails cc-rs
2025-02-15 17:30:40 +01:00
mio
54890db08e Also set /usr/bin/c++ or this fails cc-rs 2025-02-15 23:50:43 +08:00
6c4b2f0c8e fix compile warnings 2025-02-15 12:15:16 +01:00
bed20d40b1 Merge pull request #2303 from manyhus/debug_path_fix
Fix debug prefix for afl-cc, llvm-rt
2025-02-14 14:49:13 +01:00
ea2f112016 Fix debug prefix for afl-cc, llvm-rt
After the llvm_mode directory was removed in 996986bed5 and compilation
started happening from the root, adding llvm_mode to the debug path is
incorrect and causes source file lookups to fail when debugging e.g.
afl-cc or the llvm pass.
2025-02-14 12:19:36 +01:00
f639668032 Merge pull request #2302 from AFLplusplus/dev
push to stable
2025-02-14 10:52:37 +01:00
1709eb59a8 Merge pull request #2301 from etanner1/fix-issue-2298
Addressed frida-mode exec speed regression on ARM64 for #2298
2025-02-14 10:27:40 +01:00
bbdcfb0e8e not 2025-02-14 10:25:44 +01:00
cab4609e1a Merge pull request #2300 from manyhus/optarg_fix
afl-fuzz: fix -a option
2025-02-14 10:23:38 +01:00
feed691dc0 Addressed frida-mode exec-speed regression on ARM64 for #2298
Co-authored-by: WorksButNotTested <@WorksButNotTested>
2025-02-13 16:23:22 -05:00
e4f7a4738e afl-fuzz: fix -a option
This fixes the option string so -a will be parsed with an argument
again, unbreaking the option. The result of the missing : was that
optarg would always be NULL and we would abort in stricmp.

Introduced in 1c9925c7d7
2025-02-13 14:13:56 +01:00
625df13d0e Merge pull request #2299 from AFLplusplus/dev
push to stable
2025-02-12 16:44:18 +01:00
a3c038efd6 new gcc + llvm in ci 2025-02-12 15:48:02 +01:00
4f3812f00d try docker ci fix 2025-02-12 10:09:55 +01:00
887d104dae update ci to ubuntu 24.04, remove 20.04 2025-02-12 10:00:25 +01:00
47954cd04c try macos fix 2025-02-12 09:16:01 +01:00
a441f517e7 Merge pull request #2297 from SonicStark/dev-ltoctx-0211
Excess `afl_global_id` Increase of LTO-CTX
2025-02-12 09:06:19 +01:00
9cb3fe98dd Merge pull request #2290 from vnc0/FridaGum16.6.0
Update FRIDA mode for Frida Gum 16.6.x API compatibility
2025-02-11 13:42:25 +01:00
e6f15f02e1 fix 32 bit compile 2025-02-11 12:02:40 +01:00
65b99d25e1 make gcc 15 happy 2025-02-11 11:57:57 +01:00
7b86d735df Set default GUM_DEVKIT_VERSION to 16.1.11
Due to a performance regression in Frida Gum 16.2.0, revert the default GUM_DEVKIT_VERSION to 16.1.11. This change ensures that the expected performance levels are maintained until the issues in Frida Gum 16.2.0 are resolved.
2025-02-11 11:30:58 +01:00
b56b24d251 Merge branch 'FridaGum16.6.0-cflag' into FridaGum16.6.0 2025-02-11 08:17:45 +01:00
c2383761cb Set default GUM_DEVKIT_VERSION to 16.5.9
Execution speed seems better than recent versions.
2025-02-11 08:16:39 +01:00
f87a669aa3 Add conditional compiler flag for Frida 16.6+ compatibility 2025-02-11 08:05:21 +01:00
8489112ab1 Fix excess afl_global_id increase
introduced in commit 44a769616
2025-02-11 13:06:09 +08:00
ebd6d4b8bb update qemuafl 2025-02-10 19:45:58 +01:00
125027f5bf v4.32a 2025-02-10 14:40:12 +01:00
9cac7ced05 Merge pull request #2294 from AFLplusplus/dev
push to stable
2025-02-10 13:42:28 +01:00
ecaddc09e8 code format 2025-02-10 13:29:22 +01:00
287edf2754 v4.31c release 2025-02-10 13:22:37 +01:00
7765d4ac33 Fix various spelling errors (#2293)
* Fix spelling errors in log messages

* Fix doc comment syntax

* Fix spelling errors in Markdown documentation

* Fix spelling errors in comments
2025-02-10 00:32:42 +01:00
6a4b5807b6 Merge pull request #2288 from wtdcode/upstream
[RFC] Upstream "SAND: Decoupling Sanitization from Fuzzing for Low Overhead"
2025-01-27 16:39:37 +01:00
mio
72d248ae57 cmplog is working! 2025-01-27 19:41:33 +08:00
mio
c78643f566 Add an example 2025-01-27 19:37:21 +08:00
mio
0b53a5a8aa Fix typo 2025-01-27 19:30:52 +08:00
mio
80e1a95378 Remove the unused field 2025-01-27 19:24:46 +08:00
mio
5fa1a9c365 Add inline 2025-01-27 19:24:31 +08:00
mio
522da5e9b5 Update docs accordingly 2025-01-27 19:23:21 +08:00
mio
c7e919333e Update help usage of afl-fuzz 2025-01-26 18:40:37 +08:00
mio
c64813b7d5 Update more instructions 2025-01-26 15:52:29 +08:00
mio
b96047d7b0 Fix typo 2025-01-26 15:51:35 +08:00
mio
604cf2cf80 Use AFL hash32 2025-01-26 15:46:25 +08:00
mio
c7c66bd0d6 Fix plot_file header 2025-01-26 15:34:56 +08:00
mio
40991801bd Fix cmplog srv not deinit 2025-01-26 15:28:56 +08:00
fd780e8eba Update FRIDA mode for Frida Gum 16.6.x API compatibility
- Bumped the frida-gum version to 16.6.5.
- Refactored functions to use `GumModule` instead of deprecated `GumModuleDetails`.
2025-01-25 18:26:30 +01:00
mio
96dc77e410 Fix typos 2025-01-24 22:31:21 +08:00
mio
60b92dcef3 Fix incorrect docs 2025-01-24 22:25:15 +08:00
mio
12a88c52df Update docs 2025-01-24 22:24:10 +08:00
mio
be3c665eee Fix integration 2025-01-23 23:18:35 +08:00
mio
f905087e8e Remove var bytes makeups 2025-01-23 19:17:44 +08:00
mio
99cf15bd30 Fix building 2025-01-23 19:12:48 +08:00
mio
5c239d9207 nit with code formatt-ed 2025-01-23 19:11:45 +08:00
mio
c4d576b4e0 Add myself to contributor 2025-01-23 19:04:53 +08:00
mio
efa2120935 Update help 2025-01-20 00:09:32 +08:00
mio
967b81736d Fix pass 2025-01-19 23:55:44 +08:00
mio
f4346e423d No AFL_SAN_RECOVER 2025-01-19 23:53:03 +08:00
mio
a60003e3cf Fix 2025-01-19 23:51:44 +08:00
mio
1c9925c7d7 Initial integration 2025-01-19 23:49:52 +08:00
635cd7374e fix unicorn test 2025-01-16 15:48:04 +01:00
fb52b8edf8 Merge pull request #2287 from AFLplusplus/dev
push to stable
2025-01-16 15:34:48 +01:00
30861b5d54 llvm 20 support 2025-01-16 15:32:58 +01:00
b2a01936c3 do not auto-enable splicing 2025-01-16 14:07:41 +01:00
8dbfcde798 Merge pull request #2286 from AFLplusplus/dev
push to stable
2025-01-13 14:08:30 +01:00
7ad694716b no splicing is the new default 2025-01-13 11:57:19 +01:00
e93ab23823 python 3.13+ support 2025-01-13 11:38:38 +01:00
79a24685b2 update unicorn mode 2025-01-06 20:26:32 +01:00
cad7536036 Mutation Chain Tool (#2281)
* Mutation Chain Tool

* Address comments domenukk

* Address comments domenukk 2
2025-01-05 12:35:50 +01:00
1ddfb1fec2 Merge pull request #2282 from vnc0/stable
Enhance compatibility in update_frida_version.sh
2025-01-03 11:28:09 +01:00
ae8df744ee Merge branch 'AFLplusplus:stable' into stable 2024-12-30 01:09:48 +01:00
aaaa96af6d Merge pull request #2280 from GAP-dev/dev
Fix macOS env optimization
2024-12-28 15:46:29 +01:00
2e2a3a2718 Fix macOS env optimization 2024-12-26 17:46:10 +09:00
eee4be90c1 Merge pull request #2279 from jschwartzentruber/upd-filter-docs
update dynamic covfilter readme
2024-12-24 21:12:25 +01:00
5fe21c3797 update dynamic covfilter readme 2024-12-24 10:49:33 -05:00
4eaacfb095 Merge pull request #2278 from AFLplusplus/dev
Push to stable
2024-12-24 14:08:20 +01:00
82b0cf0540 Fix fuzz targets killing on exit (#2277) 2024-12-24 11:11:10 +01:00
5a352adb19 Merge pull request #2276 from martinus/dev
Fix overflow in execs_ps_last_min calculation
2024-12-19 10:34:54 +01:00
9afba51ec1 renamed last_avg_execs -> last_avg_total_execs
This should make it a bit more clear that it stores the total number of executions from the previous update
2024-12-19 07:59:45 +01:00
99402aa31c Fix overflow in execs_ps_last_min calculation
last_avg_execs should be 64bit, same as total_execs, otherwise there is an overflow once total_execs reaches 2^32. Which can happen in practice for long-running fuzzing campaigns.
2024-12-19 07:56:15 +01:00
af11b80fda Enhance compatibility in update_frida_version.sh
Modify sed command to support FreeBSD and macOS
2024-12-18 17:50:55 +01:00
10db3a35cf Merge pull request #2274 from AFLplusplus/dev
Dev
2024-12-17 19:18:52 +01:00
af44b07b31 Merge pull request #2273 from vnc0/stable
Fix macro syntax error in config.h
2024-12-17 19:18:12 +01:00
9b433e2d8c Fix macro syntax error in config.h 2024-12-17 17:55:29 +01:00
85e14cf8d1 Merge pull request #2272 from AFLplusplus/dev
fix gcc plugin test
2024-12-15 18:07:00 +01:00
f2f417325f fix gcc plugin test 2024-12-15 18:06:02 +01:00
3e18b1a10c Merge pull request #2270 from AFLplusplus/dev
fix map size difference bug
2024-12-14 08:17:46 +01:00
1d3e885441 fix map size difference bug 2024-12-13 18:59:26 +01:00
0c69d0a0d8 Merge pull request #2269 from AFLplusplus/dev
push to stable
2024-12-13 12:28:39 +01:00
bbffece7d7 nit 2024-12-13 11:27:26 +01:00
2956b9cc4c support LLVMFuzzerTestOneInput archive targets 2024-12-13 11:05:17 +01:00
9160805f4a add __sanitizer_weak_hook_ support 2024-12-12 15:26:39 +01:00
50e2f9d46c loose file and shared memory permissions on Android and iPhone 2024-12-11 10:36:31 +01:00
223b14134c Merge pull request #2265 from AFLplusplus/dev
push to stable
2024-12-04 11:14:01 +01:00
f5a672f9d8 update makefile for llvm 2024-12-04 08:45:54 +01:00
9ce45665d7 Merge pull request #2264 from exoosh/bump-llvm-version-to-20
Bump LLVM version to 20 available in prerelease, 19 being latest stable
2024-12-04 08:43:12 +01:00
10883b1392 Bumping the upper version boundary for LLVM to 20, which is currently available in prerelease, 19 being latest stable 2024-12-03 15:57:50 +00:00
d206d5fc46 v4.31a 2024-12-03 15:53:01 +01:00
4f53803dfe Merge pull request #2261 from AFLplusplus/dev
v4.30c
2024-12-03 15:47:49 +01:00
ed06b3bc9f v4.30c 2024-12-03 15:46:45 +01:00
3081f589cc Merge pull request #2260 from AFLplusplus/dev
fix readme
2024-12-03 09:50:27 +01:00
5d08f33a5f fix readme 2024-12-03 09:47:49 +01:00
46cbe22feb Merge pull request #2258 from AFLplusplus/dev
push to stable
2024-12-02 15:47:30 +01:00
6cba007c76 finishing touches of removing afl-gcc 2024-12-02 15:14:38 +01:00
1461f3a0ee remove afl-as 2024-12-02 15:04:16 +01:00
03d306a97f code format 2024-12-02 14:58:43 +01:00
0278eb5351 Merge pull request #2259 from AFLplusplus/removeoutdated
Remove outdated afl-gcc/afl-clang
2024-12-02 14:54:58 +01:00
8e88ef02ad keep symlinks 2024-12-02 14:54:16 +01:00
ad2eaf54ad fix multiple loading of allow/denylist and do proper counting 2024-12-02 11:59:32 +01:00
a287076ac0 Merge pull request #2257 from S0fr/S0fr-patch-1
Update afl-analyze.c
2024-11-27 22:27:29 +01:00
c352943aa5 Update afl-analyze.c
To fix the issue with fields splitting in the afl-analysis.
2024-11-27 09:06:03 +08:00
bd3900c084 Remove reference to ZAFL's license
Lincense changed. See #2253
2024-11-22 12:02:06 -03:00
48002fe146 remove symlinks 2024-11-21 16:15:04 +01:00
31c8a052a6 Merge pull request #2252 from StepanGulyaev/dev
Added CFISAN option for verbose output on crash
2024-11-21 15:51:51 +01:00
46b87a6d62 adding details 2024-11-21 17:36:30 +03:00
b4208dde94 little fix for docs 2024-11-21 17:23:30 +03:00
4a492d5d8e Code formatting 2024-11-21 17:23:30 +03:00
945309c316 Typing fix 2024-11-21 17:23:30 +03:00
41de569353 Adding envs to docs 2024-11-21 17:22:30 +03:00
7aecf14c07 Added AFL_UBSAN_VERBOSE variable 2024-11-21 16:37:24 +03:00
7b24f4a329 remove afl-gcc/afl-clang 2024-11-21 14:31:36 +01:00
ebb919f771 Code formatted 2024-11-21 15:31:34 +03:00
b43f37456f Adding AFL_CFISAN_VERBOSE variable 2024-11-21 15:14:54 +03:00
701e89bbcd fixes 2024-11-21 10:39:49 +01:00
e3fae3e9b0 Added CFISAN option for verbose output on crash 2024-11-21 12:32:48 +03:00
464ec516d5 check afl-clang/gcc with sanitize-fuzzer 2024-11-21 09:43:20 +01:00
3af042d5bf Merge pull request #2248 from AFLplusplus/dev
push to stable
2024-11-20 16:34:35 +01:00
c1e4b8f7f6 idea cmplog 2024-11-20 15:53:04 +01:00
79deeb46dd add missing envs 2024-11-20 15:44:18 +01:00
9cf260ca1f remove outdated sanitize-undefined-trap-on-error 2024-11-20 15:38:17 +01:00
82752fe38d code format 2024-11-19 16:25:50 +01:00
d11ade56e2 remove compiler warning 2024-11-18 19:20:37 +01:00
665d32a0dc -g/-G value checks 2024-11-15 09:48:34 +01:00
e1bd9fc6ac update docs on asan instances 2024-11-15 09:48:34 +01:00
2c6f2c970d Merge pull request #2242 from abhigargrepo/dev
Unsetting AFL_LLVM_ALLOWLIST and AFL_LLVM_DENYLIST environment variables in make files
2024-11-11 15:24:40 +01:00
0e3157375b Unsetting AFL_LLVM_ALLOWLIST and AFL_LLVM_DENYLIST environment variables 2024-11-11 01:24:11 -08:00
f39cf57eac enhance backward compatibility and portability 2024-11-09 22:31:07 +01:00
e62999c95f install all includes 2024-11-09 16:28:26 +01:00
jma
0b22665391 Add support for post_process in Rust custom mutator + associated example with lain (#2241) 2024-11-08 17:15:51 +01:00
5777ceaf23 Merge pull request #2240 from AFLplusplus/dev
Push to stable
2024-11-07 15:42:48 +01:00
21916a7f60 changes 2024-11-07 15:41:48 +01:00
6c83a9ccc1 update unicorn checkout 2024-11-07 15:39:51 +01:00
bc9fda61a3 Merge pull request #2239 from wtdcode/fix-uc2-breakage
Force 2.0.1.post1 for unicornal temporarily
2024-11-07 15:37:51 +01:00
mio
4e0b8beba8 Force 2.0.1.post1 for unicornal temporarily 2024-11-07 22:20:17 +08:00
1448eab8ec Merge pull request #2235 from CowBoy4mH3LL/patch-3
Update README: Link to OpenSSF talk added
2024-11-04 11:08:59 +01:00
55aec64038 Update README: Link to OpenSSF talk added 2024-11-04 12:14:11 +05:30
42fc9acf5b Merge pull request #2234 from McSinyx/include
Install {config,types}.h
2024-11-01 07:58:26 +01:00
cdbd86a112 Install {config,types}.h 2024-11-01 12:01:21 +09:00
1aa58a1972 update qemuafl 2024-10-30 13:24:15 +01:00
d0587a3ac4 Merge pull request #2226 from AFLplusplus/dev
push to stable
2024-10-30 13:20:48 +01:00
d1fd072b79 fix 2024-10-30 10:55:44 +01:00
c282156451 Merge pull request #2232 from michaelmior/jsonschema-dict
Add JSON Schema dictionary
2024-10-30 10:55:07 +01:00
a9bda37d18 Add JSON Schema dictionary 2024-10-29 12:31:09 -04:00
577b286508 fix explanation how to obtain the map size 2024-10-28 09:53:01 +01:00
009f663e2c Merge pull request #2231 from dergoegge/2024-08-fix-start-off
Make `__AFL_COVERAGE_START_OFF` work for targets with "small" maps
2024-10-25 17:47:27 +02:00
1efb7c8a8b Make __AFL_COVERAGE_START_OFF work for targets with "small" maps 2024-10-25 11:37:55 +01:00
7f614be3a5 Merge pull request #2229 from g0ku704/feat/disable_gcc_version_check
Introduce `AFL_GCC_DISABLE_VERSION_CHECK` to disable GCC version check
2024-10-20 09:23:56 +02:00
04d2476b32 doc: add description for AFL_GCC_DISABLE_VERSION_CHECK 2024-10-20 16:00:17 +09:00
c1d9a4fab9 feat: introduce GCC disable environment variable
This change is to disable the GCC plugin version check for
GCC plugin and CMPLOG, to overcome the issues with incompatability
with expected GCC version and actual GCC version used to compile
using `AFL_GCC_DISABLE_VERSION_CHECK` environment variable.
2024-10-19 22:19:41 +09:00
8a060a4b68 fix the cleanup of previous generated SHA1 files in function handle_existing_out_dir() 2024-10-19 13:54:48 +02:00
a11488b9dc changelog 2024-10-16 18:27:10 +02:00
4cc9232485 add AFL_OPT_LEVEL support 2024-10-16 18:26:08 +02:00
20c46c0ed6 nits 2024-10-15 15:18:51 +02:00
b3d16f7b8c update how AFL_EXIT_WHEN_DONE and colors of cycles done are working 2024-10-14 09:45:59 +02:00
c0837409bd fix cycles_wo_finds count 2024-10-14 09:29:10 +02:00
78b7e14c73 Merge pull request #2222 from AFLplusplus/dev
push to stable
2024-10-07 16:46:12 +02:00
f9a8b60b3b add LLVMFuzzerTestOneInput -1 support for non-asan 2024-10-07 16:44:24 +02:00
4a1cf0b9af code format 2024-10-07 13:43:19 +02:00
c1e40c5fb7 Merge pull request #2220 from AFLplusplus/dev
push to stable
2024-10-07 10:12:51 +02:00
d6a2edb42a update nyx 2024-10-07 10:11:16 +02:00
5e8e233755 Merge pull request #2217 from carlocab/macos-flags
Update macOS linker flags in GNUmakefile.llvm
2024-10-07 10:01:25 +02:00
31ed850c4b Merge pull request #2218 from ea/stable
Fix uninitialized alloc_canary in libdislocator
2024-10-07 10:00:04 +02:00
ea
994ac55878 Fix uninitialized alloc_canary in libdislocator
When random alloc_canary env var option was introduced, a possibility for use of uninitialized alloc_canary value was made. 

In most cases, constructor will be called during shared library load and the alloc_canary would be initialized to either its default value or a randomly generated one if forced by AFL_RANDOM_ALLOC_CANARY env var.

However, in some cases, libraries loaded before libdislocator will make allocations (still using libdislocator's allocation functions) while alloc_canary is still uninitialized. In such cases, canary value is usually NULL. 
If such allocated value is then free()'d after libdislocator's constructor has been run, call to free() will fail causing a false positive. This condition usually happens while calling library destructors at process termination. 

The patch ensures the canary value is initialized in all cases, and introduces a destructor that reverts it to default value. 

This  does mean that certain number of early allocations will use the default canary value rather than the random one set afterwards.  This seems like a reasonable tradeoff as I haven't found a surefire way of forcing libdislocator's constructor to run first in all possible cases (if nothing else, libphtread usually  has priority).
2024-10-02 13:08:24 -05:00
cb5a61d8a1 Update macOS linker flags in GNUmakefile.llvm
`-flat_namespace` is effectively deprecated and doesn't really work as
expected these days. Omitting the `-flat_namespace` means that binaries
are built with a two-level namespace, which don't support
`-undefined suppress`.

The idiomatic way of telling the linker to look up undefined symbols at
runtime is using `-undefined dynamic_lookup`, which is supported by a
two-level namespace.

See also:
ocaml/ocaml#10723
mono/mono#21257
2024-10-02 17:56:43 +08:00
146e535f7b persistent record for frida and qmeu 2024-10-01 10:13:35 +02:00
b88f132975 llvm20 fix 2024-09-29 17:11:07 +02:00
12271064f8 fix fix 2024-09-27 09:20:08 +02:00
55b67f1372 fix postprocess for calibration 2024-09-26 14:42:59 +02:00
d21fb1a558 Merge pull request #2214 from AFLplusplus/dev
push to stable
2024-09-24 11:57:36 +03:00
2e6c74f9b9 2nd macos ci attempt 2024-09-24 09:55:35 +02:00
2a4281ce8d update qemuafl 2024-09-24 09:50:14 +02:00
9cd702e75d try macos ci 2024-09-24 09:41:27 +02:00
8b35dd49be Fix macOS build 2024-09-23 21:22:17 +02:00
703fd0b610 Merge pull request #2212 from nj00001/dev
Save crash log returned by nyx when AFL_CRASHING_SEEDS_AS_NEW_CRASH e…
2024-09-23 17:02:47 +03:00
db172473b5 Save crash log returned by nyx when AFL_CRASHING_SEEDS_AS_NEW_CRASH environment variable is enabled
nyx also returns a crash log when reporting a crash, both files are saved in the afl++ fuzzing run, whereas with the AFL_CRASHING_SEEDS_AS_NEW_CRASH setting, only the crash file is saved in the dry run phase if crashes are included in the supplied seeds.
This commit adds crash log saving to keep the behavior consistent
2024-09-23 15:50:20 +08:00
5b44067e9c Update fuzzing_in_depth.md for a typo (#2209) 2024-09-16 12:23:10 +02:00
8531928fa4 Merge pull request #2207 from schumilo/dev
fix AFL_AUTORESUME=1 for Nyx mode
2024-09-14 16:02:21 +02:00
804c98a1e8 Merge pull request #2208 from 20urc3/patch-1
Update COMPARISON.md
2024-09-14 16:01:32 +02:00
1792ce2825 Update COMPARISON.md
- Add Ampere Altra Q80-30 benchmark
2024-09-14 15:33:55 +02:00
1d6cd5dd19 fix AFL_AUTORESUME=1 for Nyx mode 2024-09-14 03:51:20 +02:00
7e9abf1bba Merge pull request #2206 from smoelius/afl-sha1-filenames-test
Add `AFL_SHA1_FILENAMES` test
2024-09-12 21:50:20 +02:00
6a28502191 Adjust cmplog test to use AFL_SHA1_FILENAMES=1 2024-09-12 10:05:23 -04:00
fc7c95e9f4 nits 2024-09-12 10:24:05 +02:00
4086b93ad7 Merge pull request #2205 from ktpss95112/patch-1
Update env_variables.md
2024-09-09 09:02:09 +02:00
837a9693ab Update env_variables.md 2024-09-09 11:32:32 +08:00
60d3ecab63 Fix broken link in CONTRIBUTING.md (#2196)
* Fix broken link in CONTRIBUTING.md

* Also change link text
2024-09-06 23:26:03 +02:00
d0f39849c2 update qemu persisten readme 2024-09-06 12:36:57 +02:00
8820bf4758 update qemu persisten readme 2024-09-06 12:36:57 +02:00
75d8c47a6b Merge pull request #2204 from AFLplusplus/dev
push to stable
2024-09-06 12:16:31 +02:00
3ec794c806 Merge pull request #2203 from ktpss95112/patch-1
Update the doc string of read_foreign_testcases()
2024-09-06 11:50:33 +02:00
bf46ff8823 Merge pull request #2202 from smoelius/permissive_create-in-mark_as_variable
Use `permissive_create` in `mark_as_variable`
2024-09-06 11:48:34 +02:00
6f61fca15a Update the doc string of read_foreign_testcases() 2024-09-06 11:39:49 +08:00
b8cb35fa8c Use permissive_create in mark_as_variable 2024-09-05 09:56:38 -04:00
dfc9b3dba0 already support LLVMFuzzerCleanup 2024-09-04 16:34:09 +02:00
ab5f95e17a enhance autotokens standalone 2024-08-29 14:12:32 +02:00
fe66a95d96 add autotokens-standalone 2024-08-28 15:31:15 +02:00
72a24e6439 improve aflpp-standalone 2024-08-28 13:17:49 +02:00
088dd6476c Merge pull request #2195 from intrigus-lgtm/patch-4
Install package without asking for confirmation
2024-08-22 18:32:08 +02:00
30df52cd8c Merge pull request #2193 from ncoghlan/core-dump-notice-rewording
Offer more explicit core dump handling tip
2024-08-22 18:30:28 +02:00
74d262c7b5 Install package without asking for confirmation 2024-08-21 15:50:00 +02:00
d7c99007ff No longer need the extra line break 2024-08-21 20:04:30 +10:00
bdb5622bd4 Skip the save/restore example 2024-08-21 20:03:33 +10:00
cf2ddf437b Wording tweaks 2024-08-21 19:05:41 +10:00
2b7aae66b6 Offer more explicit core dump handling tip 2024-08-21 19:02:38 +10:00
598a3c6b5e Merge pull request #2192 from AFLplusplus/dev
fix unicorn build
2024-08-20 12:51:03 +02:00
0978283915 fix unicorn build 2024-08-20 12:49:49 +02:00
f27cbdb793 Merge pull request #2190 from AFLplusplus/dev
push to stable
2024-08-19 16:51:42 +02:00
1689a8e053 code format, llvm 18 2024-08-19 16:25:32 +02:00
6edc3b51ba fix AFL_OLD_FORKSERVER 2024-08-18 16:06:57 +02:00
93fb1d1a24 fix custom post process with custom send 2024-08-16 10:46:01 +02:00
bf7a6d69cf update changelog 2024-08-15 11:52:01 +02:00
6ddd5ecf4a fix missing trace_mini check 2024-08-14 18:47:44 +02:00
e2099114aa Merge pull request #2186 from R9295/fix/unicorn-mode-build
fix unicorn and unicornafl build script
2024-08-14 14:00:15 +02:00
db84f75a81 remove deprecated -d option in unicorn CI test 2024-08-14 13:45:10 +02:00
9111035495 fix incorrect check for unicorn CI 2024-08-14 13:44:44 +02:00
d78a8698e4 fix rebuild message 2024-08-13 16:56:22 +02:00
7b2f983bf3 fix unicorn and unicornafl build script 2024-08-13 16:54:53 +02:00
1910b0ad42 Merge pull request #2183 from NareshBiradar1/fix/image-tag-typo
#2182 - Fix Typo in Image Tag `heigh` Attribute in `README.md`
2024-08-11 16:59:39 +02:00
9a04df5d97 Corrected the 'heigh' attribute to 'height' in the HTML image tag for the AFL++ logo to ensure proper display. 2024-08-11 19:55:01 +05:30
4f03f380ea Merge pull request #2180 from tchebb/fix-shell-errors
Fix `/bin/sh:` errors when building without LLVM
2024-08-08 09:30:19 +02:00
e3b08d430c Merge pull request #2173 from ahuo1/dev
To support AFL instrumentation, add default settings of map_size in forkserver.
2024-08-08 09:21:38 +02:00
4f35c30371 Merge pull request #2181 from tchebb/fix-no-zlib
Fix syntax error when compiling without zlib
2024-08-07 12:28:08 +02:00
9df9064549 Fix syntax error when compiling without zlib
commit ecb5854be0 ("add zlib compression for fast resume") added new
logic selected at compile-time when zlib is present. Unfortunately, it
also broke the existing logic by removing the last line of a multi-line
if statement, resulting in a syntax error when zlib isn't present.

Restore the line as it was.
2024-08-06 11:37:19 -07:00
256bc6ab42 Fix "/bin/sh:" errors when building without LLVM
In GNUmakefile.llvm, several variables are unconditionally populated
by expanding $(LLVMVER) and $(LLVM_CONFIG) inside shell commands.
However, when LLVM is not present, both those variables are empty,
meaning that the shell commands end up malformed and emit harmless, but
noisy, errors like this one:

  /bin/sh: --: invalid option
  Usage:	/bin/sh [GNU long option] [option] ...
  	/bin/sh [GNU long option] [option] script-file ...
  GNU long options:
  	--debug
  	--debugger
  	--dump-po-strings
  	--dump-strings
  	--help
  	--init-file
  	--login
  	--noediting
  	--noprofile
  	--norc
  	--posix
  	--pretty-print
  	--rcfile
  	--rpm-requires
  	--restricted
  	--verbose
  	--version
  Shell options:
  	-ilrsD or -c command or -O shopt_option		(invocation only)
  	-abefhkmnptuvxBCHP or -o option
  /bin/sh: line 1: test: -gt: unary operator expected
  /bin/sh: line 1: test: -lt: unary operator expected
  /bin/sh: line 1: test: -ge: unary operator expected
  /bin/sh: line 1: test: -ge: unary operator expected

Fix the problem by only populating the "downstream" variables if the
upstream ones have values.
2024-08-06 11:27:01 -07:00
614c5127ca Merge pull request #2179 from fish98/revise_docs
Update local building docs with missing dependencies
2024-08-06 14:01:49 +02:00
5bb894f1ee remove redundant tracked tmp files during building
Signed-off-by: TTFISH <jiongchiyu@gmail.com>
2024-08-05 23:35:22 +08:00
8d72f41e20 update build dependencies for source-only/distrib
Otherwise the building of nyx_mode, frida_mode, unicorn_mode with source_only/all/distrib flag will fail due to missing dependencies.

Signed-off-by: TTFISH <jiongchiyu@gmail.com>
2024-08-05 23:33:31 +08:00
b928303dd0 Merge branch 'AFLplusplus:dev' into dev 2024-08-05 22:21:52 +08:00
76b26ac2c6 Merge pull request #2174 from killerra/dev
Fixed lsan defaults evaluation
2024-08-03 10:19:15 +02:00
dd16be405a Handle detect_leaks 0 and false 2024-08-02 14:51:42 +01:00
2e57d86576 lower mem usage attempt 2024-08-02 15:27:57 +02:00
4369d6209f Removed bogus free in instrument_coverage_unstable_find_output 2024-07-28 19:57:55 +01:00
26ae4124f3 fixed lasan defaults evaluation 2024-07-28 11:30:48 +01:00
25945d51a4 To support AFL instrumentation, add default settings. 2024-07-28 16:45:45 +08:00
db23931e7c Merge pull request #2172 from AFLplusplus/dev
push to stable
2024-07-24 14:50:57 +02:00
6e37f9b237 new cmplog map 2024-07-24 14:48:23 +02:00
2f2ddbbd79 fix afl-whatup time calc 2024-07-24 10:19:57 +02:00
ba7c012427 Merge pull request #2169 from killerra/dev
Fixed AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE to work for instances that are  not named "default"
2024-07-23 22:42:01 +02:00
5bfe0c1a15 added free for new strings 2024-07-23 20:52:15 +01:00
bb72cc752a Fixed frida unstable coverage for instances not named "default" 2024-07-23 17:31:13 +02:00
8c4ecd90a8 Merge pull request #2168 from AFLplusplus/fix_macos
Fix LLVM mode on MacOS
2024-07-23 15:44:05 +02:00
c0d53a1aa7 oops 2024-07-23 14:42:43 +02:00
31a1fbae33 Fix LLVM mode build on MacOS 2024-07-23 14:06:19 +02:00
09f1854cd1 Merge pull request #2165 from meowmeowxw/fix-fasan-arm64
Fix FASAN operand access on aarch64
2024-07-21 21:01:04 +02:00
4a6b751b93 frida_mode: fix fasan operand access order 2024-07-21 18:26:13 +02:00
bbcb3dd53e mini performance opt 2024-07-17 13:01:39 +02:00
eac53afe7b fix autodict 2024-07-15 23:42:55 +02:00
19ca7b3761 Merge pull request #2158 from AFLplusplus/dev
push to stable
2024-07-14 11:23:51 +02:00
55a2362348 code format 2024-07-14 10:33:12 +02:00
8afb60d2f9 Merge pull request #2160 from exoosh/dev
Fixing change from PR#2152, misspelled variable names
2024-07-14 10:21:24 +02:00
69a596c089 ensure this does not happen again 2024-07-14 10:20:53 +02:00
ccb952dde8 Revert "Replace gettimeofday with clock_gettime (#2159)"
This reverts commit 7c380a6612.
2024-07-14 10:18:23 +02:00
7c380a6612 Replace gettimeofday with clock_gettime (#2159) 2024-07-14 00:25:58 +02:00
88e2affe73 Fixing change from PR#2152, misspelled variable names 2024-07-13 21:29:41 +00:00
3f26818d97 Merge pull request #2157 from trail-of-forks/fix-syncid-len
check the sync_id length once
2024-07-12 23:05:30 +02:00
bd83eb0f42 check the sync_id length once 2024-07-12 16:22:17 -04:00
c5acf3f137 Merge pull request #2156 from choller/patch-1
Initialize max_length in afl_fsrv_init #2155
2024-07-12 20:13:14 +02:00
ea42feb06a Initialize max_length in afl_fsrv_init #2155 2024-07-12 20:08:52 +02:00
a09720665d Merge pull request #2154 from hazohelet/fix-missed-alias-table-recreation
Fix missed updates of alias table when INTROSPECTION is on
2024-07-10 16:53:39 +02:00
6f394842be Merge pull request #2152 from exoosh/exocad/stable
Some fixups to the GNUmakefile.llvm
2024-07-10 14:39:31 +02:00
02f4f75526 Fix missed updates of alias table when INTROSPECTION is on
In src/afl-fuzz.c `prev_queued_items` is used to decide whether the alias table should be recreated through the comparison with `afl->queued_items`.
43f462c91b/src/afl-fuzz.c (L3103-L3117)

However, this variable is also updated to `afl->queued_items` when INTROSPECTION is enabled and the `fuzz_one` appends seeds.
43f462c91b/src/afl-fuzz.c (L3135-L3140)

Due to the update of `prev_queued_items` when INTROSPECTION is on, alias table may not be recreated when it actually should be.

This can lead to potential heap buffer-overflow in `select_next_queue_entry` due to the lack of `afl_realloc` called in `create_alias_table`.

This patch fixes this bug by utilizing another variable for the INTROSPECTION part like other variables such as `prev_saved_tmouts`.
2024-07-10 21:39:04 +09:00
43f462c91b Merge pull request #2138 from meowmeowxw/ijon-set
IJON SET
2024-07-10 13:51:08 +02:00
77bad3ad23 ijon set: use __afl_coverage_interesting 2024-07-10 10:16:14 +02:00
835a4b6497 Some fixups to the GNUmakefile.llvm
* rely less on the shell and more on GNU make to parse the versions
* fixed retrieval of minor version (for 18.1.8 it gave 8 instead of 1!)
* auto-detection of llvm-config within the supported version range
* replaced backticks by `$(...)` syntax
* tested against `busybox static-sh`, `bash`, `dash` and `csh`
2024-07-10 07:55:37 +00:00
d1a7b6988c update timeout for custom mutator tests 2024-07-08 09:46:51 +02:00
365129d811 Update sample_all.sh (#2146)
Incorrect shell syntax
2024-07-08 08:34:06 +02:00
b840ac91dc Fixed the syntax errors in unicorn_loader.py within unicorn_mode. (#2144)
Replaced a Chinese comma "," with an English comma "," to ensure the code runs correctly.
2024-07-05 10:43:20 +02:00
dcd2f9ac77 Merge pull request #2143 from r-barnes/patch-1
Make fallthroughs explicit in afl-fuzz-extras.c
2024-07-01 17:12:42 +02:00
37d9afc5cc Make fallthroughs explicit in afl-fuzz-extras.c
Using `__attribute__((fallthrough))` makes fallthroughs explicit in a way the compiler can understand. This allows the enablement of `-Wimplicit-fallthrough`.
2024-07-01 06:59:37 -07:00
62b3a1e800 Merge pull request #2142 from CowBoy4mH3LL/patch-2
Update README.md to reflect latest changes
2024-07-01 11:35:53 +02:00
9c54be6cf1 Update README.md to reflect latest changes
1. fixed hook name length to 16
2. no native debug logging at this time -- will bridge with AFL++ macros latter
2024-07-01 14:54:01 +05:30
53409530b3 Merge pull request #2141 from AFLplusplus/dev
push to stable
2024-07-01 08:57:38 +02:00
43014cd465 changelog 2024-07-01 08:57:26 +02:00
e27e3622d4 Merge pull request #2140 from CowBoy4mH3LL/dev
Adding of QEMU hooking bridge
2024-07-01 08:55:00 +02:00
b169629dbd Fresh commit with all -- post revertion due to unicornafl update 2024-07-01 05:52:06 +00:00
8fbeeb1439 ijon set: discard source code instrumentation 2024-06-30 15:50:37 +02:00
2a489f844b ijon set: remove gdb_history 2024-06-29 23:08:51 +02:00
a161aac7c1 ijon set: init 2024-06-29 22:05:22 +02:00
a7f928ac31 update qemuafl 2024-06-29 16:45:01 +02:00
50ae95cee4 add AFL_OLD_FORKSERVER feature 2024-06-29 16:31:08 +02:00
f6bfa96a96 todo 2024-06-29 03:32:37 +02:00
e86dcc9f18 update qemu mode 2024-06-29 02:15:35 +02:00
9d33580aac code format 2024-06-28 16:46:42 +02:00
77cfd504cf update grammar mutator 2024-06-28 16:33:48 +02:00
f7bbd467b5 add custom_send_tcp 2024-06-28 16:00:19 +02:00
8993ba4305 add ruby dict 2024-06-27 19:42:58 +02:00
ba7313b521 AFL_CUSTOM_MUTATOR_LATE_SEND added 2024-06-27 18:51:58 +02:00
e2d30641be Merge pull request #2136 from jakelamberson/enhance-nyx-instructions
Enhance Nyx mode instructions
2024-06-27 03:26:56 +02:00
2248773566 Add nyx_mode to contribution instructions 2024-06-26 20:21:05 -04:00
5f43d0ad42 Fix and enhance Nyx mode instructions 2024-06-26 20:21:05 -04:00
af47531745 improved seed selection algorithm 2024-06-26 01:12:10 +02:00
e80bd2d30c Merge pull request #2133 from visitorckw/optimize-bit-counting
Optimize bit counting using __builtin_popcount
2024-06-24 01:37:09 +02:00
ac5815d994 Optimize bit counting using __builtin_popcount
Use the __builtin_popcount intrinsic to optimize the bit counting
function if the compiler supports it. This change replaces the manual
bit counting algorithm with the more efficient built-in function, which
leverages hardware support on compatible processors.

This modification ensures that the code remains backward-compatible by
falling back to the original implementation when __builtin_popcount is
not available.
2024-06-24 06:52:07 +08:00
540d741df0 nits atnwalk 2024-06-22 22:22:01 +02:00
ecb5854be0 add zlib compression for fast resume 2024-06-21 14:40:23 +02:00
25b650f59d Merge pull request #2132 from tylzh97/stable
Fix typo in unicorn_mode
2024-06-21 09:22:38 +02:00
ed6f19d3d8 Fix typo in unicorn_mode
in `unicorn_mode/samples`, python example floder's name is `python_simple`, there is a typo in README file.
2024-06-21 09:52:28 +08:00
aecd157244 nit 2024-06-20 18:49:40 +02:00
43a98b0ec2 todos 2024-06-20 18:49:40 +02:00
3b00cee858 Merge pull request #2130 from killerra/dev
Auto disable memory limits for FASAN
2024-06-20 08:47:20 +02:00
2fbc0aefb1 Auto disable memory limits for FASAN 2024-06-20 00:10:40 +02:00
2276a2f5c3 Merge pull request #2129 from choller/persist-code-cov
Collect persistent coverage data and dump it at the end of the run
2024-06-19 14:09:06 +02:00
8fcca6fb41 Collect persistent coverage data and dump it at the end of the run
With CODE_COVERAGE builds, we need to collect the coverage data of each
iteration in a persistant buffer that has the same size as the regular
trace buffer used for fuzzing. We dump this information at the end of
the run and when combined with pointer data and module info, this can be
used to calculate code coverage.
2024-06-19 12:36:58 +02:00
b8568034f0 code format and changelog 2024-06-18 15:42:34 +02:00
3ebf41ba34 Merge pull request #2128 from AFLplusplus/fastrestart
Fastrestart
2024-06-18 15:28:56 +02:00
304e84502d fast resume option 2024-06-18 15:24:38 +02:00
a6e42d98d9 llvm 19 fixes 2024-06-18 15:09:11 +02:00
de176a10bc nit 2024-06-17 09:31:42 +02:00
e3183f7cda Merge pull request #2125 from visitorckw/fix-libradamsa-signed-integer-overflow
Fix signed integer overflow in radamsa
2024-06-14 08:14:03 +02:00
b5e0fff6b9 Fix signed integer overflow in radamsa
When UBSan was enabled and 'make test' was executed, the following
runtime error was observed:

libradamsa.c:26055:29: runtime error: left shift of 16777215 by 8 places cannot be represented in type 'int'

This issue was caused by a left shift operation on a signed integer.
The fix involved changing the integer literal to an unsigned integer by
adding a 'U' suffix, ensuring the left shift operation produces the
correct value without overflow.

Fixes: 8178f4df ("remove radamsa, add radamsa custom mutator")
2024-06-14 09:53:57 +08:00
36db3428ab Merge pull request #2123 from AFLplusplus/dev
push to stable
2024-06-13 09:20:42 +02:00
e7da8b9d6b Revert "MONOTONIC"
This reverts commit 0c9b460cc4.
2024-06-13 09:19:11 +02:00
c134df30db Merge pull request #2121 from visitorckw/remove-Wno-shift-count-overflow
Remove -Wno-shift-count-overflow flag and hashmap from compilation
2024-06-13 07:57:06 +02:00
b5e6c2d6e2 Remove -Wno-shift-count-overflow flag and hashmap from compilation
After commit 0c9d8e59 ("Fix undefined behavior by casting to uint64_t
before left shift"), the -Wno-shift-count-overflow flag is no longer
necessary to suppress compilation warnings. This commit removes the
flag, allowing the compiler to provide appropriate warnings for any
potential future cases of shifting too many bits.

Additionally, after commit eaf4a299 ("make redqueen hashmap not
default"), the hashmap is no longer in use. Therefore, this commit also
removes the hashmap from the GNUmakefile.
2024-06-13 09:34:03 +08:00
b6f8509234 Merge pull request #2122 from visitorckw/fix-realloc-check
Fix memory allocation check in aflpp custom mutators
2024-06-12 19:27:13 +02:00
d45cd63583 Fix memory allocation check in aflpp custom mutators
The memory allocation check in afl_custom_fuzz function was incorrect.
The condition was erroneously checking if ptr was non-null, whereas it
should return 0 when ptr is null. Correct the condition to properly
handle memory allocation failures.

Fixes: 32ffa266 ("max_len support")
2024-06-13 00:42:12 +08:00
0c9b460cc4 MONOTONIC 2024-06-12 09:17:07 +02:00
dd762726dc fastresume implementation 2024-06-12 09:10:35 +02:00
e68d57feec Merge pull request #2120 from visitorckw/fix-shift-too-many-bits
Fix undefined behavior by casting to uint64_t before left shift
2024-06-12 08:23:14 +02:00
0c9d8e5929 Fix undefined behavior by casting to uint64_t before left shift
According to the C standard, left-shifting a value by an amount greater
than or equal to the width of its promoted type results in undefined
behavior. To prevent potential unexpected results, explicitly cast the
uint8_t variable type to uint64_t before performing the left shift
operation by 56 bits. This ensures the operation is well-defined and
adheres to the standard.

Fixes: 40df85d1 ("adjust cmplog header")
2024-06-12 12:48:13 +08:00
75c3fa91dc update changelog 2024-06-10 22:25:38 +02:00
a37c7e1246 Merge pull request #2119 from WorksButNotTested/frida-persistent
Frida persistent
2024-06-10 22:24:25 +02:00
392dcd57c6 Fixes to build on arm32 2024-06-10 18:16:30 +01:00
1369cf7176 Fixes for arm/arm64 2024-06-10 18:16:30 +01:00
eccd0985a0 Fixes for x86 2024-06-10 18:16:30 +01:00
0617b8898a Update comment 2024-06-10 18:16:30 +01:00
fbcdeb8439 Improve persistent mode 2024-06-10 18:16:30 +01:00
6ed0a2b4aa fast resume setup detection 2024-06-10 18:22:06 +02:00
8e50c0c103 frida verbose 2024-06-10 09:08:44 +02:00
f2cd5e1d8e v4.22a init 2024-06-09 19:15:12 +02:00
262 changed files with 14136 additions and 4478 deletions

View File

@ -21,12 +21,15 @@ import os
# import re # TODO: for future use # import re # TODO: for future use
import shutil import shutil
import importlib.metadata import importlib.metadata
import hashlib
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use # string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use
CURRENT_LLVM = os.getenv('LLVM_VERSION', 17) CURRENT_LLVM = os.getenv('LLVM_VERSION', 18)
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "") CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
FORMAT_CACHE_DIR = '.format-cache'
os.makedirs(FORMAT_CACHE_DIR, exist_ok=True)
def check_clang_format_pip_version(): def check_clang_format_pip_version():
""" """
@ -69,6 +72,8 @@ to install via pip.")
if CLANG_FORMAT_PIP: if CLANG_FORMAT_PIP:
CLANG_FORMAT_BIN = shutil.which("clang-format") CLANG_FORMAT_BIN = shutil.which("clang-format")
CLANG_FORMAT_VERSION = subprocess.check_output([CLANG_FORMAT_BIN, '--version'])
COLUMN_LIMIT = 80 COLUMN_LIMIT = 80
for line in fmt.split("\n"): for line in fmt.split("\n"):
line = line.split(":") line = line.split(":")
@ -86,9 +91,10 @@ def custom_format(filename):
out = "" out = ""
for line in src.split("\n"): for line in src.split("\n"):
define_start = False
if line.lstrip().startswith("#"): if line.lstrip().startswith("#"):
if line[line.find("#") + 1:].lstrip().startswith("define"): if line[line.find("#") + 1:].lstrip().startswith("define"):
in_define = True define_start = True
if ( if (
"/*" in line "/*" in line
@ -126,9 +132,7 @@ def custom_format(filename):
and last_line.strip() != "" and last_line.strip() != ""
): ):
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
in_define = (define_start or in_define) and line.endswith("\\")
if not line.endswith("\\"):
in_define = False
out += line + "\n" out += line + "\n"
last_line = line last_line = line
@ -136,6 +140,38 @@ def custom_format(filename):
return out return out
def hash_code_and_formatter(code):
hasher = hashlib.sha256()
hasher.update(code.encode())
hasher.update(CLANG_FORMAT_VERSION)
with open(__file__, 'rb') as f:
hasher.update(f.read())
return hasher.hexdigest()
def custom_format_cached(filename):
filename_hash = hashlib.sha256(filename.encode()).hexdigest()
cache_file = os.path.join(FORMAT_CACHE_DIR, filename_hash)
if os.path.exists(cache_file):
with open(filename) as f:
code = f.read()
code_hash = hash_code_and_formatter(code)
with open(cache_file) as f:
if f.read() == code_hash:
return code
code = custom_format(filename)
code_hash = hash_code_and_formatter(code)
with open(cache_file, 'w') as f:
f.write(code_hash)
return code
args = sys.argv[1:] args = sys.argv[1:]
if len(args) == 0: if len(args) == 0:
print("Usage: ./format.py [-i] <filename>") print("Usage: ./format.py [-i] <filename>")
@ -151,7 +187,7 @@ if args[0] == "-i":
args = args[1:] args = args[1:]
for filename in args: for filename in args:
code = custom_format(filename) code = custom_format_cached(filename)
if in_place: if in_place:
with open(filename, "w") as f: with open(filename, "w") as f:
f.write(code) f.write(code)

View File

@ -14,18 +14,18 @@ jobs:
runs-on: "${{ matrix.os }}" runs-on: "${{ matrix.os }}"
strategy: strategy:
matrix: matrix:
os: [ubuntu-22.04, ubuntu-20.04] os: [ubuntu-24.04, ubuntu-22.04, ubuntu-24.04-arm]
env: env:
AFL_SKIP_CPUFREQ: 1 AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: update - name: update
run: sudo apt-get update && sudo apt-get upgrade -y run: sudo apt-get update && sudo apt-get upgrade -y
- name: debug - name: debug
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format- run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
- name: install packages - name: install packages
run: sudo apt-get install -y -m -f build-essential gcc-10 g++-10 git libtool libtool-bin automake flex bison libglib2.0-0 clang-12 llvm-12-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-10-plugin-dev run: sudo apt-get install -y -m -f build-essential gcc-12 g++-12 git libtool libtool-bin automake flex bison libglib2.0-0 clang-15 llvm-15-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-12-plugin-dev
- name: compiler installed - name: compiler installed
run: gcc -v; echo; clang -v run: gcc -v; echo; clang -v
- name: install gcc plugin - name: install gcc plugin
@ -34,20 +34,22 @@ jobs:
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-12; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-12 distrib run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-12; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-12 distrib
- name: run tests - name: run tests
run: sudo -E ./afl-system-config; make tests run: sudo -E ./afl-system-config; make tests
# macos: macos:
# runs-on: macOS-latest runs-on: macOS-latest
# env: env:
# AFL_MAP_SIZE: 65536 AFL_MAP_SIZE: 65536
# AFL_SKIP_CPUFREQ: 1 AFL_SKIP_CPUFREQ: 1
# AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
# steps: steps:
# - uses: actions/checkout@v3 - uses: actions/checkout@v3
# - name: install - name: install
# run: brew install make gcc llvm run: brew install make gcc llvm
# - name: fix install # - name: fix install
# run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v # run: cd /usr/local/bin; ln -s gcc-12 gcc; ln -s g++-12 g++; which gcc; gcc -v
# - name: build # - name: build
# run: export PATH=/usr/local/Cellar/llvm/*/":$PATH"; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; sudo -E ./afl-system-config; gmake ASAN_BUILD=1 # run: export PATH=/usr/local/Cellar/llvm/*/":$PATH"; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; sudo -E ./afl-system-config; gmake ASAN_BUILD=1 afl-fuzz
- name: build
run: sudo -E ./afl-system-config; gmake ASAN_BUILD=1 afl-fuzz
# - name: frida # - name: frida
# run: export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; cd frida_mode; gmake # run: export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; cd frida_mode; gmake
# - name: run tests # - name: run tests

View File

@ -16,11 +16,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v3
- name: Build amd64 - name: Build amd64
uses: docker/build-push-action@v3 uses: docker/build-push-action@v6
with: with:
context: . context: .
tags: aflplusplus:test-amd64 tags: aflplusplus:test-amd64
@ -35,20 +35,41 @@ jobs:
apt-get install -y libcmocka-dev && apt-get install -y libcmocka-dev &&
make -i tests make -i tests
" "
build-and-test-arm64:
name: Test arm64 image
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build arm64
uses: docker/build-push-action@v6
with:
context: .
tags: aflplusplus:test-arm64
load: true
cache-to: type=gha,mode=max
build-args: |
TEST_BUILD=1
- name: Test arm64
run: >
docker run --rm aflplusplus:test-arm64 bash -c "
apt-get update &&
apt-get install -y libcmocka-dev &&
make -i tests
"
push: push:
name: Push amd64 and arm64 images name: Push amd64 and arm64 images
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
- build-and-test-amd64 - build-and-test-amd64
- build-and-test-arm64
if: ${{ github.event_name == 'push' && github.repository == 'AFLplusplus/AFLplusplus' }} if: ${{ github.event_name == 'push' && github.repository == 'AFLplusplus/AFLplusplus' }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: arm64
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Login to docker.io - name: Login to docker.io

View File

@ -18,7 +18,7 @@ jobs:
working-directory: custom_mutators/rust working-directory: custom_mutators/rust
strategy: strategy:
matrix: matrix:
os: [ubuntu-22.04, ubuntu-20.04] os: [ubuntu-22.04]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install Rust Toolchain - name: Install Rust Toolchain

4
.gitignore vendored
View File

@ -6,6 +6,8 @@
*.pyc *.pyc
*.so *.so
*.swp *.swp
.DS_Store
.format-cache
.sync_tmp .sync_tmp
.test .test
.test2 .test2
@ -111,3 +113,5 @@ utils/replay_record/persistent_demo_replay_compat
utils/replay_record/persistent_demo_replay_argparse utils/replay_record/persistent_demo_replay_argparse
utils/plot_ui/afl-plot-ui utils/plot_ui/afl-plot-ui
vuln_prog vuln_prog
argv_fuzz_demo
argv_fuzz_persistent_demo

View File

@ -34,6 +34,7 @@ file in one the following folders:
* [docs/](docs/) (this is where you can find most of our docs content) * [docs/](docs/) (this is where you can find most of our docs content)
* [frida_mode/](frida_mode/) * [frida_mode/](frida_mode/)
* [instrumentation/](instrumentation/) * [instrumentation/](instrumentation/)
* [nyx_mode/](nyx_mode/)
* [qemu_mode/](qemu_mode/) * [qemu_mode/](qemu_mode/)
* [unicorn_mode/](unicorn_mode/) * [unicorn_mode/](unicorn_mode/)
@ -47,7 +48,7 @@ When working on the docs, please keep the following guidelines in mind:
* Don't: fuzzing-network-service.md * Don't: fuzzing-network-service.md
* Use a maximum of 80 characters per line to make reading in a console easier. * Use a maximum of 80 characters per line to make reading in a console easier.
* Make all pull requests against `dev`, see * Make all pull requests against `dev`, see
[#how-to-submit-a-pull-request-to-afl](#how-to-submit-a-pull-request-to-afl). [#how-to-submit-a-pull-request](#how-to-submit-a-pull-request).
And finally, here are some best practices for writing docs content: And finally, here are some best practices for writing docs content:

View File

@ -61,6 +61,7 @@ RUN apt-get update && \
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0 && \ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0 && \
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} 0 && \ update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} 0 && \
update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${GCC_VERSION} 0 && \
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 0 && \ update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 0 && \
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_VERSION} 0 update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_VERSION} 0

View File

@ -25,15 +25,15 @@ HELPER_PATH = $(PREFIX)/lib/afl
DOC_PATH = $(PREFIX)/share/doc/afl DOC_PATH = $(PREFIX)/share/doc/afl
MISC_PATH = $(PREFIX)/share/afl MISC_PATH = $(PREFIX)/share/afl
MAN_PATH = $(PREFIX)/share/man/man8 MAN_PATH = $(PREFIX)/share/man/man8
INCLUDE_PATH = $(PREFIX)/include/afl
PROGNAME = afl PROGNAME = afl
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2) VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
# PROGS intentionally omit afl-as, which gets installed elsewhere.
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-cmin.py afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8 HEADERS = include/afl-fuzz.h include/afl-mutations.h include/afl-persistent-replay.h include/afl-prealloc.h include/afl-record-compat.h include/alloc-inl.h include/android-ashmem.h include/cmplog.h include/common.h include/config.h include/coverage-32.h include/coverage-64.h include/debug.h include/envs.h include/forkserver.h include/hash.h include/list.h include/sharedmem.h include/snapshot-inl.h include/t1ha.h include/t1ha0_ia32aes_b.h include/t1ha_bits.h include/t1ha_selfcheck.h include/types.h include/xxhash.h
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
ASAN_OPTIONS=detect_leaks=0 ASAN_OPTIONS=detect_leaks=0
SYS = $(shell uname -s) SYS = $(shell uname -s)
@ -41,10 +41,6 @@ ARCH = $(shell uname -m)
$(info [*] Compiling AFL++ for OS $(SYS) on ARCH $(ARCH)) $(info [*] Compiling AFL++ for OS $(SYS) on ARCH $(ARCH))
ifdef NO_SPLICING
override CFLAGS_OPT += -DNO_SPLICING
endif
ifdef NO_UTF ifdef NO_UTF
override CFLAGS_OPT += -DFANCY_BOXES_NO_UTF override CFLAGS_OPT += -DFANCY_BOXES_NO_UTF
endif endif
@ -65,12 +61,22 @@ ifdef MSAN_BUILD
override CFLAGS += -fsanitize=memory -fno-omit-frame-pointer override CFLAGS += -fsanitize=memory -fno-omit-frame-pointer
override LDFLAGS += -fsanitize=memory override LDFLAGS += -fsanitize=memory
endif endif
ifdef NO_SPLICING
$(info The NO_SPLICING parameter is deprecated)
endif
ifdef CODE_COVERAGE ifdef CODE_COVERAGE
override CFLAGS += -D__AFL_CODE_COVERAGE=1 override CFLAGS += -D__AFL_CODE_COVERAGE=1
endif endif
IS_IOS:=$(findstring ios, $(shell $(CC) --version 2>/dev/null))
ifdef IS_IOS
override CFLAGS += -DTARGET_OS_IPHONE -DTARGET_OS_IOS -isysroot $(IOS_SDK_PATH)
endif
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" "" ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
ifndef ASAN_BUILD
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=full CFLAGS_FLTO ?= -flto=full
else else
@ -83,6 +89,7 @@ else
endif endif
endif endif
endif endif
endif
ifdef PERFORMANCE ifdef PERFORMANCE
SPECIAL_PERFORMANCE := -D_AFL_SPECIAL_PERFORMANCE SPECIAL_PERFORMANCE := -D_AFL_SPECIAL_PERFORMANCE
@ -101,6 +108,7 @@ else
SPECIAL_PERFORMANCE := SPECIAL_PERFORMANCE :=
endif endif
ifndef IS_IOS
ifneq "$(SYS)" "Darwin" ifneq "$(SYS)" "Darwin"
#ifeq "$(HAVE_MARCHNATIVE)" "1" #ifeq "$(HAVE_MARCHNATIVE)" "1"
# SPECIAL_PERFORMANCE += -march=native # SPECIAL_PERFORMANCE += -march=native
@ -113,11 +121,12 @@ else
SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib
override LDFLAGS += $(SDK_LD) override LDFLAGS += $(SDK_LD)
endif endif
endif
COMPILER_TYPE=$(shell $(CC) --version|grep "Free Software Foundation") COMPILER_TYPE=$(shell $(CC) --version|grep "Free Software Foundation")
ifneq "$(COMPILER_TYPE)" "" ifneq "$(COMPILER_TYPE)" ""
#$(info gcc is being used) #$(info gcc is being used)
override CFLAGS_OPT += -Wno-error=format-truncation -Wno-format-truncation override CFLAGS_OPT += -Wno-format-truncation
endif endif
ifeq "$(SYS)" "SunOS" ifeq "$(SYS)" "SunOS"
@ -282,7 +291,7 @@ ifneq "$(findstring OpenBSD, $(SYS))" ""
override LDFLAGS += -lpthread -lm override LDFLAGS += -lpthread -lm
endif endif
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h include/afl-fuzz.h include/hash.h include/sharedmem.h include/forkserver.h include/common.h include/list.h
ifeq "$(shell echo '$(HASH)include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" ifeq "$(shell echo '$(HASH)include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
PYTHON_OK=1 PYTHON_OK=1
@ -306,8 +315,8 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1
endif endif
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD -fno-lto
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -fno-lto
endif endif
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
@ -325,10 +334,12 @@ ifdef TEST_MMAP
endif endif
.PHONY: all .PHONY: all
all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done all: test_x86 test_shm test_python ready $(PROGS) llvm gcc_plugin test_build all_done
-$(MAKE) -C utils/aflpp_driver -$(MAKE) -C utils/aflpp_driver
@echo @echo
@echo @echo
@echo
@echo
@echo Build Summary: @echo Build Summary:
@test -e afl-fuzz && echo "[+] afl-fuzz and supporting tools successfully built" || echo "[-] afl-fuzz could not be built, please set CC to a working compiler" @test -e afl-fuzz && echo "[+] afl-fuzz and supporting tools successfully built" || echo "[-] afl-fuzz could not be built, please set CC to a working compiler"
@test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md" @test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@ -337,6 +348,7 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
ifneq "$(SYS)" "Darwin" ifneq "$(SYS)" "Darwin"
@test -e afl-gcc-pass.so && echo "[+] gcc_mode successfully built" || echo "[-] gcc_mode could not be built, it is optional, install gcc-VERSION-plugin-dev to enable this" @test -e afl-gcc-pass.so && echo "[+] gcc_mode successfully built" || echo "[-] gcc_mode could not be built, it is optional, install gcc-VERSION-plugin-dev to enable this"
endif endif
@test -e afl-cc || echo "[-] AFL++ instrumentation compilers could not be built! Install llvm-VERSION-dev or gcc-VERSION-plugin-dev, see docs/INSTALL.md!"
@echo @echo
.PHONY: llvm .PHONY: llvm
@ -405,7 +417,6 @@ help:
@echo PROFILING - compile afl-fuzz with profiling information @echo PROFILING - compile afl-fuzz with profiling information
@echo INTROSPECTION - compile afl-fuzz with mutation introspection @echo INTROSPECTION - compile afl-fuzz with mutation introspection
@echo NO_PYTHON - disable python support @echo NO_PYTHON - disable python support
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
@echo "NO_UTF - do not use UTF-8 for line rendering in status screen (fallback to G1 box drawing, of vanilla AFL)" @echo "NO_UTF - do not use UTF-8 for line rendering in status screen (fallback to G1 box drawing, of vanilla AFL)"
@echo NO_NYX - disable building nyx mode dependencies @echo NO_NYX - disable building nyx mode dependencies
@echo "NO_CORESIGHT - disable building coresight (arm64 only)" @echo "NO_CORESIGHT - disable building coresight (arm64 only)"
@ -441,6 +452,14 @@ test_shm:
@echo "[-] shmat seems not to be working, switching to mmap implementation" @echo "[-] shmat seems not to be working, switching to mmap implementation"
endif endif
ifeq "$(shell echo '$(HASH)include <zlib.h>@int main() {return 0; }' | tr @ '\n' | $(CC) $(CFLAGS) -Werror -x c - -lz -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
override SPECIAL_PERFORMANCE += -DHAVE_ZLIB
override LDFLAGS += -lz
$(info [+] ZLIB detected)
else
$(info [!] Warning: no ZLIB detected)
endif
.PHONY: test_python .PHONY: test_python
ifeq "$(PYTHON_OK)" "1" ifeq "$(PYTHON_OK)" "1"
test_python: test_python:
@ -455,36 +474,47 @@ endif
ready: ready:
@echo "[+] Everything seems to be working, ready to compile. ($(shell $(CC) --version 2>&1|head -n 1))" @echo "[+] Everything seems to be working, ready to compile. ($(shell $(CC) --version 2>&1|head -n 1))"
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86 src/afl-performance.o: $(COMM_HDR) src/afl-performance.c
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS) $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
@ln -sf afl-as as
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h src/afl-common.o: $(COMM_HDR) src/afl-common.c include/envs.h
$(CC) $(CFLAGS) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-common.c -o src/afl-common.o $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-common.c -o src/afl-common.o
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h src/afl-forkserver.o: $(COMM_HDR) src/afl-forkserver.c
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-forkserver.c -o src/afl-forkserver.o $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-forkserver.c -o src/afl-forkserver.o
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h src/afl-sharedmem.o: $(COMM_HDR) src/afl-sharedmem.c include/android-ashmem.h include/cmplog.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-sharedmem.c -o src/afl-sharedmem.o $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/hashmap.c | test_x86 afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o include/cmplog.h include/envs.h | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -Wno-shift-count-overflow $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/hashmap.c -o $@ $(PYFLAGS) $(LDFLAGS) -lm $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 afl-showmap: src/afl-showmap.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/afl-fuzz-python.o src/afl-fuzz-mutators.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/afl-fuzz-python.o src/afl-fuzz-mutators.o -o $@ $(PYFLAGS) $(LDFLAGS)
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o $(COMM_HDR) | test_x86 afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS) $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS)
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86 afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o -o $@ $(LDFLAGS) $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
.PHONY: document .PHONY: document
document: afl-fuzz-document document: afl-fuzz-document
@ -492,6 +522,9 @@ document: afl-fuzz-document
# document all mutations and only do one run (use with only one input file!) # document all mutations and only do one run (use with only one input file!)
afl-fuzz-document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86 afl-fuzz-document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86
$(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS) $(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES) test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES)
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
@ -499,20 +532,29 @@ test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittes
unit_maybe_alloc: test/unittests/unit_maybe_alloc.o unit_maybe_alloc: test/unittests/unit_maybe_alloc.o
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka @$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_maybe_alloc ./test/unittests/unit_maybe_alloc
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o @$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
unit_hash: test/unittests/unit_hash.o src/afl-performance.o unit_hash: test/unittests/unit_hash.o src/afl-performance.o
@$(CC) $(CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka @$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_hash ./test/unittests/unit_hash
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o @$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka @$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_rand ./test/unittests/unit_rand
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES) test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES)
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
@ -520,6 +562,9 @@ test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list
unit_list: test/unittests/unit_list.o unit_list: test/unittests/unit_list.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_list ./test/unittests/unit_list
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES) test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES)
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
@ -527,6 +572,9 @@ test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unitte
unit_preallocable: test/unittests/unit_preallocable.o unit_preallocable: test/unittests/unit_preallocable.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_preallocable ./test/unittests/unit_preallocable
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
.PHONY: unit_clean .PHONY: unit_clean
unit_clean: unit_clean:
@ -566,27 +614,27 @@ code-format:
.PHONY: test_build .PHONY: test_build
ifndef AFL_NO_X86 ifndef AFL_NO_X86
test_build: afl-cc afl-gcc afl-as afl-showmap test_build: afl-cc afl-showmap
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..." @echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN AFL_LLVM_ALLOWLIST AFL_LLVM_DENYLIST; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
-ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -q -m none -o .test-instr0 ./test-instr < /dev/null -ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -q -m none -o .test-instr0 ./test-instr < /dev/null
-echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr -echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
@rm -f test-instr @rm -f test-instr
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
@echo @echo
@echo "[+] All right, the instrumentation of afl-cc seems to be working!" @echo "[+] All right, the instrumentation of afl-cc seems to be working!"
# @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..." # @echo "[*] Testing the CC wrapper and its instrumentation output..."
# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 ) # @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-clang-fast test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-clang-fast failed"; exit 1 )
# ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null # ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
# echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr # echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
# @rm -f test-instr # @rm -f test-instr
# @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-gcc does not seem to be behaving correctly!"; \ # @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-clang-fast does not seem to be behaving correctly!"; \
# gcc -v 2>&1 | grep -q -- --with-as= && ( echo; echo "Gcc is configured not to use an external assembler with the -B option." ) || \ # gcc -v 2>&1 | grep -q -- --with-as= && ( echo; echo "Gcc is configured not to use an external assembler with the -B option." ) || \
# ( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi # ( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi
# @echo # @echo
# @echo "[+] All right, the instrumentation of afl-gcc seems to be working!" # @echo "[+] All right, the instrumentation of afl-clang-fast seems to be working!"
else else
test_build: afl-cc afl-as afl-showmap test_build: afl-cc afl-showmap
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)." @echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
endif endif
@ -596,7 +644,8 @@ all_done: test_build
@test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to build, likely you either don't have llvm installed, or you need to set LLVM_CONFIG, to point to e.g. llvm-config-11. See instrumentation/README.llvm.md how to do this. Highly recommended!" @test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to build, likely you either don't have llvm installed, or you need to set LLVM_CONFIG, to point to e.g. llvm-config-11. See instrumentation/README.llvm.md how to do this. Highly recommended!"
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it" @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it"
@test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it" @test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it"
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful." @test -e afl-cc && echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
@test -e afl-cc || echo "[-] ERROR - neither afl-clang-fast or afl-gcc-fast could be compiled - YOU ARE MISSING PACKAGES! Read docs/INSTALL.md!"
@if [ "$(SYS)" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi @if [ "$(SYS)" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null @! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
@ -604,7 +653,7 @@ all_done: test_build
.PHONY: clean .PHONY: clean
clean: clean:
rm -rf $(PROGS) afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-cs-proxy afl-qemu-trace afl-gcc-fast afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM lib*.a rm -rf $(PROGS) afl-fuzz-document as afl-as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-cs-proxy afl-qemu-trace afl-gcc-fast afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM lib*.a
-$(MAKE) -f GNUmakefile.llvm clean -$(MAKE) -f GNUmakefile.llvm clean
-$(MAKE) -f GNUmakefile.gcc_plugin clean -$(MAKE) -f GNUmakefile.gcc_plugin clean
-$(MAKE) -C utils/libdislocator clean -$(MAKE) -C utils/libdislocator clean
@ -637,6 +686,7 @@ deepclean: clean
rm -rf unicorn_mode/unicornafl rm -rf unicorn_mode/unicornafl
rm -rf qemu_mode/qemuafl rm -rf qemu_mode/qemuafl
rm -rf nyx_mode/libnyx nyx_mode/packer nyx_mode/QEMU-Nyx rm -rf nyx_mode/libnyx nyx_mode/packer nyx_mode/QEMU-Nyx
rm -rf .format-cache
ifeq "$(IN_REPO)" "1" ifeq "$(IN_REPO)" "1"
git checkout coresight_mode/coresight-trace git checkout coresight_mode/coresight-trace
git checkout unicorn_mode/unicornafl git checkout unicorn_mode/unicornafl
@ -817,10 +867,10 @@ endif
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++ ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang++ ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang++
@mkdir -m 755 -p $${DESTDIR}$(INCLUDE_PATH)
install -m 644 $(HEADERS) $${DESTDIR}$(INCLUDE_PATH)
@mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH) @mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
install -m0644 *.8 ${DESTDIR}$(MAN_PATH) install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH) install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
cp -r testcases/ $${DESTDIR}$(MISC_PATH) cp -r testcases/ $${DESTDIR}$(MISC_PATH)
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH) cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
@ -828,12 +878,14 @@ endif
.PHONY: uninstall .PHONY: uninstall
uninstall: uninstall:
-cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-cs-proxy afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-client afl-network-server afl-g* afl-plot.sh afl-as afl-ld-lto afl-c* afl-lto* -cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-cs-proxy afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-client afl-network-server afl-g* afl-plot.sh afl-ld-lto afl-c* afl-lto*
-cd $${DESTDIR}$(INCLUDE_PATH) && rm -f $(HEADERS:include/%=%)
-cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so libnyx.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a as afl-as SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt injections.dic -cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so libnyx.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a as afl-as SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt injections.dic
-rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries -rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries
-sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f" -sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f"
-cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES) -cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES)
-rmdir $${DESTDIR}$(BIN_PATH) 2>/dev/null -rmdir $${DESTDIR}$(BIN_PATH) 2>/dev/null
-rmdir $${DESTDIR}$(INCLUDE_PATH) 2>/dev/null
-rmdir $${DESTDIR}$(HELPER_PATH) 2>/dev/null -rmdir $${DESTDIR}$(HELPER_PATH) 2>/dev/null
-rmdir $${DESTDIR}$(MISC_PATH) 2>/dev/null -rmdir $${DESTDIR}$(MISC_PATH) 2>/dev/null
-rmdir $${DESTDIR}$(DOC_PATH) 2>/dev/null -rmdir $${DESTDIR}$(DOC_PATH) 2>/dev/null

View File

@ -148,7 +148,7 @@ afl-common.o: ./src/afl-common.c
$(PASSES): instrumentation/afl-gcc-common.h $(PASSES): instrumentation/afl-gcc-common.h
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps ./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ $(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ $(LDFLAGS)
ln -sf afl-cc afl-gcc-fast ln -sf afl-cc afl-gcc-fast
ln -sf afl-cc afl-g++-fast ln -sf afl-cc afl-g++-fast
ln -sf afl-cc.8 afl-gcc-fast.8 ln -sf afl-cc.8 afl-gcc-fast.8
@ -163,7 +163,7 @@ $(PASSES): instrumentation/afl-gcc-common.h
.PHONY: test_build .PHONY: test_build
test_build: $(PROGS) test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..." @echo "[*] Testing the CC wrapper and instrumentation output..."
unset AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ./afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS) unset AFL_USE_ASAN AFL_USE_MSAN AFL_LLVM_ALLOWLIST AFL_LLVM_DENYLIST; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ./afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
@rm -f test-instr @rm -f test-instr

View File

@ -28,10 +28,13 @@ MAN_PATH ?= $(PREFIX)/share/man/man8
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d") BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2) VERSION = $(shell grep '^ *$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
SYS = $(shell uname -s) SYS = $(shell uname -s)
override LLVM_TOO_NEW_DEFAULT := 21
override LLVM_TOO_OLD_DEFAULT := 14
ifeq "$(SYS)" "OpenBSD" ifeq "$(SYS)" "OpenBSD"
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
@ -39,31 +42,43 @@ ifeq "$(SYS)" "OpenBSD"
$(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 13) -> e.g. "pkg_add llvm-7.0.1p9") $(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 13) -> e.g. "pkg_add llvm-7.0.1p9")
endif endif
else else
LLVM_CONFIG ?= llvm-config # Small function to use Bash to detect the latest available clang and clang++ binaries, if using them by that name fails
override _CLANG_VERSIONS_TO_TEST := $(patsubst %,-%,$(shell seq $(LLVM_TOO_NEW_DEFAULT) -1 $(LLVM_TOO_OLD_DEFAULT)))
detect_newest=$(shell for v in "" $(_CLANG_VERSIONS_TO_TEST); do test -n "$$(command -v -- $1$$v)" && { echo "$1$$v"; break; }; done)
LLVM_CONFIG ?= $(call detect_newest,llvm-config)
endif endif
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' ) ifneq "$(LLVM_CONFIG)" ""
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' ) override LLVM_RAW_VER := $(shell $(LLVM_CONFIG) --version 2>/dev/null)
LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' | sed 's/rc.*//' ) LLVMVER := $(subst svn,,$(subst git,,$(LLVM_RAW_VER)))
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[0-2]\.|^3.[0-8]\.' && echo 1 || echo 0 )
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^19|^2[0-9]' && echo 1 || echo 0 ) LLVM_BINDIR := $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
LLVM_TOO_OLD = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[1-9]\.|^1[012]\.' && echo 1 || echo 0 ) LLVM_LIBDIR := $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[0-9]' && echo 1 || echo 0 ) endif
LLVM_NEWER_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[6-9]' && echo 1 || echo 0 )
LLVM_13_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[3-9]' && echo 1 || echo 0 ) ifneq "$(LLVMVER)" ""
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[2-9]' && echo 1 || echo 0 ) LLVM_MAJOR := $(firstword $(subst ., ,$(LLVMVER)))
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null) LLVM_MINOR := $(firstword $(subst ., ,$(subst $(LLVM_MAJOR).,,$(LLVMVER))))
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null) LLVM_TOO_NEW := $(shell test $(LLVM_MAJOR) -gt $(LLVM_TOO_NEW_DEFAULT) && echo 1 || echo 0)
LLVM_STDCXX = gnu++11 LLVM_TOO_OLD := $(shell test $(LLVM_MAJOR) -lt $(LLVM_TOO_OLD_DEFAULT) && echo 1 || echo 0)
LLVM_APPLE_XCODE = $(shell $(CC) -v 2>&1 | grep -q Apple && echo 1 || echo 0) LLVM_NEW_API := $(shell test $(LLVM_MAJOR) -ge 10 && echo 1 || echo 0)
LLVM_LTO = 0 LLVM_NEWER_API := $(shell test $(LLVM_MAJOR) -ge 16 && echo 1 || echo 0)
LLVM_13_OK := $(shell test $(LLVM_MAJOR) -ge 13 && echo 1 || echo 0)
LLVM_HAVE_LTO := $(shell test $(LLVM_MAJOR) -ge 12 && echo 1 || echo 0)
endif
LLVM_STDCXX := gnu++11
LLVM_LTO := 0
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[2-9]\.' && echo 1 || echo 0)
# Uncomment to see the values assigned above
# $(foreach var,_CLANG_VERSIONS_TO_TEST LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
ifeq "$(LLVMVER)" "" ifeq "$(LLVMVER)" ""
$(warning [!] llvm_mode needs llvm-config, which was not found. Set LLVM_CONFIG to its path and retry.) $(warning [!] llvm_mode needs llvm-config, which was not found. Set LLVM_CONFIG to its path and retry.)
endif endif
ifeq "$(LLVM_UNSUPPORTED)" "1" ifeq "$(LLVM_UNSUPPORTED)" "1"
$(error llvm_mode only supports llvm from version 3.8 onwards) $(error llvm_mode only supports llvm from version 3.8 onwards - or your version is too new. Upgrade AFL++ if possible or downgrade LLVM.)
endif endif
ifeq "$(LLVM_TOO_NEW)" "1" ifeq "$(LLVM_TOO_NEW)" "1"
@ -103,10 +118,6 @@ ifeq "$(LLVM_LTO)" "0"
$(info [+] llvm_mode detected llvm < 12, afl-lto LTO will not be build.) $(info [+] llvm_mode detected llvm < 12, afl-lto LTO will not be build.)
endif endif
ifeq "$(LLVM_APPLE_XCODE)" "1"
$(warning llvm_mode will not compile with Xcode clang...)
endif
# We were using llvm-config --bindir to get the location of clang, but # We were using llvm-config --bindir to get the location of clang, but
# this seems to be busted on some distros, so using the one in $PATH is # this seems to be busted on some distros, so using the one in $PATH is
# probably better. # probably better.
@ -114,6 +125,11 @@ endif
CC = $(LLVM_BINDIR)/clang CC = $(LLVM_BINDIR)/clang
CXX = $(LLVM_BINDIR)/clang++ CXX = $(LLVM_BINDIR)/clang++
LLVM_APPLE_XCODE := $(shell $(CC) -v 2>&1 | grep -q Apple && echo 1 || echo 0)
ifeq "$(LLVM_APPLE_XCODE)" "1"
$(warning llvm_mode will not compile with Xcode clang...)
endif
# llvm-config --bindir may not providing a valid path, so ... # llvm-config --bindir may not providing a valid path, so ...
ifeq "$(shell test -e $(CC) || echo 1 )" "1" ifeq "$(shell test -e $(CC) || echo 1 )" "1"
# however we must ensure that this is not a "CC=gcc make" # however we must ensure that this is not a "CC=gcc make"
@ -147,7 +163,7 @@ endif
# sanity check. # sanity check.
# Are versions of clang --version and llvm-config --version equal? # Are versions of clang --version and llvm-config --version equal?
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p') CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ ([12]?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
# I disable this because it does not make sense with what we did before (marc) # I disable this because it does not make sense with what we did before (marc)
# We did exactly set these 26 lines above with these values, and it would break # We did exactly set these 26 lines above with these values, and it would break
@ -221,9 +237,10 @@ ifeq "$(LLVM_LTO)" "1"
ifeq "$(AFL_REAL_LD)" "" ifeq "$(AFL_REAL_LD)" ""
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" "" ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
else ifneq "$(shell command -v ld.lld 2>/dev/null)" "" else
ifneq "$(shell command -v ld.lld 2>/dev/null)" ""
AFL_REAL_LD = $(shell command -v ld.lld) AFL_REAL_LD = $(shell command -v ld.lld)
TMP_LDLDD_VERSION = $(shell $(AFL_REAL_LD) --version | awk '{ print $$2 }') TMP_LDLDD_VERSION = $(shell $(AFL_REAL_LD) --version | sed -E -ne '/^.*LLD\ ([12]?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
ifeq "$(LLVMVER)" "$(TMP_LDLDD_VERSION)" ifeq "$(LLVMVER)" "$(TMP_LDLDD_VERSION)"
$(warning ld.lld found in a weird location ($(AFL_REAL_LD)), but its the same version as LLVM so we will allow it) $(warning ld.lld found in a weird location ($(AFL_REAL_LD)), but its the same version as LLVM so we will allow it)
else else
@ -231,12 +248,12 @@ ifeq "$(LLVM_LTO)" "1"
AFL_REAL_LD= AFL_REAL_LD=
LLVM_LTO = 0 LLVM_LTO = 0
endif endif
undefine TMP_LDLDD_VERSION
else else
$(warning ld.lld not found, cannot enable LTO mode) $(warning ld.lld not found, cannot enable LTO mode)
LLVM_LTO = 0 LLVM_LTO = 0
endif endif
endif endif
endif
else else
$(warning clang option -flto is not working - maybe LLVMgold.so not found - cannot enable LTO mode) $(warning clang option -flto is not working - maybe LLVMgold.so not found - cannot enable LTO mode)
LLVM_LTO = 0 LLVM_LTO = 0
@ -245,7 +262,7 @@ endif
AFL_CLANG_FUSELD= AFL_CLANG_FUSELD=
ifeq "$(LLVM_LTO)" "1" ifeq "$(LLVM_LTO)" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=$$(command -v ld) -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FUSELD=1 AFL_CLANG_FUSELD=1
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(AFL_REAL_LD) -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(AFL_REAL_LD) -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_LDPATH=1 AFL_CLANG_LDPATH=1
@ -256,11 +273,7 @@ ifeq "$(LLVM_LTO)" "1"
endif endif
endif endif
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fdebug-prefix-map=$(CURDIR)=llvm_mode -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" IS_IOS := $(findstring ios, $(shell $(CC) --version 2>/dev/null))
AFL_CLANG_DEBUG_PREFIX = -fdebug-prefix-map="$(CURDIR)=llvm_mode"
else
AFL_CLANG_DEBUG_PREFIX =
endif
CFLAGS ?= -O3 -funroll-loops -fPIC CFLAGS ?= -O3 -funroll-loops -fPIC
# -D_FORTIFY_SOURCE=1 # -D_FORTIFY_SOURCE=1
@ -272,11 +285,15 @@ CFLAGS_SAFE := -Wall -g -Wno-cast-qual -Wno-variadic-macros -Wno-pointer-sig
-DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \ -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \
-DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \ -DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
-DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) \ -DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) \
-Wno-unused-function $(AFL_CLANG_DEBUG_PREFIX) -Wno-unused-function
ifndef LLVM_DEBUG ifndef LLVM_DEBUG
CFLAGS_SAFE += -Wno-deprecated CFLAGS_SAFE += -Wno-deprecated
endif endif
ifdef IOS_SDK_PATH
override CFLAGS_SAFE += -isysroot $(IOS_SDK_PATH)
endif
ifdef CODE_COVERAGE ifdef CODE_COVERAGE
override CFLAGS_SAFE += -D__AFL_CODE_COVERAGE=1 override CFLAGS_SAFE += -D__AFL_CODE_COVERAGE=1
override LDFLAGS += -ldl override LDFLAGS += -ldl
@ -294,14 +311,18 @@ override CXXFLAGS += -Wall -g -I ./include/ \
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros -Wno-deprecated-copy-with-dtor \ -DVERSION=\"$(VERSION)\" -Wno-variadic-macros -Wno-deprecated-copy-with-dtor \
-DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR) -DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR)
ifdef IOS_SDK_PATH
override CXXFLAGS += -isysroot $(IOS_SDK_PATH)
endif
ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" "" ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" ""
CLANG_CFL = -I$(shell $(LLVM_CONFIG) --includedir) CLANG_CFL = -I$(shell $(LLVM_CONFIG) --includedir)
endif endif
ifneq "$(LLVM_CONFIG)" "" ifneq "$(LLVM_CONFIG)" ""
CLANG_CFL += -I$(shell dirname $(LLVM_CONFIG))/../include CLANG_CFL += -I$(shell dirname $(LLVM_CONFIG))/../include
endif endif
CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fno-exceptions -fPIC $(CXXFLAGS) $(CPPFLAGS) -Wno-deprecated-declarations CLANG_CPPFL = $$($(LLVM_CONFIG) --cxxflags) -fno-rtti -fno-exceptions -fPIC $(CXXFLAGS) $(CPPFLAGS) -Wno-deprecated-declarations
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS) CLANG_LFL = $$($(LLVM_CONFIG) --ldflags) $(LDFLAGS)
# wasm fuzzing: disable thread-local storage and unset LLVM debug flag # wasm fuzzing: disable thread-local storage and unset LLVM debug flag
ifdef WAFL_MODE ifdef WAFL_MODE
@ -311,7 +332,7 @@ endif
# User teor2345 reports that this is required to make things work on MacOS X. # User teor2345 reports that this is required to make things work on MacOS X.
ifeq "$(SYS)" "Darwin" ifeq "$(SYS)" "Darwin"
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress CLANG_LFL += -Wl,-undefined,dynamic_lookup
override LLVM_HAVE_LTO := 0 override LLVM_HAVE_LTO := 0
override LLVM_LTO := 0 override LLVM_LTO := 0
else else
@ -319,7 +340,7 @@ else
endif endif
ifeq "$(SYS)" "OpenBSD" ifeq "$(SYS)" "OpenBSD"
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so CLANG_LFL += $(LLVM_LIBDIR)/libLLVM.so
CLANG_CPPFL += -mno-retpoline CLANG_CPPFL += -mno-retpoline
CFLAGS += -mno-retpoline CFLAGS += -mno-retpoline
# Needed for unwind symbols # Needed for unwind symbols
@ -415,29 +436,44 @@ ifeq "$(LLVM_LTO)" "1"
@ln -sf afl-cc ./afl-lto++ @ln -sf afl-cc ./afl-lto++
endif endif
endif endif
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h
$(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@ $(CXX) $(CFLAGS) $(CPPFLAGS) $$($(LLVM_CONFIG) --cxxflags) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps ./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
ifeq "$(LLVM_MIN_4_0_1)" "0" ifeq "$(LLVM_MIN_4_0_1)" "0"
$(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER)) $(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER))
endif endif
$(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps ./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
ifeq "$(LLVM_13_OK)" "1" ifeq "$(LLVM_13_OK)" "1"
-$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o -$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
endif endif
./afl-llvm-lto-instrumentlist.so: instrumentation/afl-llvm-lto-instrumentlist.so.cc instrumentation/afl-llvm-common.o ./afl-llvm-lto-instrumentlist.so: instrumentation/afl-llvm-lto-instrumentlist.so.cc instrumentation/afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1" ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
endif endif
./afl-ld-lto: src/afl-ld-lto.c ./afl-ld-lto: src/afl-ld-lto.c
ifeq "$(LLVM_LTO)" "1" ifeq "$(LLVM_LTO)" "1"
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LDFLAGS)
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
endif endif
./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc instrumentation/afl-llvm-common.o ./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc instrumentation/afl-llvm-common.o
@ -446,31 +482,58 @@ ifeq "$(LLVM_LTO)" "1"
$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o $(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi @$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi @$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
endif endif
# laf # laf
./split-switches-pass.so: instrumentation/split-switches-pass.so.cc instrumentation/afl-llvm-common.o | test_deps ./split-switches-pass.so: instrumentation/split-switches-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
./compare-transform-pass.so: instrumentation/compare-transform-pass.so.cc instrumentation/afl-llvm-common.o | test_deps ./compare-transform-pass.so: instrumentation/compare-transform-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
./split-compares-pass.so: instrumentation/split-compares-pass.so.cc instrumentation/afl-llvm-common.o | test_deps ./split-compares-pass.so: instrumentation/split-compares-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
# /laf # /laf
./cmplog-routines-pass.so: instrumentation/cmplog-routines-pass.cc instrumentation/afl-llvm-common.o | test_deps ./cmplog-routines-pass.so: instrumentation/cmplog-routines-pass.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps ./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
./cmplog-switches-pass.so: instrumentation/cmplog-switches-pass.cc instrumentation/afl-llvm-common.o | test_deps ./cmplog-switches-pass.so: instrumentation/cmplog-switches-pass.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
./injection-pass.so: instrumentation/injection-pass.cc instrumentation/afl-llvm-common.o | test_deps ./injection-pass.so: instrumentation/injection-pass.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
.PHONY: document .PHONY: document
document: document:
@ -492,7 +555,10 @@ document:
.PHONY: test_build .PHONY: test_build
test_build: $(PROGS) test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..." @echo "[*] Testing the CC wrapper and instrumentation output..."
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS) unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO AFL_LLVM_ALLOWLIST AFL_LLVM_DENYLIST; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
ifdef IS_IOS
@ldid -Sentitlements.plist test-instr && echo "[+] Signed test-instr" || echo "[-] Failed to sign test-instr"
endif
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
@rm -f test-instr @rm -f test-instr

View File

@ -1,10 +1,10 @@
# American Fuzzy Lop plus plus (AFL++) # American Fuzzy Lop plus plus (AFL++)
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/main/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250"> <img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/main/static/aflpp_bg.svg" alt="AFL++ logo" width="250" height="250">
Release version: [4.21c](https://github.com/AFLplusplus/AFLplusplus/releases) Release version: [4.32c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 4.21c GitHub version: 4.33a
Repository: Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@ -16,7 +16,6 @@ AFL++ is maintained by:
* Andrea Fioraldi <andreafioraldi@gmail.com> * Andrea Fioraldi <andreafioraldi@gmail.com>
* Heiko "hexcoder-" Eissfeldt <heiko.eissfeldt@hexco.de> * Heiko "hexcoder-" Eissfeldt <heiko.eissfeldt@hexco.de>
* frida_mode is maintained by @Worksbutnottested * frida_mode is maintained by @Worksbutnottested
* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
Originally developed by Michal "lcamtuf" Zalewski. Originally developed by Michal "lcamtuf" Zalewski.
@ -230,6 +229,8 @@ Thank you! (For people sending pull requests - please add yourself to this list
Ruben ten Hove Joey Jiao Ruben ten Hove Joey Jiao
fuzzah @intrigus-lgtm fuzzah @intrigus-lgtm
Yaakov Saxon Sergej Schumilo Yaakov Saxon Sergej Schumilo
Ziqiao Kong Ryan Berger
Sangjun Park Scott Guest
``` ```
</details> </details>
@ -258,3 +259,5 @@ presented at WOOT'20:
``` ```
</details> </details>
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/AFLplusplus/AFLplusplus)

View File

@ -2,7 +2,8 @@
## Must ## Must
- fast restart of afl-fuzz if cmdline + target hash is the same - afl_fsrv_deinit cmplog
- ijon support?
- check for null ptr for xml/curl/g_ string transform functions - check for null ptr for xml/curl/g_ string transform functions
- hardened_usercopy=0 page_alloc.shuffle=0 - hardened_usercopy=0 page_alloc.shuffle=0
- add value_profile but only enable after 15 minutes without finds - add value_profile but only enable after 15 minutes without finds

View File

@ -1,12 +1,19 @@
#!/usr/bin/env sh #!/usr/bin/env sh
THISPATH=`dirname ${0}`
# call afl-cmin.py if it can be executed successfully.
if $THISPATH/afl-cmin.py --help > /dev/null 2>&1; then
exec $THISPATH/afl-cmin.py "$@"
fi
SYS=$(uname -s) SYS=$(uname -s)
test "$SYS" = "Darwin" && { test "$SYS" = "Darwin" && {
echo Error: afl-cmin does not work on Apple currently. please use afl-cmin.bash instead. echo Error: afl-cmin does not work on Apple currently. please use afl-cmin.bash instead.
exit 1 exit 1
} }
export AFL_QUIET=1 export AFL_QUIET=1
export ASAN_OPTIONS=detect_leaks=0 export ASAN_OPTIONS=detect_leaks=0
THISPATH=`dirname ${0}`
export PATH="${THISPATH}:$PATH" export PATH="${THISPATH}:$PATH"
awk -f - -- ${@+"$@"} <<'EOF' awk -f - -- ${@+"$@"} <<'EOF'
#!/usr/bin/awk -f #!/usr/bin/awk -f
@ -331,7 +338,7 @@ BEGIN {
} }
if (0 == system ( "grep -aq AFL_DUMP_MAP_SIZE " target_bin )) { if (0 == system ( "grep -aq AFL_DUMP_MAP_SIZE " target_bin )) {
echo "[!] Trying to obtain the map size of the target ..." print "[!] Trying to obtain the map size of the target ..."
get_map_size = "AFL_DUMP_MAP_SIZE=1 " target_bin get_map_size = "AFL_DUMP_MAP_SIZE=1 " target_bin
get_map_size | getline mapsize get_map_size | getline mapsize
close(get_map_size) close(get_map_size)
@ -432,7 +439,7 @@ BEGIN {
} else { } else {
stat_format = "-f '%z %N'" # *BSD, MacOS stat_format = "-f '%z %N'" # *BSD, MacOS
} }
cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r) | grep -Ev '^0'" cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o \\( -type f -a ! -name \"cmdline\" -a ! -name \"fastresume.bin\" -a ! -name \"fuzz_bitmap\" -a ! -name \"fuzzer_setup\" -a ! -name \"fuzzer_stats\" -a ! -name \"plot_data\" -a ! -name \"target_hash\" \\) -exec stat "stat_format" \\{\\} + | sort -k1n -k2r) | grep -Ev '^0'"
#cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r" #cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
#cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r"
#cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r"

760
afl-cmin.py Executable file
View File

@ -0,0 +1,760 @@
#!/usr/bin/env python3
# Copyright 2016-2025 Google Inc.
# Copyright 2025 AFLplusplus Project. All rights reserved.
#
# 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
#
# http://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.
#
import argparse
import array
import base64
import collections
import glob
import hashlib
import itertools
import logging
import multiprocessing
import os
import shutil
import subprocess
import sys
# https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/recipes.html#batched
from sys import hexversion
def _batched(iterable, n, *, strict=False):
"""Batch data into tuples of length *n*. If the number of items in
*iterable* is not divisible by *n*:
* The last batch will be shorter if *strict* is ``False``.
* :exc:`ValueError` will be raised if *strict* is ``True``.
>>> list(batched('ABCDEFG', 3))
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]
On Python 3.13 and above, this is an alias for :func:`itertools.batched`.
"""
if n < 1:
raise ValueError('n must be at least one')
iterator = iter(iterable)
while batch := tuple(itertools.islice(iterator, n)):
if strict and len(batch) != n:
raise ValueError('batched(): incomplete batch')
yield batch
if hexversion >= 0x30D00A2: # pragma: no cover
from itertools import batched as itertools_batched
def batched(iterable, n, *, strict=False):
return itertools_batched(iterable, n, strict=strict)
else:
batched = _batched
batched.__doc__ = _batched.__doc__
try:
from tqdm import tqdm
except ImportError:
print('Hint: install python module "tqdm" to show progress bar')
class tqdm:
def __init__(self, data=None, *args, **argd):
self.data = data
def __iter__(self):
yield from self.data
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
def update(self, *args):
pass
parser = argparse.ArgumentParser()
cpu_count = multiprocessing.cpu_count()
group = parser.add_argument_group("Required parameters")
group.add_argument(
"-i",
dest="input",
action="append",
metavar="dir",
required=True,
help="input directory with the starting corpus",
)
group.add_argument(
"-o",
dest="output",
metavar="dir",
required=True,
help="output directory for minimized files",
)
group = parser.add_argument_group("Execution control settings")
group.add_argument(
"-f",
dest="stdin_file",
metavar="file",
help="location read by the fuzzed program (stdin)",
)
group.add_argument(
"-m",
dest="memory_limit",
default="none",
metavar="megs",
type=lambda x: x if x == "none" else int(x),
help="memory limit for child process (default: %(default)s)",
)
group.add_argument(
"-t",
dest="time_limit",
default=5000,
metavar="msec",
type=lambda x: x if x == "none" else int(x),
help="timeout for each run (default: %(default)s)",
)
group.add_argument(
"-O",
dest="frida_mode",
action="store_true",
default=False,
help="use binary-only instrumentation (FRIDA mode)",
)
group.add_argument(
"-Q",
dest="qemu_mode",
action="store_true",
default=False,
help="use binary-only instrumentation (QEMU mode)",
)
group.add_argument(
"-U",
dest="unicorn_mode",
action="store_true",
default=False,
help="use unicorn-based instrumentation (Unicorn mode)",
)
group.add_argument(
"-X", dest="nyx_mode", action="store_true", default=False, help="use Nyx mode"
)
group = parser.add_argument_group("Minimization settings")
group.add_argument(
"--crash-dir",
dest="crash_dir",
metavar="dir",
default=None,
help="move crashes to a separate dir, always deduplicated",
)
group.add_argument(
"-A",
dest="allow_any",
action="store_true",
help="allow crashes and timeouts (not recommended)",
)
group.add_argument(
"-C",
dest="crash_only",
action="store_true",
help="keep crashing inputs, reject everything else",
)
group.add_argument(
"-e",
dest="edge_mode",
action="store_true",
default=False,
help="solve for edge coverage only, ignore hit counts",
)
group = parser.add_argument_group("Misc")
group.add_argument(
"-T",
dest="workers",
type=lambda x: cpu_count if x == "all" else int(x),
default=1,
help="number of concurrent worker (default: %(default)d)",
)
group.add_argument(
"--as_queue",
action="store_true",
help='output file name like "id:000000,hash:value"',
)
group.add_argument(
"--no-dedup", action="store_true", help="skip deduplication step for corpus files"
)
group.add_argument("--debug", action="store_true")
parser.add_argument("exe", metavar="/path/to/target_app")
parser.add_argument("args", nargs="*")
args = parser.parse_args()
logger = None
afl_showmap_bin = None
tuple_index_type_code = "I"
file_index_type_code = None
def init():
global logger
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
if args.stdin_file and args.workers > 1:
logger.error("-f is only supported with one worker (-T 1)")
sys.exit(1)
if args.memory_limit != "none" and args.memory_limit < 5:
logger.error("dangerously low memory limit")
sys.exit(1)
if args.time_limit != "none" and args.time_limit < 10:
logger.error("dangerously low timeout")
sys.exit(1)
if not os.path.isfile(args.exe):
logger.error('binary "%s" not found or not regular file', args.exe)
sys.exit(1)
if not os.environ.get("AFL_SKIP_BIN_CHECK") and not any(
[args.qemu_mode, args.frida_mode, args.unicorn_mode, args.nyx_mode]
):
if b"__AFL_SHM_ID" not in open(args.exe, "rb").read():
logger.error("binary '%s' doesn't appear to be instrumented", args.exe)
sys.exit(1)
for dn in args.input:
if not os.path.isdir(dn) and not glob.glob(dn):
logger.error('directory "%s" not found', dn)
sys.exit(1)
global afl_showmap_bin
searches = [
None,
os.path.dirname(__file__),
os.getcwd(),
]
if os.environ.get("AFL_PATH"):
searches.append(os.environ["AFL_PATH"])
for search in searches:
afl_showmap_bin = shutil.which("afl-showmap", path=search)
if afl_showmap_bin:
break
if not afl_showmap_bin:
logger.fatal("cannot find afl-showmap, please set AFL_PATH")
sys.exit(1)
trace_dir = os.path.join(args.output, ".traces")
shutil.rmtree(trace_dir, ignore_errors=True)
try:
os.rmdir(args.output)
except OSError:
pass
if os.path.exists(args.output):
logger.error(
'directory "%s" exists and is not empty - delete it first', args.output
)
sys.exit(1)
if args.crash_dir and not os.path.exists(args.crash_dir):
os.makedirs(args.crash_dir)
os.makedirs(trace_dir)
logger.info("use %d workers (-T)", args.workers)
def detect_type_code(size):
for type_code in ["B", "H", "I", "L", "Q"]:
if 256 ** array.array(type_code).itemsize > size:
return type_code
def afl_showmap(input_path=None, batch=None, afl_map_size=None, first=False):
assert input_path or batch
# yapf: disable
cmd = [
afl_showmap_bin,
'-m', str(args.memory_limit),
'-t', str(args.time_limit),
'-Z', # cmin mode
]
# yapf: enable
found_atat = False
for arg in args.args:
if "@@" in arg:
found_atat = True
if args.stdin_file:
assert args.workers == 1
input_from_file = True
stdin_file = args.stdin_file
cmd += ["-H", stdin_file]
elif found_atat:
input_from_file = True
stdin_file = os.path.join(args.output, f".input.{os.getpid()}")
cmd += ["-H", stdin_file]
else:
input_from_file = False
if batch:
input_from_file = True
filelist = os.path.join(args.output, f".filelist.{os.getpid()}")
with open(filelist, "w") as f:
for _, path in batch:
f.write(path + "\n")
cmd += ["-I", filelist]
output_path = os.path.join(args.output, f".showmap.{os.getpid()}")
cmd += ["-o", output_path]
else:
if input_from_file:
shutil.copy(input_path, stdin_file)
cmd += ["-o", "-"]
if args.frida_mode:
cmd += ["-O"]
if args.qemu_mode:
cmd += ["-Q"]
if args.unicorn_mode:
cmd += ["-U"]
if args.nyx_mode:
cmd += ["-X"]
if args.edge_mode:
cmd += ["-e"]
cmd += ["--", args.exe] + args.args
env = os.environ.copy()
env["AFL_QUIET"] = "1"
env["ASAN_OPTIONS"] = "detect_leaks=0"
if first:
logger.debug("run command line: %s", subprocess.list2cmdline(cmd))
env["AFL_CMIN_ALLOW_ANY"] = "1"
if afl_map_size:
env["AFL_MAP_SIZE"] = str(afl_map_size)
if args.crash_only:
env["AFL_CMIN_CRASHES_ONLY"] = "1"
if args.allow_any:
env["AFL_CMIN_ALLOW_ANY"] = "1"
if input_from_file:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env, bufsize=1048576)
else:
p = subprocess.Popen(
cmd,
stdin=open(input_path, "rb"),
stdout=subprocess.PIPE,
env=env,
bufsize=1048576,
)
out = p.stdout.read()
p.wait()
if batch:
result = []
for idx, input_path in batch:
basename = os.path.basename(input_path)
values = []
try:
trace_file = os.path.join(output_path, basename)
with open(trace_file, "r") as f:
values = list(map(int, f))
crashed = len(values) == 0
os.unlink(trace_file)
except FileNotFoundError:
a = None
crashed = True
values = [(t // 1000) * 9 + t % 1000 for t in values]
a = array.array(tuple_index_type_code, values)
result.append((idx, a, crashed))
os.unlink(filelist)
os.rmdir(output_path)
return result
else:
values = []
for line in out.split():
if not line.isdigit():
continue
values.append(int(line))
values = [(t // 1000) * 9 + t % 1000 for t in values]
a = array.array(tuple_index_type_code, values)
crashed = p.returncode in [2, 3]
if input_from_file and stdin_file != args.stdin_file:
os.unlink(stdin_file)
return a, crashed
class JobDispatcher(multiprocessing.Process):
def __init__(self, job_queue, jobs):
super().__init__()
self.job_queue = job_queue
self.jobs = jobs
def run(self):
for job in self.jobs:
self.job_queue.put(job)
self.job_queue.close()
class Worker(multiprocessing.Process):
def __init__(self, idx, afl_map_size, q_in, p_out, r_out):
super().__init__()
self.idx = idx
self.afl_map_size = afl_map_size
self.q_in = q_in
self.p_out = p_out
self.r_out = r_out
def run(self):
map_size = self.afl_map_size or 65536
max_tuple = map_size * 9
max_file_index = 256 ** array.array(file_index_type_code).itemsize - 1
m = array.array(file_index_type_code, [max_file_index] * max_tuple)
counter = collections.Counter()
crashes = []
pack_name = os.path.join(args.output, ".traces", f"{self.idx}.pack")
pack_pos = 0
with open(pack_name, "wb") as trace_pack:
while True:
batch = self.q_in.get()
if batch is None:
break
for idx, r, crash in afl_showmap(
batch=batch, afl_map_size=self.afl_map_size
):
counter.update(r)
used = False
if crash:
crashes.append(idx)
# If we aren't saving crashes to a separate dir, handle them
# the same as other inputs. However, unless AFL_CMIN_ALLOW_ANY=1,
# afl_showmap will not return any coverage for crashes so they will
# never be retained.
if not crash or not args.crash_dir:
for t in r:
if idx < m[t]:
m[t] = idx
used = True
if used:
tuple_count = len(r)
r.tofile(trace_pack)
self.p_out.put((idx, self.idx, pack_pos, tuple_count))
pack_pos += tuple_count * r.itemsize
else:
self.p_out.put(None)
self.r_out.put((self.idx, m, counter, crashes))
class CombineTraceWorker(multiprocessing.Process):
def __init__(self, pack_name, jobs, r_out):
super().__init__()
self.pack_name = pack_name
self.jobs = jobs
self.r_out = r_out
def run(self):
already_have = set()
with open(self.pack_name, "rb") as f:
for pos, tuple_count in self.jobs:
f.seek(pos)
result = array.array(tuple_index_type_code)
result.fromfile(f, tuple_count)
already_have.update(result)
self.r_out.put(already_have)
def hash_file(path):
m = hashlib.sha1()
with open(path, "rb") as f:
m.update(f.read())
return m.digest()
def dedup(files):
with multiprocessing.Pool(args.workers) as pool:
seen_hash = set()
result = []
hash_list = []
# use large chunksize to reduce multiprocessing overhead
chunksize = max(1, min(256, len(files) // args.workers))
for i, h in enumerate(
tqdm(
pool.imap(hash_file, files, chunksize),
desc="dedup",
total=len(files),
ncols=0,
leave=(len(files) > 100000),
)
):
if h in seen_hash:
continue
seen_hash.add(h)
result.append(files[i])
hash_list.append(h)
return result, hash_list
def is_afl_dir(dirnames, filenames):
return (
"queue" in dirnames
and "hangs" in dirnames
and "crashes" in dirnames
and "fuzzer_setup" in filenames
)
def collect_files(input_paths):
paths = []
for s in input_paths:
paths += glob.glob(s)
files = []
with tqdm(desc="search", unit=" files", ncols=0) as pbar:
for path in paths:
for root, dirnames, filenames in os.walk(path, followlinks=True):
for dirname in dirnames:
if dirname.startswith("."):
dirnames.remove(dirname)
if not args.crash_only and is_afl_dir(dirnames, filenames):
continue
for filename in filenames:
if filename.startswith("."):
continue
pbar.update(1)
files.append(os.path.join(root, filename))
return files
def main():
init()
files = collect_files(args.input)
if len(files) == 0:
logger.error("no inputs in the target directory - nothing to be done")
sys.exit(1)
logger.info("Found %d input files in %d directories", len(files), len(args.input))
if not args.no_dedup:
files, hash_list = dedup(files)
logger.info("Remain %d files after dedup", len(files))
else:
logger.info("Skipping file deduplication.")
global file_index_type_code
file_index_type_code = detect_type_code(len(files))
logger.info("Sorting files.")
with multiprocessing.Pool(args.workers) as pool:
chunksize = max(1, min(512, len(files) // args.workers))
size_list = list(pool.map(os.path.getsize, files, chunksize))
idxes = sorted(range(len(files)), key=lambda x: size_list[x])
files = [files[idx] for idx in idxes]
hash_list = [hash_list[idx] for idx in idxes]
afl_map_size = None
if b"AFL_DUMP_MAP_SIZE" in open(args.exe, "rb").read():
output = subprocess.run(
[args.exe], capture_output=True, env={"AFL_DUMP_MAP_SIZE": "1", "ASAN_OPTIONS": "detect_leaks=0"}
).stdout
afl_map_size = int(output)
logger.info("Setting AFL_MAP_SIZE=%d", afl_map_size)
global tuple_index_type_code
tuple_index_type_code = detect_type_code(afl_map_size * 9)
logger.info("Testing the target binary")
tuples, _ = afl_showmap(files[0], afl_map_size=afl_map_size, first=True)
if tuples:
logger.info("ok, %d tuples recorded", len(tuples))
else:
logger.error("no instrumentation output detected")
sys.exit(1)
job_queue = multiprocessing.Queue()
progress_queue = multiprocessing.Queue()
result_queue = multiprocessing.Queue()
workers = []
for i in range(args.workers):
p = Worker(i, afl_map_size, job_queue, progress_queue, result_queue)
p.start()
workers.append(p)
chunk = max(1, min(128, len(files) // args.workers))
jobs = list(batched(enumerate(files), chunk))
jobs += [None] * args.workers # sentinel
dispatcher = JobDispatcher(job_queue, jobs)
dispatcher.start()
logger.info("Processing traces")
effective = 0
trace_info = {}
for _ in tqdm(files, ncols=0, smoothing=0.01):
r = progress_queue.get()
if r is not None:
idx, worker_idx, pos, tuple_count = r
trace_info[idx] = worker_idx, pos, tuple_count
effective += 1
dispatcher.join()
logger.info("Obtaining trace results")
ms = []
crashes = []
counter = collections.Counter()
for _ in tqdm(range(args.workers), ncols=0):
idx, m, c, crs = result_queue.get()
ms.append(m)
counter.update(c)
crashes.extend(crs)
workers[idx].join()
best_idxes = list(map(min, zip(*ms)))
if not args.crash_dir:
logger.info(
"Found %d unique tuples across %d files (%d effective)",
len(counter),
len(files),
effective,
)
else:
logger.info(
"Found %d unique tuples across %d files (%d effective, %d crashes)",
len(counter),
len(files),
effective,
len(crashes),
)
all_unique = counter.most_common()
logger.info("Processing candidates and writing output")
already_have = set()
count = 0
def save_file(idx):
input_path = files[idx]
fn = (
base64.b16encode(hash_list[idx]).decode("utf8").lower()
if not args.no_dedup
else os.path.basename(input_path)
)
if args.as_queue:
if args.no_dedup:
fn = "id:%06d,orig:%s" % (count, fn)
else:
fn = "id:%06d,hash:%s" % (count, fn)
output_path = os.path.join(args.output, fn)
try:
os.link(input_path, output_path)
except OSError:
shutil.copy(input_path, output_path)
jobs = [[] for i in range(args.workers)]
saved = set()
for t, c in all_unique:
if c != 1:
continue
idx = best_idxes[t]
if idx in saved:
continue
save_file(idx)
saved.add(idx)
count += 1
worker_idx, pos, tuple_count = trace_info[idx]
job = (pos, tuple_count)
jobs[worker_idx].append(job)
trace_packs = []
workers = []
for i in range(args.workers):
pack_name = os.path.join(args.output, ".traces", f"{i}.pack")
trace_f = open(pack_name, "rb")
trace_packs.append(trace_f)
p = CombineTraceWorker(pack_name, jobs[i], result_queue)
p.start()
workers.append(p)
for _ in range(args.workers):
result = result_queue.get()
already_have.update(result)
for t, c in tqdm(list(reversed(all_unique)), ncols=0):
if t in already_have:
continue
idx = best_idxes[t]
save_file(idx)
count += 1
worker_idx, pos, tuple_count = trace_info[idx]
trace_pack = trace_packs[worker_idx]
trace_pack.seek(pos)
result = array.array(tuple_index_type_code)
result.fromfile(trace_pack, tuple_count)
already_have.update(result)
for f in trace_packs:
f.close()
if args.crash_dir:
logger.info("Saving crashes to %s", args.crash_dir)
crash_files = [files[c] for c in crashes]
if args.no_dedup:
# Unless we deduped previously, we have to dedup the crash files
# now.
crash_files, hash_list = dedup(crash_files)
for idx, crash_path in enumerate(crash_files):
fn = base64.b16encode(hash_list[idx]).decode("utf8").lower()
output_path = os.path.join(args.crash_dir, fn)
try:
os.link(crash_path, output_path)
except OSError:
try:
shutil.copy(crash_path, output_path)
except shutil.Error:
# This error happens when src and dest are hardlinks of the
# same file. We have nothing to do in this case, but handle
# it gracefully.
pass
if count == 1:
logger.warning("all test cases had the same traces, check syntax!")
logger.info('narrowed down to %s files, saved in "%s"', count, args.output)
if not os.environ.get("AFL_KEEP_TRACES"):
logger.info("Deleting trace files")
trace_dir = os.path.join(args.output, ".traces")
shutil.rmtree(trace_dir, ignore_errors=True)
if __name__ == "__main__":
main()

View File

@ -121,6 +121,7 @@ kernel.sched_child_runs_first=1
kernel.sched_autogroup_enabled=1 kernel.sched_autogroup_enabled=1
kernel.sched_migration_cost_ns=50000000 kernel.sched_migration_cost_ns=50000000
kernel.sched_latency_ns=250000000 kernel.sched_latency_ns=250000000
vm.swappiness=10
EOF EOF
} }
@ -129,7 +130,7 @@ EOF
if ! grep -E "^$KEY=" /etc/default/grub | grep -E -q 'noibrs pcid nopti'; then if ! grep -E "^$KEY=" /etc/default/grub | grep -E -q 'noibrs pcid nopti'; then
echo "Configuring performance boot options" echo "Configuring performance boot options"
LINE=`grep -E "^$KEY=" /etc/default/grub | sed "s/^$KEY=//" | tr -d '"'` LINE=`grep -E "^$KEY=" /etc/default/grub | sed "s/^$KEY=//" | tr -d '"'`
OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off" OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off nokaslr no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
echo Setting boot options in /etc/default/grub to $KEY=\"$OPTIONS\" echo Setting boot options in /etc/default/grub to $KEY=\"$OPTIONS\"
sed -i "s|^$KEY=.*|$KEY=\"$OPTIONS\"|" /etc/default/grub sed -i "s|^$KEY=.*|$KEY=\"$OPTIONS\"|" /etc/default/grub
fi fi

View File

@ -41,6 +41,7 @@ if [ "$PLATFORM" = "Linux" ] ; then
sysctl -w kernel.sched_autogroup_enabled=1 sysctl -w kernel.sched_autogroup_enabled=1
sysctl -w kernel.sched_migration_cost_ns=50000000 2>/dev/null sysctl -w kernel.sched_migration_cost_ns=50000000 2>/dev/null
sysctl -w kernel.sched_latency_ns=250000000 2>/dev/null sysctl -w kernel.sched_latency_ns=250000000 2>/dev/null
sysctl -w vm.swappiness=10 2>/dev/null
echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/enabled
test -e /sys/devices/system/cpu/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/scaling_governor test -e /sys/devices/system/cpu/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/scaling_governor
test -e /sys/devices/system/cpu/cpufreq/policy0/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/policy*/scaling_governor test -e /sys/devices/system/cpu/cpufreq/policy0/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/policy*/scaling_governor
@ -54,7 +55,7 @@ if [ "$PLATFORM" = "Linux" ] ; then
echo echo
dmesg | grep -E -q 'noibrs pcid nopti' || { dmesg | grep -E -q 'noibrs pcid nopti' || {
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this: echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"' echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off nokaslr no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"'
echo echo
} }
echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed. echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed.

View File

@ -112,12 +112,12 @@ if [ -z "$NO_COLOR" ]; then
fi fi
PLATFORM=`uname -s` PLATFORM=`uname -s`
if [ "$PLATFORM" = "Linux" ] ; then #if [ "$PLATFORM" = "Linux" ] ; then
CUR_TIME=`cat /proc/uptime | awk '{printf "%.0f\n", $1}'` # CUR_TIME=`cat /proc/uptime | awk '{printf "%.0f\n", $1}'`
else #else
# This will lead to inacurate results but will prevent the script from breaking on platforms other than Linux # This will lead to inaccurate results but will prevent the script from breaking on platforms other than Linux
CUR_TIME=`date +%s` CUR_TIME=`date +%s`
fi #fi
TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || exit 1 TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || exit 1
trap "rm -f $TMP" 1 2 3 13 15 trap "rm -f $TMP" 1 2 3 13 15

View File

@ -11,3 +11,4 @@
|AMD Ryzen 9 6900HS with Radeon Graphics | 4745 | 16 | 135501 | 991133 | both | |AMD Ryzen 9 6900HS with Radeon Graphics | 4745 | 16 | 135501 | 991133 | both |
|AMD Ryzen 9 7950X3D 16-Core Processor | 5400 | 32 | 71566 | 1566279 | system | |AMD Ryzen 9 7950X3D 16-Core Processor | 5400 | 32 | 71566 | 1566279 | system |
|AMD Ryzen 9 7950X3D 16-Core Processor | 5478 | 32 | 161960 | 2173959 | both | |AMD Ryzen 9 7950X3D 16-Core Processor | 5478 | 32 | 161960 | 2173959 | both |
|Ampere Altra Q80-30 | 0 | 80 | 54477 | 1604482 | system |

View File

@ -1,4 +1,4 @@
# custum mutator: AFL++ # custom mutator: AFL++
this is the AFL++ havoc mutator as a custom mutator module for AFL++. this is the AFL++ havoc mutator as a custom mutator module for AFL++.

View File

@ -48,7 +48,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
u8 *ptr = realloc(data->buf, max_size); u8 *ptr = realloc(data->buf, max_size);
if (ptr) { if (!ptr) {
return 0; return 0;

View File

@ -4,7 +4,7 @@ CFLAGS = -O3 -funroll-loops -fPIC
all: aflpp-standalone all: aflpp-standalone
aflpp-standalone: aflpp-standalone.c aflpp-standalone: aflpp-standalone.c
$(CC) $(CFLAGS) -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c $(CC) $(CFLAGS) -w -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
clean: clean:
rm -f *.o *~ aflpp-standalone core rm -f *.o *~ aflpp-standalone core

View File

@ -5,6 +5,6 @@ this is the AFL++ havoc mutator as a standalone mutator
just type `make` to build. just type `make` to build.
``` ```
aflpp-standalone inputfile outputfile [splicefile] aflpp-standalone -h # to see all parameteres
cat file | aflpp-standalone -m 4 -x foo.dict - outputfile splicefile # example
``` ```

View File

@ -1,6 +1,12 @@
#include "afl-fuzz.h" #include "afl-fuzz.h"
#include "afl-mutations.h" #include "afl-mutations.h"
#include <unistd.h>
#include <getopt.h>
static int max_havoc = 16, verbose;
static unsigned char *dict;
typedef struct my_mutator { typedef struct my_mutator {
afl_state_t *afl; afl_state_t *afl;
@ -36,9 +42,23 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
data->afl = calloc(1, sizeof(afl_state_t)); data->afl = calloc(1, sizeof(afl_state_t));
data->afl->queue_cycle = 1; data->afl->queue_cycle = 1;
data->afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY); data->afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
if (data->afl->fsrv.dev_urandom_fd < 0) { PFATAL("Unable to open /dev/urandom"); } if (data->afl->fsrv.dev_urandom_fd < 0) {
PFATAL("Unable to open /dev/urandom");
}
rand_set_seed(data->afl, getpid()); rand_set_seed(data->afl, getpid());
if (dict) {
load_extras(data->afl, dict);
if (verbose)
fprintf(stderr, "Loaded dictionary: %s (%u entries)\n", dict,
data->afl->extras_cnt);
}
return data; return data;
} }
@ -53,7 +73,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
u8 *ptr = realloc(data->buf, max_size); u8 *ptr = realloc(data->buf, max_size);
if (ptr) { if (!ptr) {
return 0; return 0;
@ -66,14 +86,20 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
} }
u32 havoc_steps = 1 + rand_below(data->afl, 16); u32 havoc_steps = 1 + rand_below(data->afl, max_havoc);
if (verbose) fprintf(stderr, "Havoc steps: %u\n", havoc_steps);
/* set everything up, costly ... :( */ /* set everything up, costly ... :( */
memcpy(data->buf, buf, buf_size); memcpy(data->buf, buf, buf_size);
/* the mutation */ /* the mutation */
u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps, u32 out_buf_len;
false, true, add_buf, add_buf_size, max_size); do {
out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps, false,
true, add_buf, add_buf_size, max_size);
} while (out_buf_len == buf_size && memcmp(buf, data->buf, buf_size) == 0);
/* return size of mutated data */ /* return size of mutated data */
*out_buf = data->buf; *out_buf = data->buf;
@ -84,80 +110,143 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc > 1 && strncmp(argv[1], "-h", 2) == 0) { if (argc > 1 && strncmp(argv[1], "-h", 2) == 0) {
printf("Syntax: %s [-v] [inputfile [outputfile [splicefile]]]\n\n", argv[0]);
printf("Reads a testcase from stdin when no input file (or '-') is specified,\n"); printf(
printf("mutates according to AFL++'s mutation engine, and write to stdout when '-' or\n"); "Syntax: %s [-v] [-m maxmutations] [-x dict] [inputfile [outputfile "
printf("no output filename is given. As an optional third parameter you can give a file\n"); "[splicefile]]]\n\n",
argv[0]);
printf(
"Reads a testcase from stdin when no input file (or '-') is "
"specified,\n");
printf(
"mutates according to AFL++'s mutation engine, and write to stdout "
"when '-' or\n");
printf(
"no output filename is given. As an optional third parameter you can "
"give a file\n");
printf("for splicing. Maximum input and output length is 1MB.\n"); printf("for splicing. Maximum input and output length is 1MB.\n");
printf("The -v verbose option prints debug output to stderr.\n"); printf("Options:\n");
printf(" -v verbose debug output to stderr.\n");
printf(" -m val max mutations (1-val, val default is 16)\n");
printf(" -x file dictionary file (AFL++ format)\n");
return 0; return 0;
} }
FILE *in = stdin, *out = stdout, *splice = NULL; FILE *in = stdin, *out = stdout, *splice = NULL;
unsigned char *inbuf = malloc(1024 * 1024), *outbuf, *splicebuf = NULL; unsigned char *inbuf = malloc(1024 * 1024), *outbuf = NULL, *splicebuf = NULL;
int verbose = 0, splicelen = 0; int splicelen = 0, opt;
if (argc > 1 && strcmp(argv[1], "-v") == 0) { while ((opt = getopt(argc, argv, "vm:x:")) > 0) {
switch (opt) {
case 'm':
max_havoc = atoi(optarg);
break;
case 'v':
verbose = 1; verbose = 1;
argc--; break;
argv++; case 'x':
fprintf(stderr, "Verbose active\n"); dict = optarg;
break;
default:
fprintf(stderr, "Error: unknown parameter -%c\n", opt);
exit(-1);
}
}
if (max_havoc < 1) {
fprintf(stderr, "Error: illegal -m value\n");
exit(-1);
} }
my_mutator_t *data = afl_custom_init(NULL, 0); my_mutator_t *data = afl_custom_init(NULL, 0);
if (argc > 1 && strcmp(argv[1], "-") != 0) { if (argc > optind && strcmp(argv[optind], "-") != 0) {
if ((in = fopen(argv[1], "r")) == NULL) {
if ((in = fopen(argv[optind], "r")) == NULL) {
perror(argv[1]); perror(argv[1]);
return -1; return -1;
} }
if (verbose) fprintf(stderr, "Input: %s\n", argv[1]);
if (verbose) fprintf(stderr, "Input: %s\n", argv[optind]);
} }
size_t inlen = fread(inbuf, 1, 1024 * 1024, in); size_t inlen = fread(inbuf, 1, 1024 * 1024, in);
if (!inlen) { if (!inlen) {
fprintf(stderr, "Error: empty file %s\n", argv[1] ? argv[1] : "stdin");
fprintf(stderr, "Error: empty file %s\n",
argv[optind] ? argv[optind] : "stdin");
return -1; return -1;
} }
if (argc > 2 && strcmp(argv[2], "-") != 0) { if (argc > optind + 1 && strcmp(argv[optind + 1], "-") != 0) {
if ((out = fopen(argv[2], "w")) == NULL) {
perror(argv[2]); if ((out = fopen(argv[optind + 1], "w")) == NULL) {
perror(argv[optind + 1]);
return -1; return -1;
}
if (verbose) fprintf(stderr, "Output: %s\n", argv[2]);
} }
if (argc > 3) { if (verbose) fprintf(stderr, "Output: %s\n", argv[optind + 1]);
if ((splice = fopen(argv[3], "r")) == NULL) {
perror(argv[3]);
return -1;
} }
if (verbose) fprintf(stderr, "Splice: %s\n", argv[3]);
if (argc > optind + 2) {
if ((splice = fopen(argv[optind + 2], "r")) == NULL) {
perror(argv[optind + 2]);
return -1;
}
if (verbose) fprintf(stderr, "Splice: %s\n", argv[optind + 2]);
splicebuf = malloc(1024 * 1024); splicebuf = malloc(1024 * 1024);
size_t splicelen = fread(splicebuf, 1, 1024 * 1024, splice); size_t splicelen = fread(splicebuf, 1, 1024 * 1024, splice);
if (!splicelen) { if (!splicelen) {
fprintf(stderr, "Error: empty file %s\n", argv[3]);
fprintf(stderr, "Error: empty file %s\n", argv[optind + 2]);
return -1; return -1;
} }
if (verbose) fprintf(stderr, "Mutation splice length: %zu\n", splicelen); if (verbose) fprintf(stderr, "Mutation splice length: %zu\n", splicelen);
} }
if (verbose) fprintf(stderr, "Mutation input length: %zu\n", inlen); if (verbose) fprintf(stderr, "Mutation input length: %zu\n", inlen);
unsigned int outlen = afl_custom_fuzz(data, inbuf, inlen, &outbuf, splicebuf, splicelen, 1024*1024); unsigned int outlen = afl_custom_fuzz(data, inbuf, inlen, &outbuf, splicebuf,
splicelen, 1024 * 1024);
if (outlen == 0 || !outbuf) { if (outlen == 0 || !outbuf) {
fprintf(stderr, "Error: no mutation data returned.\n"); fprintf(stderr, "Error: no mutation data returned.\n");
return -1; return -1;
} }
if (verbose) fprintf(stderr, "Mutation output length: %u\n", outlen); if (verbose) fprintf(stderr, "Mutation output length: %u\n", outlen);
if (fwrite(outbuf, 1, outlen, out) != outlen) { if (fwrite(outbuf, 1, outlen, out) != outlen) {
fprintf(stderr, "Warning: incomplete write.\n"); fprintf(stderr, "Warning: incomplete write.\n");
return -1; return -1;
} }
return 0; return 0;
} }

View File

@ -13,7 +13,7 @@ Just type `make` to build `atnwalk.so`.
**NOTE:** The commands below just demonstrate an example how running ATNwalk looks like and require a working [testbed](https://github.com/atnwalk/testbed) **NOTE:** The commands below just demonstrate an example how running ATNwalk looks like and require a working [testbed](https://github.com/atnwalk/testbed)
```bash ```bash
# create the required a random seed first # create the required random seed first
mkdir -p ~/campaign/example/seeds mkdir -p ~/campaign/example/seeds
cd ~/campaign/example/seeds cd ~/campaign/example/seeds
head -c1 /dev/urandom | ~/atnwalk/build/javascript/bin/decode -wb > seed.decoded 2> seed.encoded head -c1 /dev/urandom | ~/atnwalk/build/javascript/bin/decode -wb > seed.decoded 2> seed.encoded

View File

@ -180,7 +180,8 @@ size_t fail_fatal(int fd_socket, uint8_t **out_buf) {
if (fd_socket != -1) { close(fd_socket); } if (fd_socket != -1) { close(fd_socket); }
*out_buf = NULL; *out_buf = NULL;
return 0; fprintf(stderr, "atnwalk.socket not found in current directory!\n");
exit(-1);
} }
@ -408,7 +409,7 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size,
} else { } else {
// new_size fits into buf, so re-use it // new_size fits into buf, so reuse it
*out_buf = buf; *out_buf = buf;
} }

View File

@ -39,6 +39,7 @@ extern "C" {
#ifndef AFL_TXT_MAX_LEN #ifndef AFL_TXT_MAX_LEN
#define AFL_TXT_MAX_LEN 65535 #define AFL_TXT_MAX_LEN 65535
#endif #endif
#define AUTOTOKENS_TXT_MIN_LEN 1
#if AUTOTOKENS_SPLICE_MIN >= AUTOTOKENS_SIZE_MIN #if AUTOTOKENS_SPLICE_MIN >= AUTOTOKENS_SIZE_MIN
#error SPLICE_MIN must be lower than SIZE_MIN #error SPLICE_MIN must be lower than SIZE_MIN
@ -57,8 +58,9 @@ typedef struct my_mutator {
if (unlikely(debug)) fprintf if (unlikely(debug)) fprintf
#define IFDEBUG if (unlikely(debug)) #define IFDEBUG if (unlikely(debug))
int module_disabled = 0;
static afl_state *afl_ptr; static afl_state *afl_ptr;
static int module_disabled = 0;
static int auto_disable = AUTOTOKENS_AUTO_DISABLE; static int auto_disable = AUTOTOKENS_AUTO_DISABLE;
static int debug = AUTOTOKENS_DEBUG; static int debug = AUTOTOKENS_DEBUG;
static int only_fav = AUTOTOKENS_ONLY_FAV; static int only_fav = AUTOTOKENS_ONLY_FAV;
@ -104,9 +106,9 @@ static void first_run(void *data) {
if (afl_ptr->custom_only || !auto_disable) { return; } if (afl_ptr->custom_only || !auto_disable) { return; }
if (unlikely(afl_ptr->active_items == 1 && if (unlikely(afl_ptr->active_items == 1 &&
afl_ptr->queue_cur->len < AFL_TXT_MIN_LEN)) { afl_ptr->queue_cur->len < AUTOTOKENS_TXT_MIN_LEN)) {
if (afl_ptr->extras_cnt > 8) { if (afl_ptr->extras_cnt) {
u32 valid = 0; u32 valid = 0;
@ -237,7 +239,7 @@ extern "C" u32 afl_custom_fuzz_count(void *data, const u8 *buf,
} }
extern "C" size_t afl_custom_fuzz(my_mutator_t *data, u8 *buf, size_t buf_size, extern "C" size_t afl_custom_fuzz(void *data, u8 *buf, size_t buf_size,
u8 **out_buf, u8 *add_buf, u8 **out_buf, u8 *add_buf,
size_t add_buf_size, size_t max_size) { size_t add_buf_size, size_t max_size) {
@ -655,6 +657,7 @@ extern "C" unsigned char afl_custom_queue_get(void *data,
if (current_id > whitespace_ids + 6 && afl_ptr->active_items == 1 && if (current_id > whitespace_ids + 6 && afl_ptr->active_items == 1 &&
afl_ptr->queue_cur->len < AFL_TXT_MIN_LEN) { afl_ptr->queue_cur->len < AFL_TXT_MIN_LEN) {
retry_thin_air:
DEBUGF(stderr, "Creating an entry from thin air...\n"); DEBUGF(stderr, "Creating an entry from thin air...\n");
structure = new vector<u32>(); structure = new vector<u32>();
u32 item, prev, cnt = current_id >> 1; u32 item, prev, cnt = current_id >> 1;
@ -684,8 +687,6 @@ extern "C" unsigned char afl_custom_queue_get(void *data,
} }
create_from_thin_air = 0;
} }
if (entry == file_mapping.end()) { if (entry == file_mapping.end()) {
@ -693,7 +694,7 @@ extern "C" unsigned char afl_custom_queue_get(void *data,
// this input file was not analyzed for tokens yet, so let's do it! // this input file was not analyzed for tokens yet, so let's do it!
size_t len = afl_ptr->queue_cur->len; size_t len = afl_ptr->queue_cur->len;
if (len < AFL_TXT_MIN_LEN) { if (len < AUTOTOKENS_TXT_MIN_LEN) {
file_mapping[fn] = structure; // NULL ptr so we don't read the file again file_mapping[fn] = structure; // NULL ptr so we don't read the file again
s = NULL; s = NULL;
@ -895,6 +896,7 @@ extern "C" unsigned char afl_custom_queue_get(void *data,
if (tokens.size() < AUTOTOKENS_SIZE_MIN) { if (tokens.size() < AUTOTOKENS_SIZE_MIN) {
if (create_from_thin_air) { goto retry_thin_air; }
file_mapping[fn] = NULL; file_mapping[fn] = NULL;
s = NULL; s = NULL;
DEBUGF(stderr, "too few tokens\n"); DEBUGF(stderr, "too few tokens\n");
@ -955,7 +957,7 @@ extern "C" unsigned char afl_custom_queue_get(void *data,
} }
extern "C" my_mutator_t *afl_custom_init(afl_state *afl, unsigned int seed) { extern "C" void *afl_custom_init(afl_state_t *afl, unsigned int seed) {
(void)(seed); (void)(seed);
my_mutator_t *data = (my_mutator_t *)calloc(1, sizeof(my_mutator_t)); my_mutator_t *data = (my_mutator_t *)calloc(1, sizeof(my_mutator_t));
@ -1070,7 +1072,7 @@ extern "C" my_mutator_t *afl_custom_init(afl_state *afl, unsigned int seed) {
id_to_token[current_id] = "'"; id_to_token[current_id] = "'";
++current_id; ++current_id;
return data; return (void *)data;
} }

View File

@ -0,0 +1,20 @@
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-pointer-sign
CXXFLAGS= -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1
all: autotokens-standalone
autotokens.o: ../autotokens.cpp
$(CXX) $(CXXFLAGS) -g -I../../../include -I. -I../.. -c ../autotokens.cpp
autotokens-standalone: autotokens-standalone.c autotokens.o
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
$(CXX) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
@rm -f ../../../src/afl-common.o ../../../src/afl-fuzz-queue.o ../../../src/afl-fuzz-extras.o ../../../src/afl-performance.o
clean:
rm -f *.o *~ autotokens-standalone core

View File

@ -0,0 +1,12 @@
# Autotokens standalone mutator
this is a standalone version of the AFL++ autotokens custom mutator.
just type `make` to build.
You *MUST* use a dictionary file to have an effective grammarless grammar fuzzer!
```
autotokens-standalone -h # to see all parameters
autotokens-standalone -x foo.dict inputfile outputfile # example
```

View File

@ -0,0 +1,205 @@
#include "afl-fuzz.h"
#include "afl-mutations.h"
#include "forkserver.h"
#include <unistd.h>
#include <getopt.h>
static int max_havoc = 16, verbose;
static char _mh[4] = "16";
static char *dict, *mh = _mh;
extern int module_disabled;
void *afl_custom_init(afl_state_t *, unsigned int);
u8 afl_custom_queue_get(void *data, const u8 *filename);
size_t afl_custom_fuzz(void *data, u8 *buf, size_t buf_size, u8 **out_buf,
u8 *add_buf, size_t add_buf_size, size_t max_size);
u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
return 0;
}
fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
u32 i) {
return FSRV_RUN_OK;
}
int main(int argc, char *argv[]) {
if (argc > 1 && strncmp(argv[1], "-h", 2) == 0) {
printf(
"Syntax: %s [-v] [-m maxmutations] [-x dict] [inputfile [outputfile "
"[splicefile]]]\n\n",
argv[0]);
printf("Reads a testcase from a file (not stdin!),\n");
printf("writes to stdout when '-' or\n");
printf(
"no output filename is given. As an optional third parameter you can "
"give a file\n");
printf("for splicing. Maximum input and output length is 1MB.\n");
printf("Options:\n");
printf(" -v verbose debug output to stderr.\n");
printf(" -m val max mutations (1-val, val default is 16)\n");
printf(" -x file dictionary file (AFL++ format)\n");
printf("You can set the following environment variable parameters:\n");
printf("AUTOTOKENS_COMMENT` - what character or string starts a comment which will be\n");
printf(" removed. Default: \"/* ... */\"\n");
return 0;
}
FILE *in = stdin, *out = stdout, *splice = NULL;
unsigned char *inbuf = malloc(1024 * 1024), *outbuf = NULL, *splicebuf = NULL;
int splicelen = 0, opt;
while ((opt = getopt(argc, argv, "vm:x:")) > 0) {
switch (opt) {
case 'm':
max_havoc = atoi(optarg);
mh = optarg;
break;
case 'v':
verbose = 1;
break;
case 'x':
dict = optarg;
break;
default:
fprintf(stderr, "Error: unknown parameter -%c\n", opt);
exit(-1);
}
}
if (max_havoc < 1) {
fprintf(stderr, "Error: illegal -m value\n");
exit(-1);
}
if (argc > optind && strcmp(argv[optind], "-") != 0) {
if ((in = fopen(argv[optind], "r")) == NULL) {
perror(argv[1]);
return -1;
}
if (verbose) fprintf(stderr, "Input: %s\n", argv[optind]);
}
size_t inlen = fread(inbuf, 1, 1024 * 1024, in);
if (!inlen) {
fprintf(stderr, "Error: empty file %s\n",
argv[optind] ? argv[optind] : "stdin");
return -1;
}
if (argc > optind + 1 && strcmp(argv[optind + 1], "-") != 0) {
if ((out = fopen(argv[optind + 1], "w")) == NULL) {
perror(argv[optind + 1]);
return -1;
}
if (verbose) fprintf(stderr, "Output: %s\n", argv[optind + 1]);
}
if (argc > optind + 2) {
if ((splice = fopen(argv[optind + 2], "r")) == NULL) {
perror(argv[optind + 2]);
return -1;
}
if (verbose) fprintf(stderr, "Splice: %s\n", argv[optind + 2]);
splicebuf = malloc(1024 * 1024);
size_t splicelen = fread(splicebuf, 1, 1024 * 1024, splice);
if (!splicelen) {
fprintf(stderr, "Error: empty file %s\n", argv[optind + 2]);
return -1;
}
if (verbose) fprintf(stderr, "Mutation splice length: %zu\n", splicelen);
}
/* configure autotokens */
setenv("AUTOTOKENS_LEARN_DICT", "1", 0);
setenv("AUTOTOKENS_CREATE_FROM_THIN_AIR", "1", 0);
setenv("AUTOTOKENS_CHANGE_MAX", mh, 0);
/* fake AFL++ state */
afl_state_t *afl = (afl_state_t *)calloc(1, sizeof(afl_state_t));
afl->queue_cycle = afl->havoc_div = afl->active_items = afl->queued_items = 1;
afl->shm.cmplog_mode = 0;
afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
if (afl->fsrv.dev_urandom_fd < 0) { PFATAL("Unable to open /dev/urandom"); }
rand_set_seed(afl, getpid());
if (dict) {
load_extras(afl, (u8*)dict);
if (verbose)
fprintf(stderr, "Loaded dictionary: %s (%u entries)\n", dict,
afl->extras_cnt);
}
// setup a fake queue entry
afl->queue_buf = malloc(64);
afl->queue_buf[0] = afl->queue_cur =
(struct queue_entry *)malloc(sizeof(struct queue_entry));
afl->queue_cur->testcase_buf = inbuf;
afl->queue_cur->fname = (u8 *)argv[optind];
afl->queue_cur->len = inlen;
afl->queue_cur->perf_score = 100;
afl->queue_cur->favored = afl->queue_cur->is_ascii = 1;
// afl->custom_only = 1;
void *data = (void *)afl_custom_init(afl, (u32)0);
u8 res = afl_custom_queue_get(inbuf, (u8 *)argv[optind]);
if (verbose) fprintf(stderr, "Mutation input length: %zu\n", inlen);
unsigned int outlen = afl_custom_fuzz(data, inbuf, inlen, &outbuf, splicebuf,
splicelen, 1024 * 1024);
if (outlen == 0 || !outbuf) {
fprintf(stderr, "Error: no mutation data returned.\n");
return -1;
}
if (verbose) fprintf(stderr, "Mutation output length: %u\n", outlen);
if (fwrite(outbuf, 1, outlen, out) != outlen) {
fprintf(stderr, "Warning: incomplete write.\n");
return -1;
}
return 0;
}

View File

@ -0,0 +1,7 @@
all: custom_send_tcp.so
custom_send_tcp.so:
$(CC) -Wno-unused-result -g -O3 -shared -fPIC -o custom_send_tcp.so -I../../include custom_send_tcp.c
clean:
rm -f custom_send_tcp.so *.o *~ core

View File

@ -0,0 +1,13 @@
# Send testcases via TCP custom mutator
This custom mutator sends the fuzzing testcases via TCP.
`AFL_CUSTOM_MUTATOR_LATE_SEND` - MUST be set!
`CUSTOM_SEND_IP` - the IP address to send to (basically only 127.0.0.1 makes sense)
`CUSTOM_SEND_PORT` - the TCP port to send to
`CUSTOM_SEND_READ` - if the custom mutator should wait for a reply from the target
Example:
```
CUSTOM_SEND_IP=127.0.0.1 CUSTOM_SEND_PORT=8000 CUSTOM_SEND_READ=1 AFL_CUSTOM_MUTATOR_LATE_SEND=1 AFL_CUSTOM_MUTATOR_LIBRARY=custom_send_tcp.so ./afl-fuzz ...
```

View File

@ -0,0 +1,113 @@
#include <time.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include "afl-fuzz.h"
static int my_debug = 0;
static int my_read = 0;
#define DEBUG(...) if (my_debug) printf(__VA_ARGS__)
typedef struct tcp_send_mutator {
afl_state_t* afl;
struct sockaddr_in server_addr;
} tcp_send_mutator_t;
void *afl_custom_init(afl_state_t* afl, uint32_t seed) {
const char* ip = getenv("CUSTOM_SEND_IP");
const char* port = getenv("CUSTOM_SEND_PORT");
if (getenv("AFL_DEBUG")) my_debug = 1;
if (getenv("CUSTOM_SEND_READ")) my_read = 1;
if (!ip || !port) {
fprintf(stderr, "You forgot to set CUSTOM_SEND_IP and/or CUSTOM_SEND_PORT\n");
exit(1);
}
tcp_send_mutator_t* mutator = calloc(1, sizeof(tcp_send_mutator_t));
if (!mutator) {
fprintf(stderr, "Failed to allocate mutator struct\n");
exit(1);
}
mutator->afl = afl;
bzero(&mutator->server_addr, sizeof(mutator->server_addr));
mutator->server_addr.sin_family = AF_INET;
if (inet_pton(AF_INET, ip, &mutator->server_addr.sin_addr) <= 0) {
fprintf(stderr, "Could not convert target ip address!\n");
exit(1);
}
mutator->server_addr.sin_port = htons(atoi(port));
printf("[+] Custom tcp send mutator setup ready to go!\n");
return mutator;
}
int try_connect(tcp_send_mutator_t *mutator, int sock, int max_attempts) {
while (max_attempts > 0) {
if (connect(sock, (struct sockaddr*)&mutator->server_addr, sizeof(mutator->server_addr)) == 0) {
return 0;
}
// Even with AFL_CUSTOM_LATE_SEND=1, there is a race between the
// application under test having started to listen for connections and
// afl_custom_fuzz_send being called. To address this race, we attempt
// to connect N times and sleep a short period of time in between
// connection attempts.
struct timespec t;
t.tv_sec = 0;
t.tv_nsec = 100;
nanosleep(&t, NULL);
--max_attempts;
}
return 1;
}
void afl_custom_fuzz_send(tcp_send_mutator_t *mutator, uint8_t *buf, size_t buf_size) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
int written = 0;
if (sock >= 0 && try_connect(mutator, sock, 10000) == 0) {
DEBUG("connected, write()\n");
written = write(sock, buf, buf_size);
} else {
DEBUG("socket() or connect() error: %d\n", errno);
}
if (written < 0) {
DEBUG("write() error: %d\n", errno);
} else if (my_read) {
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
fd_set set;
FD_ZERO(&set);
FD_SET(sock, &set);
int select_res = select(sock + 1, &set, NULL, NULL, &timeout);
if (select_res == -1) {
DEBUG("select() error: %d\n", errno);
} else if (select_res == 0) {
DEBUG("read() timeout!\n");
} else {
uint8_t buf[64];
(void)read(sock, buf, sizeof(buf));
}
}
close(sock);
}
void afl_custom_deinit(tcp_send_mutator_t* mutator) {
free(mutator);
}

View File

@ -304,7 +304,7 @@ class XmlMutatorMin:
# Log something # Log something
if self.verbose: if self.verbose:
print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag)) print("Resetting tag #%i '%s'" % (rand_elem_id, rand_elem.tag))
# Reset the node # Reset the node
rand_elem.clear() rand_elem.clear()

View File

@ -80,12 +80,12 @@ def fuzz(buf, add_buf, max_size):
via_buffer = False via_buffer = False
log("fuzz(): Can't initialize mutator with AFL buffer") log("fuzz(): Can't initialize mutator with AFL buffer")
# If init from AFL buffer wasn't succesful # If init from AFL buffer wasn't successful
if not via_buffer: if not via_buffer:
log("fuzz(): Returning unmodified AFL buffer") log("fuzz(): Returning unmodified AFL buffer")
return buf return buf
# Sucessful initialization -> mutate # Successful initialization -> mutate
try: try:
__mutator__.mutate(max=5) __mutator__.mutate(max=5)
log("fuzz(): Input mutated") log("fuzz(): Input mutated")

View File

@ -143,7 +143,7 @@ test -e json-c/.libs/libjson-c.a || {
echo echo
echo echo
echo "[+] Json-c successfully prepared!" echo "[+] Json-c successfully prepared!"
echo "[+] Builing gramatron now." echo "[+] Building gramatron now."
$CC -O3 -g -fPIC -Wno-unused-result -Wl,--allow-multiple-definition -I../../include -o gramatron.so -shared -I. -I/prg/dev/include gramfuzz.c gramfuzz-helpers.c gramfuzz-mutators.c gramfuzz-util.c hashmap.c ../../src/afl-performance.o json-c/.libs/libjson-c.a || exit 1 $CC -O3 -g -fPIC -Wno-unused-result -Wl,--allow-multiple-definition -I../../include -o gramatron.so -shared -I. -I/prg/dev/include gramfuzz.c gramfuzz-helpers.c gramfuzz-mutators.c gramfuzz-util.c hashmap.c ../../src/afl-performance.o json-c/.libs/libjson-c.a || exit 1
echo echo
echo "[+] gramatron successfully built!" echo "[+] gramatron successfully built!"

View File

@ -1 +1 @@
95a6857 05d8f53

View File

@ -1,4 +1,4 @@
# custum mutator: honggfuzz mangle # custom mutator: honggfuzz mangle
this is the honggfuzz mutator in mangle.c as a custom mutator this is the honggfuzz mutator in mangle.c as a custom mutator
module for AFL++. It is the original mangle.c, mangle.h and honggfuzz.h module for AFL++. It is the original mangle.c, mangle.h and honggfuzz.h

View File

@ -850,7 +850,7 @@ static void mangle_ASCIINumChange(run_t *run, bool printable) {
size_t len = 0; size_t len = 0;
uint64_t val = 0; uint64_t val = 0;
/* 20 is maximum lenght of a string representing a 64-bit unsigned value */ /* 20 is maximum length of a string representing a 64-bit unsigned value */
for (len = 0; (len < 20) && (len < left); len++) { for (len = 0; (len < 20) && (len < left); len++) {
char c = run->dynfile->data[off + len]; char c = run->dynfile->data[off + len];

View File

@ -40,7 +40,7 @@ bool BlockCoverage::AppendCoverage(const std::string &S) {
// Coverage lines have this form: // Coverage lines have this form:
// CN X Y Z T // CN X Y Z T
// where N is the number of the function, T is the total number of instrumented // where N is the number of the function, T is the total number of instrumented
// BBs, and X,Y,Z, if present, are the indecies of covered BB. // BBs, and X,Y,Z, if present, are the indices of covered BB.
// BB #0, which is the entry block, is not explicitly listed. // BB #0, which is the entry block, is not explicitly listed.
bool BlockCoverage::AppendCoverage(std::istream &IN) { bool BlockCoverage::AppendCoverage(std::istream &IN) {

View File

@ -106,7 +106,7 @@ private:
}; };
// Parses one dictionary entry. // Parses one dictionary entry.
// If successful, write the enty to Unit and returns true, // If successful, write the entry to Unit and returns true,
// otherwise returns false. // otherwise returns false.
bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
// Parses the dictionary file, fills Units, returns true iff all lines // Parses the dictionary file, fills Units, returns true iff all lines

View File

@ -427,7 +427,7 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
Env.RunOneMergeJob(Job.get()); Env.RunOneMergeJob(Job.get());
// Continue if our crash is one of the ignorred ones. // Continue if our crash is one of the ignored ones.
if (Options.IgnoreTimeouts && ExitCode == Options.TimeoutExitCode) if (Options.IgnoreTimeouts && ExitCode == Options.TimeoutExitCode)
Env.NumTimeouts++; Env.NumTimeouts++;
else if (Options.IgnoreOOMs && ExitCode == Options.OOMExitCode) else if (Options.IgnoreOOMs && ExitCode == Options.OOMExitCode)

View File

@ -452,7 +452,7 @@ void CrashResistantMerge(const Vector<std::string> &Args,
auto ExitCode = ExecuteCommand(Cmd); auto ExitCode = ExecuteCommand(Cmd);
if (!ExitCode) { if (!ExitCode) {
VPrintf(V, "MERGE-OUTER: succesfull in %zd attempt(s)\n", Attempt); VPrintf(V, "MERGE-OUTER: succesful in %zd attempt(s)\n", Attempt);
break; break;
} }

View File

@ -498,9 +498,9 @@ size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
T Add = Rand(21); T Add = Rand(21);
Add -= 10; Add -= 10;
if (Rand.RandBool()) if (Rand.RandBool())
Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes. Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endianness.
else else
Val = Val + Add; // Add assuming current endiannes. Val = Val + Add; // Add assuming current endianness.
if (Add == 0 || Rand.RandBool()) // Maybe negate. if (Add == 0 || Rand.RandBool()) // Maybe negate.
Val = -Val; Val = -Val;

View File

@ -460,7 +460,7 @@ static size_t InternalStrnlen(const char *S, size_t MaxLen) {
} }
// Finds min of (strlen(S1), strlen(S2)). // Finds min of (strlen(S1), strlen(S2)).
// Needed bacause one of these strings may actually be non-zero terminated. // Needed because one of these strings may actually be non-zero terminated.
static size_t InternalStrnlen2(const char *S1, const char *S2) { static size_t InternalStrnlen2(const char *S1, const char *S2) {
size_t Len = 0; size_t Len = 0;

View File

@ -1,4 +1,4 @@
# custum mutator: libfuzzer LLVMFuzzerMutate() # custom mutator: libfuzzer LLVMFuzzerMutate()
This uses the libfuzzer LLVMFuzzerMutate() function in llvm 12. This uses the libfuzzer LLVMFuzzerMutate() function in llvm 12.

View File

@ -2,7 +2,7 @@ CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
all: radamsa-mutator.so all: radamsa-mutator.so
# These can be overriden: # These can be overridden:
CFLAGS ?= $(CFLAGS_FLTO) CFLAGS ?= $(CFLAGS_FLTO)
# These are required: (otherwise radamsa gets very very slooooow) # These are required: (otherwise radamsa gets very very slooooow)

View File

@ -1,4 +1,4 @@
# custum mutator: libradamsa # custom mutator: libradamsa
Pretranslated radamsa library. This code belongs to the radamsa author. Pretranslated radamsa library. This code belongs to the radamsa author.

View File

@ -3707,7 +3707,7 @@ typedef intptr_t wdiff;
1024 * 1024 * 8 /* static malloc'd heap size if used as a library */ 1024 * 1024 * 8 /* static malloc'd heap size if used as a library */
#define FBITS 24 /* bits in fixnum, on the way to 24 and beyond */ #define FBITS 24 /* bits in fixnum, on the way to 24 and beyond */
#define FMAX \ #define FMAX \
((1 << FBITS) - 1) /* maximum fixnum (and most negative fixnum) \ ((1U << FBITS) - 1) /* maximum fixnum (and most negative fixnum) \
*/ */
#define MAXOBJ 0xffff /* max words in tuple including header */ #define MAXOBJ 0xffff /* max words in tuple including header */
#define MAXPAYL \ #define MAXPAYL \

View File

@ -5,4 +5,5 @@ members = [
"example", "example",
# Lain needs a nightly toolchain # Lain needs a nightly toolchain
# "example_lain", # "example_lain",
# "example_lain_post_process",
] ]

View File

@ -9,3 +9,11 @@ A minimal example can be found in `example`. Build it using `cargo build --examp
An example using [lain](https://github.com/microsoft/lain) for structured fuzzing can be found in `example_lain`. An example using [lain](https://github.com/microsoft/lain) for structured fuzzing can be found in `example_lain`.
Since lain requires a nightly rust toolchain, you need to set one up before you can play with it. Since lain requires a nightly rust toolchain, you need to set one up before you can play with it.
An example for the use of the post_process function, using [lain](https://github.com/microsoft/lain) with [serde](https://github.com/serde-rs/serde) and [bincode](https://github.com/bincode-org/bincode) can be found in `example_lain_post_process`.
In order for it to work you need to:
- disable input trimming with `AFL_DISABLE_TRIM=1`
- provide an initial instance serialized with `bincode` or use the `AFL_NO_STARTUP_CALIBRATION=1` environment variable.
Note that `bincode` can also be used to serialize/deserialize the lain-generated structure and mutate it rather than generating a new one at each iteration, but it requires some structure serialized with `bincode` as input seed.

View File

@ -73,6 +73,8 @@ pub trait RawCustomMutator {
None None
} }
fn post_process<'b, 's: 'b>(&'s mut self, buffer: &'b mut [u8]) -> Option<&'b [u8]>;
/*fn post_process(&self, buffer: &[u8], unsigned char **out_buf)-> usize; /*fn post_process(&self, buffer: &[u8], unsigned char **out_buf)-> usize;
int afl_custom_init_trim(&self, buffer: &[u8]); int afl_custom_init_trim(&self, buffer: &[u8]);
size_t afl_custom_trim(&self, unsigned char **out_buf); size_t afl_custom_trim(&self, unsigned char **out_buf);
@ -353,6 +355,33 @@ pub mod wrappers {
Err(err) => panic_handler("afl_custom_queue_get", &err), Err(err) => panic_handler("afl_custom_queue_get", &err),
} }
} }
/// Internal function used in the macro
pub unsafe fn afl_custom_post_process<M: RawCustomMutator>(
data: *mut c_void,
buf: *mut u8,
buf_size: usize,
out_buf: *mut *const u8,
) -> usize {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
assert!(!buf.is_null(), "null buf passed to afl_custom_post_process");
assert!(
!out_buf.is_null(),
"null out_buf passed to afl_custom_post_process"
);
let buff_slice = slice::from_raw_parts_mut(buf, buf_size);
if let Some(buffer) = context.mutator.post_process(buff_slice) {
*out_buf = buffer.as_ptr();
return buffer.len();
}
0
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_post_process", &err),
}
}
} }
/// An exported macro to defined afl_custom_init meant for insternal usage /// An exported macro to defined afl_custom_init meant for insternal usage
@ -480,6 +509,16 @@ macro_rules! export_mutator {
pub unsafe extern "C" fn afl_custom_deinit(data: *mut ::std::os::raw::c_void) { pub unsafe extern "C" fn afl_custom_deinit(data: *mut ::std::os::raw::c_void) {
$crate::wrappers::afl_custom_deinit_::<$mutator_type>(data) $crate::wrappers::afl_custom_deinit_::<$mutator_type>(data)
} }
#[no_mangle]
pub unsafe extern "C" fn afl_custom_post_process(
data: *mut ::std::os::raw::c_void,
buf: *mut u8,
buf_size: usize,
out_buf: *mut *const u8,
) -> usize {
$crate::wrappers::afl_custom_post_process::<$mutator_type>(data, buf, buf_size, out_buf)
}
}; };
} }
@ -512,6 +551,10 @@ mod sanity_test {
) -> Option<&'b [u8]> { ) -> Option<&'b [u8]> {
unimplemented!() unimplemented!()
} }
fn post_process<'b, 's: 'b>(&'s mut self, buffer: &'b mut [u8]) -> Option<&'b [u8]> {
unimplemented!()
}
} }
export_mutator!(ExampleMutator); export_mutator!(ExampleMutator);
@ -579,6 +622,13 @@ pub trait CustomMutator {
fn introspection(&mut self) -> Result<Option<&str>, Self::Error> { fn introspection(&mut self) -> Result<Option<&str>, Self::Error> {
Ok(None) Ok(None)
} }
fn post_process<'b, 's: 'b>(
&'s mut self,
buffer: &'b mut [u8],
) -> Result<Option<&'b [u8]>, Self::Error> {
Ok(Some(buffer))
}
} }
impl<M> RawCustomMutator for M impl<M> RawCustomMutator for M
@ -682,6 +732,16 @@ where
} }
} }
} }
fn post_process<'b, 's: 'b>(&'s mut self, buffer: &'b mut [u8]) -> Option<&'b [u8]> {
match self.post_process(buffer) {
Ok(r) => r,
Err(e) => {
Self::handle_error(e);
None
}
}
}
} }
/// the default value to return from [`CustomMutator::describe`]. /// the default value to return from [`CustomMutator::describe`].

View File

@ -8,7 +8,7 @@ edition = "2021"
[dependencies] [dependencies]
custom_mutator = { path = "../custom_mutator" } custom_mutator = { path = "../custom_mutator" }
lain="0.5" lain = { git = "https://github.com/AFLplusplus/lain.git" }
[[example]] [[example]]
name = "example_lain" name = "example_lain"

View File

@ -0,0 +1,21 @@
[package]
name = "example_lain_post_process"
version = "0.1.0"
authors = [
"Julius Hohnerlein <julihoh@users.noreply.github.com>",
"jma <94166787+jma-qb@users.noreply.github.com>",
]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
custom_mutator = { path = "../custom_mutator" }
lain = { git = "https://github.com/AFLplusplus/lain.git" }
bincode = "1.3.3"
serde = { version = "1.0.214", features = ["derive"] }
[[example]]
name = "example_lain_post_process"
path = "./src/lain_mutator.rs"
crate-type = ["cdylib"]

View File

@ -0,0 +1 @@
nightly

View File

@ -0,0 +1,70 @@
#![cfg(unix)]
use custom_mutator::{export_mutator, CustomMutator};
use lain::{
mutator::Mutator,
prelude::*,
rand::{rngs::StdRng, SeedableRng},
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Mutatable, NewFuzzed, BinarySerialize)]
struct MyStruct {
tag: u8,
#[lain(ignore)]
length: u32,
#[lain(min = 0, max = 10)]
data: Vec<u8>,
}
struct LainMutator {
mutator: Mutator<StdRng>,
buffer: Vec<u8>,
post_buffer: Vec<u8>,
}
impl CustomMutator for LainMutator {
type Error = ();
fn init(seed: u32) -> Result<Self, ()> {
Ok(Self {
mutator: Mutator::new(StdRng::seed_from_u64(seed as u64)),
buffer: Vec::new(),
post_buffer: Vec::new(),
})
}
fn fuzz<'b, 's: 'b>(
&'s mut self,
_buffer: &'b mut [u8],
_add_buff: Option<&[u8]>,
max_size: usize,
) -> Result<Option<&'b [u8]>, ()> {
// we just sample an instance of MyStruct, ignoring the current input
let instance = MyStruct::new_fuzzed(&mut self.mutator, None);
let serialized = bincode::serialize(&instance).unwrap();
let size = serialized.len();
if size > max_size {
return Err(());
}
self.buffer.clear();
self.buffer.reserve(size);
self.buffer.extend_from_slice(&serialized);
Ok(Some(self.buffer.as_slice()))
}
fn post_process<'b, 's: 'b>(
&'s mut self,
buffer: &'b mut [u8],
) -> Result<Option<&'b [u8]>, Self::Error> {
let mut instance = bincode::deserialize::<MyStruct>(&buffer).unwrap();
instance.length = instance.data.len() as u32;
let size = instance.serialized_size();
self.post_buffer.clear();
self.post_buffer.reserve(size);
instance.binary_serialize::<_, BigEndian>(&mut self.post_buffer);
Ok(Some(&self.post_buffer))
}
}
export_mutator!(LainMutator);

View File

@ -1,4 +1,4 @@
# custum mutator: symcc # custom mutator: symcc
This uses the symcc to find new paths into the target. This uses the symcc to find new paths into the target.

View File

@ -1,4 +1,4 @@
# custum mutator: symqemu # custom mutator: symqemu
This uses the symcc to find new paths into the target. This uses the symcc to find new paths into the target.

View File

@ -0,0 +1,120 @@
#
# AFL dictionary for JSON Schema
# https://json-schema.org/
# -----------------------
#
"\"$schema\""
"\"$id\""
"\"$ref\""
"\"$defs\""
"\"definitions\""
"\"enum\""
"\"const\""
"\"type\""
# Annotations
"\"title\""
"\"description\""
"\"default\""
"\"examples\""
"\"$comment\""
"\"readOnly\""
"\"writeOnly\""
"\"deprecated\""
# Types
"\"string\""
"\"integer\""
"\"number\""
"\"object\""
"\"array\""
"\"null\""
"\"boolean\""
# String
"\"minLength\""
"\"maxLength\""
"\"pattern\""
"\"format\""
"\"contentMediaType\""
"\"contentEncoding\""
"\"contentSchema\""
# Formats
"\"date-time\""
"\"time\""
"\"date\""
"\"duration\""
"\"email\""
"\"idn-email\""
"\"hostname\""
"\"idn-hostname\""
"\"ipv4\""
"\"ipv6\""
"\"uuid\""
"\"uri\""
"\"uri-reference\""
"\"iri\""
"\"iri-reference\""
"\"uri-template\""
"\"json-pointer\""
"\"relative-json-pointer\""
"\"regex\""
# Numeric
"\"multipleOf\""
"\"minimum\""
"\"exclusiveMinimum\""
"\"maximum\""
"\"exclusiveMaximum\""
# Object
"\"properties\""
"\"patternProperties\""
"\"additionalProperties\""
"\"unevaluatedProperties\""
"\"required\""
"\"propertyNames\""
"\"minProperties\""
"\"maxProperties\""
"\"dependencies\""
# Array
"\"items\""
"\"prefixItems\""
"\"additionalItems\""
"\"unevaluatedItems\""
"\"contains\""
"\"minContains\""
"\"maxContains\""
"\"minItems\""
"\"maxItems\""
"\"uniqueItems\""
# Booleans
"true"
"false"
# Composition
"\"allOf\""
"\"anyOf\""
"\"oneOf\""
"\"not\""
# Conditions
"\"dependentRequired\""
"\"dependentSchemas\""
"\"if\""
"\"then\""
"\"else\""

5713
dictionaries/ruby.dict Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,116 @@
This is the list of all noteworthy changes made in every public This is the list of all noteworthy changes made in every public
release of the tool. See README.md for the general instruction manual. release of the tool. See README.md for the general instruction manual.
### Version ++4.33a (dev)
- afl-fuzz:
- Use `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT` if you use AFL_PRELOAD
to disable fork, see docs (thanks to @alexandredoyen29)
- Fix for FAST power schedules (introduced in 4.32c) (thanks to @kcwu)
- Colors for NO_UI output (thanks to @smoelius)
- Fix potential sync issues when resuming sessions and when instances in a
campaign are restarted and skip entries that were synced from itself
(thanks to @kcwu for raising the issues and providing support!)
- more 64 bit archicture support by @maribu
- afl-cc:
- Added instrumenting hidden edges (approx 5% edges were not instrumented,
LLVM sancov overall misses 8% of edges compared to our implementation)
Note that is is currently only implemented for our PCGUARD plugin, not
LTO, CLASSIC, etc.!
- Fix to make AFL_SAN_NO_INST work with gcc_plugin
- MacOS aflpp driver compilation fix (-fsanitize=fuzzer implementation)
- Make AFL_DUMP_MAP_SIZE work even if the target has sanitizer issues
- qemuafl:
- Better MIPS persistent mode support
- afl-cmin:
- New afl-cmin.py which is much faster, will be executed by default via
afl-cmin if it executes successfully (thanks to @kcwu!)
- New desocketing library: utils/libaflppdesock
- Likely works when all other desocketing options fail
### Version ++4.32c (release)
- Fixed a bug where after a fast restart of a full fuzzed corpus afl-fuzz
terminates with "need at least one valid input seed that does not crash"
- Small improvements to afl-*-config
- afl-fuzz:
- memory leak fixes by @kcwu - thanks!
- many more nits and small memory saves thanks to @kcwu
- remove deprecated files from queue/.state
- fix bitmap update function if no current trace is present
- fix for afl_custom_queue_get
- various small nits
- afl-cc:
- fix pass support for LLVM 20 (passes were run too early)
- dropped plugin support for LLVM 13
- fix AFL_OLD_FORKSERVER
- various minor fixes
- frida_mode:
- fixes for new MacOS + M4 hardware
### Version ++4.31c (release)
- SAND mode added (docs/SAND.md) for more effecient fuzzing with sanitizers
(thanks to @wtdcode !)
- afl-fuzz:
- splicing phase is now DISABLED by default because research showed
it is counterproductive. New command line parameter `-u` to enable
it.
- Python 3.13+ support
- loose file and shared memory permissions on Android and iPhone
- afl-cc:
- LLVM 20 support (again - please don't change the API all the time ...)
- -fsanitize=fuzzer now inserts libAFLDriver.a addtionally early to help
compiling if LLVMFuzzerTestOneOnput is in an .a archive
- added __sanitizer_weak_hook_* functions (in case that is helpful in
weird setups)
- fix bug with large map sizes when multiple libraries are loaded after
the shared memory was obtained.
### Version ++4.30c (release)
! afl-gcc and afl-clang funcionality is now removed !
- afl-fuzz:
- fastresume feature added. if you abort fuzzing and resume fuzzing
with `-i -` or `AFL_AUTORESUME=1` and the target binary has not changed
then a dump will be loaded and the calibration phase skipped.
to disable this feature set `AFL_NO_FASTRESUME=1`
zlib compression is used if zlib is found at compile time
- improved seed selection algorithm
- added `AFL_CUSTOM_MUTATOR_LATE_SEND=1` to call the custom send()
function after the target has been restarted.
- because of bad math and undefined behaviour fixes we have to change
the CMPLOG map. **YOU NEED TO RECOMPILE CMPLOG TARGETS**
- fixed custom_post_process for calibration
- fixes for AFL_EXIT_ON_TIME and AFL_EXIT_WHEN_DONE, changed behaviour of
AFL_EXIT_WHEN_DONE to finish when really done :-)
- frida_mode:
- AFL_FRIDA_PERSISTENT_ADDR can now be be any reachable address not just
a function entry
- AFL_DEBUG is now the same as AFL_FRIDA_VERBOSE
- AFL_FRIDA_DEBUG_MAPS now works as expected
- qemu_mode:
- new hooks supported (optional), see qemu_mode/hooking_bridge - thanks to
@CowBoy4mH3LL
- unicorn_mode:
- fix install and forkserver (thanks aarnav!)
- pin unicorn version
- nyx_mode:
- bugfixes
- custom mutators:
- custom_send_tcp custom mutator added, thanks to @dergoegge
- afl-cc
- fix to support pointless changes in LLVM 20
- new runtime (!) variable: `AFL_OLD_FORKSERVER` to use the old vanilla
AFL type forkserver. Useful for symcc/symqemu/nautilus/etc. with
AFL_LLVM_INSTRUMENT=CLASSIC
- new compile time variable: `AFL_OPT_LEVEL` to set a specific optimization
level, default is `3`
- correctly explain how to get the correct map size for large targets
- small fix for weird LLVM defines in redhat
- code formatting updated to llvm 18
- improved custom_mutators/aflpp/standalone/aflpp-standalone
- added custom_mutators/autotokens/standalone/autotokens-standalone
- AFL++ headers are now installed to $PREFIX/include/afl
### Version ++4.21c (release) ### Version ++4.21c (release)
* afl-fuzz * afl-fuzz
- fixed a regression in afl-fuzz that resulted in a 5-10% performace loss - fixed a regression in afl-fuzz that resulted in a 5-10% performace loss
@ -42,7 +152,6 @@
* Fixed a shmem mmap bug (that rarely came up on MacOS) * Fixed a shmem mmap bug (that rarely came up on MacOS)
* libtokencap: script generate_libtoken_dict.sh added by @a-shvedov * libtokencap: script generate_libtoken_dict.sh added by @a-shvedov
### Version ++4.20c (release) ### Version ++4.20c (release)
! A new forkserver communication model is now introduced. afl-fuzz is ! A new forkserver communication model is now introduced. afl-fuzz is
backward compatible to old compiled targets if they are not built backward compatible to old compiled targets if they are not built

View File

@ -11,7 +11,7 @@ If you find an interesting or important question missing, submit it via
AFL++ is a superior fork to Google's AFL - more speed, more and better AFL++ is a superior fork to Google's AFL - more speed, more and better
mutations, more and better instrumentation, custom module support, etc. mutations, more and better instrumentation, custom module support, etc.
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting American Fuzzy Lop (AFL) was developed by Michal "lcamtuf" Zalewski starting
in 2013/2014, and when he left Google end of 2017 he stopped developing it. in 2013/2014, and when he left Google end of 2017 he stopped developing it.
At the end of 2019, the Google fuzzing team took over maintenance of AFL, At the end of 2019, the Google fuzzing team took over maintenance of AFL,
@ -106,7 +106,7 @@ If you find an interesting or important question missing, submit it via
<details> <details>
<summary id="should-you-ever-stop-afl-fuzz-minimize-the-corpus-and-restart">Should you ever stop afl-fuzz, minimize the corpus and restart?</summary><p> <summary id="should-you-ever-stop-afl-fuzz-minimize-the-corpus-and-restart">Should you ever stop afl-fuzz, minimize the corpus and restart?</summary><p>
To stop afl-fuzz, minimize it's corpus and restart you would usually do: To stop afl-fuzz, minimize its corpus and restart you would usually do:
``` ```
Control-C # to terminate afl-fuzz Control-C # to terminate afl-fuzz
@ -236,7 +236,7 @@ If you find an interesting or important question missing, submit it via
[AFLFast](https://github.com/mboehme/aflfast), however, modified to be more [AFLFast](https://github.com/mboehme/aflfast), however, modified to be more
effective and several more modes added. effective and several more modes added.
The most effective modes are `-p fast` (default) and `-p explore`. The most effective modes are `-p explore` (default) and `-p fast`.
If you fuzz with several parallel afl-fuzz instances, then it is beneficial If you fuzz with several parallel afl-fuzz instances, then it is beneficial
to assign a different schedule to each instance, however the majority should to assign a different schedule to each instance, however the majority should
@ -274,7 +274,7 @@ If you find an interesting or important question missing, submit it via
the existing map will be used also for the newly loaded libraries, which the existing map will be used also for the newly loaded libraries, which
allows it to work, however, the efficiency of the fuzzing will be partially allows it to work, however, the efficiency of the fuzzing will be partially
degraded. Note that there is additionally `AFL_IGNORE_PROBLEMS_COVERAGE` to degraded. Note that there is additionally `AFL_IGNORE_PROBLEMS_COVERAGE` to
additionally tell AFL++ to ignore any coverage from the late loaded libaries. additionally tell AFL++ to ignore any coverage from the late loaded libraries.
</p></details> </p></details>
<details> <details>
@ -284,14 +284,14 @@ If you find an interesting or important question missing, submit it via
afl-cc/afl-clang-fast/afl-clang-lto: afl-cc/afl-clang-fast/afl-clang-lto:
``` ```
/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv /prg/tmp/llvm-project/build/bin/clang-18: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
clang-13: error: unable to execute command: No such file or directory clang-18: error: unable to execute command: No such file or directory
clang-13: error: clang frontend command failed due to signal (use -v to see invocation) clang-18: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad) clang version 18.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
Target: x86_64-unknown-linux-gnu Target: x86_64-unknown-linux-gnu
Thread model: posix Thread model: posix
InstalledDir: /prg/tmp/llvm-project/build/bin InstalledDir: /prg/tmp/llvm-project/build/bin
clang-13: note: diagnostic msg: clang-18: note: diagnostic msg:
******************** ********************
``` ```

View File

@ -21,7 +21,7 @@ If you want to build AFL++ yourself, you have many options. The easiest choice
is to build and install everything: is to build and install everything:
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
whatever llvm version is available. We recommend llvm 13 or newer. whatever llvm version is available. We recommend llvm 14 or newer.
```shell ```shell
sudo apt-get update sudo apt-get update
@ -30,6 +30,9 @@ sudo apt-get install -y build-essential python3-dev automake cmake git flex biso
sudo apt-get install -y lld-14 llvm-14 llvm-14-dev clang-14 || sudo apt-get install -y lld llvm llvm-dev clang sudo apt-get install -y lld-14 llvm-14 llvm-14-dev clang-14 || sudo apt-get install -y lld llvm llvm-dev clang
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev
sudo apt-get install -y ninja-build # for QEMU mode sudo apt-get install -y ninja-build # for QEMU mode
sudo apt-get install -y cpio libcapstone-dev # for Nyx mode
sudo apt-get install -y wget curl # for Frida mode
sudo apt-get install -y python3-pip # for Unicorn mode
git clone https://github.com/AFLplusplus/AFLplusplus git clone https://github.com/AFLplusplus/AFLplusplus
cd AFLplusplus cd AFLplusplus
make distrib make distrib
@ -87,7 +90,6 @@ These build options exist:
* PROFILING - compile afl-fuzz with profiling information * PROFILING - compile afl-fuzz with profiling information
* INTROSPECTION - compile afl-fuzz with mutation introspection * INTROSPECTION - compile afl-fuzz with mutation introspection
* NO_PYTHON - disable python support * NO_PYTHON - disable python support
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
* NO_UTF - do not use UTF-8 for line rendering in status screen (fallback to G1 box drawing, of vanilla AFL) * NO_UTF - do not use UTF-8 for line rendering in status screen (fallback to G1 box drawing, of vanilla AFL)
* NO_NYX - disable building nyx mode dependencies * NO_NYX - disable building nyx mode dependencies
* NO_CORESIGHT - disable building coresight (arm64 only) * NO_CORESIGHT - disable building coresight (arm64 only)
@ -167,3 +169,47 @@ and definitely don't look POSIX-compliant. This means two things:
User emulation mode of QEMU does not appear to be supported on macOS, so User emulation mode of QEMU does not appear to be supported on macOS, so
black-box instrumentation mode (`-Q`) will not work. However, FRIDA mode (`-O`) black-box instrumentation mode (`-Q`) will not work. However, FRIDA mode (`-O`)
works on both x86 and arm64 macOS boxes. works on both x86 and arm64 macOS boxes.
## iOS on arm64 and arm64e
**Option 1: Compilation on jailbroken iOS (recommended)**
To compile directly on a jailbroken iOS device, it is recommended to use a jailbreak that supports Procursus,
as Procursus provides up-to-date pre-built packages for the required tools.
Ensure `openssh` is installed on your iOS device, then SSH into it.
Install the following packages:
```shell
sudo apt install wget git make cmake clang gawk llvm ldid coreutils build-essential xz-utils
```
Configure the environment for compilation:
```shell
export IOS_SDK_PATH="/usr/share/SDKs/iPhoneOS.sdk"
export CC=clang
export CXX=clang++
```
Then build following the general Linux instructions.
**Option 2: Cross-Compilation on macOS for Jailbroken iOS**
In addition to the packages required for a macOS build, install `ldid` for signing binaries:
```shell
brew install ldid-procursus
```
Configure the environment for compilation:
```shell
export IOS_SDK_PATH="$(xcrun --sdk iphoneos --show-sdk-path)"
export CC="$(xcrun --sdk iphoneos -f clang) -target arm64-apple-ios14.0"
export CXX="$(xcrun --sdk iphoneos -f clang++) -target arm64-apple-ios14.0"
export HOST_CC=cc
```
Then build following the general Linux instructions.
Finally, transfer the binaries to your iOS device.

81
docs/SAND.md Normal file
View File

@ -0,0 +1,81 @@
# SAND: Decoupling Sanitization from Fuzzing for Low Overhead
- Authors: Ziqiao Kong, Shaohua Li, Heqing Huang, Zhendong Su
- Maintainer: [Ziqiao Kong](https://github.com/wtdcode)
- Preprint: [arXiv](https://arxiv.org/abs/2402.16497), accepted by ICSE 2025
- Main repo (for paper, reproduction, reference or cite): https://github.com/wtdcode/sand-aflpp
## Motivation
SAND introduces a new fuzzing workflow that can greatly reduce (or even eliminate) sanitizer overhead and combine different sanitizers in one fuzzing campaign.
The key point of SAND is that: sanitizing all inputs is wasting fuzzing power, because bug-triggering inputs are extremely rare (~1%). Obviously, not all inputs worth going through sanitizers. Therefore, if we can somehow "predict" if an input could trigger bugs (defined as "execution pattern"), we could greatly save fuzzing power by only sanitizing a small proportion of all inputs. That's exactly how SAND works.
## Usage
For a normal fuzzing workflow, we have:
1. Build target project with AFL_USE_ASAN=1 to get `target_asan`
2. Fuzz the target with `afl-fuzz -i seeds -o out -- ./target_asan`
For SAND fuzzing workflow, this is slightly different:
1. Build target project _without_ any sanitizers to get `target_native`, which we will define as a "native binary". It is usually done by using `afl-clang-fast/lto(++)` to compile your project _without_ `AFL_USE_ASAN/UBSAN/MSAN`.
2. Build target project with AFL_USE_ASAN=1 AFL_LLVM_ONLY_FSRV=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
3. Fuzz the target with `afl-fuzz -i seeds -o out -w ./target_asan -- ./target_native`. Note `-w` can be specified multiple times.
Then you get:
- almost the same performance as `afl-fuzz -i seeds -o out -- ./target_native`
- and the same bug-finding capability as `afl-fuzz -i seeds -o out -- ./target_asan`
## Example Workflow
Take [test-instr.c](../test-instr.c) as an example.
1. Build the native binary
```bash
afl-clang-fast test-instr.c -o ./native
```
Just like the normal building process, except using `afl-clang-fast`
2. Build the sanitizers-enabled binaries.
```bash
AFL_LLVM_ONLY_FSRV=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
AFL_LLVM_ONLY_FSRV=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
```
Do note `AFL_LLVM_ONLY_FSRV=1` is crucial, this enables forkservers but disables pc instrumentation. You are allowed to reuse sanitizers-enabled binaries, i.e. binaries built _without_ `AFL_LLVM_ONLY_FSRV=1`, at a cost of reduced speed.
3. Start fuzzing
```bash
mkdir /tmp/test
echo "a" > /tmp/test/a
AFL_NO_UI=1 AFL_SKIP_CPUFREQ=1 afl-fuzz -i /tmp/test -o /tmp/out -w ./asanubsan -w ./msan -- ./native @@
```
That's it!
## Tips
### Alternative execution patterns
By default, SAND uses the hash value of the simplified coverage map as execution pattern, i.e. if an input has a unique simplefied coverage map, it will be sent to sanitizers for inspection. This shall work for most cases. However, if you are strongly worried about missing bugs, try `AFL_SAN_ABSTRACTION=unique_trace afl-fuzz ...`, which filters inputs having a _unique coverage map_. Do note this significantly increases the number of inputs by 4-10 times, leading to much lower throughput. Alternatively, SAND also supports `AFL_SAN_ABSTRACTION=coverage_increase`, which essentially equals to running sanitizers on the corpus and thus having almost zero overhead, but at a cost of missing ~15% bugs in our evaluation.
### Run as many sanitizers as possible
Though we just used ASAN as an example, SAND works best if you provide more sanitizers, for example, UBSAN and MSAN.
You might do it via `afl-fuzz -i seeds -o out -w ./target_asan -w ./target_msan -w ./target_ubsan -- ./target_native`. Don't worry about the slow sanitizers like MSAN, SAND could still run very fast because only rather a few inputs are sanitized.
### Bugs types
The execution pattern evaluated in our papers is targeting the common bugs, as ASAN/MSAN/UBSAN catches. For other bug types, you probably need to define new execution patterns and re-evaluate.
### My throughput is greatly impacted
Generally, this is due to too many inputs going through sanitizers, for example, because of unstable targets. You could check stats from `plot_file` to confirm this. Try to switch execution patterns as stated above.

View File

@ -6,7 +6,7 @@ coverage to effortlessly pick up subtle, local-scale changes to program control
flow. flow.
Note: If you are interested in a more current up-to-date deep dive how AFL++ Note: If you are interested in a more current up-to-date deep dive how AFL++
works then we commend this blog post: works then we recommend this blog post:
[https://blog.ritsec.club/posts/afl-under-hood/](https://blog.ritsec.club/posts/afl-under-hood/) [https://blog.ritsec.club/posts/afl-under-hood/](https://blog.ritsec.club/posts/afl-under-hood/)
Simplifying a bit, the overall algorithm can be summed up as: Simplifying a bit, the overall algorithm can be summed up as:
@ -385,10 +385,6 @@ there are several things to look at:
subsequent iterations (e.g., due to incomplete clean-up or reinitialization of subsequent iterations (e.g., due to incomplete clean-up or reinitialization of
the state) and that most of the fuzzing effort goes to waste. the state) and that most of the fuzzing effort goes to waste.
The paths where variable behavior is detected are marked with a matching entry
in the `<out_dir>/queue/.state/variable_behavior/` directory, so you can look
them up easily.
### CPU load ### CPU load
``` ```

View File

@ -38,9 +38,8 @@ For PCGUARD instrumentation `abort()` is called if this is detected, for LTO
there will either be no coverage for the instrumented dlopen()'ed libraries or there will either be no coverage for the instrumented dlopen()'ed libraries or
you will see lots of crashes in the UI. you will see lots of crashes in the UI.
Note that this is not an issue if you use the inferiour `afl-gcc-fast`, Note that this is not an issue if you use the inferiour `afl-gcc-fast`, or
`afl-gcc` or`AFL_LLVM_INSTRUMENT=CLASSIC/NGRAM/CTX afl-clang-fast` `AFL_LLVM_INSTRUMENT=CLASSIC/NGRAM/CTX afl-clang-fast` instrumentation.
instrumentation.
### Fuzzing a binary-only target ### Fuzzing a binary-only target

View File

@ -151,7 +151,7 @@ def deinit(): # optional for Python
splicing - or anything else - and can also be ignored. If you are not splicing - or anything else - and can also be ignored. If you are not
using this additional data then define `splice_optout` (see above). using this additional data then define `splice_optout` (see above).
This function is optional. This function is optional.
Returing a length of 0 is valid and is interpreted as skipping this Returning a length of 0 is valid and is interpreted as skipping this
one mutation result. one mutation result.
For non-Python: the returned output buffer is under **your** memory For non-Python: the returned output buffer is under **your** memory
management! management!
@ -198,6 +198,11 @@ def deinit(): # optional for Python
This method can be used if you want to send data to the target yourself, This method can be used if you want to send data to the target yourself,
e.g. via IPC. This replaces some usage of utils/afl_proxy but requires e.g. via IPC. This replaces some usage of utils/afl_proxy but requires
that you start the target with afl-fuzz. that you start the target with afl-fuzz.
Setting `AFL_CUSTOM_MUTATOR_LATE_SEND` will call the afl_custom_fuzz_send()
function after the target has been restarted. (This is needed for e.g. TCP
services.)
Example: [custom_mutators/examples/custom_send.c](../custom_mutators/examples/custom_send.c) Example: [custom_mutators/examples/custom_send.c](../custom_mutators/examples/custom_send.c)
- `queue_new_entry` (optional): - `queue_new_entry` (optional):

View File

@ -24,7 +24,6 @@ To select the different instrumentation modes, use one of the following options:
- Use the `AFL_CC_COMPILER` environment variable with `MODE`. To select - Use the `AFL_CC_COMPILER` environment variable with `MODE`. To select
`MODE`, use one of the following values: `MODE`, use one of the following values:
- `GCC` (afl-gcc/afl-g++)
- `GCC_PLUGIN` (afl-g*-fast) - `GCC_PLUGIN` (afl-g*-fast)
- `LLVM` (afl-clang-fast*) - `LLVM` (afl-clang-fast*)
- `LTO` (afl-clang-lto*). - `LTO` (afl-clang-lto*).
@ -45,14 +44,10 @@ fairly broad use of environment variables instead:
make make
``` ```
- Setting `AFL_AS`, `AFL_CC`, and `AFL_CXX` lets you use alternate downstream - Setting `AFL_CC`, and `AFL_CXX` lets you use alternate downstream
compilation tools, rather than the default 'as', 'clang', or 'gcc' binaries compilation tools, rather than the default 'clang', or 'gcc' binaries
in your `$PATH`. in your `$PATH`.
- If you are a weird person that wants to compile and instrument asm text
files, then use the `AFL_AS_FORCE_INSTRUMENT` variable:
`AFL_AS_FORCE_INSTRUMENT=1 afl-gcc foo.s -o foo`
- Most AFL tools do not print any output if stdout/stderr are redirected. If - Most AFL tools do not print any output if stdout/stderr are redirected. If
you want to get the output into a file, then set the `AFL_DEBUG` environment you want to get the output into a file, then set the `AFL_DEBUG` environment
variable. This is sadly necessary for various build processes which fail variable. This is sadly necessary for various build processes which fail
@ -64,6 +59,9 @@ fairly broad use of environment variables instead:
optimizations, set `AFL_DONT_OPTIMIZE`. However, if `-O...` and/or optimizations, set `AFL_DONT_OPTIMIZE`. However, if `-O...` and/or
`-fno-unroll-loops` are set, these are not overridden. `-fno-unroll-loops` are set, these are not overridden.
- The optimization level can also be set with `AFL_OPT_LEVEL`, e.g.
`AFL_OPT_LEVEL=z` for `-Oz`, default is `3`
- Setting `AFL_HARDEN` automatically adds code hardening options when invoking - Setting `AFL_HARDEN` automatically adds code hardening options when invoking
the downstream compiler. This currently includes `-D_FORTIFY_SOURCE=2` and the downstream compiler. This currently includes `-D_FORTIFY_SOURCE=2` and
`-fstack-protector-all`. The setting is useful for catching non-crashing `-fstack-protector-all`. The setting is useful for catching non-crashing
@ -80,17 +78,13 @@ fairly broad use of environment variables instead:
Setting `AFL_INST_RATIO` to 0 is a valid choice. This will instrument only Setting `AFL_INST_RATIO` to 0 is a valid choice. This will instrument only
the transitions between function entry points, but not individual branches. the transitions between function entry points, but not individual branches.
Note that this is an outdated variable. A few instances (e.g., afl-gcc) Note that this is an outdated variable. Only LLVM CLASSIC pass can use this.
still support these, but state-of-the-art (e.g., LLVM LTO and LLVM PCGUARD)
do not need this.
- `AFL_NO_BUILTIN` causes the compiler to generate code suitable for use with - `AFL_NO_BUILTIN` causes the compiler to generate code suitable for use with
libtokencap.so (but perhaps running a bit slower than without the flag). libtokencap.so (but perhaps running a bit slower than without the flag).
- `AFL_PATH` can be used to point afl-gcc to an alternate location of afl-as. - `AFL_PATH` can be used to point a directory that contains LLVM/GCC plugins
One possible use of this is utils/clang_asm_normalize/, which lets you for AFL++, AFL++'s runtime objects and QEMU/Frida support files.
instrument hand-written assembly when compiling clang code by plugging a
normalizer into the chain. (There is no equivalent feature for GCC.)
- Setting `AFL_QUIET` will prevent afl-as and afl-cc banners from being - Setting `AFL_QUIET` will prevent afl-as and afl-cc banners from being
displayed during compilation, in case you find them distracting. displayed during compilation, in case you find them distracting.
@ -101,6 +95,7 @@ fairly broad use of environment variables instead:
detection) detection)
- `AFL_USE_CFISAN=1` - activates the Control Flow Integrity sanitizer (e.g. - `AFL_USE_CFISAN=1` - activates the Control Flow Integrity sanitizer (e.g.
type confusion vulnerabilities) type confusion vulnerabilities)
- `AFL_CFISAN_VERBOSE=1` - outputs detailed information when control flow integrity violations occur, instead of simply terminating with "Illegal Instruction"
- `AFL_USE_LSAN` - activates the leak sanitizer. To perform a leak check - `AFL_USE_LSAN` - activates the leak sanitizer. To perform a leak check
within your program at a certain point (such as at the end of an within your program at a certain point (such as at the end of an
`__AFL_LOOP()`), you can run the macro `__AFL_LEAK_CHECK();` which will `__AFL_LOOP()`), you can run the macro `__AFL_LEAK_CHECK();` which will
@ -111,6 +106,14 @@ fairly broad use of environment variables instead:
- `AFL_USE_TSAN=1` - activates the thread sanitizer to find thread race - `AFL_USE_TSAN=1` - activates the thread sanitizer to find thread race
conditions conditions
- `AFL_USE_UBSAN=1` - activates the undefined behavior sanitizer - `AFL_USE_UBSAN=1` - activates the undefined behavior sanitizer
- `AFL_UBSAN_VERBOSE=1` - outputs detailed diagnostic information when undefined behavior is detected, instead of simply terminating with "Illegal Instruction"
. `AFL_USE_RTSAN` . activates the realtime sanitizer (realtime violations in deterministic run time constraints). (clang 20 minimum)
- Note: both `AFL_CFISAN_VERBOSE=1` and `AFL_UBSAN_VERBOSE=1` are disabled by default as verbose output can significantly slow down fuzzing performance. Use these options only during debugging or when additional crash diagnostics are required
- `AFL_LLVM_ONLY_FSRV`/`AFL_GCC_ONLY_FSRV` will inject forkserver but not pc instrumentation. Please note this is different compared to `AFL_LLVM_DISABLE_INSTRUMENTATION`, which will totally disable forkserver implementation. This env is pretty useful in two cases:
- [SAND](./SAND.md). In this case, the binaries built in this way will serve as extra oracles. Check the corresponding documents for details.
- Compatible with LibAFL ForkserverExecutor implementation and thus faster to repeatedly run, compared to simple CommandExecutor.
- `TMPDIR` is used by afl-as for temporary files; if this variable is not set, - `TMPDIR` is used by afl-as for temporary files; if this variable is not set,
the tool defaults to /tmp. the tool defaults to /tmp.
@ -249,7 +252,7 @@ used if several separated instrumentations are performed which are then later
combined. combined.
- `AFL_LLVM_LTO_CALLER` activates collision free CALLER instrumentation - `AFL_LLVM_LTO_CALLER` activates collision free CALLER instrumentation
- `AFL_LLVM_LTO_CALLER` sets the maximum mumber of single block functions - `AFL_LLVM_LTO_CALLER` sets the maximum number of single block functions
to dig deeper into a real function. Default 0. to dig deeper into a real function. Default 0.
- `AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge ID was given - `AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge ID was given
to which function. This helps to identify functions with variable bytes or to which function. This helps to identify functions with variable bytes or
@ -323,6 +326,11 @@ mode.
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
for more information. for more information.
Setting `AFL_GCC_DISABLE_VERSION_CHECK=1` will disable the GCC plugin
version check if the target GCC plugin differs from the system-installed
version, resolving issues caused by version mismatches between GCC and
the plugin.
Setting `AFL_GCC_OUT_OF_LINE=1` will instruct afl-gcc-fast to instrument the Setting `AFL_GCC_OUT_OF_LINE=1` will instruct afl-gcc-fast to instrument the
code with calls to an injected subroutine instead of the much more efficient code with calls to an injected subroutine instead of the much more efficient
inline instrumentation. inline instrumentation.
@ -331,7 +339,26 @@ mode.
the target performs only a few loops, then this will give a small the target performs only a few loops, then this will give a small
performance boost. performance boost.
## 4) Settings for afl-fuzz ## 4) Runtime settings
The following environment variables are for a compiled AFL++ target.
- Setting `AFL_DUMP_MAP_SIZE` when executing the target directly will
dump the map size of the target and exit.
- Setting `AFL_OLD_FORKSERVER` will use the old AFL vanilla forkserver.
This makes only sense when you
a) compile in a classic colliding coverage mode (e.g.
AFL_LLVM_INSTRUMENT=CLASSIC) or if the map size of the target is
below MAP_SIZE (65536 by default), AND
b) you want to use this compiled AFL++ target with a different tool
that expects vanilla AFL behaviour, e.g. symcc, symqemu, nautilus, etc.
You would use this option together with the target fuzzing application.
- Setting `AFL_DISABLE_LLVM_INSTRUMENTATION` will disable collecting
instrumentation. (More of an internal option.)
## 5) Settings for afl-fuzz
The main fuzzer binary accepts several options that disable a couple of sanity The main fuzzer binary accepts several options that disable a couple of sanity
checks or alter some of the more exotic semantics of the tool: checks or alter some of the more exotic semantics of the tool:
@ -368,6 +395,10 @@ checks or alter some of the more exotic semantics of the tool:
XML or other highly flexible structured input. For details, see XML or other highly flexible structured input. For details, see
[custom_mutators.md](custom_mutators.md). [custom_mutators.md](custom_mutators.md).
- Setting `AFL_CUSTOM_MUTATOR_LATE_SEND` will call the afl_custom_fuzz_send()
function after the target has been restarted. (This is needed for e.g. TCP
services.)
- Setting `AFL_CYCLE_SCHEDULES` will switch to a different schedule every time - Setting `AFL_CYCLE_SCHEDULES` will switch to a different schedule every time
a cycle is finished. a cycle is finished.
@ -401,9 +432,8 @@ checks or alter some of the more exotic semantics of the tool:
types of automated jobs. types of automated jobs.
- `AFL_EXIT_WHEN_DONE` causes afl-fuzz to terminate when all existing paths - `AFL_EXIT_WHEN_DONE` causes afl-fuzz to terminate when all existing paths
have been fuzzed and there were no new finds for a while. This would be have been fuzzed and there were no new finds for a while. This is basically
normally indicated by the cycle counter in the UI turning green. May be when the fuzzing state says `state: finished`
convenient for some types of automated jobs.
- Setting `AFL_EXPAND_HAVOC_NOW` will start in the extended havoc mode that - Setting `AFL_EXPAND_HAVOC_NOW` will start in the extended havoc mode that
includes costly mutations. afl-fuzz automatically enables this mode when includes costly mutations. afl-fuzz automatically enables this mode when
@ -514,6 +544,8 @@ checks or alter some of the more exotic semantics of the tool:
- `AFL_NO_SNAPSHOT` will advise afl-fuzz not to use the snapshot feature if - `AFL_NO_SNAPSHOT` will advise afl-fuzz not to use the snapshot feature if
the snapshot lkm is loaded. the snapshot lkm is loaded.
- `AFL_NO_FASTRESUME` will not try to read or write a fast resume file.
- Setting `AFL_NO_UI` inhibits the UI altogether and just periodically prints - Setting `AFL_NO_UI` inhibits the UI altogether and just periodically prints
some basic stats. This behavior is also automatically triggered when the some basic stats. This behavior is also automatically triggered when the
output from afl-fuzz is redirected to a file or to a pipe. output from afl-fuzz is redirected to a file or to a pipe.
@ -585,7 +617,7 @@ checks or alter some of the more exotic semantics of the tool:
see [rpc_statsd.md](rpc_statsd.md). see [rpc_statsd.md](rpc_statsd.md).
- `AFL_SYNC_TIME` allows you to specify a different minimal time (in minutes) - `AFL_SYNC_TIME` allows you to specify a different minimal time (in minutes)
between fuzzing instances synchronization. Default sync time is 30 minutes, between fuzzing instances synchronization. Default sync time is 20 minutes,
note that time is halved for -M main nodes. note that time is halved for -M main nodes.
- `AFL_NO_SYNC` disables any syncing whatsoever and takes priority on all - `AFL_NO_SYNC` disables any syncing whatsoever and takes priority on all
@ -636,7 +668,25 @@ checks or alter some of the more exotic semantics of the tool:
Note that will not be exact and with slow targets it can take seconds Note that will not be exact and with slow targets it can take seconds
until there is a slice for the time test. until there is a slice for the time test.
## 5) Settings for afl-qemu-trace - When using `AFL_PRELOAD` with a preload that disable `fork()` calls in
the target, the forkserver becomes unable to fork.
To overcome this issue, the `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT`
permits to be able to check in the preloaded library if the environment
variable `AFL_FORKSERVER_PARENT` is set, to be able to use vanilla
`fork()` in the forkserver, and the placeholder in the target.
Here is a POC :
```C
// AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT=1 afl-fuzz ...
pid_t fork(void)
{
if (getenv("AFL_FORKSERVER_PARENT") == NULL)
return 0; // We are in the target
else
return real_fork(); // We are in the forkserver
}
```
## 6) Settings for afl-qemu-trace
The QEMU wrapper used to instrument binary-only code supports several settings: The QEMU wrapper used to instrument binary-only code supports several settings:
@ -708,7 +758,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
crash is found. Setting `AFL_NO_CRASH_README` will prevent this. Useful when crash is found. Setting `AFL_NO_CRASH_README` will prevent this. Useful when
counting crashes based on a file count in that directory. counting crashes based on a file count in that directory.
## 7) Settings for afl-frida-trace ## 8) Settings for afl-frida-trace
The FRIDA wrapper used to instrument binary-only code supports many of the same The FRIDA wrapper used to instrument binary-only code supports many of the same
options as `afl-qemu-trace`, but also has a number of additional advanced options as `afl-qemu-trace`, but also has a number of additional advanced
@ -798,7 +848,7 @@ support.
dump you must set a sufficient timeout (using `-t`) to avoid `afl-fuzz` dump you must set a sufficient timeout (using `-t`) to avoid `afl-fuzz`
killing the process whilst it is being dumped. killing the process whilst it is being dumped.
## 8) Settings for afl-cmin ## 9) Settings for afl-cmin
The corpus minimization script offers very little customization: The corpus minimization script offers very little customization:
@ -816,7 +866,7 @@ The corpus minimization script offers very little customization:
- `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed. - `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed.
This can help when embedding `afl-cmin` or `afl-showmap` in other scripts. This can help when embedding `afl-cmin` or `afl-showmap` in other scripts.
## 9) Settings for afl-tmin ## 10) Settings for afl-tmin
Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be
searched for afl-qemu-trace. In addition to this, `TMPDIR` may be used if a searched for afl-qemu-trace. In addition to this, `TMPDIR` may be used if a
@ -827,12 +877,12 @@ to match when minimizing crashes. This will make minimization less useful, but
may prevent the tool from "jumping" from one crashing condition to another in may prevent the tool from "jumping" from one crashing condition to another in
very buggy software. You probably want to combine it with the `-e` flag. very buggy software. You probably want to combine it with the `-e` flag.
## 10) Settings for afl-analyze ## 11) Settings for afl-analyze
You can set `AFL_ANALYZE_HEX` to get file offsets printed as hexadecimal instead You can set `AFL_ANALYZE_HEX` to get file offsets printed as hexadecimal instead
of decimal. of decimal.
## 11) Settings for libdislocator ## 12) Settings for libdislocator
The library honors these environment variables: The library honors these environment variables:
@ -854,12 +904,12 @@ The library honors these environment variables:
- `AFL_LD_VERBOSE` causes the library to output some diagnostic messages that - `AFL_LD_VERBOSE` causes the library to output some diagnostic messages that
may be useful for pinpointing the cause of any observed issues. may be useful for pinpointing the cause of any observed issues.
## 11) Settings for libtokencap ## 13) Settings for libtokencap
This library accepts `AFL_TOKEN_FILE` to indicate the location to which the This library accepts `AFL_TOKEN_FILE` to indicate the location to which the
discovered tokens should be written. discovered tokens should be written.
## 12) Third-party variables set by afl-fuzz & other tools ## 14) Third-party variables set by afl-fuzz & other tools
Several variables are not directly interpreted by afl-fuzz, but are set to Several variables are not directly interpreted by afl-fuzz, but are set to
optimal values if not already present in the environment: optimal values if not already present in the environment:

View File

@ -6,20 +6,22 @@ QEMU 5.1 with laf-intel and Redqueen, FRIDA mode, unicorn mode, gcc plugin, full
## Features and instrumentation ## Features and instrumentation
| Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | FRIDA mode(9) | QEMU mode(10) | unicorn_mode(10) | nyx_mode(12) | coresight_mode(11) | Note that afl-gcc and afl-clang have been removed because their instrumentation is absolutely outdated.
| ------------------------------|:--------:|:---------:|:----------:|:--------------:|:----------------:|:----------------:|:------------:|:------------------:|
| Threadsafe counters [A] | | x(3) | | | | | x | | | Feature/Instrumentation | llvm | gcc_plugin | FRIDA mode(9) | QEMU mode(10) | unicorn_mode(10) | nyx_mode(12) | coresight_mode(11) |
| NeverZero [B] | x86[_64] | x(1) | x | x | x | x | | | | ------------------------------|:---------:|:----------:|:--------------:|:----------------:|:----------------:|:------------:|:------------------:|
| Persistent Mode [C] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | | | Threadsafe counters [A] | x(3) | | | | | x | |
| LAF-Intel / CompCov [D] | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | | | NeverZero [B] | x(1) | x | x | x | x | | |
| CmpLog [E] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | | | | | Persistent Mode [C] | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | |
| Selective Instrumentation [F] | | x | x | x | x | | | | | LAF-Intel / CompCov [D] | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | |
| Non-Colliding Coverage [G] | | x(4) | | | (x)(5) | | | | | CmpLog [E] | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
| Ngram prev_loc Coverage [H] | | x(6) | | | | | | | | Selective Instrumentation [F] | x | x | x | x | | | |
| Context Coverage [I] | | x(6) | | | | | | | | Non-Colliding Coverage [G] | x(4) | | | (x)(5) | | | |
| Auto Dictionary [J] | | x(7) | | | | | | | | Ngram prev_loc Coverage [H] | x(6) | | | | | | |
| Snapshot Support [K] | | (x)(8) | (x)(8) | | (x)(5) | | x | | | Context Coverage [I] | x(6) | | | | | | |
| Shared Memory Test cases [L] | | x | x | x86[_64]/arm64 | x | x | x | | | Auto Dictionary [J] | x(7) | | | | | | |
| Snapshot Support [K] | (x)(8) | (x)(8) | | (x)(5) | | x | |
| Shared Memory Test cases [L] | x | x | x86[_64]/arm64 | x | x | x | |
## More information about features ## More information about features
@ -43,7 +45,7 @@ E. CmpLog is our enhanced
implementation, see implementation, see
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md) [instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md)
F. Similar and compatible to clang 13+ sancov sanitize-coverage-allow/deny but F. Similar and compatible to clang 14+ sancov sanitize-coverage-allow/deny but
for all llvm versions and all our compile modes, only instrument what should for all llvm versions and all our compile modes, only instrument what should
be instrumented, for more speed, directed fuzzing and less instability; see be instrumented, for more speed, directed fuzzing and less instability; see
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
@ -94,7 +96,7 @@ L. Faster fuzzing and less kernel syscall overhead by in-memory fuzz testcase
Among others, the following features and patches have been integrated: Among others, the following features and patches have been integrated:
* NeverZero patch for afl-gcc, instrumentation, QEMU mode and unicorn_mode which * NeverZero for llvm/gcc instrumentation, QEMU mode and unicorn_mode which
prevents a wrapping map value to zero, increases coverage prevents a wrapping map value to zero, increases coverage
* Persistent mode, deferred forkserver and in-memory fuzzing for QEMU mode * Persistent mode, deferred forkserver and in-memory fuzzing for QEMU mode
* Unicorn mode which allows fuzzing of binaries from completely different * Unicorn mode which allows fuzzing of binaries from completely different
@ -104,6 +106,7 @@ Among others, the following features and patches have been integrated:
* Win32 PE binary-only fuzzing with QEMU and Wine * Win32 PE binary-only fuzzing with QEMU and Wine
* AFLfast's power schedules by Marcel Böhme: * AFLfast's power schedules by Marcel Böhme:
[https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast) [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
* The fast deterministic stage by Han Zheng: [https://github.com/hexhive/mendelFuzz-Artifact/](https://github.com/hexhive/mendelFuzz-Artifact/)
* The MOpt mutator: * The MOpt mutator:
[https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL) [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
* LLVM mode Ngram coverage by Adrian Herrera * LLVM mode Ngram coverage by Adrian Herrera

View File

@ -46,10 +46,9 @@ The following setup to use QEMU mode is recommended:
`AFL_COMPCOV_LEVEL=2`), alternatively you can use FRIDA mode, just switch `-Q` `AFL_COMPCOV_LEVEL=2`), alternatively you can use FRIDA mode, just switch `-Q`
with `-O` and remove the LAF instance with `-O` and remove the LAF instance
Then run as many instances as you have cores left with either -Q mode or - even Then run as many instances as you have cores left with either `-Q` mode or use
better - use a binary rewriter like Dyninst, RetroWrite, ZAFL, etc. a static binary rewriter like Dyninst, RetroWrite, ZAFL, etc.
The binary rewriters all have their own advantages and caveats. The binary rewriters all have their own advantages and caveats, but ZAFL is a good choice.
ZAFL is the best but cannot be used in a business/commercial context.
If a binary rewriter works for your target then you can use afl-fuzz normally If a binary rewriter works for your target then you can use afl-fuzz normally
and it will have twice the speed compared to QEMU mode (but slower than QEMU and it will have twice the speed compared to QEMU mode (but slower than QEMU
@ -197,9 +196,10 @@ afl-clang-fast's.
RetroWrite is a static binary rewriter that can be combined with AFL++. If you RetroWrite is a static binary rewriter that can be combined with AFL++. If you
have an x86_64 or arm64 binary that does not contain C++ exceptions and - if have an x86_64 or arm64 binary that does not contain C++ exceptions and - if
x86_64 - still has it's symbols and compiled with position independent code x86_64 - still has its symbols and compiled with position independent code
(PIC/PIE), then the RetroWrite solution might be for you. (PIC/PIE), then the RetroWrite solution might be for you.
It decompiles to ASM files which can then be instrumented with afl-gcc. It decompiles to ASM files which can then be instrumented with afl-gcc.
Note that afl-gcc is only present until AFL++ v4.21c and was subsequently removed as it is obsolete.
Binaries that are statically instrumented for fuzzing using RetroWrite are close Binaries that are statically instrumented for fuzzing using RetroWrite are close
in performance to compiler-instrumented binaries and outperform the QEMU-based in performance to compiler-instrumented binaries and outperform the QEMU-based

View File

@ -61,6 +61,8 @@ evaluation flow will help you to select the best possible.
It is highly recommended to have the newest llvm version possible installed, It is highly recommended to have the newest llvm version possible installed,
anything below 9 is not recommended. anything below 9 is not recommended.
IMPORTANT NOTICE: afl-gcc/afl-clang have been removed from AFL++ as they are obsolete.
``` ```
+--------------------------------+ +--------------------------------+
| clang/clang++ 11+ is available | --> use LTO mode (afl-clang-lto/afl-clang-lto++) | clang/clang++ 11+ is available | --> use LTO mode (afl-clang-lto/afl-clang-lto++)
@ -84,7 +86,7 @@ anything below 9 is not recommended.
| if not, or if you do not have a gcc with plugin support | if not, or if you do not have a gcc with plugin support
| |
v v
use GCC mode (afl-gcc/afl-g++) (or afl-clang/afl-clang++ for clang) GAME OVER! Install gcc-VERSION-plugin-dev or llvm-VERSION-dev
``` ```
Clickable README links for the chosen compiler: Clickable README links for the chosen compiler:
@ -92,14 +94,12 @@ Clickable README links for the chosen compiler:
* [LTO mode - afl-clang-lto](../instrumentation/README.lto.md) * [LTO mode - afl-clang-lto](../instrumentation/README.lto.md)
* [LLVM mode - afl-clang-fast](../instrumentation/README.llvm.md) * [LLVM mode - afl-clang-fast](../instrumentation/README.llvm.md)
* [GCC_PLUGIN mode - afl-gcc-fast](../instrumentation/README.gcc_plugin.md) * [GCC_PLUGIN mode - afl-gcc-fast](../instrumentation/README.gcc_plugin.md)
* GCC/CLANG modes (afl-gcc/afl-clang) have no README as they have no own
features
You can select the mode for the afl-cc compiler by one of the following methods: You can select the mode for the afl-cc compiler by one of the following methods:
* Using a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++, * Using a symlink to afl-cc:
afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++, afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++,
afl-gcc-fast, afl-g++-fast (recommended!). afl-gcc-fast, afl-g++-fast.
* Using the environment variable `AFL_CC_COMPILER` with `MODE`. * Using the environment variable `AFL_CC_COMPILER` with `MODE`.
* Passing --afl-`MODE` command line options to the compiler via * Passing --afl-`MODE` command line options to the compiler via
`CFLAGS`/`CXXFLAGS`/`CPPFLAGS`. `CFLAGS`/`CXXFLAGS`/`CPPFLAGS`.
@ -108,8 +108,7 @@ You can select the mode for the afl-cc compiler by one of the following methods:
* LTO (afl-clang-lto*) * LTO (afl-clang-lto*)
* LLVM (afl-clang-fast*) * LLVM (afl-clang-fast*)
* GCC_PLUGIN (afl-g*-fast) or GCC (afl-gcc/afl-g++) * GCC_PLUGIN (afl-g*-fast)
* CLANG(afl-clang/afl-clang++)
Because no AFL++ specific command-line options are accepted (beside the Because no AFL++ specific command-line options are accepted (beside the
--afl-MODE command), the compile-time tools make fairly broad use of environment --afl-MODE command), the compile-time tools make fairly broad use of environment
@ -133,11 +132,15 @@ options are available:
locations. This technique is very fast and good - if the target does not locations. This technique is very fast and good - if the target does not
transform input data before comparison. Therefore, this technique is called transform input data before comparison. Therefore, this technique is called
`input to state` or `redqueen`. If you want to use this technique, then you `input to state` or `redqueen`. If you want to use this technique, then you
have to compile the target twice, once specifically with/for this mode by have to compile the target with `AFL_LLVM_CMPLOG=1`.
setting `AFL_LLVM_CMPLOG=1`, and pass this binary to afl-fuzz via the `-c` You could use the resulting binary for both normal fuzzing and `-c` CMPLOG
parameter. Note that you can compile also just a cmplog binary and use that mode (with `-c 0`), however this will result in a performance loss of about
for both, however, there will be a performance penalty. You can read more 20%.
about this in It is therefore better to compile a specific CMPLOG target with
`AFL_LLVM_ONLY_FSRV=1 AFL_LLVM_CMPLOG=1` and pass this binary name via
`-c cmplog-fuzzing-target` and compile target again normally with `afl-cc`
and use this is the fuzzing target as usual.
You can read more about this in
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md). [instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
If you use LTO, LLVM, or GCC_PLUGIN mode If you use LTO, LLVM, or GCC_PLUGIN mode
@ -201,6 +204,12 @@ type. This is enough because e.g. a use-after-free bug will be picked up by ASAN
(address sanitizer) anyway after syncing test cases from other fuzzing (address sanitizer) anyway after syncing test cases from other fuzzing
instances, so running more than one address sanitized target would be a waste. instances, so running more than one address sanitized target would be a waste.
*IF* you are running a saturated corpus, then you can run up to half of the
instances with sanitizers.
An alternative but more effective approach is to use [SAND](./SAND.md) which could
combine different sanitizers at a much higher throughput.
The following sanitizers have built-in support in AFL++: The following sanitizers have built-in support in AFL++:
* ASAN = Address SANitizer, finds memory corruption vulnerabilities like * ASAN = Address SANitizer, finds memory corruption vulnerabilities like
@ -242,6 +251,12 @@ CFISAN. You might need to experiment which sanitizers you can combine in a
target (which means more instances can be run without a sanitized target, which target (which means more instances can be run without a sanitized target, which
is more effective). is more effective).
Note that some sanitizers (MSAN and LSAN) exit with a particular exit code
instead of aborting. afl-fuzz treats these exit codes as a crash when these
sanitizers are enabled. If the target uses these exit codes there could be false
positives among the saved crashes. LSAN uses exit code 23 and MSAN uses exit
code 86.
### d) Modifying the target ### d) Modifying the target
If the target has features that make fuzzing more difficult, e.g., checksums, If the target has features that make fuzzing more difficult, e.g., checksums,
@ -491,6 +506,8 @@ Note:
protection against attacks! So set strong firewall rules and only expose SSH protection against attacks! So set strong firewall rules and only expose SSH
as a network service if you use these (which is highly recommended). as a network service if you use these (which is highly recommended).
If you execute afl-fuzz in a Docker container, it is recommended to pass [`--cpuset-cpus`](https://docs.docker.com/engine/containers/resource_constraints/#configure-the-default-cfs-scheduler) option with free CPU cores to docker daemon when starting the container, or pass `AFL_NO_AFFINITY` to afl-fuzz. This is due to the fact that AFL++ will bind to a free CPU core by default, while Docker container will prevent AFL++ instance from seeing processes in other containers or host, which leads to all AFL++ instances trying to bind the same CPU core.
If you have an input corpus from [step 2](#2-preparing-the-fuzzing-campaign), If you have an input corpus from [step 2](#2-preparing-the-fuzzing-campaign),
then specify this directory with the `-i` option. Otherwise, create a new then specify this directory with the `-i` option. Otherwise, create a new
directory and create a file with any content as test data in there. directory and create a file with any content as test data in there.
@ -622,8 +639,8 @@ The other secondaries should be run like this:
* 40% should run with `-P explore` and 20% with `-P exploit` * 40% should run with `-P explore` and 20% with `-P exploit`
* If you use `-a` then set 30% of the instances to not use `-a`; if you did * If you use `-a` then set 30% of the instances to not use `-a`; if you did
not set `-a` (why??), then set 30% to `-a ascii` and 30% to `-a binary`. not set `-a` (why??), then set 30% to `-a ascii` and 30% to `-a binary`.
* run each with a different power schedule, recommended are: `fast` (default), * run each with a different power schedule, recommended are: `explore` (default),
`explore`, `coe`, `lin`, `quad`, `exploit`, and `rare` which you can set with `fast`, `coe`, `lin`, `quad`, `exploit`, and `rare` which you can set with
the `-p` option, e.g., `-p explore`. See the the `-p` option, e.g., `-p explore`. See the
[FAQ](FAQ.md#what-are-power-schedules) for details. [FAQ](FAQ.md#what-are-power-schedules) for details.
@ -632,7 +649,7 @@ crash or timeout during startup.
Also, it is recommended to set `export AFL_IMPORT_FIRST=1` to load test cases Also, it is recommended to set `export AFL_IMPORT_FIRST=1` to load test cases
from other fuzzers in the campaign first. But note that can slow down the start from other fuzzers in the campaign first. But note that can slow down the start
of the first fuzz by quite a lot of you have many fuzzers and/or many seeds. of the first fuzz by quite a lot if you have many fuzzers and/or many seeds.
If you have a large corpus, a corpus from a previous run or are fuzzing in a CI, If you have a large corpus, a corpus from a previous run or are fuzzing in a CI,
then also set `export AFL_CMPLOG_ONLY_NEW=1` and `export AFL_FAST_CAL=1`. then also set `export AFL_CMPLOG_ONLY_NEW=1` and `export AFL_FAST_CAL=1`.
@ -852,10 +869,13 @@ Here are some of the most important caveats for AFL++:
- There is no direct support for fuzzing network services, background daemons, - There is no direct support for fuzzing network services, background daemons,
or interactive apps that require UI interaction to work. You may need to make or interactive apps that require UI interaction to work. You may need to make
simple code changes to make them behave in a more traditional way. Preeny or simple code changes to make them behave in a more traditional way. Preeny,
libdesock may offer a relatively simple option, too - see: libdesock or desockmulti may offer a relatively simple option, too - see:
[https://github.com/zardus/preeny](https://github.com/zardus/preeny) or [https://github.com/zardus/preeny](https://github.com/zardus/preeny) or
[https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock) [https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
[https://github.com/zyingp/desockmulti](https://github.com/zyingp/desockmulti)
If these fail then try our own which might be a bit slower but is more
reliable: [utils/libaflppdesock](../utils/libaflppdesock)
Some useful tips for modifying network-based services can be also found at: Some useful tips for modifying network-based services can be also found at:
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop) [https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)

29
entitlements.plist Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/ PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>research.com.apple.license-to-operate</key> <true/>
<key>application-identifier</key> <string>aflplusplus</string>
<key>com.apple.asl.access_as_root</key> <true/>
<key>com.apple.backboardd.launchapplications</key> <true/>
<key>com.apple.companionappd.connect.allow</key> <true/>
<key>com.apple.multitasking.termination</key> <true/>
<key>com.apple.private.security.container-required</key> <false/>
<key>com.apple.seld.cm</key> <true/>
<key>com.apple.sh</key> <true/>
<key>com.apple.private.thread-set-state</key> <true/>
<key>com.apple.private.cs.debugger</key> <true/>
<key>com.apple.springboard.debugapplications</key> <true/>
<key>com.apple.springboard.launchapplications</key> <true/>
<key>com.apple.springboard.opensensitiveurl</key> <true/>
<key>dynamic-codesigning</key> <true/>
<key>get-task-allow</key> <true/>
<key>platform-application</key> <true/>
<key>run-unsigned-code</key> <true/>
<key>task_for_pid-allow</key> <true/>
<key>com.apple.private.skip-library-validation</key> <true/>
<key>com.apple.private.amfi.can-load-cdhash</key> <true/>
<key>com.apple.private.amfi.can-execute-cdhash</key> <true/>
<key>com.apple.private.security.no-container</key> <true/>
</dict>
</plist>

View File

@ -39,7 +39,7 @@ is *VERY* important to carry out these basic steps first before taking on the
additional complexity of debugging with FRIDA mode or `afl-fuzz`. additional complexity of debugging with FRIDA mode or `afl-fuzz`.
- Run your harness outside of the fuzzer, passing it a representative seed as - Run your harness outside of the fuzzer, passing it a representative seed as
it's input `./harness <input>`. its input `./harness <input>`.
- Pass your harness multiple seeds to check that it is stable when running - Pass your harness multiple seeds to check that it is stable when running
multiple tests as it will when running in fork server mode `./harness <input1> multiple tests as it will when running in fork server mode `./harness <input1>
<intput2>`. <intput2>`.

View File

@ -15,15 +15,20 @@ JS_OBJ:=$(BUILD_DIR)api.o
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c) SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src)))) OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
XTOOLS_HOST?=x86_64-linux-gnu
TARGET_CC?=$(CC) TARGET_CC?=$(CC)
TARGET_CXX?=$(CXX) TARGET_CXX?=$(CXX)
HOST_CC?=$(CC) HOST_CC?=$(CC)
HOST_CXX?=$(CXX) HOST_CXX?=$(CXX)
IS_ANDROID:=$(findstring android, $(shell $(TARGET_CC) --version 2>/dev/null)) TARGET_CC_INFO=$(shell $(TARGET_CC) --version)
IS_x86:=$(findstring i686, $(shell $(TARGET_CC) --version 2>/dev/null)) IS_IOS:=$(findstring ios, $(TARGET_CC_INFO))
IS_x86_64:=$(findstring x86_64, $(shell $(TARGET_CC) --version 2>/dev/null)) IS_SIMULATOR:=$(findstring sim, $(TARGET_CC_INFO))
IS_ARM:=$(findstring arm, $(shell $(TARGET_CC) --version 2>/dev/null)) IS_ANDROID:=$(findstring android, $(TARGET_CC_INFO))
IS_ARM64:=$(findstring aarch64, $(shell $(TARGET_CC) --version 2>/dev/null)) IS_x86:=$(findstring i686, $(TARGET_CC_INFO))
IS_x86_64:=$(findstring x86_64, $(TARGET_CC_INFO))
IS_ARM:=$(findstring arm, $(TARGET_CC_INFO))
IS_ARM64E:=$(findstring arm64e, $(TARGET_CC_INFO))
IS_ARM64 := $(or $(findstring aarch64,$(TARGET_CC_INFO)), $(findstring arm64,$(TARGET_CC_INFO)))
CFLAGS+=-fPIC \ CFLAGS+=-fPIC \
-D_GNU_SOURCE \ -D_GNU_SOURCE \
-D_FORTIFY_SOURCE=2 \ -D_FORTIFY_SOURCE=2 \
@ -95,7 +100,24 @@ endif
GUM_ARCH="-$(ARCH)" GUM_ARCH="-$(ARCH)"
ifeq "$(shell uname)" "Darwin" ifdef IS_IOS
OS:=ios
ifdef IS_SIMULATOR
ifdef IS_x86_64
ARCH := x86_64-simulator
else ifdef IS_ARM64
ARCH := arm64-simulator
endif
else
ifdef IS_ARM64E
ARCH := arm64e
else ifdef IS_ARM64
ARCH := arm64
endif
endif
override CFLAGS += -isysroot $(IOS_SDK_PATH)
override LDFLAGS += -L$(IOS_SDK_PATH)/usr/lib
else ifeq "$(shell uname)" "Darwin"
OS:=macos OS:=macos
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-deprecated-declarations AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-deprecated-declarations
GUM_ARCH:="" GUM_ARCH:=""
@ -165,17 +187,13 @@ ifndef OS
$(error "Operating system unsupported") $(error "Operating system unsupported")
endif endif
GUM_DEVKIT_VERSION=16.0.11 GUM_DEVKIT_VERSION=17.0.7
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)" GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME) GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
ifdef FRIDA_SOURCE
GUM_DEVIT_LIBRARY=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gumjs-1.0.a
else
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
endif
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
FRIDA_DIR:=$(PWD)build/frida-source/ FRIDA_DIR:=$(PWD)build/frida-source/
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
@ -209,10 +227,13 @@ BIN2C_SRC:=$(PWD)util/bin2c.c
all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN) all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN)
32: 32:
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all XTOOLS_HOST=i686-linux-gnu CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
arm: arm:
CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all XTOOLS_HOST=arm-linux-gnueabihf CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
arm64:
XTOOLS_HOST=aarch64-linux-gnu ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
$(BUILD_DIR): $(BUILD_DIR):
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
@ -225,114 +246,29 @@ $(OBJ_DIR): | $(BUILD_DIR)
$(FRIDA_BUILD_DIR): | $(BUILD_DIR) $(FRIDA_BUILD_DIR): | $(BUILD_DIR)
mkdir -p $@ mkdir -p $@
#TODO Set architecture
ifdef FRIDA_SOURCE ifdef FRIDA_SOURCE
$(FRIDA_MAKEFILE): | $(BUILD_DIR) $(FRIDA_MAKEFILE): | $(BUILD_DIR)
git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR) git clone https://github.com/frida/frida-gum.git $(FRIDA_DIR)
cd $(FRIDA_DIR) && \
./configure \
--host=$(XTOOLS_HOST) \
--enable-tests \
--enable-gumpp \
--enable-gumjs \
--with-devkits=gum,gumjs
.PHONY: $(GUM_DEVIT_LIBRARY) .PHONY: $(GUM_DEVIT_LIBRARY)
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE) $(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH) FRIDA_V8=disabled echo $(GUM_DEVIT_LIBRARY) $(FRIDA_MAKEFILE) $(FRIDA_BUILD_DIR)
cd $(FRIDA_DIR) && make FRIDA_V8=disabled
$(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR) cp $(FRIDA_DIR)build/bindings/gumjs/devkit/frida-gumjs.h $(GUM_DEVIT_HEADER)
echo "#include <stdio.h>" > $@ cp $(FRIDA_DIR)build/bindings/gumjs/devkit/libfrida-gumjs.a $(GUM_DEVIT_LIBRARY)
echo "#include <unistd.h>" >> $@
echo "#include <gum/gumreturnaddress.h>" >> $@
echo "#include <gum/gumbacktracer.h>" >> $@
echo "#include <gum/gumsymbolutil.h>" >> $@
echo "#include <gum/gumstalker.h>" >> $@
echo "#include <gum/gumlibc.h>" >> $@
echo "#include <gumjs/gumscriptbackend.h>" >> $@
ifeq "$(OS)" "macos"
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libiconv.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libv8-8.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgmodule-2.0.a \
else ifeq "$(ARCH)" "arm64"
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
ifeq "$(OS)" "android" ifeq "$(OS)" "android"
CFLAGS += -static-libstdc++ CFLAGS += -static-libstdc++
endif endif
else
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
endif
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
ifeq "$(OS)" "android"
CFLAGS += -static-libstdc++
endif
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
else else
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR) $(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
@ -370,6 +306,11 @@ $(AFL_PERFORMANCE_OBJ): $(AFL_PERFORMANCE_SRC)
$(BIN2C): $(BIN2C_SRC) $(BIN2C): $(BIN2C_SRC)
$(HOST_CC) -D_GNU_SOURCE -o $@ $< $(HOST_CC) -D_GNU_SOURCE -o $@ $<
ifdef IS_IOS
ifeq ($(HOST_CC),$(TARGET_CC))
@ldid -S../entitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
endif
$(JS_SRC): $(JS) $(BIN2C)| $(BUILD_DIR) $(JS_SRC): $(JS) $(BIN2C)| $(BUILD_DIR)
cd $(JS_DIR) && $(BIN2C) api_js $(JS) $@ cd $(JS_DIR) && $(BIN2C) api_js $(JS) $@
@ -410,8 +351,10 @@ $(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL
$(TRACE_LDFLAGS) \ $(TRACE_LDFLAGS) \
$(LDFLAGS) \ $(LDFLAGS) \
$(LDSCRIPT) \ $(LDSCRIPT) \
-o $@ \ -o $@
ifdef IS_IOS
@ldid -S../entitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
cp -v $(FRIDA_TRACE) $(ROOT) cp -v $(FRIDA_TRACE) $(ROOT)
$(FRIDA_TRACE_LIB): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL_COMPILER_RT_OBJ) $(AFL_PERFORMANCE_OBJ) GNUmakefile | $(BUILD_DIR) $(FRIDA_TRACE_LIB): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL_COMPILER_RT_OBJ) $(AFL_PERFORMANCE_OBJ) GNUmakefile | $(BUILD_DIR)
@ -427,9 +370,15 @@ $(FRIDA_TRACE_LIB): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $
$(AFLPP_FRIDA_DRIVER_HOOK_OBJ): $(AFLPP_FRIDA_DRIVER_HOOK_SRC) $(GUM_DEVIT_HEADER) | $(BUILD_DIR) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ): $(AFLPP_FRIDA_DRIVER_HOOK_SRC) $(GUM_DEVIT_HEADER) | $(BUILD_DIR)
$(TARGET_CC) $(CFLAGS) $(LDFLAGS) -I $(FRIDA_BUILD_DIR) $< -o $@ $(TARGET_CC) $(CFLAGS) $(LDFLAGS) -I $(FRIDA_BUILD_DIR) $< -o $@
ifdef IS_IOS
@ldid -S../entitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
$(AFLPP_QEMU_DRIVER_HOOK_OBJ): $(AFLPP_QEMU_DRIVER_HOOK_SRC) | $(BUILD_DIR) $(AFLPP_QEMU_DRIVER_HOOK_OBJ): $(AFLPP_QEMU_DRIVER_HOOK_SRC) | $(BUILD_DIR)
$(TARGET_CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(TARGET_CC) $(CFLAGS) $(LDFLAGS) $< -o $@
ifdef IS_IOS
@ldid -S../entitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif
hook: $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) hook: $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ)

View File

@ -107,7 +107,7 @@ every block of code we execute, performance is critical.
However, the design of the binary instrumentation modes of AFL++ has moved on. However, the design of the binary instrumentation modes of AFL++ has moved on.
Both QEMU and FRIDA modes use a two stage process when executing a target Both QEMU and FRIDA modes use a two stage process when executing a target
application. Each block is first compiled or instrumented, and then it is application. Each block is first compiled or instrumented, and then it is
executed. The compiled blocks can be re-used each time the target executes them. executed. The compiled blocks can be reused each time the target executes them.
Since a blocks ID is based on its address, and this is known at compile time, we Since a blocks ID is based on its address, and this is known at compile time, we
only need to generate this ID once per block and so this ID generation no longer only need to generate this ID once per block and so this ID generation no longer

View File

@ -200,10 +200,10 @@ instrumented address block translations.
* `AFL_FRIDA_INST_NO_SUPPRESS` - Disable deterministic branch suppression. * `AFL_FRIDA_INST_NO_SUPPRESS` - Disable deterministic branch suppression.
Deterministic branch suppression skips the preamble which generates coverage Deterministic branch suppression skips the preamble which generates coverage
information at the start of each block, if the block is reached by a information at the start of each block, if the block is reached by a
deterministic branch. This reduces map polution, and may improve performance deterministic branch. This reduces map pollution, and may improve performance
when all the executing blocks have been prefetched and backpatching applied. when all the executing blocks have been prefetched and backpatching applied.
However, in the event that backpatching is incomplete, this may incur a However, in the event that backpatching is incomplete, this may incur a
performance penatly as branch instructions are disassembled on each branch. performance penalty as branch instructions are disassembled on each branch.
* `AFL_FRIDA_INST_SEED` - Sets the initial seed for the hash function used to * `AFL_FRIDA_INST_SEED` - Sets the initial seed for the hash function used to
generate block (and hence edge) IDs. Setting this to a constant value may be generate block (and hence edge) IDs. Setting this to a constant value may be
useful for debugging purposes, e.g., investigating unstable edges. useful for debugging purposes, e.g., investigating unstable edges.
@ -215,7 +215,7 @@ instrumented address block translations.
coverage information for unstable edges (e.g., to be loaded within IDA coverage information for unstable edges (e.g., to be loaded within IDA
lighthouse). lighthouse).
* `AFL_FRIDA_JS_SCRIPT` - Set the script to be loaded by the FRIDA scripting * `AFL_FRIDA_JS_SCRIPT` - Set the script to be loaded by the FRIDA scripting
engine. See [Scipting.md](Scripting.md) for details. engine. See [Scripting.md](Scripting.md) for details.
* `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target * `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target
application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`). application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`).
* `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target * `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target

View File

@ -724,16 +724,16 @@ class Afl {
* it takes as arguments a `NativePointer` and a `number`. It can be * it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to exclude several ranges. * called multiple times to exclude several ranges.
*/ */
static addExcludedRange(addressess, size) { static addExcludedRange(addresses, size) {
Afl.jsApiAddExcludeRange(addressess, size); Afl.jsApiAddExcludeRange(addresses, size);
} }
/** /**
* This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`, * This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be * it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to include several ranges. * called multiple times to include several ranges.
*/ */
static addIncludedRange(addressess, size) { static addIncludedRange(addresses, size) {
Afl.jsApiAddIncludeRange(addressess, size); Afl.jsApiAddIncludeRange(addresses, size);
} }
/** /**
* This must always be called at the end of your script. This lets * This must always be called at the end of your script. This lets
@ -771,7 +771,7 @@ class Afl {
} }
/** /**
* Print a message to the STDOUT. This should be preferred to * Print a message to the STDOUT. This should be preferred to
* FRIDA's `console.log` since FRIDA will queue it's log messages. * FRIDA's `console.log` since FRIDA will queue its log messages.
* If `console.log` is used in a callback in particular, then there * If `console.log` is used in a callback in particular, then there
* may no longer be a thread running to service this queue. * may no longer be a thread running to service this queue.
*/ */
@ -893,14 +893,14 @@ class Afl {
} }
/** /**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
* `NativePointer` should be provided as it's argument. * `NativePointer` should be provided as its argument.
*/ */
static setPersistentAddress(address) { static setPersistentAddress(address) {
Afl.jsApiSetPersistentAddress(address); Afl.jsApiSetPersistentAddress(address);
} }
/** /**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a * This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
* `number` should be provided as it's argument. * `number` should be provided as its argument.
*/ */
static setPersistentCount(count) { static setPersistentCount(count) {
Afl.jsApiSetPersistentCount(count); Afl.jsApiSetPersistentCount(count);
@ -920,7 +920,7 @@ class Afl {
} }
/** /**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a * This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
* `NativePointer` should be provided as it's argument. * `NativePointer` should be provided as its argument.
*/ */
static setPersistentReturn(address) { static setPersistentReturn(address) {
Afl.jsApiSetPersistentReturn(address); Afl.jsApiSetPersistentReturn(address);

View File

@ -6,17 +6,19 @@
#define UNUSED_PARAMETER(x) (void)(x) #define UNUSED_PARAMETER(x) (void)(x)
int phdr_callback(struct dl_phdr_info *info, size_t size, void *data) int phdr_callback(struct dl_phdr_info *info, size_t size, void *data) {
{
UNUSED_PARAMETER(size); UNUSED_PARAMETER(size);
ElfW(Addr) *base = data; ElfW(Addr) *base = data;
if (info->dlpi_name[0] == 0) { *base = info->dlpi_addr; } if (info->dlpi_name[0] == 0) { *base = info->dlpi_addr; }
return 0; return 0;
} }
int main(int argc, char **argv, char **envp) { int main(int argc, char **argv, char **envp) {
UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argc);
ElfW(Addr) base = 0; ElfW(Addr) base = 0;
@ -26,6 +28,7 @@ int main (int argc, char** argv, char** envp) {
printf("Failed to set ADDR_NO_RANDOMIZE: %d", errno); printf("Failed to set ADDR_NO_RANDOMIZE: %d", errno);
return 1; return 1;
} }
if ((persona & ADDR_NO_RANDOMIZE) == 0) { execvpe(argv[0], argv, envp); } if ((persona & ADDR_NO_RANDOMIZE) == 0) { execvpe(argv[0], argv, envp); }
@ -36,4 +39,6 @@ int main (int argc, char** argv, char** envp) {
if (base == 0) { return 1; } if (base == 0) { return 1; }
return 0; return 0;
} }

View File

@ -45,6 +45,7 @@
js_api_set_stdout; js_api_set_stdout;
js_api_set_traceable; js_api_set_traceable;
js_api_set_verbose; js_api_set_verbose;
js_api_ijon_set;
local: local:
*; *;

View File

@ -31,8 +31,8 @@ __attribute__((visibility("default"))) void afl_persistent_hook(
// do a length check matching the target! // do a length check matching the target!
void **esp = (void **)regs->esp; void **esp = (void **)regs->esp;
void *arg1 = esp[0]; void *arg1 = esp[1];
void **arg2 = &esp[1]; void **arg2 = &esp[2];
memcpy(arg1, input_buf, input_buf_len); memcpy(arg1, input_buf, input_buf_len);
*arg2 = (void *)input_buf_len; *arg2 = (void *)input_buf_len;

View File

@ -84,6 +84,7 @@ void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
*arg2 = (void *)input_buf_len; *arg2 = (void *)input_buf_len;
} }
#elif defined(__aarch64__) #elif defined(__aarch64__)
struct arm64_regs { struct arm64_regs {
@ -180,6 +181,7 @@ void afl_persistent_hook(struct arm64_regs *regs, uint64_t guest_base,
(void)guest_base; /* unused */ (void)guest_base; /* unused */
memcpy((void *)regs->x0, input_buf, input_buf_len); memcpy((void *)regs->x0, input_buf, input_buf_len);
regs->x1 = input_buf_len; regs->x1 = input_buf_len;
} }
#else #else
@ -193,3 +195,4 @@ int afl_persistent_hook_init(void) {
return 1; return 1;
} }

View File

@ -22,6 +22,7 @@ extern guint64 instrument_fixed_seed;
extern uint8_t *__afl_area_ptr; extern uint8_t *__afl_area_ptr;
extern uint32_t __afl_map_size; extern uint32_t __afl_map_size;
extern void __afl_coverage_interesting(uint8_t, uint32_t);
extern __thread guint64 *instrument_previous_pc_addr; extern __thread guint64 *instrument_previous_pc_addr;
@ -72,5 +73,7 @@ void instrument_cache(const cs_insn *instr, GumStalkerOutput *output);
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data); void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data);
void instrument_regs_format(int fd, char *format, ...); void instrument_regs_format(int fd, char *format, ...);
void ijon_set(uint32_t edge);
#endif #endif

View File

@ -4,6 +4,6 @@ This folder contains a Docker image to allow the building of
`afl-frida-trace.so` using the `many-linux` docker image. This docker image is `afl-frida-trace.so` using the `many-linux` docker image. This docker image is
based on CentOS Linux 5. By building `afl-frida-trace.so` for such an old based on CentOS Linux 5. By building `afl-frida-trace.so` for such an old
version of Linux, given the strong backward compatibility of Linux, this should version of Linux, given the strong backward compatibility of Linux, this should
work on the majority of Linux environments. This may be useful for targetting work on the majority of Linux environments. This may be useful for targeting
Linux distributions other than your development environment. `many-local` builds Linux distributions other than your development environment. `many-local` builds
`AFLplusplus` from the local working copy in the `many-linux` environment. `AFLplusplus` from the local working copy in the `many-linux` environment.

View File

@ -27,25 +27,21 @@ void asan_init(void) {
} }
static gboolean asan_exclude_module(const GumModuleDetails *details, static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
gpointer user_data) {
gchar *symbol_name = (gchar *)user_data; gchar *symbol_name = (gchar *)user_data;
GumAddress address; GumAddress address;
const GumMemoryRange *range = gum_module_get_range(module);
address = gum_module_find_export_by_name(details->name, symbol_name); address = gum_module_find_export_by_name(module, symbol_name);
if (address == 0) { return TRUE; } if (address == 0) { return TRUE; }
/* If the reported address of the symbol is outside of the range of the module /* If the reported address of the symbol is outside of the range of the module
* then ignore it */ * then ignore it */
if (address < details->range->base_address) { return TRUE; } if (address < range->base_address) { return TRUE; }
if (address > (details->range->base_address + details->range->size)) { if (address > (range->base_address + range->size)) { return TRUE; }
return TRUE; ranges_add_exclude((GumMemoryRange *)range);
}
ranges_add_exclude((GumMemoryRange *)details->range);
return FALSE; return FALSE;
} }

View File

@ -39,18 +39,18 @@ static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
address = base + index + mem->disp; address = base + index + mem->disp;
if ((operand->access & CS_AC_READ) == CS_AC_READ) {
asan_loadN(address, asan_ctx->size);
}
if ((operand->access & CS_AC_WRITE) == CS_AC_WRITE) { if ((operand->access & CS_AC_WRITE) == CS_AC_WRITE) {
asan_storeN(address, asan_ctx->size); asan_storeN(address, asan_ctx->size);
} }
if ((operand->access & CS_AC_READ) == CS_AC_READ) {
asan_loadN(address, asan_ctx->size);
}
} }
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {

View File

@ -166,7 +166,7 @@ gboolean cmplog_is_readable(guint64 addr, size_t size) {
*/ */
if (addr < DEFAULT_MMAP_MIN_ADDR) { return false; } if (addr < DEFAULT_MMAP_MIN_ADDR) { return false; }
/* Check our addres/length don't wrap around */ /* Check our address/length don't wrap around */
if (SIZE_MAX - addr < size) { return false; } if (SIZE_MAX - addr < size) { return false; }
GumAddress inner_base = addr; GumAddress inner_base = addr;

View File

@ -186,7 +186,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
* execution), we instead ensure that we honour the additional * execution), we instead ensure that we honour the additional
* instrumentation requested (e.g. coverage, asan and complog) when a block * instrumentation requested (e.g. coverage, asan and complog) when a block
* is compiled no matter where we are during initialization. We will end up * is compiled no matter where we are during initialization. We will end up
* re-using these blocks if the code under test calls a block which is also * reusing these blocks if the code under test calls a block which is also
* used during initialization. * used during initialization.
* *
* Coverage data generated during initialization isn't a problem since the * Coverage data generated during initialization isn't a problem since the
@ -449,3 +449,9 @@ void instrument_regs_format(int fd, char *format, ...) {
} }
void ijon_set(uint32_t edge) {
__afl_coverage_interesting(1, edge);
}

View File

@ -285,7 +285,7 @@ static void instrument_coverage_switch(GumStalkerObserver *self,
/* /*
* If the branch is deterministic, then we should start execution at the * If the branch is deterministic, then we should start execution at the
* begining of the block. From here, we will branch and skip the coverage * beginning of the block. From here, we will branch and skip the coverage
* code and jump right to the target code of the instrumented block. * code and jump right to the target code of the instrumented block.
* Otherwise, if the branch is non-deterministic, then we need to branch * Otherwise, if the branch is non-deterministic, then we need to branch
* part way into the block to where the coverage instrumentation starts. * part way into the block to where the coverage instrumentation starts.
@ -516,7 +516,7 @@ void instrument_coverage_optimize(const cs_insn *instr,
* an instruction to load x16,x17 from beyond the red-zone on the stack. A * an instruction to load x16,x17 from beyond the red-zone on the stack. A
* pair of registers are saved/restored because on AARCH64, the stack pointer * pair of registers are saved/restored because on AARCH64, the stack pointer
* must be 16 byte aligned. This instruction is emitted into the block before * must be 16 byte aligned. This instruction is emitted into the block before
* the tranformer (from which we are called) is executed. If is is possible * the transformer (from which we are called) is executed. If is is possible
* for Stalker to make a direct branch (the target block is close enough), it * for Stalker to make a direct branch (the target block is close enough), it
* can forego pushing the registers and instead branch at an offset into the * can forego pushing the registers and instead branch at an offset into the
* block to skip this restoration prolog. * block to skip this restoration prolog.

View File

@ -818,6 +818,9 @@ void instrument_coverage_unstable_find_output(void) {
GDir *dir = g_dir_open(fds_name, 0, NULL); GDir *dir = g_dir_open(fds_name, 0, NULL);
gchar *path_tmp = getenv("AFL_CUSTOM_INFO_OUT");
gchar *instance_name = g_path_get_basename(path_tmp);
FVERBOSE("Coverage Unstable - fds: %s", fds_name); FVERBOSE("Coverage Unstable - fds: %s", fds_name);
for (const gchar *filename = g_dir_read_name(dir); filename != NULL; for (const gchar *filename = g_dir_read_name(dir); filename != NULL;
@ -829,7 +832,7 @@ void instrument_coverage_unstable_find_output(void) {
if (link == NULL) { FFATAL("Failed to read link: %s", fullname); } if (link == NULL) { FFATAL("Failed to read link: %s", fullname); }
gchar *basename = g_path_get_basename(link); gchar *basename = g_path_get_basename(link);
if (g_strcmp0(basename, "default") != 0) { if (g_strcmp0(basename, instance_name) != 0) {
g_free(basename); g_free(basename);
g_free(link); g_free(link);
@ -874,6 +877,7 @@ void instrument_coverage_unstable_find_output(void) {
} }
g_dir_close(dir); g_dir_close(dir);
g_free(instance_name);
g_free(fds_name); g_free(fds_name);
if (unstable_coverage_fuzzer_stats == NULL) { if (unstable_coverage_fuzzer_stats == NULL) {

View File

@ -5,16 +5,16 @@ class Afl {
* it takes as arguments a `NativePointer` and a `number`. It can be * it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to exclude several ranges. * called multiple times to exclude several ranges.
*/ */
static addExcludedRange(addressess, size) { static addExcludedRange(addresses, size) {
Afl.jsApiAddExcludeRange(addressess, size); Afl.jsApiAddExcludeRange(addresses, size);
} }
/** /**
* This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`, * This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be * it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to include several ranges. * called multiple times to include several ranges.
*/ */
static addIncludedRange(addressess, size) { static addIncludedRange(addresses, size) {
Afl.jsApiAddIncludeRange(addressess, size); Afl.jsApiAddIncludeRange(addresses, size);
} }
/** /**
* This must always be called at the end of your script. This lets * This must always be called at the end of your script. This lets
@ -52,7 +52,7 @@ class Afl {
} }
/** /**
* Print a message to the STDOUT. This should be preferred to * Print a message to the STDOUT. This should be preferred to
* FRIDA's `console.log` since FRIDA will queue it's log messages. * FRIDA's `console.log` since FRIDA will queue its log messages.
* If `console.log` is used in a callback in particular, then there * If `console.log` is used in a callback in particular, then there
* may no longer be a thread running to service this queue. * may no longer be a thread running to service this queue.
*/ */
@ -205,14 +205,14 @@ class Afl {
} }
/** /**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
* `NativePointer` should be provided as it's argument. * `NativePointer` should be provided as its argument.
*/ */
static setPersistentAddress(address) { static setPersistentAddress(address) {
Afl.jsApiSetPersistentAddress(address); Afl.jsApiSetPersistentAddress(address);
} }
/** /**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a * This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
* `number` should be provided as it's argument. * `number` should be provided as its argument.
*/ */
static setPersistentCount(count) { static setPersistentCount(count) {
Afl.jsApiSetPersistentCount(count); Afl.jsApiSetPersistentCount(count);
@ -232,7 +232,7 @@ class Afl {
} }
/** /**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a * This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
* `NativePointer` should be provided as it's argument. * `NativePointer` should be provided as its argument.
*/ */
static setPersistentReturn(address) { static setPersistentReturn(address) {
Afl.jsApiSetPersistentReturn(address); Afl.jsApiSetPersistentReturn(address);
@ -326,6 +326,12 @@ class Afl {
static jsApiGetSymbol(name) { static jsApiGetSymbol(name) {
return Afl.module.getExportByName(name); return Afl.module.getExportByName(name);
} }
static IJON = class {
static set(addr, val) {
Afl.jsApiIjonSet((addr ^ val) & 0xffffffff);
}
}
} }
/** /**
* Field containing the `Module` object for `afl-frida-trace.so` (the FRIDA mode * Field containing the `Module` object for `afl-frida-trace.so` (the FRIDA mode
@ -376,4 +382,5 @@ Afl.jsApiSetTraceable = Afl.jsApiGetFunction("js_api_set_traceable", "void", [])
Afl.jsApiSetVerbose = Afl.jsApiGetFunction("js_api_set_verbose", "void", []); Afl.jsApiSetVerbose = Afl.jsApiGetFunction("js_api_set_verbose", "void", []);
Afl.jsApiWrite = new NativeFunction( Afl.jsApiWrite = new NativeFunction(
/* tslint:disable-next-line:no-null-keyword */ /* tslint:disable-next-line:no-null-keyword */
Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]); Module.getGlobalExportByName("write"), "int", ["int", "pointer", "int"]);
Afl.jsApiIjonSet = Afl.jsApiGetFunction("js_api_ijon_set", "void", ["uint32"]);

View File

@ -316,3 +316,9 @@ __attribute__((visibility("default"))) void js_api_set_verbose(void) {
} }
__attribute__((visibility("default"))) void js_api_ijon_set(uint32_t edge) {
ijon_set(edge);
}

View File

@ -39,17 +39,19 @@ typedef struct {
static guint64 text_base = 0; static guint64 text_base = 0;
static guint64 text_limit = 0; static guint64 text_limit = 0;
static gboolean lib_find_exe(const GumModuleDetails *details, static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
gpointer user_data) {
lib_details_t *lib_details = (lib_details_t *)user_data; lib_details_t *lib_details = (lib_details_t *)user_data;
const gchar *name = gum_module_get_name(module);
const gchar *path = gum_module_get_path(module);
const GumMemoryRange *range = gum_module_get_range(module);
strncpy(lib_details->name, details->name, PATH_MAX); strncpy(lib_details->name, name, PATH_MAX);
strncpy(lib_details->path, details->path, PATH_MAX); strncpy(lib_details->path, path, PATH_MAX);
lib_details->name[PATH_MAX] = '\0'; lib_details->name[PATH_MAX] = '\0';
lib_details->path[PATH_MAX] = '\0'; lib_details->path[PATH_MAX] = '\0';
lib_details->base_address = details->range->base_address; lib_details->base_address = range->base_address;
lib_details->size = details->range->size; lib_details->size = range->size;
return FALSE; return FALSE;
} }

View File

@ -12,17 +12,18 @@ extern void gum_darwin_enumerate_modules(mach_port_t task,
static guint64 text_base = 0; static guint64 text_base = 0;
static guint64 text_limit = 0; static guint64 text_limit = 0;
static gboolean lib_get_main_module(const GumModuleDetails *details, static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
gpointer user_data) {
GumDarwinModule **ret = (GumDarwinModule **)user_data; GumDarwinModule **ret = (GumDarwinModule **)user_data;
GumDarwinModule *module = gum_darwin_module_new_from_memory( const gchar *path = gum_module_get_path(module);
details->path, mach_task_self(), details->range->base_address, const GumMemoryRange *range = gum_module_get_range(module);
GUM_DARWIN_MODULE_FLAGS_NONE, NULL); GumDarwinModule *darwin_module = gum_darwin_module_new_from_memory(
path, mach_task_self(), range->base_address, GUM_DARWIN_MODULE_FLAGS_NONE,
NULL);
FVERBOSE("Found main module: %s", module->name); FVERBOSE("Found main module: %s", darwin_module->name);
*ret = module; *ret = darwin_module;
return FALSE; return FALSE;

View File

@ -46,6 +46,7 @@ gboolean found_range(const GumRangeDetails *details, gpointer user_data) {
static int on_dlclose(void *handle) { static int on_dlclose(void *handle) {
GArray *ranges = NULL; GArray *ranges = NULL;
GumModule *module = NULL;
struct link_map *lm = NULL; struct link_map *lm = NULL;
gum_range_t *range = NULL; gum_range_t *range = NULL;
GumAddress base; GumAddress base;
@ -61,8 +62,12 @@ static int on_dlclose(void *handle) {
FVERBOSE("on_dlclose: %s", lm->l_name); FVERBOSE("on_dlclose: %s", lm->l_name);
ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t)); ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t));
gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range,
ranges); module = gum_process_find_module_by_name(lm->l_name);
if (module == NULL) { FATAL("Failed to find module: %s", lm->l_name); }
gum_module_enumerate_ranges(module, GUM_PAGE_EXECUTE, found_range, ranges);
int ret = dlclose(handle); int ret = dlclose(handle);
if (ret != 0) { if (ret != 0) {

View File

@ -33,7 +33,7 @@
// r15 - pc // r15 - pc
static GumCpuContext saved_regs = {0}; static GumCpuContext saved_regs = {0};
static gpointer saved_lr = NULL; static gpointer persistent_loop = NULL;
gboolean persistent_is_supported(void) { gboolean persistent_is_supported(void) {
@ -141,17 +141,10 @@ static void instrument_persitent_restore_regs(GumArmWriter *cw,
} }
static void instrument_exit(GumArmWriter *cw) { static void instrument_afl_persistent_loop_func(void) {
gum_arm_writer_put_sub_reg_reg_reg(cw, ARM_REG_R0, ARM_REG_R0, ARM_REG_R0); if (__afl_persistent_loop(persistent_count) == 0) { _exit(0); }
gum_arm_writer_put_call_address_with_arguments(cw, GUM_ADDRESS(_exit), 1,
GUM_ARG_REGISTER, ARM_REG_R0);
}
static int instrument_afl_persistent_loop_func(void) {
int ret = __afl_persistent_loop(persistent_count);
if (instrument_previous_pc_addr == NULL) { if (instrument_previous_pc_addr == NULL) {
FATAL("instrument_previous_pc_addr uninitialized"); FATAL("instrument_previous_pc_addr uninitialized");
@ -159,7 +152,6 @@ static int instrument_afl_persistent_loop_func(void) {
} }
*instrument_previous_pc_addr = instrument_hash_zero; *instrument_previous_pc_addr = instrument_hash_zero;
return ret;
} }
@ -203,7 +195,8 @@ static void instrument_persitent_save_lr(GumArmWriter *cw) {
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP, gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
GUM_RED_ZONE_SIZE); GUM_RED_ZONE_SIZE);
gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(&saved_lr)); gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0,
GUM_ADDRESS(&persistent_ret));
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0, 0); gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0, 0);
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP, gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
@ -214,65 +207,35 @@ static void instrument_persitent_save_lr(GumArmWriter *cw) {
void persistent_prologue_arch(GumStalkerOutput *output) { void persistent_prologue_arch(GumStalkerOutput *output) {
/* /*
* SAVE RET (Used to write the epilogue if persistent_ret is not set)
* SAVE REGS * SAVE REGS
* SAVE RET * loop: (Save address of where the eiplogue should jump back to)
* POP RET
* loop:
* CALL instrument_afl_persistent_loop * CALL instrument_afl_persistent_loop
* TEST EAX, EAX * CALL hook (optionally)
* JZ end:
* call hook (optionally)
* RESTORE REGS * RESTORE REGS
* call original
* jmp loop:
*
* end:
* JMP SAVED RET
*
* original:
* INSTRUMENTED PERSISTENT FUNC * INSTRUMENTED PERSISTENT FUNC
*/ */
GumArmWriter *cw = output->writer.arm; GumArmWriter *cw = output->writer.arm;
gconstpointer loop = cw->code + 1;
FVERBOSE("Persistent loop reached"); FVERBOSE("Persistent loop reached");
if (persistent_ret == 0) { instrument_persitent_save_lr(cw); }
/* Save the current context */
instrument_persitent_save_regs(cw, &saved_regs); instrument_persitent_save_regs(cw, &saved_regs);
/* loop: */ /* Store a pointer to where we should return for our next iteration */
gum_arm_writer_put_label(cw, loop); persistent_loop = gum_arm_writer_cur(cw);
/* call instrument_prologue_func */ /* call __afl_persistent_loop and _exit if zero. Also reset our previous_pc */
instrument_afl_persistent_loop(cw); instrument_afl_persistent_loop(cw);
/* jz done */
gconstpointer done = cw->code + 1;
gum_arm_writer_put_cmp_reg_imm(cw, ARM_REG_R0, 0);
gum_arm_writer_put_b_cond_label(cw, ARM_CC_EQ, done);
/* Optionally call the persistent hook */ /* Optionally call the persistent hook */
persistent_prologue_hook(cw, &saved_regs); persistent_prologue_hook(cw, &saved_regs);
/* Restore our CPU context before we continue execution */
instrument_persitent_restore_regs(cw, &saved_regs); instrument_persitent_restore_regs(cw, &saved_regs);
gconstpointer original = cw->code + 1;
/* call original */
gum_arm_writer_put_bl_label(cw, original);
/* jmp loop */
gum_arm_writer_put_b_label(cw, loop);
/* done: */
gum_arm_writer_put_label(cw, done);
instrument_exit(cw);
/* original: */
gum_arm_writer_put_label(cw, original);
instrument_persitent_save_lr(cw);
if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); } if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); }
@ -284,7 +247,8 @@ void persistent_epilogue_arch(GumStalkerOutput *output) {
if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); } if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); }
gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(&saved_lr)); gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0,
GUM_ADDRESS(&persistent_loop));
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_R0, 0); gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_R0, 0);

View File

@ -16,7 +16,7 @@ typedef struct {
} persistent_ctx_t; } persistent_ctx_t;
static persistent_ctx_t saved_regs = {0}; static persistent_ctx_t saved_regs = {0};
static gpointer saved_lr = NULL; static gpointer persistent_loop = NULL;
gboolean persistent_is_supported(void) { gboolean persistent_is_supported(void) {
@ -216,17 +216,10 @@ static void instrument_persitent_restore_regs(GumArm64Writer *cw,
} }
static void instrument_exit(GumArm64Writer *cw) { static void instrument_afl_persistent_loop_func(void) {
gum_arm64_writer_put_mov_reg_reg(cw, ARM64_REG_X0, ARM64_REG_XZR); if (__afl_persistent_loop(persistent_count) == 0) { _exit(0); }
gum_arm64_writer_put_call_address_with_arguments(
cw, GUM_ADDRESS(_exit), 1, GUM_ARG_REGISTER, ARM64_REG_X0);
}
static int instrument_afl_persistent_loop_func(void) {
int ret = __afl_persistent_loop(persistent_count);
if (instrument_previous_pc_addr == NULL) { if (instrument_previous_pc_addr == NULL) {
FATAL("instrument_previous_pc_addr uninitialized"); FATAL("instrument_previous_pc_addr uninitialized");
@ -234,7 +227,6 @@ static int instrument_afl_persistent_loop_func(void) {
} }
*instrument_previous_pc_addr = instrument_hash_zero; *instrument_previous_pc_addr = instrument_hash_zero;
return ret;
} }
@ -284,7 +276,7 @@ static void instrument_persitent_save_lr(GumArm64Writer *cw) {
GUM_INDEX_PRE_ADJUST); GUM_INDEX_PRE_ADJUST);
gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0, gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0,
GUM_ADDRESS(&saved_lr)); GUM_ADDRESS(&persistent_ret));
gum_arm64_writer_put_str_reg_reg_offset(cw, ARM64_REG_LR, ARM64_REG_X0, 0); gum_arm64_writer_put_str_reg_reg_offset(cw, ARM64_REG_LR, ARM64_REG_X0, 0);
@ -297,66 +289,69 @@ static void instrument_persitent_save_lr(GumArm64Writer *cw) {
void persistent_prologue_arch(GumStalkerOutput *output) { void persistent_prologue_arch(GumStalkerOutput *output) {
/* /*
* SAVE RET (Used to write the epilogue if persistent_ret is not set)
* SAVE REGS * SAVE REGS
* SAVE RET * loop: (Save address of where the eiplogue should jump back to)
* POP RET
* loop:
* CALL instrument_afl_persistent_loop * CALL instrument_afl_persistent_loop
* TEST EAX, EAX * CALL hook (optionally)
* JZ end:
* call hook (optionally)
* RESTORE REGS * RESTORE REGS
* call original * CALL INSTRUMENTED PERSISTENT FUNC
* jmp loop: * JMP loop
*
* end:
* JMP SAVED RET
*
* original:
* INSTRUMENTED PERSISTENT FUNC * INSTRUMENTED PERSISTENT FUNC
*/ */
GumArm64Writer *cw = output->writer.arm64; GumArm64Writer *cw = output->writer.arm64;
gconstpointer loop = cw->code + 1;
FVERBOSE("Persistent loop reached"); FVERBOSE("Persistent loop reached");
/* This is the location our epilogue should be written below */
if (persistent_ret == 0) { instrument_persitent_save_lr(cw); }
/* Save the current context */
instrument_persitent_save_regs(cw, &saved_regs); instrument_persitent_save_regs(cw, &saved_regs);
/* loop: */ /*
* Store a pointer to where we should return for our next iteration.
* This is the location our epilogue should branch to
*/
persistent_loop = gum_arm64_writer_cur(cw);
gconstpointer loop = cw->code + 1;
gum_arm64_writer_put_label(cw, loop); gum_arm64_writer_put_label(cw, loop);
/* call instrument_prologue_func */ /*
* call __afl_persistent_loop which will _exit if we have reached our
* loop count. Also reset our previous_pc
*/
instrument_afl_persistent_loop(cw); instrument_afl_persistent_loop(cw);
/* jz done */
gconstpointer done = cw->code + 1;
gum_arm64_writer_put_cmp_reg_reg(cw, ARM64_REG_X0, ARM64_REG_XZR);
gum_arm64_writer_put_b_cond_label(cw, ARM64_CC_EQ, done);
/* Optionally call the persistent hook */ /* Optionally call the persistent hook */
persistent_prologue_hook(cw, &saved_regs); persistent_prologue_hook(cw, &saved_regs);
/* Restore our CPU context before we continue execution */
instrument_persitent_restore_regs(cw, &saved_regs); instrument_persitent_restore_regs(cw, &saved_regs);
gconstpointer original = cw->code + 1;
/* call original */
gconstpointer original = cw->code + 1;
/*
* Call our original code, that way we regain control if our target
* function returns without reaching the epilogue as an additional
* safety net
*/
gum_arm64_writer_put_bl_label(cw, original); gum_arm64_writer_put_bl_label(cw, original);
/* jmp loop */ /*
* Return for our next iteration if our original function returns
* and control hasn't reached the epilogue for some reason
*/
gum_arm64_writer_put_b_label(cw, loop); gum_arm64_writer_put_b_label(cw, loop);
/* done: */ /*
gum_arm64_writer_put_label(cw, done); * The original code for our target function will be emitted
* immediately following this
instrument_exit(cw); */
/* original: */
gum_arm64_writer_put_label(cw, original); gum_arm64_writer_put_label(cw, original);
instrument_persitent_save_lr(cw);
if (persistent_debug) { gum_arm64_writer_put_brk_imm(cw, 0); } if (persistent_debug) { gum_arm64_writer_put_brk_imm(cw, 0); }
} }
@ -368,7 +363,7 @@ void persistent_epilogue_arch(GumStalkerOutput *output) {
if (persistent_debug) { gum_arm64_writer_put_brk_imm(cw, 0); } if (persistent_debug) { gum_arm64_writer_put_brk_imm(cw, 0); }
gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0, gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0,
GUM_ADDRESS(&saved_lr)); GUM_ADDRESS(&persistent_loop));
gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X0, ARM64_REG_X0, 0); gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X0, ARM64_REG_X0, 0);

View File

@ -17,7 +17,7 @@ typedef struct {
} persistent_ctx_t; } persistent_ctx_t;
static persistent_ctx_t saved_regs = {0}; static persistent_ctx_t saved_regs = {0};
static gpointer saved_ret = NULL; static gpointer persistent_loop = NULL;
gboolean persistent_is_supported(void) { gboolean persistent_is_supported(void) {
@ -162,17 +162,10 @@ static void instrument_persitent_restore_regs(GumX86Writer *cw,
} }
static void instrument_exit(GumX86Writer *cw) { static void instrument_afl_persistent_loop_func(void) {
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, GUM_ADDRESS(_exit)); if (__afl_persistent_loop(persistent_count) == 0) { _exit(0); }
gum_x86_writer_put_mov_reg_u32(cw, GUM_X86_RDI, 0);
gum_x86_writer_put_call_reg(cw, GUM_X86_RAX);
}
static int instrument_afl_persistent_loop_func(void) {
int ret = __afl_persistent_loop(persistent_count);
if (instrument_previous_pc_addr == NULL) { if (instrument_previous_pc_addr == NULL) {
FATAL("instrument_previous_pc_addr uninitialized"); FATAL("instrument_previous_pc_addr uninitialized");
@ -180,7 +173,6 @@ static int instrument_afl_persistent_loop_func(void) {
} }
*instrument_previous_pc_addr = instrument_hash_zero; *instrument_previous_pc_addr = instrument_hash_zero;
return ret;
} }
@ -190,7 +182,6 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) {
-(GUM_RED_ZONE_SIZE)); -(GUM_RED_ZONE_SIZE));
gum_x86_writer_put_call_address_with_arguments( gum_x86_writer_put_call_address_with_arguments(
cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0); cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0);
gum_x86_writer_put_test_reg_reg(cw, GUM_X86_RAX, GUM_X86_RAX);
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP, gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
(GUM_RED_ZONE_SIZE)); (GUM_RED_ZONE_SIZE));
@ -235,7 +226,8 @@ static void instrument_persitent_save_ret(GumX86Writer *cw) {
gum_x86_writer_put_push_reg(cw, GUM_X86_RAX); gum_x86_writer_put_push_reg(cw, GUM_X86_RAX);
gum_x86_writer_put_push_reg(cw, GUM_X86_RBX); gum_x86_writer_put_push_reg(cw, GUM_X86_RBX);
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, GUM_ADDRESS(&saved_ret)); gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX,
GUM_ADDRESS(&persistent_ret));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RBX, GUM_X86_RSP, gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RBX, GUM_X86_RSP,
offset); offset);
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_X86_RAX, GUM_X86_RBX); gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_X86_RAX, GUM_X86_RBX);
@ -252,70 +244,44 @@ static void instrument_persitent_save_ret(GumX86Writer *cw) {
void persistent_prologue_arch(GumStalkerOutput *output) { void persistent_prologue_arch(GumStalkerOutput *output) {
/* /*
* SAVE RET (Used to write the epilogue if persistent_ret is not set)
* SAVE REGS * SAVE REGS
* SAVE RET * loop: (Save address of where the eiplogue should jump back to)
* POP RET
* loop:
* CALL instrument_afl_persistent_loop * CALL instrument_afl_persistent_loop
* TEST EAX, EAX * CALL hook (optionally)
* JZ end:
* call hook (optionally)
* RESTORE REGS * RESTORE REGS
* call original
* jmp loop:
*
* end:
* JMP SAVED RET
*
* original:
* INSTRUMENTED PERSISTENT FUNC * INSTRUMENTED PERSISTENT FUNC
*/ */
GumX86Writer *cw = output->writer.x86; GumX86Writer *cw = output->writer.x86;
gconstpointer loop = cw->code + 1;
FVERBOSE("Persistent loop reached"); FVERBOSE("Persistent loop reached");
/* Pop the return value */ /*
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP, 8); * If we haven't set persistent_ret, then assume that we are dealing with a
* function and we should loop when that function returns.
*/
if (persistent_ret == 0) { instrument_persitent_save_ret(cw); }
/* Save the current context */
instrument_persitent_save_regs(cw, &saved_regs); instrument_persitent_save_regs(cw, &saved_regs);
/* loop: */ /* Store a pointer to where we should return for our next iteration */
gum_x86_writer_put_label(cw, loop); persistent_loop = gum_x86_writer_cur(cw);
/* call instrument_prologue_func */ /* call __afl_persistent_loop and _exit if zero. Also reset our previous_pc */
instrument_afl_persistent_loop(cw); instrument_afl_persistent_loop(cw);
/* jz done */
gconstpointer done = cw->code + 1;
gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY);
/* Optionally call the persistent hook */ /* Optionally call the persistent hook */
persistent_prologue_hook(cw, &saved_regs); persistent_prologue_hook(cw, &saved_regs);
/* Restore our CPU context before we continue execution */
instrument_persitent_restore_regs(cw, &saved_regs); instrument_persitent_restore_regs(cw, &saved_regs);
gconstpointer original = cw->code + 1;
/* call original */
gum_x86_writer_put_call_near_label(cw, original);
/* jmp loop */
gum_x86_writer_put_jmp_near_label(cw, loop);
/* done: */
gum_x86_writer_put_label(cw, done);
instrument_exit(cw);
/* original: */
gum_x86_writer_put_label(cw, original);
instrument_persitent_save_ret(cw);
if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
/* The original instrumented code is emitted here. */
} }
void persistent_epilogue_arch(GumStalkerOutput *output) { void persistent_epilogue_arch(GumStalkerOutput *output) {
@ -331,7 +297,8 @@ void persistent_epilogue_arch(GumStalkerOutput *output) {
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP, -8); gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP, -8);
gum_x86_writer_put_label(cw, zero); gum_x86_writer_put_label(cw, zero);
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, GUM_ADDRESS(&saved_ret)); gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX,
GUM_ADDRESS(&persistent_loop));
gum_x86_writer_put_jmp_reg_ptr(cw, GUM_X86_RAX); gum_x86_writer_put_jmp_reg_ptr(cw, GUM_X86_RAX);
} }

View File

@ -16,8 +16,7 @@ typedef struct {
} persistent_ctx_t; } persistent_ctx_t;
static persistent_ctx_t saved_regs = {0}; static persistent_ctx_t saved_regs = {0};
static gpointer persistent_loop = NULL;
static gpointer saved_ret = NULL;
gboolean persistent_is_supported(void) { gboolean persistent_is_supported(void) {
@ -118,18 +117,10 @@ static void instrument_persitent_restore_regs(GumX86Writer *cw,
} }
static void instrument_exit(GumX86Writer *cw) { static void instrument_afl_persistent_loop_func(void) {
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX, GUM_ADDRESS(_exit)); if (__afl_persistent_loop(persistent_count) == 0) { _exit(0); };
gum_x86_writer_put_mov_reg_u32(cw, GUM_X86_EDI, 0);
gum_x86_writer_put_push_reg(cw, GUM_X86_EDI);
gum_x86_writer_put_call_reg(cw, GUM_X86_EAX);
}
static int instrument_afl_persistent_loop_func(void) {
int ret = __afl_persistent_loop(persistent_count);
if (instrument_previous_pc_addr == NULL) { if (instrument_previous_pc_addr == NULL) {
FATAL("instrument_previous_pc_addr uninitialized"); FATAL("instrument_previous_pc_addr uninitialized");
@ -137,7 +128,6 @@ static int instrument_afl_persistent_loop_func(void) {
} }
*instrument_previous_pc_addr = instrument_hash_zero; *instrument_previous_pc_addr = instrument_hash_zero;
return ret;
} }
@ -145,7 +135,6 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) {
gum_x86_writer_put_call_address_with_arguments( gum_x86_writer_put_call_address_with_arguments(
cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0); cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0);
gum_x86_writer_put_test_reg_reg(cw, GUM_X86_EAX, GUM_X86_EAX);
} }
@ -179,7 +168,8 @@ static void instrument_persitent_save_ret(GumX86Writer *cw) {
gum_x86_writer_put_push_reg(cw, GUM_X86_EAX); gum_x86_writer_put_push_reg(cw, GUM_X86_EAX);
gum_x86_writer_put_push_reg(cw, GUM_X86_EBX); gum_x86_writer_put_push_reg(cw, GUM_X86_EBX);
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX, GUM_ADDRESS(&saved_ret)); gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX,
GUM_ADDRESS(&persistent_ret));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EBX, GUM_X86_ESP, gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EBX, GUM_X86_ESP,
offset); offset);
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_X86_EAX, GUM_X86_EBX); gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_X86_EAX, GUM_X86_EBX);
@ -193,68 +183,44 @@ static void instrument_persitent_save_ret(GumX86Writer *cw) {
void persistent_prologue_arch(GumStalkerOutput *output) { void persistent_prologue_arch(GumStalkerOutput *output) {
/* /*
* SAVE RET (Used to write the epilogue if persistent_ret is not set)
* SAVE REGS * SAVE REGS
* SAVE RET * loop: (Save address of where the eiplogue should jump back to)
* POP RET
* loop:
* CALL instrument_afl_persistent_loop * CALL instrument_afl_persistent_loop
* TEST EAX, EAX * CALL hook (optionally)
* JZ end:
* call hook (optionally)
* RESTORE REGS * RESTORE REGS
* call original
* jmp loop:
*
* end:
* JMP SAVED RET
*
* original:
* INSTRUMENTED PERSISTENT FUNC * INSTRUMENTED PERSISTENT FUNC
*/ */
GumX86Writer *cw = output->writer.x86; GumX86Writer *cw = output->writer.x86;
gconstpointer loop = cw->code + 1;
FVERBOSE("Persistent loop reached"); FVERBOSE("Persistent loop reached");
/* Pop the return value */ /*
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_ESP, GUM_X86_ESP, 4); * If we haven't set persistent_ret, then assume that we are dealing with a
* function and we should loop when that function returns.
*/
if (persistent_ret == 0) { instrument_persitent_save_ret(cw); }
/* Save the current context */
instrument_persitent_save_regs(cw, &saved_regs); instrument_persitent_save_regs(cw, &saved_regs);
/* loop: */ /* Store a pointer to where we should return for our next iteration */
gum_x86_writer_put_label(cw, loop); persistent_loop = gum_x86_writer_cur(cw);
/* call instrument_prologue_func */ /* call __afl_persistent_loop and _exit if zero. Also reset our previous_pc */
instrument_afl_persistent_loop(cw); instrument_afl_persistent_loop(cw);
/* jz done */
gconstpointer done = cw->code + 1;
gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY);
/* Optionally call the persistent hook */ /* Optionally call the persistent hook */
persistent_prologue_hook(cw, &saved_regs); persistent_prologue_hook(cw, &saved_regs);
/* Restore our CPU context before we continue execution */
instrument_persitent_restore_regs(cw, &saved_regs); instrument_persitent_restore_regs(cw, &saved_regs);
gconstpointer original = cw->code + 1;
/* call original */
gum_x86_writer_put_call_near_label(cw, original);
/* jmp loop */
gum_x86_writer_put_jmp_near_label(cw, loop);
/* done: */
gum_x86_writer_put_label(cw, done);
instrument_exit(cw);
/* original: */
gum_x86_writer_put_label(cw, original);
instrument_persitent_save_ret(cw);
if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
/* The original instrumented code is emitted here. */
} }
void persistent_epilogue_arch(GumStalkerOutput *output) { void persistent_epilogue_arch(GumStalkerOutput *output) {
@ -263,7 +229,12 @@ void persistent_epilogue_arch(GumStalkerOutput *output) {
if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX, GUM_ADDRESS(&saved_ret)); /* The stack should be aligned when we re-enter our loop */
gum_x86_writer_put_and_reg_u32(cw, GUM_X86_ESP, 0xfffffff0);
gum_x86_writer_put_sub_reg_imm(cw, GUM_X86_ESP, 0x4);
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX,
GUM_ADDRESS(&persistent_loop));
gum_x86_writer_put_jmp_reg_ptr(cw, GUM_X86_EAX); gum_x86_writer_put_jmp_reg_ptr(cw, GUM_X86_EAX);
} }

View File

@ -264,7 +264,7 @@ static int prefetch_on_fork(void) {
static void prefetch_hook_fork(void) { static void prefetch_hook_fork(void) {
void *fork_addr = void *fork_addr =
GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork")); GSIZE_TO_POINTER(gum_module_find_global_export_by_name("fork"));
intercept_hook(fork_addr, prefetch_on_fork, NULL); intercept_hook(fork_addr, prefetch_on_fork, NULL);
} }

Some files were not shown because too many files have changed in this diff Show More