Compare commits

...

218 Commits
4.06c ... cov

Author SHA1 Message Date
cc7c4c763a implement covmap in forkserver 2023-07-10 13:46:07 +02:00
d8e1c65418 fix 2023-07-08 17:15:47 +02:00
a68d6ff1a0 fix 2023-07-08 17:11:54 +02:00
afeb870045 more coverage code for outside of nyx 2023-07-08 17:01:42 +02:00
ed3b03c95f codecov support 2023-07-07 14:56:53 +02:00
6e5ca0c78c higher tuples for afl-clang and afl-gcc in tests 2023-07-06 14:28:37 +02:00
f37c4c8662 update llvm recommendations 2023-07-05 13:03:17 +02:00
da33510855 nits 2023-07-04 11:34:22 +02:00
db96b04aba Merge pull request #1796 from kobrineli/max_params
Fix MAX_PARAMS_NUM define.
2023-07-03 19:02:13 +03:00
0966957631 Fix max_params define. 2023-07-03 18:09:36 +03:00
dcbfc88e7d comment 2023-07-03 09:17:41 +02:00
d518426335 no_ui: display time 2023-07-02 14:50:18 +02:00
03bae6c4fe switch exploit strategy 2023-07-01 12:19:44 +02:00
317a9df668 Merge pull request #1790 from AFLplusplus/bugfind
afl-showmap fix
2023-06-30 13:18:34 +03:00
819ad95f03 afl-showmap fix 2023-06-30 12:17:57 +02:00
3e1d794107 update mutation strategy 2023-06-29 16:57:20 +02:00
15fc47a62c Merge pull request #1789 from AFLplusplus/orig_mut3
better mutator weightings
2023-06-29 15:01:41 +03:00
7b1238b0f4 Merge pull request #1786 from coc-cyqh/IncNumOfParams
Increase the number of afl-cc supported params
2023-06-26 23:07:49 +03:00
32d5ccb92d Increase the number of afl-cc supported params 2023-06-27 01:20:24 +08:00
aaa1d113e7 Merge pull request #1784 from AFLplusplus/toka_0624
delete duplicate branches
2023-06-26 10:03:03 +03:00
cac713ec30 llvm 15 2023-06-24 15:48:23 +02:00
1e3890ea7f delete duplicate branches 2023-06-24 15:34:12 +02:00
edd352612d code format 2023-06-24 09:30:09 +02:00
2106738d6b Merge pull request #1783 from AFLplusplus/toka_laf_fix
laf-intel fix
2023-06-24 10:27:10 +03:00
0616f368c8 fixing laf 2023-06-24 00:21:45 +02:00
c2c27349c3 new mutation weighting 2023-06-23 17:08:21 +02:00
b28b63f873 Merge pull request #1782 from WorksButNotTested/frida-long
Support for long form instrumentation on x64
2023-06-23 00:25:26 +03:00
9926f07082 Support for long form instrumentation on x64 2023-06-22 17:36:02 +01:00
90f83c13d0 remove dead code, code format 2023-06-22 09:26:46 +02:00
224e884ba1 Merge pull request #1779 from mmisc/llvm13_update
updated llvm requirements
2023-06-21 18:03:30 +03:00
93362c6e67 updated llvm requirements 2023-06-21 16:39:05 +02:00
ec4ed66b1e nits 2023-06-21 13:51:02 +02:00
64b15a00f2 fix afl-cmin* for old afl vanilla issue 2023-06-21 12:20:10 +02:00
936b6dcb5d nits 2023-06-21 09:57:24 +02:00
2366c00235 switch back to normal mutations 2023-06-21 09:38:21 +02:00
51ab51ca27 update tutorial list 2023-06-21 09:04:08 +02:00
68aacc4269 Merge pull request #1774 from amykweon/dev
fix bug in SanitizerCoveragePCGUARD
2023-06-20 21:04:21 +03:00
7b29f2cd24 fix timeout for sessions restart and + usage 2023-06-20 19:58:14 +02:00
420e36dcd3 SanitizerCoveragePCGUARD: select counter off by one error 2023-06-16 05:49:49 -04:00
a0242db421 Merge pull request #1773 from cuanduo/dev
fix bug
2023-06-16 08:25:25 +03:00
450e00446d fix bug 2023-06-16 08:28:05 +08:00
4231d33bc0 improve afl-plot plots 2023-06-14 13:18:44 +02:00
a360344247 minor cmplog bugfix 2023-06-14 13:11:44 +02:00
9a0931858a Merge pull request #1771 from forky2/dev
Fixes #1770: afl-cmin in -T mode doesn't correctly divide inputs amon…
2023-06-14 10:53:01 +03:00
fc1e352965 Fixes #1770: afl-cmin in -T mode doesn't correctly divide inputs among threads 2023-06-14 08:43:06 +01:00
091d66fa92 increase strategy switch 2023-06-12 13:05:35 +02:00
3ad8e9856c update changelog 2023-06-12 09:23:57 +02:00
f1a616406e Merge pull request #1767 from AFLplusplus/mutationnew
Mutationnew
2023-06-12 10:16:45 +03:00
61b6f4ed9e 4.08a init 2023-06-12 09:16:15 +02:00
ed97dbacef enable text mode 2023-06-12 09:13:24 +02:00
af8c68a774 Merge pull request #1766 from AFLplusplus/dev
v4.07c release
2023-06-12 10:03:15 +03:00
25eba95bba update new feature config 2023-06-12 08:43:30 +02:00
bf2727b763 v4.07c release 2023-06-12 08:28:47 +02:00
6ec70fc084 binary mutations 2023-06-09 09:33:33 +02:00
31e2c6c2b4 Merge pull request #1764 from AFLplusplus/mncomp
class afl++ mutations
2023-06-09 10:29:19 +03:00
c28779adc5 show fuzzing state 2023-06-08 12:32:51 +02:00
e71d422b3c enhance custom mutator docs 2023-06-08 08:42:23 +02:00
88603a2c2e add issue to faq 2023-06-07 15:17:46 +02:00
a4b9272416 fix gcc cmplog crash 2023-06-07 10:58:10 +02:00
f6471dd256 fix gcc cmplog crash 2023-06-07 10:57:52 +02:00
26cbc1e993 Merge pull request #1761 from AFLplusplus/dev
fix ci
2023-06-06 19:04:53 +03:00
f0ccca123a fix ci 2023-06-06 17:32:32 +02:00
c7c6ad1a94 no_ui mode 2023-06-06 17:04:31 +02:00
14e25340fb comparison 2023-06-06 16:55:32 +02:00
9b2c4a2a5a nit 2023-06-06 16:54:12 +02:00
62bacf4fc8 better cmplog ci 2023-06-06 16:45:20 +02:00
7c84331dc5 Merge pull request #1760 from AFLplusplus/dev
push to stable
2023-06-06 17:43:19 +03:00
ee2cab73ac reduce false positive ci failures 2023-06-06 16:42:52 +02:00
4deb45f3b3 Merge pull request #1759 from AFLplusplus/dev
Dev
2023-06-06 17:36:04 +03:00
8de7f6131d add current mutation strategy to include 2023-06-06 13:12:31 +02:00
2f6b54e441 Merge pull request #1758 from fanquake/development_llvm
build: adjust LLVM development version check
2023-06-06 13:23:25 +03:00
234d55ccd5 build: adjust LLVM development version check
Adjust version check to only warn for LLVM 17.x and newer, which are the
development versions. Otherwise we'll get:
```bash
make LLVM_CONFIG=llvm-config-15 CC=clang-15 CXX=clang++-15
<snip>
GNUmakefile.llvm:69: you are using an in-development llvm version - this might break llvm_mode!
```

for versions that are supported, and not in development.
2023-06-06 10:29:54 +01:00
993d0c267d Merge pull request #1757 from cocochpie/fix-llvm-17-pcguard-compile-error
Fix llvm 17 pcguard compile error
2023-06-06 10:03:04 +03:00
281f6c1ea1 Merge pull request #1756 from fanquake/ready_to_build_use_CC
build: fix compiler version in build output
2023-06-06 10:01:20 +03:00
9585f5cdfe change the ‘#if’ to >= 17 instead of < 17 2023-06-06 04:07:38 +00:00
abc26a932a Revive f567a89dae 2023-06-05 20:33:33 +00:00
28fd971608 build: fix compiler version in build output
Currently, if I build like with Clang, I'll get:
```bash
make LLVM_CONFIG=llvm-config-15 CC=clang-15 CXX=clang++-15
<snip>
[+] Everything seems to be working, ready to compile. (gcc version 12.1.0 (Ubuntu 12.1.0-2ubuntu1~22.04) )
clang-15 -O2 -D_FORTIFY_SOURCE=1 ....
```

Which is somewhat confusing. Fix this, and in a way that still outputs
the correct version info for Clang and GCC. Use `--version`, and pick
the first line, as that is where they are consistent in output. `clang
-v` gives the version first, whereas `gcc -v` gives the version on the
last line.

We switch to using $(CC), otherwise we also get incorrect output,
and dropping CCVER altogether, given this is it's only use.
2023-06-05 17:00:42 +01:00
f9b72b6f2f Merge pull request #1755 from AFLplusplus/dev
push to stable
2023-06-05 14:12:56 +03:00
b644e48f36 more llvm 15 specialities 2023-06-01 13:28:07 +02:00
2b500ce97e llvm 15 fixes 2023-06-01 12:27:34 +02:00
9324f3f628 rewrote PCGUARD 2023-06-01 12:19:45 +02:00
63a7a816e7 Merge pull request #1753 from WorksButNotTested/delay_start
Changes to support defered start
2023-06-01 13:12:47 +03:00
06e1c64745 Changes to support defered start 2023-06-01 09:33:51 +01:00
7870ece6dc Merge pull request #1750 from WorksButNotTested/arm64_long
Support for instrumentation more than GB away from data structures
2023-05-31 21:42:51 +03:00
e596c9856b Support for instrumentation more than GB away from data structures 2023-05-31 19:15:18 +01:00
ed73c632a5 Merge pull request #1749 from AFLplusplus/dev
push to stable
2023-05-31 12:41:32 +03:00
ad8f7d6eb3 switch user mailinglist reference to discord 2023-05-31 11:40:54 +02:00
074b5ba54d Merge pull request #1748 from fanquake/remove_versions_install
doc: recommend llvm/clang-14 in docs
2023-05-30 18:36:57 +03:00
b08e6bf8c6 doc: recommend llvm/clang-14 in docs
Might as well recommend installing 14, as that's newer, and what's used
in Docker.

Also remove outdated Dockerfile versions, likely easier to remove
versions here entirely, and anyone that wants to see what version is
used, can look in the Dockerfile.
2023-05-30 16:31:09 +01:00
c7ced56066 Merge pull request #1747 from AFLplusplus/dev
push to stable
2023-05-30 17:29:44 +03:00
287128a196 Merge pull request #1746 from fanquake/fix_cuteness
doc: fix logo link in README.md
2023-05-30 17:22:20 +03:00
c9dfc279c7 doc: fix logo link in README.md 2023-05-30 14:47:34 +01:00
c323e0dc63 revert fix 2023-05-23 19:46:35 +02:00
b10a091408 real gcc gnumakefile fix 2023-05-23 18:48:03 +02:00
eeed38c5f8 fix gnumakefile for non-gcc 2023-05-23 18:31:34 +02:00
501226c992 correct rtn cmplog map size 2023-05-23 14:41:59 +02:00
8e1df8e53d Merge pull request #1740 from AFLplusplus/dev
push to stable
2023-05-23 15:16:27 +03:00
8985524d3a todo 2023-05-23 14:15:36 +02:00
b81e0fece6 Merge branch 'stable' into dev 2023-05-23 13:21:50 +03:00
22837b5ad2 response file fix 2023-05-23 12:14:58 +02:00
dd736126dc allow llvm_instrument native 2023-05-23 09:06:29 +02:00
d5e3223f03 fix custom mutator only check 2023-05-23 09:01:49 +02:00
029e039cbc code format 2023-05-21 17:49:14 +02:00
1416fea160 cleaner tritondse 2023-05-21 14:49:24 +02:00
d4085314c1 fix 2023-05-21 13:44:07 +02:00
9a6c0ec0c0 make AFL_CUSTOM_INFO overridable 2023-05-21 13:04:17 +02:00
53a869b757 act on invalid AFL_CUSTOM_MUTATOR_ONLY usage 2023-05-18 14:45:45 +02:00
eec2c38a68 symqemu fix 2023-05-18 12:29:43 +02:00
401d7617ef symqemu mutator options 2023-05-18 10:50:10 +02:00
abd6eace9d improved symqemu custom mutator 2023-05-18 10:32:15 +02:00
f664eb58c5 fix debug build 2023-05-17 19:21:41 +02:00
3e3adb4d37 enforce python setting detection 2023-05-17 18:39:54 +02:00
1d0694df86 add symqemu custom mutator 2023-05-17 15:25:26 +02:00
dfdc6fd12c add missing envs in the docs 2023-05-16 14:54:02 +02:00
49997e60cb fix 2023-05-16 12:33:58 +02:00
1ad63a6a32 fix tritondse 2023-05-16 12:20:58 +02:00
6d23df2c7c add target_intelligence 2023-05-15 17:13:28 +02:00
9a55bbdb44 fix 2023-05-15 15:17:33 +02:00
ab148aeed8 standalone mutator 2023-05-15 15:12:26 +02:00
d1ec5dc089 standalone mutator 2023-05-15 15:11:34 +02:00
c4b1566ba3 push to stable (#1734)
* afl++ -> AFL++

* update readme

* more debug

* slightly different weighting algo (#1719)

* better seed selection

* slightly different weighting calculation

* remove unnecessary memset

* Add "Hangs saved" to afl-whatsup (#1717)

The hangs could show long or infinite loops. This is important.

Co-authored-by: van Hauser <vh@thc.org>

* nits

* afl-showmap: Start a only a single fork server (#1718)

A forkserver is started by afl_fsrv_get_mapsize() when dynamically
finding the map size.  When an input directory option is specified a
second fork server was also started.  This commit re-arranges the inits
for several forkserver struct members so that we can re-use the server
started by the get_mapsize() call when not in coresight/qemu/unicorn
modes and just start the server otherwise.

* Source Code Coverage support for Nyx (Part 1) (#1720)

* Additional source code reformatting in afl-compiler-rt

* Add source code coverage support to afl-compiler-rt (for use with Nyx)

* doc, code format

* llvm 17 changes

* more llvm 17

* add frida mode tutorial

* fix effector map

* docs

* Should memset EFF_ALEN(len) of eff_map (#1722)

* fix reallocs

* fix afl-system-config for macos

* afl-fuzz.c: Document -i - in --help (#1725)

afl-fuzz.c: Document `-i -` in `--help`, to write that `-i` can be passed '-' to resume the prior fuzzing job. Also reference AFL_AUTORESUME so users know they can set that parameter to sidestep the issue entirely.

* tritondse custom mutator attempt

* tritondse fixes

* update libnyx (#1727)

* GNUmakefile: Update LLVM instructions (#1728)

Update LLVM instructions, because versions higher than 14 are supported and to be explicit that LLD is also required

* disable macos in the ci, works fine for me

* fix makefile

* better tritondse support

* next steps for tritondse

* qemuafl: Persistent mode for PPC32 targets

* update qemu_mode

* afl-clang-lto incomptable with -flto=thin

* add @responsefile support for afl-cc

---------

Co-authored-by: fxlb <devel.fx.lebail@orange.fr>
Co-authored-by: Nick Potenski <nick.potenski@garmin.com>
Co-authored-by: Christian Holler (:decoder) <choller@mozilla.com>
Co-authored-by: lazymio <mio@lazym.io>
Co-authored-by: Moshe Kaplan <me@moshekaplan.com>
Co-authored-by: Sergej Schumilo <sergej@schumilo.de>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-05-15 10:51:37 +02:00
d91f8fa655 Merge branch 'stable' into dev 2023-05-15 11:51:20 +03:00
7f636dbfc2 add @responsefile support for afl-cc 2023-05-12 15:58:20 +02:00
93c821aaa3 afl-clang-lto incomptable with -flto=thin 2023-05-12 08:39:11 +02:00
a752b15921 update qemu_mode 2023-05-12 08:29:31 +02:00
3a98d7af18 qemuafl: Persistent mode for PPC32 targets 2023-05-11 21:02:46 +02:00
eaf59d5a19 next steps for tritondse 2023-05-11 07:55:17 +02:00
70da0c2e40 better tritondse support 2023-05-10 16:09:18 +02:00
c97caa6e10 fix makefile 2023-05-09 14:17:09 +02:00
c092892488 disable macos in the ci, works fine for me 2023-05-06 09:26:24 +02:00
001d9d3d20 GNUmakefile: Update LLVM instructions (#1728)
Update LLVM instructions, because versions higher than 14 are supported and to be explicit that LLD is also required
2023-05-05 16:02:00 +02:00
2c421d48fa update libnyx (#1727) 2023-05-05 14:08:01 +02:00
f585f26266 tritondse fixes 2023-05-05 14:04:53 +02:00
396157deda tritondse custom mutator attempt 2023-05-05 13:53:05 +02:00
f516926f00 afl-fuzz.c: Document -i - in --help (#1725)
afl-fuzz.c: Document `-i -` in `--help`, to write that `-i` can be passed '-' to resume the prior fuzzing job. Also reference AFL_AUTORESUME so users know they can set that parameter to sidestep the issue entirely.
2023-05-04 17:23:30 +02:00
a7b7f3cde9 fix afl-system-config for macos 2023-05-02 18:25:56 +02:00
22db79aefa fix reallocs 2023-05-01 15:07:57 +02:00
2cd07abca9 Should memset EFF_ALEN(len) of eff_map (#1722) 2023-05-01 13:12:05 +02:00
fcab3ec990 docs 2023-05-01 08:55:37 +02:00
9065d4ba86 fix effector map 2023-05-01 08:38:13 +02:00
ed96f9b209 add frida mode tutorial 2023-04-28 16:02:09 +02:00
vH
f567a89dae more llvm 17 2023-04-28 15:39:01 +02:00
vH
00c86b7cb1 llvm 17 changes 2023-04-28 14:56:52 +02:00
vH
74be9ab5ce llvm 17 changes 2023-04-28 14:55:35 +02:00
5813a4319c doc, code format 2023-04-28 11:42:21 +02:00
e956f23a77 Source Code Coverage support for Nyx (Part 1) (#1720)
* Additional source code reformatting in afl-compiler-rt

* Add source code coverage support to afl-compiler-rt (for use with Nyx)
2023-04-28 11:35:22 +02:00
41b0fe7280 afl-showmap: Start a only a single fork server (#1718)
A forkserver is started by afl_fsrv_get_mapsize() when dynamically
finding the map size.  When an input directory option is specified a
second fork server was also started.  This commit re-arranges the inits
for several forkserver struct members so that we can re-use the server
started by the get_mapsize() call when not in coresight/qemu/unicorn
modes and just start the server otherwise.
2023-04-27 18:57:55 +02:00
6cad585bdc nits 2023-04-27 18:57:28 +02:00
6172bc7312 Add "Hangs saved" to afl-whatsup (#1717)
The hangs could show long or infinite loops. This is important.

Co-authored-by: van Hauser <vh@thc.org>
2023-04-27 18:00:26 +02:00
a2daef29f9 slightly different weighting algo (#1719)
* better seed selection

* slightly different weighting calculation

* remove unnecessary memset
2023-04-27 17:57:22 +02:00
e983e2e9cf more debug 2023-04-27 16:24:43 +02:00
a25439cfa1 update readme 2023-04-27 11:50:12 +02:00
3e84d6a2ae afl++ -> AFL++ 2023-04-27 11:49:00 +02:00
7ca1b85c5e Merge pull request #1715 from AFLplusplus/dev
push to stable
2023-04-26 16:33:42 +02:00
b18bc7b98f changelog updates 2023-04-26 16:25:03 +02:00
432671449f nits 2023-04-25 18:19:25 +02:00
96848398d4 fix 2023-04-25 17:56:36 +02:00
21865c6224 rename env to AFL_IGNORE_PROBLEMS_COVERAGE 2023-04-25 16:47:37 +02:00
b96ba509d0 Merge pull request #1714 from choller/dev
Add env var to ignore coverage from dynamically loaded code after forkserver
2023-04-25 16:34:23 +02:00
f94a7e8890 Add env var to ignore coverage from dynamically loaded code after forkserver.
When using TRACEPC instrumentation, loading code dynamically (e.g.
through dlopen()) it can be useful to completely ignore the loaded code,
esp. when it cannot be preloaded and is not the target to be tested.
This patch allows setting AFL_LLVM_IGNORE_PROBLEMS_COVERAGE=1 to do so.
2023-04-25 16:27:25 +02:00
2e23418a09 remove symlinks 2023-04-25 14:55:31 +02:00
f3dc56f59a update custom mutators 2023-04-25 14:54:38 +02:00
d822181467 afl-cmin -T support 2023-04-25 13:13:43 +02:00
bc969f78f6 fixes 2023-04-25 11:56:50 +02:00
7b877e2c1d afl-cmin.bash -T support 2023-04-25 09:30:25 +02:00
c0ecf7cf61 only reverse reading the queue on restart 2023-04-25 08:33:51 +02:00
7b33148b75 add AFL_LLVM_LTO_SKIPINIT to envs.h 2023-04-25 08:23:27 +02:00
b66d7f99a7 Merge pull request #1713 from kenohassler/wafl-mode
llvm-lto: allow skipping initialisation
2023-04-25 08:21:42 +02:00
7c3c0b26d1 document new env var 2023-04-24 20:32:04 +02:00
46237c3332 makefile for atwalk 2023-04-24 19:20:52 +02:00
8c228b0d23 afl-showmap -I option 2023-04-24 18:08:27 +02:00
531380d6ab llvm-lto: allow skipping initialization 2023-04-24 17:55:58 +02:00
dbb3171624 Merge pull request #1712 from AFLplusplus/dev
push to stable
2023-04-22 11:40:50 +02:00
6bd48a48cb code format 2023-04-22 11:39:44 +02:00
c5e5a17d67 Merge pull request #1711 from atnwalk/atnwalk
AFL_POST_PROCESS_KEEP_ORIGINAL env variable for intermediate file formats and ATNwalk custom mutator
2023-04-22 11:32:42 +02:00
599b4631a3 typo 2023-04-22 11:31:29 +02:00
228e9527cb fixed formatting with make code-format 2023-04-21 17:21:47 +02:00
53ff09969c Merge pull request #3 from voidptr127/atnwalk
Create README.md
2023-04-21 17:11:40 +02:00
d7e6f8cb38 Create README.md 2023-04-21 17:10:19 +02:00
e99d4ba976 Merge pull request #2 from AFLplusplus/dev
Dev
2023-04-21 16:48:47 +02:00
de717cd225 Merge pull request #1 from voidptr127/atnwalk
fixed AFL_POST_PROCESS_KEEP_ORIGINAL for version 4.07a
2023-04-21 16:47:19 +02:00
779a72ef8c fixed AFL_POST_PROCESS_KEEP_ORIGINAL for version 4.07a 2023-04-21 16:46:15 +02:00
dae5f94bce Merge pull request #1710 from Ha0ris/frida-inst-no-dynamic-load
frida mode: add dynamic loaded code exclusion
2023-04-21 15:34:49 +02:00
c49d346e37 remove ubuntu 18.04 from ci, no resources for this on github 2023-04-21 15:22:48 +02:00
7a8d0a10ce add dummy functions to afl-showmap for old gcc compilers 2023-04-21 15:21:11 +02:00
369ec31f0e debug output 2023-04-21 15:15:34 +02:00
0a297ed9ef dummy function for afl-showmap 2023-04-21 15:09:35 +02:00
30495e6bfe frida mode: add dynamic loaded code exclusion
Add the AFL_FRIDA_INST_NO_DYNAMIC_LOAD environment variable and its
associated JS function setInstrumentNoDynamicLoad to prevent the
instrumentation of late dynamic loaded code.

Resolve #1708
2023-04-21 12:00:56 +02:00
7101ffa1ae Merge remote-tracking branch 'origin/dev' into atnwalk
# Conflicts:
#	include/afl-fuzz.h
#	src/afl-fuzz-run.c
2023-04-21 11:31:22 +02:00
4e5f42cab6 afl-showmap custom mutator support 2023-04-20 10:39:23 +02:00
9ab902402c fixed code clones in atnwalk.c, introduced new environment variable AFL_POST_PROCESS_KEEP_ORIGINAL in AFL++ to integrate atnwalk without re-compiling afl-fuzz 2023-04-17 17:09:48 +02:00
529a51c160 implemented status screen and 50% havoc and 50% splice schedule with limited rounds per queue entry 2023-04-17 17:09:48 +02:00
e55b5c5408 fixed the server handshake commands, works now 2023-04-17 17:09:48 +02:00
450dbae8cd first version with unix domain sockets is ready for testing 2023-04-17 17:09:48 +02:00
a3bc8d3440 fixed wrong implementation of control bits in atnwalk.c 2023-04-17 17:09:48 +02:00
70e3095864 added first dummy atnwalk.c file 2023-04-17 17:09:48 +02:00
02b9e583f2 v4.07a init 2023-04-17 14:41:05 +02:00
400c5e92cb renaming 2023-04-07 09:41:22 +02:00
fcb5eda5d0 nit 2023-04-05 16:34:08 +02:00
a74561b0e7 implement switch mode 2023-04-05 12:12:05 +02:00
e313180e4d fix for clang 2023-04-05 10:32:37 +02:00
1fc0731604 stack pow 2023-04-05 09:42:27 +02:00
53b70ef104 mut changes 2023-04-05 09:33:09 +02:00
41a452d4e8 mutation lists 2023-04-04 21:48:51 +02:00
3ab18d2861 mode switch 2023-04-04 19:44:12 +02:00
2bff92c603 nit 2023-04-04 16:25:05 +02:00
32ffa2664c max_len support 2023-04-04 16:23:19 +02:00
fcd2125678 prepare for strategies 2023-04-04 15:47:53 +02:00
635da39bd1 preparation for mutation arrays 2023-04-03 14:41:52 +02:00
71e2aa5d2b more fix 2023-04-02 13:42:08 +02:00
21203c2ea6 fix 2023-04-02 12:39:02 +02:00
9eed60d105 nit 2023-03-31 08:12:32 +02:00
8f17c81691 less mutation 2023-03-30 22:41:02 +02:00
74baebd93e fix 2023-03-30 20:02:59 +02:00
506f6b1349 nits 2023-03-30 19:28:59 +02:00
145748a7e0 prepare new mutation strategies 2023-03-30 14:00:45 +02:00
7893347e13 final touches 2023-03-29 22:56:12 +02:00
5218c0b187 all mutation strategies 2023-03-29 22:53:15 +02:00
114 changed files with 8937 additions and 2104 deletions

View File

@ -24,7 +24,7 @@ import importlib.metadata
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use
CURRENT_LLVM = os.getenv('LLVM_VERSION', 14)
CURRENT_LLVM = os.getenv('LLVM_VERSION', 16)
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")

View File

@ -14,7 +14,7 @@ jobs:
runs-on: "${{ matrix.os }}"
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04]
os: [ubuntu-22.04, ubuntu-20.04]
env:
AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
@ -36,23 +36,23 @@ jobs:
run: make distrib ASAN_BUILD=1 NO_NYX=1
- name: run tests
run: sudo -E ./afl-system-config; make tests
macos:
runs-on: macOS-latest
env:
AFL_MAP_SIZE: 65536
AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
steps:
- uses: actions/checkout@v3
- name: install
run: brew install make gcc llvm
- name: fix install
run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v
- 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
- name: frida
run: export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; cd frida_mode; gmake
- name: run tests
run: sudo -E ./afl-system-config; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export PATH=/usr/local/Cellar/llvm/*/":/usr/local/bin:$PATH"; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; gmake tests
- name: force frida test for MacOS
run: export AFL_PATH=`pwd`; /usr/local/bin/gcc -o test-instr test-instr.c; mkdir in; echo > in/in; AFL_NO_UI=1 ./afl-fuzz -O -i in -o out -V 5 -- ./test-instr
# macos:
# runs-on: macOS-latest
# env:
# AFL_MAP_SIZE: 65536
# AFL_SKIP_CPUFREQ: 1
# AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
# steps:
# - uses: actions/checkout@v3
# - name: install
# run: brew install make gcc llvm
# - name: fix install
# run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v
# - 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
# - name: frida
# run: export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; cd frida_mode; gmake
# - name: run tests
# run: sudo -E ./afl-system-config; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export PATH=/usr/local/Cellar/llvm/*/":/usr/local/bin:$PATH"; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; gmake tests
# - name: force frida test for MacOS
# run: export AFL_PATH=`pwd`; /usr/local/bin/gcc -o test-instr test-instr.c; mkdir in; echo > in/in; AFL_NO_UI=1 ./afl-fuzz -O -i in -o out -V 5 -- ./test-instr

View File

@ -6,7 +6,7 @@
#
FROM ubuntu:22.04 AS aflplusplus
LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
LABEL "maintainer"="AFL++ team <afl@aflplus.plus>"
LABEL "about"="AFLplusplus container image"
### Comment out to enable these features
@ -94,4 +94,4 @@ RUN sed -i.bak 's/^ -/ /g' GNUmakefile && \
RUN echo "set encoding=utf-8" > /root/.vimrc && \
echo ". /etc/bash_completion" >> ~/.bashrc && \
echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc && \
echo "export PS1='"'[afl++ \h] \w \$ '"'" >> ~/.bashrc
echo "export PS1='"'[AFL++ \h] \w \$ '"'" >> ~/.bashrc

View File

@ -39,7 +39,7 @@ ASAN_OPTIONS=detect_leaks=0
SYS = $(shell uname -s)
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
@ -100,8 +100,13 @@ else
LDFLAGS += $(SDK_LD)
endif
COMPILER_TYPE=$(shell $(CC) --version|grep "Free Software Foundation")
ifneq "$(COMPILER_TYPE)" ""
#$(info gcc is being used)
CFLAGS_OPT += -Wno-error=format-truncation -Wno-format-truncation
endif
ifeq "$(SYS)" "SunOS"
CFLAGS_OPT += -Wno-format-truncation
LDFLAGS = -lkstat -lrt -lsocket -lnsl
endif
@ -145,7 +150,7 @@ else
endif
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wno-pointer-arith \
-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
# -fstack-protector
@ -180,13 +185,13 @@ AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
ifneq "$(shell command -v python3m 2>/dev/null)" ""
ifneq "$(shell command -v python3m-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python3m-config --includes)
PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1))
PYTHON_INCLUDE := $(shell python3m-config --includes)
PYTHON_VERSION := $(strip $(shell python3m --version 2>&1))
# Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
PYTHON_LIB ?= $(shell python3m-config --libs --embed --ldflags)
PYTHON_LIB := $(shell python3m-config --libs --embed --ldflags)
else
PYTHON_LIB ?= $(shell python3m-config --ldflags)
PYTHON_LIB := $(shell python3m-config --ldflags)
endif
endif
endif
@ -194,13 +199,13 @@ endif
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python3 2>/dev/null)" ""
ifneq "$(shell command -v python3-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python3-config --includes)
PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
PYTHON_INCLUDE := $(shell python3-config --includes)
PYTHON_VERSION := $(strip $(shell python3 --version 2>&1))
# Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags)
PYTHON_LIB := $(shell python3-config --libs --embed --ldflags)
else
PYTHON_LIB ?= $(shell python3-config --ldflags)
PYTHON_LIB := $(shell python3-config --ldflags)
endif
endif
endif
@ -209,9 +214,9 @@ endif
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python 2>/dev/null)" ""
ifneq "$(shell command -v python-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python-config --includes)
PYTHON_LIB ?= $(shell python-config --ldflags)
PYTHON_VERSION ?= $(strip $(shell python --version 2>&1))
PYTHON_INCLUDE := $(shell python-config --includes)
PYTHON_LIB := $(shell python-config --ldflags)
PYTHON_VERSION := $(strip $(shell python --version 2>&1))
endif
endif
endif
@ -220,9 +225,9 @@ endif
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python3.7 2>/dev/null)" ""
ifneq "$(shell command -v python3.7-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python3.7-config --includes)
PYTHON_LIB ?= $(shell python3.7-config --ldflags)
PYTHON_VERSION ?= $(strip $(shell python3.7 --version 2>&1))
PYTHON_INCLUDE := $(shell python3.7-config --includes)
PYTHON_LIB := $(shell python3.7-config --ldflags)
PYTHON_VERSION := $(strip $(shell python3.7 --version 2>&1))
endif
endif
endif
@ -231,9 +236,9 @@ endif
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python2.7 2>/dev/null)" ""
ifneq "$(shell command -v python2.7-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python2.7-config --includes)
PYTHON_LIB ?= $(shell python2.7-config --ldflags)
PYTHON_VERSION ?= $(strip $(shell python2.7 --version 2>&1))
PYTHON_INCLUDE := $(shell python2.7-config --includes)
PYTHON_LIB := $(shell python2.7-config --ldflags)
PYTHON_VERSION := $(strip $(shell python2.7 --version 2>&1))
endif
endif
endif
@ -313,8 +318,8 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
@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-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 SanitizerCoveragePCGUARD.so && echo "[+] LLVM 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 SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM 11-14. More information at instrumentation/README.lto.md on how to build it"
@test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-13 and clang-13 or newer, see docs/INSTALL.md"
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM and LLD 11+. More information at instrumentation/README.lto.md on how to build it"
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"
endif
@ -357,7 +362,7 @@ performance-test: source-only
help:
@echo "HELP --- the following make targets exist:"
@echo "=========================================="
@echo "all: the main afl++ binaries and llvm/gcc instrumentation"
@echo "all: the main AFL++ binaries and llvm/gcc instrumentation"
@echo "binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode, qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator, libtokencap"
@echo "source-only: everything for source code fuzzing: nyx_mode, libdislocator, libtokencap"
@echo "distrib: everything (for both binary-only and source code fuzzing)"
@ -365,7 +370,7 @@ help:
@echo "install: installs everything you have compiled with the build option above"
@echo "clean: cleans everything compiled (not downloads when on a checkout)"
@echo "deepclean: cleans everything including downloads"
@echo "uninstall: uninstall afl++ from the system"
@echo "uninstall: uninstall AFL++ from the system"
@echo "code-format: format the code, do this before you commit and send a PR please!"
@echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
@echo "unit: perform unit tests (based on cmocka and GNU linker)"
@ -377,6 +382,7 @@ help:
@echo Known build environment options:
@echo "=========================================="
@echo STATIC - compile AFL++ static
@echo "CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md)"
@echo ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
@echo UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes
@echo DEBUG - no optimization, -ggdb3, all warnings and -Werror
@ -392,7 +398,7 @@ help:
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)"
@echo "=========================================="
@echo e.g.: make ASAN_BUILD=1
@echo e.g.: make LLVM_CONFIG=llvm-config-16
.PHONY: test_x86
ifndef AFL_NO_X86
@ -431,7 +437,7 @@ endif
.PHONY: ready
ready:
@echo "[+] Everything seems to be working, ready to compile."
@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
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
@ -453,7 +459,7 @@ afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
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
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) 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) 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)
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
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
@ -734,7 +740,7 @@ endif
@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-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 SanitizerCoveragePCGUARD.so && echo "[+] LLVM 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 SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-13 and clang-13 or newer, see docs/INSTALL.md"
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM 11-14. More information at instrumentation/README.lto.md on how to build it"
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"
@ -747,7 +753,7 @@ endif
@echo
%.8: %
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
@echo .TH $* 8 $(BUILD_DATE) "AFL++" > $@
@echo .SH NAME >> $@
@echo .B $* >> $@
@echo >> $@
@ -759,8 +765,8 @@ endif
@./$* -hh 2>&1 | tail -n +4 >> $@
@echo >> $@
@echo .SH AUTHOR >> $@
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> $@
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
@echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Dominik Maier <domenukk@gmail.com>, Andrea Fioraldi <andreafioraldi@gmail.com> and Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>" >> $@
@echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
@echo >> $@
@echo .SH LICENSE >> $@
@echo Apache License Version 2.0, January 2004 >> $@

View File

@ -175,7 +175,7 @@ all_done: test_build
.NOTPARALLEL: clean
%.8: %
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ./$@
@echo .TH $* 8 `date "+%Y-%m-%d"` "AFL++" > ./$@
@echo .SH NAME >> ./$@
@echo .B $* >> ./$@
@echo >> ./$@
@ -187,8 +187,8 @@ all_done: test_build
@./$* -h 2>&1 | tail -n +4 >> ./$@
@echo >> ./$@
@echo .SH AUTHOR >> ./$@
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
@echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Dominik Maier <domenukk@gmail.com>, Andrea Fioraldi <andreafioraldi@gmail.com> and Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>" >> ./$@
@echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
@echo >> ./$@
@echo .SH LICENSE >> ./$@
@echo Apache License Version 2.0, January 2004 >> ./$@

View File

@ -46,10 +46,11 @@ LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 )
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[5-9]' && echo 1 || echo 0 )
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[7-9]' && echo 1 || echo 0 )
LLVM_TOO_OLD = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[1-9]\.|^1[012]\.' && echo 1 || echo 0 )
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[0-9]' && echo 1 || echo 0 )
LLVM_NEWER_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[6-9]' && echo 1 || echo 0 )
LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-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 )
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]' && echo 1 || echo 0 )
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
@ -69,6 +70,12 @@ ifeq "$(LLVM_TOO_NEW)" "1"
$(warning you are using an in-development llvm version - this might break llvm_mode!)
endif
ifeq "$(LLVM_TOO_OLD)" "1"
$(warning you are using an outdated LLVM version! Please use at least LLVM 13 or newer!)
$(shell sleep 2)
endif
# No switching the meaning of LLVM_TOO_OLD
LLVM_TOO_OLD=1
ifeq "$(LLVM_MAJOR)" "9"
@ -87,11 +94,6 @@ ifeq "$(LLVM_NEWER_API)" "1"
LLVM_STDCXX = c++17
endif
ifeq "$(LLVM_TOO_OLD)" "1"
$(info [!] llvm_mode detected an old version of llvm, upgrade to at least 9 or preferable 11!)
$(shell sleep 1)
endif
ifeq "$(LLVM_HAVE_LTO)" "1"
$(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
LLVM_LTO = 1
@ -274,6 +276,11 @@ ifndef LLVM_DEBUG
CFLAGS_SAFE += -Wno-deprecated
endif
ifdef CODE_COVERAGE
override CFLAGS_SAFE += -D__AFL_CODE_COVERAGE=1
override LDFLAGS += -ldl
endif
override CFLAGS += $(CFLAGS_SAFE)
ifdef AFL_TRACE_PC
@ -417,7 +424,7 @@ endif
$(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
ifeq "$(LLVM_10_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
endif
@ -510,7 +517,7 @@ install: all
install -m 644 instrumentation/README.*.md $${DESTDIR}$(DOC_PATH)/
%.8: %
@echo .TH $* 8 $(BUILD_DATE) "afl++" > ./$@
@echo .TH $* 8 $(BUILD_DATE) "AFL++" > ./$@
@echo .SH NAME >> ./$@
@printf "%s" ".B $* \- " >> ./$@
@./$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> ./$@
@ -524,8 +531,8 @@ install: all
@./$* -h 2>&1 | tail -n +4 >> ./$@
@echo >> ./$@
@echo .SH AUTHOR >> ./$@
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
@echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Dominik Maier <domenukk@gmail.com>, Andrea Fioraldi <andreafioraldi@gmail.com> and Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>" >> ./$@
@echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
@echo >> ./$@
@echo .SH LICENSE >> ./$@
@echo Apache License Version 2.0, January 2004 >> ./$@

View File

@ -1,10 +1,10 @@
# American Fuzzy Lop plus plus (AFL++)
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/master/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" heigh="250">
Release version: [4.06c](https://github.com/AFLplusplus/AFLplusplus/releases)
Release version: [4.07c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 4.07a
GitHub version: 4.08a
Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@ -12,9 +12,9 @@ Repository:
AFL++ is maintained by:
* Marc "van Hauser" Heuse <mh@mh-sec.de>
* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>
* Andrea Fioraldi <andreafioraldi@gmail.com>
* Dominik Maier <mail@dmnk.co>
* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>
* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
Originally developed by Michał "lcamtuf" Zalewski.

View File

@ -2,9 +2,9 @@
## Should
- splicing selection weighted?
- support afl_custom_{send,post_process}, persistent and deferred fork
server in afl-showmap
- afl-crash-analysis
- test cmplog for less than 16bit
- support persistent and deferred fork server in afl-showmap?
- better autodetection of shifting runtime timeout values
- Update afl->pending_not_fuzzed for MOpt
- afl-plot to support multiple plot_data

182
afl-cmin
View File

@ -103,9 +103,10 @@ function usage() {
" -o dir - output directory for minimized files\n" \
"\n" \
"Execution control settings:\n" \
" -T tasks - how many parallel tasks to run (default: 1, all=nproc)\n" \
" -f file - location read by the fuzzed program (stdin)\n" \
" -m megs - memory limit for child process ("mem_limit" MB)\n" \
" -t msec - run time limit for child process (default: none)\n" \
" -t msec - run time limit for child process (default: 5000)\n" \
" -O - use binary-only instrumentation (FRIDA mode)\n" \
" -Q - use binary-only instrumentation (QEMU mode)\n" \
" -U - use unicorn-based instrumentation (unicorn mode)\n" \
@ -119,7 +120,6 @@ function usage() {
"For additional tips, please consult README.md\n" \
"\n" \
"Environment variables used:\n" \
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
@ -133,6 +133,8 @@ function usage() {
"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
"printed to stdout\n" \
"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n"
"AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)\n"
"AFL_PYTHON_MODULE: custom mutator library (post_process and send)\n"
exit 1
}
@ -147,7 +149,7 @@ BEGIN {
redirected = 0
}
print "corpus minimization tool for afl++ (awk version)\n"
print "corpus minimization tool for AFL++ (awk version)\n"
# defaults
extra_par = ""
@ -157,13 +159,19 @@ BEGIN {
# process options
Opterr = 1 # default is to diagnose
Optind = 1 # skip ARGV[0]
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXY?")) != -1) {
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXYT:?")) != -1) {
if (_go_c == "i") {
if (!Optarg) usage()
if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
in_dir = Optarg
continue
} else
if (_go_c == "T") {
if (!Optarg) usage()
if (threads) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
threads = Optarg
continue
} else
if (_go_c == "o") {
if (!Optarg) usage()
if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
@ -232,7 +240,7 @@ BEGIN {
} # while options
if (!mem_limit) mem_limit = "none"
if (!timeout) timeout = "none"
if (!timeout) timeout = "5000"
# get program args
i = 0
@ -251,21 +259,30 @@ BEGIN {
# Do a sanity check to discourage the use of /tmp, since we can't really
# handle this safely from an awk script.
if (!ENVIRON["AFL_ALLOW_TMP"]) {
dirlist[0] = in_dir
dirlist[1] = target_bin
dirlist[2] = out_dir
dirlist[3] = stdin_file
"pwd" | getline dirlist[4] # current directory
for (dirind in dirlist) {
dir = dirlist[dirind]
#if (!ENVIRON["AFL_ALLOW_TMP"]) {
# dirlist[0] = in_dir
# dirlist[1] = target_bin
# dirlist[2] = out_dir
# dirlist[3] = stdin_file
# "pwd" | getline dirlist[4] # current directory
# for (dirind in dirlist) {
# dir = dirlist[dirind]
#
# if (dir ~ /^(\/var)?\/tmp/) {
# print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
# exit 1
# }
# }
# delete dirlist
#}
if (dir ~ /^(\/var)?\/tmp/) {
print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
exit 1
}
}
delete dirlist
if (threads && stdin_file) {
print "[-] Error: -T and -f cannot be used together." > "/dev/stderr"
exit 1
}
if (!threads && !stdin_file && !nyx_mode) {
print "[*] Are you aware of the '-T all' parallelize option that improves the speed for large/slow corpuses?"
}
# If @@ is specified, but there's no -f, let's come up with a temporary input
@ -301,7 +318,9 @@ BEGIN {
if (!nyx_mode && target_bin && !exists_and_is_executable(target_bin)) {
"command -v "target_bin" 2>/dev/null" | getline tnew
cmd = "command -v "target_bin" 2>/dev/null"
cmd | getline tnew
close(cmd)
if (!tnew || !exists_and_is_executable(tnew)) {
print "[-] Error: binary '"target_bin"' not found or not executable." > "/dev/stderr"
exit 1
@ -313,6 +332,7 @@ BEGIN {
echo "[!] Trying to obtain the map size of the target ..."
get_map_size = "AFL_DUMP_MAP_SIZE=1 " target_bin
get_map_size | getline mapsize
close(get_map_size)
if (mapsize && mapsize > 65535 && mapsize < 100000000) {
AFL_MAP_SIZE = "AFL_MAP_SIZE="mapsize" "
print "[+] Setting "AFL_MAP_SIZE
@ -342,12 +362,28 @@ BEGIN {
system("rm -rf "trace_dir" 2>/dev/null");
system("rm "out_dir"/id[:_]* 2>/dev/null")
"ls "out_dir"/* 2>/dev/null | wc -l" | getline noofentries
cmd = "ls "out_dir"/* 2>/dev/null | wc -l"
cmd | getline noofentries
close(cmd)
if (0 == system( "test -d "out_dir" -a "noofentries" -gt 0" )) {
print "[-] Error: directory '"out_dir"' exists and is not empty - delete it first." > "/dev/stderr"
exit 1
}
if (threads) {
cmd = "nproc"
cmd | getline nproc
close(cmd)
if (threads == "all") {
threads = nproc
} else {
if (!(threads > 1 && threads <= nproc)) {
print "[-] Error: -T option must be between 1 and "nproc" or \"all\"." > "/dev/stderr"
exit 1
}
}
}
# Check for the more efficient way to copy files...
if (0 != system("mkdir -p -m 0700 "trace_dir)) {
print "[-] Error: Cannot create directory "trace_dir > "/dev/stderr"
@ -357,12 +393,14 @@ BEGIN {
if (stdin_file) {
# truncate input file
printf "" > stdin_file
close( stdin_file )
close(stdin_file)
}
# First we look in PATH
if (0 == system("command -v afl-showmap >/dev/null 2>&1")) {
"command -v afl-showmap 2>/dev/null" | getline showmap
cmd = "command -v afl-showmap 2>/dev/null"
cmd | getline showmap
close(cmd)
} else {
# then we look in the current directory
if (0 == system("test -x ./afl-showmap")) {
@ -384,7 +422,9 @@ BEGIN {
# yuck, gnu stat is option incompatible to bsd stat
# we use a heuristic to differentiate between
# GNU stat and other stats
"stat --version 2>/dev/null" | getline statversion
cmd = "stat --version 2>/dev/null"
cmd | getline statversion
close(cmd)
if (statversion ~ /GNU coreutils/) {
stat_format = "-c '%s %n'" # GNU
} else {
@ -403,6 +443,7 @@ BEGIN {
infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i]
i++
}
close(cmdline)
in_count = i
first_file = infilesSmallToBigFull[0]
@ -439,6 +480,7 @@ BEGIN {
while ((getline < runtest) > 0) {
++first_count
}
close(runtest)
if (first_count) {
print "[+] OK, "first_count" tuples recorded."
@ -457,27 +499,79 @@ BEGIN {
# STEP 1: Collecting traces #
#############################
if (threads) {
inputsperfile = int(in_count / threads)
if (in_count % threads) {
inputsperfile++;
}
cnt = 0;
tmpfile=out_dir "/.filelist"
for (instance = 1; instance < threads; instance++) {
for (i = 0; i < inputsperfile; i++) {
print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."instance
cnt++
}
}
for (; cnt < in_count; cnt++) {
print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."threads
}
}
print "[*] Obtaining traces for "in_count" input files in '"in_dir"'."
cur = 0;
if (!stdin_file) {
print " Processing "in_count" files (forkserver mode)..."
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string
retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
} else {
print " Processing "in_count" files (forkserver mode)..."
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null"
retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
}
if (retval && (!AFL_CMIN_CRASHES_ONLY && !AFL_CMIN_ALLOW_ANY)) {
print "[!] Exit code "retval" != 0 received from afl-showmap (this means a crashing or timeout input is likely present), terminating..."
if (threads > 1) {
if (!ENVIRON["AFL_KEEP_TRACES"]) {
system("rm -rf "trace_dir" 2>/dev/null")
system("rmdir "out_dir)
print "[*] Creating " threads " parallel tasks with about " inputsperfile " items each."
for (i = 1; i <= threads; i++) {
if (!stdin_file) {
# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &"
retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &")
} else {
stdin_file=tmpfile"."i".stdin"
# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &"
retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &")
}
}
exit retval
print "[*] Waiting for parallel tasks to complete ..."
# wait for all processes to finish
ok=0
while (ok < threads) {
ok=0
for (i = 1; i <= threads; i++) {
if (system("test -f "tmpfile"."i".done") == 0) {
ok++
}
}
}
print "[*] Done!"
system("rm -f "tmpfile"*")
} else {
if (!stdin_file) {
print " Processing "in_count" files (forkserver mode)..."
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string
retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
} else {
print " Processing "in_count" files (forkserver mode)..."
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null"
retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
}
if (retval && (!AFL_CMIN_CRASHES_ONLY && !AFL_CMIN_ALLOW_ANY)) {
print "[!] Exit code "retval" != 0 received from afl-showmap (this means a crashing or timeout input is likely present), terminating..."
if (!ENVIRON["AFL_KEEP_TRACES"]) {
system("rm -rf "trace_dir" 2>/dev/null")
system("rmdir "out_dir)
}
exit retval
}
}
#######################################################
@ -501,6 +595,15 @@ BEGIN {
else { print " Processing file "cur"/"in_count }
# create path for the trace file from afl-showmap
tracefile_path = trace_dir"/"fn
# ensure the file size is not zero
cmd = "du -b "tracefile_path
"ls -l "tracefile_path
cmd | getline output
close(cmd)
split(output, result, "\t")
if (result[1] == 0) {
print "[!] WARNING: file "fn" is crashing the target, ignoring..."
}
# gather all keys, and count them
while ((getline line < tracefile_path) > 0) {
key = line
@ -562,6 +665,7 @@ BEGIN {
}
}
close(sortedKeys)
print ""
print "[+] Found "tuple_count" unique tuples across "in_count" files."
if (out_count == 1) {

View File

@ -7,6 +7,8 @@
#
# Copyright 2014, 2015 Google Inc. All rights reserved.
#
# Copyright 2019-2023 AFLplusplus
#
# 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:
@ -36,7 +38,7 @@
# array sizes.
#
echo "corpus minimization tool for afl-fuzz by Michal Zalewski"
echo "corpus minimization tool for afl-fuzz"
echo
#########
@ -46,14 +48,14 @@ echo
# Process command-line options...
MEM_LIMIT=none
TIMEOUT=none
TIMEOUT=5000
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN F_ARG \
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE T_ARG
export AFL_QUIET=1
while getopts "+i:o:f:m:t:eOQUAChXY" opt; do
while getopts "+i:o:f:m:t:T:eOQUAChXY" opt; do
case "$opt" in
@ -69,6 +71,7 @@ while getopts "+i:o:f:m:t:eOQUAChXY" opt; do
;;
"f")
STDIN_FILE="$OPTARG"
F_ARG=1
;;
"m")
MEM_LIMIT="$OPTARG"
@ -106,6 +109,9 @@ while getopts "+i:o:f:m:t:eOQUAChXY" opt; do
EXTRA_PAR="$EXTRA_PAR -U"
UNICORN_MODE=1
;;
"T")
T_ARG="$OPTARG"
;;
"?")
exit 1
;;
@ -130,9 +136,10 @@ Required parameters:
Execution control settings:
-f file - location read by the fuzzed program (stdin)
-m megs - memory limit for child process ($MEM_LIMIT MB)
-t msec - run time limit for child process (none)
-T tasks - how many parallel processes to create (default=1, "all"=nproc)
-f file - location read by the fuzzed program (default: stdin)
-m megs - memory limit for child process (default=$MEM_LIMIT MB)
-t msec - run time limit for child process (default: 5000ms)
-O - use binary-only instrumentation (FRIDA mode)
-Q - use binary-only instrumentation (QEMU mode)
-U - use unicorn-based instrumentation (Unicorn mode)
@ -151,6 +158,8 @@ AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory
AFL_NO_FORKSRV: run target via execve instead of using the forkserver
AFL_PATH: last resort location to find the afl-showmap binary
AFL_SKIP_BIN_CHECK: skip check for target binary
AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)
AFL_PYTHON_MODULE: custom mutator library (post_process and send)
_EOF_
exit 1
fi
@ -197,6 +206,11 @@ fi
# Check for obvious errors.
if [ ! "$T_ARG" = "" -a -n "$F_ARG" -a ! "$NYX_MODE" == 1 ]; then
echo "[-] Error: -T and -f can not be used together." 1>&2
exit 1
fi
if [ ! "$MEM_LIMIT" = "none" ]; then
if [ "$MEM_LIMIT" -lt "5" ]; then
@ -231,7 +245,7 @@ if [ "$NYX_MODE" = "" ]; then
fi
grep -aq AFL_DUMP_MAP_SIZE "./$TARGET_BIN" && {
grep -aq AFL_DUMP_MAP_SIZE "$TARGET_BIN" && {
echo "[!] Trying to obtain the map size of the target ..."
MAPSIZE=`AFL_DUMP_MAP_SIZE=1 "./$TARGET_BIN" 2>/dev/null`
test -n "$MAPSIZE" && {
@ -297,14 +311,34 @@ if [ ! -x "$SHOWMAP" ]; then
exit 1
fi
THREADS=
if [ ! "$T_ARG" = "" ]; then
if [ "$T_ARG" = "all" ]; then
THREADS=$(nproc)
else
if [ "$T_ARG" -gt 1 -a "$T_ARG" -le "$(nproc)" ]; then
THREADS=$T_ARG
else
echo "[-] Error: -T parameter must between 2 and $(nproc) or \"all\"." 1>&2
fi
fi
else
if [ -z "$F_ARG" ]; then
echo "[*] Are you aware of the '-T all' parallelize option that massively improves the speed?"
fi
fi
IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`))
if [ "$IN_COUNT" = "0" ]; then
echo "[+] Hmm, no inputs in the target directory. Nothing to be done."
echo "[-] Hmm, no inputs in the target directory. Nothing to be done."
rm -rf "$TRACE_DIR"
exit 1
fi
echo "[*] Are you aware that afl-cmin is faster than this afl-cmin.bash script?"
echo "[+] Found $IN_COUNT files for minimizing."
FIRST_FILE=`ls "$IN_DIR" | head -1`
# Make sure that we're not dealing with a directory.
@ -353,6 +387,18 @@ else
fi
TMPFILE=$OUT_DIR/.list.$$
if [ ! "$THREADS" = "" ]; then
ls -- "$IN_DIR" > $TMPFILE 2>/dev/null
IN_COUNT=$(cat $TMPFILE | wc -l)
SPLIT=$(($IN_COUNT / $THREADS))
if [ "$(($IN_COUNT % $THREADS))" -gt 0 ]; then
SPLIT=$(($SPLIT + 1))
fi
echo "[+] Splitting workload into $THREADS tasks with $SPLIT items on average each."
split -l $SPLIT $TMPFILE $TMPFILE.
fi
# Let's roll!
#############################
@ -361,6 +407,7 @@ fi
echo "[*] Obtaining traces for input files in '$IN_DIR'..."
if [ "$THREADS" = "" ]; then
(
CUR=0
@ -384,17 +431,58 @@ echo "[*] Obtaining traces for input files in '$IN_DIR'..."
printf "\\r Processing file $CUR/$IN_COUNT... "
cp "$IN_DIR/$fn" "$STDIN_FILE"
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
done
fi
echo
)
echo
else
PIDS=
CNT=0
for inputs in $(ls ${TMPFILE}.*); do
(
if [ "$STDIN_FILE" = "" ]; then
cat $inputs | while read -r fn; do
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn"
done
else
STDIN_FILE="$inputs.$$"
cat $inputs | while read -r fn; do
cp "$IN_DIR/$fn" "$STDIN_FILE"
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
done
fi
) &
PIDS="$PIDS $!"
done
echo "[+] Waiting for running tasks IDs:$PIDS"
wait
echo "[+] all $THREADS running tasks completed."
rm -f ${TMPFILE}*
#echo trace dir files: $(ls $TRACE_DIR/*|wc -l)
fi
##########################
# STEP 2: SORTING TUPLES #
@ -435,6 +523,8 @@ ls -rS "$IN_DIR" | while read -r fn; do
sed "s#\$# $fn#" "$TRACE_DIR/$fn" >>"$TRACE_DIR/.candidate_list"
test -s "$TRACE_DIR/$fn" || echo Warning: $fn is ignored because of crashing the target
done
echo

View File

@ -75,8 +75,17 @@ outputdir=`get_abs_path "$2"`
if [ ! -f "$inputdir/plot_data" ]; then
echo "[-] Error: input directory is not valid (missing 'plot_data')." 1>&2
exit 1
if [ -f "$inputdir/default/plot_data" ]; then
echo "[-] Error: input directory is not valid (missing 'plot_data'), likely you mean $inputdir/default?" 1>&2
exit 1
else
echo "[-] Error: input directory is not valid (missing 'plot_data')." 1>&2
exit 1
fi
fi
@ -141,7 +150,7 @@ set output '$outputdir/high_freq.png'
$GNUPLOT_SETUP
plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'corpus count' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
'' using 1:3 with filledcurve x1 title 'current fuzz item' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
'' using 1:3 with filledcurve x1 title 'current item' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
'' using 1:5 with lines title 'pending items' linecolor rgb '#0090ff' linewidth 3, \\
'' using 1:6 with lines title 'pending favs' linecolor rgb '#c00080' linewidth 3, \\
'' using 1:2 with lines title 'cycles done' linecolor rgb '#c000f0' linewidth 3

View File

@ -110,7 +110,7 @@ if [ "$PLATFORM" = "Darwin" ] ; then
sysctl kern.sysv.shmall=131072000
echo Settings applied.
echo
if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
if $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ; then
echo
echo Unloading the default crash reporter
SL=/System/Library; PL=com.apple.ReportCrash
@ -119,6 +119,7 @@ if [ "$PLATFORM" = "Darwin" ] ; then
echo
fi
echo It is recommended to disable System Integrity Protection for increased performance.
echo See: https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection
echo
DONE=1
fi

View File

@ -88,6 +88,7 @@ TOTAL_TIME=0
TOTAL_EXECS=0
TOTAL_EPS=0
TOTAL_CRASHES=0
TOTAL_HANGS=0
TOTAL_PFAV=0
TOTAL_PENDING=0
@ -190,6 +191,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
TOTAL_EPS=$((TOTAL_EPS + EXEC_SEC))
TOTAL_EXECS=$((TOTAL_EXECS + execs_done))
TOTAL_CRASHES=$((TOTAL_CRASHES + saved_crashes))
TOTAL_HANGS=$((TOTAL_HANGS + saved_hangs))
TOTAL_PENDING=$((TOTAL_PENDING + pending_total))
TOTAL_PFAV=$((TOTAL_PFAV + pending_favs))
@ -301,6 +303,7 @@ if [ "$ALIVE_CNT" -gt "1" ]; then
fi
echo " Crashes saved : $TOTAL_CRASHES"
echo " Hangs saved : $TOTAL_HANGS"
echo "Cycles without finds : $TOTAL_WCOP"
echo " Time without finds : $TOTAL_LAST_FIND"
echo

View File

@ -11,29 +11,6 @@ The `./examples` folder contains examples for custom mutators in python and C.
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
## The AFL++ grammar agnostic grammar mutator
In `./autotokens` you find a token-level fuzzer that does not need to know
anything about the grammar of an input as long as it is in ascii and allows
whitespace.
It is very fast and effective.
If you are looking for an example of how to effectively create a custom
mutator take a look at this one.
## The AFL++ Grammar Mutator
If you use git to clone AFL++, then the following will incorporate our
excellent grammar custom mutator:
```sh
git submodule update --init
```
Read the README in the [Grammar-Mutator] repository on how to use it.
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
## Production-Ready Custom Mutators
This directory holds ready to use custom mutators.
@ -47,6 +24,42 @@ and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
### The AFL++ grammar agnostic grammar mutator
In `./autotokens` you find a token-level fuzzer that does not need to know
anything about the grammar of an input as long as it is in ascii and allows
whitespace.
It is very fast and effective.
If you are looking for an example of how to effectively create a custom
mutator take a look at this one.
### The AFL++ Grammar Mutator
If you use git to clone AFL++, then the following will incorporate our
excellent grammar custom mutator:
```sh
git submodule update --init
```
Read the README in the [Grammar-Mutator] repository on how to use it.
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
Note that this custom mutator is not very good though!
### Other Mutators
atnwalk and gramatron are grammar custom mutators. Example grammars are
provided.
honggfuzz, libfuzzer and libafl are partial implementations based on the
mutator implementations of the respective fuzzers.
More for playing than serious usage.
radamsa is slow and not very good.
## 3rd Party Custom Mutators
### Superion Mutators
@ -57,14 +70,17 @@ requires cmake (among other things):
### libprotobuf Mutators
There are two WIP protobuf projects, that require work to be working though:
There are three WIP protobuf projects, that require work to be working though:
ASN.1 example:
[https://github.com/airbus-seclab/AFLplusplus-blogpost/tree/main/src/mutator](https://github.com/airbus-seclab/AFLplusplus-blogpost/tree/main/src/mutator)
transforms protobuf raw:
https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator
[https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
has a transform function you need to fill for your protobuf format, however
needs to be ported to the updated AFL++ custom mutator API (not much work):
https://github.com/thebabush/afl-libprotobuf-mutator
[https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
same as above but is for current AFL++:
https://github.com/P1umer/AFLplusplus-protobuf-mutator
[https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator)

View File

@ -0,0 +1,10 @@
CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic
all: aflpp-mutator.so
aflpp-mutator.so: aflpp.c
$(CC) $(CFLAGS) -I../../include -I. -shared -o aflpp-mutator.so aflpp.c ../../src/afl-performance.c
clean:
rm -f *.o *~ *.so core

View File

@ -0,0 +1,8 @@
# custum mutator: AFL++
this is the AFL++ havoc mutator as a custom mutator module for AFL++.
just type `make` to build
```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/aflpp/aflpp-mutator.so afl-fuzz ...```

View File

@ -0,0 +1,89 @@
#include "afl-mutations.h"
typedef struct my_mutator {
afl_state_t *afl;
u8 *buf;
u32 buf_size;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
(void)seed;
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
if ((data->buf = malloc(MAX_FILE)) == NULL) {
perror("afl_custom_init alloc");
return NULL;
} else {
data->buf_size = MAX_FILE;
}
data->afl = afl;
return data;
}
/* here we run the AFL++ mutator, which is the best! */
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
size_t max_size) {
if (max_size > data->buf_size) {
u8 *ptr = realloc(data->buf, max_size);
if (ptr) {
return 0;
} else {
data->buf = ptr;
data->buf_size = max_size;
}
}
u32 havoc_steps = 1 + rand_below(data->afl, 16);
/* set everything up, costly ... :( */
memcpy(data->buf, buf, buf_size);
/* the mutation */
u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps,
false, true, add_buf, add_buf_size, max_size);
/* return size of mutated data */
*out_buf = data->buf;
return out_buf_len;
}
/**
* Deinitialize everything
*
* @param data The data ptr from afl_custom_init
*/
void afl_custom_deinit(my_mutator_t *data) {
free(data->buf);
free(data);
}

View File

@ -0,0 +1,10 @@
CFLAGS = -O3 -funroll-loops -fPIC
all: aflpp-standalone
aflpp-standalone: aflpp-standalone.c
$(CC) $(CFLAGS) -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c
clean:
rm -f *.o *~ aflpp-standalone core

View File

@ -0,0 +1,10 @@
# AFL++ standalone mutator
this is the AFL++ havoc mutator as a standalone mutator
just type `make` to build.
```
aflpp-standalone inputfile outputfile [splicefile]
```

View File

@ -0,0 +1,165 @@
#include "afl-mutations.h"
s8 interesting_8[] = {INTERESTING_8};
s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
typedef struct my_mutator {
afl_state_t *afl;
u8 *buf;
u32 buf_size;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
(void)seed;
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
if ((data->buf = malloc(1024*1024)) == NULL) {
perror("afl_custom_init alloc");
return NULL;
} else {
data->buf_size = 1024*1024;
}
/* fake AFL++ state */
data->afl = calloc(1, sizeof(afl_state_t));
data->afl->queue_cycle = 1;
data->afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
rand_set_seed(data->afl, getpid());
return data;
}
/* here we run the AFL++ mutator, which is the best! */
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
size_t max_size) {
if (max_size > data->buf_size) {
u8 *ptr = realloc(data->buf, max_size);
if (ptr) {
return 0;
} else {
data->buf = ptr;
data->buf_size = max_size;
}
}
u32 havoc_steps = 1 + rand_below(data->afl, 16);
/* set everything up, costly ... :( */
memcpy(data->buf, buf, buf_size);
/* the mutation */
u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps,
false, true, add_buf, add_buf_size, max_size);
/* return size of mutated data */
*out_buf = data->buf;
return out_buf_len;
}
int main(int argc, char *argv[]) {
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("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("The -v verbose option prints debug output to stderr.\n");
return 0;
}
FILE *in = stdin, *out = stdout, *splice = NULL;
unsigned char *inbuf = malloc(1024 * 1024), *outbuf, *splicebuf = NULL;
int verbose = 0, splicelen = 0;
if (argc > 1 && strcmp(argv[1], "-v") == 0) {
verbose = 1;
argc--;
argv++;
fprintf(stderr, "Verbose active\n");
}
my_mutator_t *data = afl_custom_init(NULL, 0);
if (argc > 1 && strcmp(argv[1], "-") != 0) {
if ((in = fopen(argv[1], "r")) == NULL) {
perror(argv[1]);
return -1;
}
if (verbose) fprintf(stderr, "Input: %s\n", argv[1]);
}
size_t inlen = fread(inbuf, 1, 1024*1024, in);
if (!inlen) {
fprintf(stderr, "Error: empty file %s\n", argv[1] ? argv[1] : "stdin");
return -1;
}
if (argc > 2 && strcmp(argv[2], "-") != 0) {
if ((out = fopen(argv[2], "w")) == NULL) {
perror(argv[2]);
return -1;
}
if (verbose) fprintf(stderr, "Output: %s\n", argv[2]);
}
if (argc > 3) {
if ((splice = fopen(argv[3], "r")) == NULL) {
perror(argv[3]);
return -1;
}
if (verbose) fprintf(stderr, "Splice: %s\n", argv[3]);
splicebuf = malloc(1024*1024);
size_t splicelen = fread(splicebuf, 1, 1024*1024, splice);
if (!splicelen) {
fprintf(stderr, "Error: empty file %s\n", argv[3]);
return -1;
}
if (verbose) fprintf(stderr, "Mutation splice length: %zu\n", splicelen);
}
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: %zu\n", outlen);
if (fwrite(outbuf, 1, outlen, out) != outlen) {
fprintf(stderr, "Warning: incomplete write.\n");
return -1;
}
return 0;
}

View File

@ -0,0 +1,22 @@
# An AFL++ custom mutator using TritonDSE
## Installing the requirements
`pip3 install tritondse`
## How to run with an example
```
../../afl-cc -o ../../test-instr ../../test-instr.c
mkdir -p in
echo aaaa > in/in
AFL_DISABLE_TRIM=1 AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr
```
Note that this custom mutator works differently, new finds are synced
after 10-60 seconds to the fuzzing instance. This is necessary because only
C/C++ custom mutators have access to the internal AFL++ state.
Note that you should run first with `AFL_DEBUG` for 5-10 minutes and see if
all important libraries and syscalls are hooked (look at `WARNING` and `CRITICAL`
output during the run, best use with `AFL_NO_UI=1`)

View File

@ -0,0 +1,220 @@
import sys
import os
import logging
import hashlib
from tritondse import CleLoader
from tritondse import CompositeData
from tritondse import Config
from tritondse import CoverageStrategy
from tritondse import ProcessState
from tritondse import Program
from tritondse import Seed
from tritondse import SeedFormat
from tritondse import SymbolicExecutor
from tritondse import SymbolicExplorator
is_debug = False
out_path = ""
input_file = None
prog = None
config = None
dse = None
cycle = 0
count = 0
finding = 0
hashes = set()
format = SeedFormat.RAW
def pre_exec_hook(se: SymbolicExecutor, state: ProcessState):
global count
global hashes
global finding
if se.seed.hash not in hashes:
hashes.add(se.seed.hash)
finding = 1
filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash
if not os.path.exists(filename):
if is_debug:
print('Creating queue input ' + filename)
with open(filename, 'wb') as file:
if input_file:
file.write(se.seed.content.files[input_file])
else:
file.write(se.seed.content)
count += 1
#if input_file:
# if is_debug:
# print('Writing to ' + input_file + ' the content: ' + str(se.seed.content))
# with open(input_file, 'wb') as file:
# file.write(se.seed.content)
#def rtn_open(se: SymbolicExecutor, pstate: ProcessState, pc):
# """
# The open behavior.
# """
# logging.debug('open hooked')
#
# # Get arguments
# arg0 = pstate.get_argument_value(0) # const char *pathname
# flags = pstate.get_argument_value(1) # int flags
# mode = pstate.get_argument_value(2) # int mode
# arg0s = pstate.memory.read_string(arg0)
#
# # Concretize the whole path name
# pstate.concretize_memory_bytes(arg0, len(arg0s)+1) # Concretize the whole string + \0
#
# # We use flags as concrete value
# pstate.concretize_argument(1)
#
# # Use the flags to open the file in the write mode.
# mode = ""
# if (flags & 0xFF) == 0x00: # O_RDONLY
# mode = "r"
# elif (flags & 0xFF) == 0x01: # O_WRONLY
# mode = "w"
# elif (flags & 0xFF) == 0x02: # O_RDWR
# mode = "r+"
#
# if (flags & 0x0100): # O_CREAT
# mode += "x"
# if (flags & 0x0200): # O_APPEND
# mode = "a" # replace completely value
#
# if se.seed.is_file_defined(arg0s) and "r" in mode: # input file and opened in reading
# logging.info(f"opening an input file: {arg0s}")
# # Program is opening an input
# data = se.seed.get_file_input(arg0s)
# filedesc = pstate.create_file_descriptor(arg0s, io.BytesIO(data))
# fd = filedesc.id
# else:
# # Try to open it as a regular file
# try:
# fd = open(arg0s, mode) # use the mode here
# filedesc = pstate.create_file_descriptor(arg0s, fd)
# fd = filedesc.id
# except Exception as e:
# logging.debug(f"Failed to open {arg0s} {e}")
# fd = pstate.minus_one
#
# pstate.write_register("rax", fd) # write the return value
# pstate.cpu.program_counter = pstate.pop_stack_value() # pop the return value
# se.skip_instruction() # skip the current instruction so that the engine go straight fetching the next instruction
def init(seed):
global config
global dse
global format
global input_file
global is_debug
global out_path
global prog
# Load the program (LIEF-based program loader).
prog = CleLoader(os.environ['AFL_CUSTOM_INFO_PROGRAM'])
# Process other configuration environment variables.
argv = None
try:
foo = os.environ['AFL_DEBUG']
is_debug = True
except KeyError:
pass
if is_debug:
logging.basicConfig(level=logging.WARNING)
else:
logging.basicConfig(level=logging.CRITICAL)
try:
foo = os.environ['AFL_CUSTOM_INFO_OUT']
out_path = foo + '/../tritondse/queue'
except KeyError:
pass
try:
foo = os.environ['AFL_CUSTOM_INFO_PROGRAM_INPUT']
input_file = foo
except KeyError:
pass
try:
argv_list = os.environ['AFL_CUSTOM_INFO_PROGRAM_ARGV']
argv_tmp = [ os.environ['AFL_CUSTOM_INFO_PROGRAM'] ]
argv_tmp += argv_list.split()
argv = []
# now check for @@
for item in argv_tmp:
if "@@" in item:
input_file = out_path + '/../.input'
argv.append(input_file)
else:
argv.append(item)
except KeyError:
pass
# Create the output directory
os.makedirs(out_path, exist_ok=True)
# Debug
if is_debug:
print('DEBUG target: ' + os.environ['AFL_CUSTOM_INFO_PROGRAM'])
if argv:
print('DEBUG argv: ')
print(argv)
if input_file:
print('DEBUG input_file: ' + input_file)
print('DEBUG out_path: ' + out_path)
print('')
if input_file:
format = SeedFormat.COMPOSITE
# Now set up TritonDSE
config = Config(coverage_strategy = CoverageStrategy.PATH,
debug = is_debug,
pipe_stdout = is_debug,
pipe_stderr = is_debug,
execution_timeout = 1,
program_argv = argv,
smt_timeout= 50,
seed_format = format)
# Create an instance of the Symbolic Explorator
dse = SymbolicExplorator(config, prog)
# Add callbacks.
dse.callback_manager.register_pre_execution_callback(pre_exec_hook)
#dse.callback_manager.register_function_callback("open", rtn_open)
def fuzz(buf, add_buf, max_size):
global finding
finding = 1
while finding == 1:
finding = 0
dse.step()
return b""
def queue_new_entry(filename_new_queue, filename_orig_queue):
global cycle
global dse
# Add seed to the worklist.
with open(filename_new_queue, "rb") as file:
data = file.read()
hash = hashlib.md5(data).hexdigest()
if hash not in hashes:
hashes.add(hash)
if is_debug:
print("NEW FILE " + filename_new_queue + " hash " + hash + " count " + str(cycle))
cycle += 1
if input_file:
seed = Seed(CompositeData(files={"stdin": b"", # nothing on stdin
input_file: data}))
else:
seed = Seed(data)
dse.add_input_seed(seed)
# Start exploration!
#dse.step()
#dse.explore()
pass
# we simulate just doing one single fuzz in the custom mutator
def fuzz_count(buf):
return 1
def splice_optout():
pass

View File

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

View File

@ -0,0 +1,43 @@
# ATNwalk: Grammar-Based Fuzzing using Only Bit-Mutations
This is a custom mutator integration of ATNwalk that works by communicating via UNIX domain sockets.
Refer to [https://github.com/atnwalk/testbed](https://github.com/atnwalk/testbed) for detailed instructions on how to get ATNwalk running.
## Build
Just type `make` to build `atnwalk.so`.
## Run
**NOTE:** The commands below just demonstrate an example how running ATNwalk looks like and require a working [testbed](https://github.com/atnwalk/testbed)
```bash
# create the required a random seed first
mkdir -p ~/campaign/example/seeds
cd ~/campaign/example/seeds
head -c1 /dev/urandom | ~/atnwalk/build/javascript/bin/decode -wb > seed.decoded 2> seed.encoded
# create the required atnwalk directory and copy the seed
cd ../
mkdir -p atnwalk/in
cp ./seeds/seed.encoded atnwalk/in/seed
cd atnwalk
# assign to a single core when benchmarking it, change the CPU number as required
CPU_ID=0
# start the ATNwalk server
nohup taskset -c ${CPU_ID} ${HOME}/atnwalk/build/javascript/bin/server 100 > server.log 2>&1 &
# start AFL++ with ATNwalk
AFL_SKIP_CPUFREQ=1 \
AFL_DISABLE_TRIM=1 \
AFL_CUSTOM_MUTATOR_ONLY=1 \
AFL_CUSTOM_MUTATOR_LIBRARY=${HOME}/AFLplusplus/custom_mutators/atnwalk/atnwalk.so \
AFL_POST_PROCESS_KEEP_ORIGINAL=1 \
~/AFLplusplus/afl-fuzz -t 100 -i in/ -o out -b ${CPU_ID} -- ~/jerryscript/build/bin/jerry
# make sure to kill the ATNwalk server process after you're done
kill "$(cat atnwalk.pid)"
```

View File

@ -0,0 +1,539 @@
#include "afl-fuzz.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define BUF_SIZE_INIT 4096
#define SOCKET_NAME "./atnwalk.socket"
// how many errors (e.g. timeouts) to tolerate until moving on to the next queue
// entry
#define ATNWALK_ERRORS_MAX 1
// how many execution timeouts to tolerate until moving on to the next queue
// entry
#define EXEC_TIMEOUT_MAX 2
// handshake constants
const uint8_t SERVER_ARE_YOU_ALIVE = 213;
const uint8_t SERVER_YES_I_AM_ALIVE = 42;
// control bits
const uint8_t SERVER_CROSSOVER_BIT = 0b00000001;
const uint8_t SERVER_MUTATE_BIT = 0b00000010;
const uint8_t SERVER_DECODE_BIT = 0b00000100;
const uint8_t SERVER_ENCODE_BIT = 0b00001000;
typedef struct atnwalk_mutator {
afl_state_t *afl;
uint8_t atnwalk_error_count;
uint64_t prev_timeouts;
uint32_t prev_hits;
uint32_t stage_havoc_cur;
uint32_t stage_havoc_max;
uint32_t stage_splice_cur;
uint32_t stage_splice_max;
uint8_t *fuzz_buf;
size_t fuzz_size;
uint8_t *post_process_buf;
size_t post_process_size;
} atnwalk_mutator_t;
int read_all(int fd, uint8_t *buf, size_t buf_size) {
int n;
size_t offset = 0;
while (offset < buf_size) {
n = read(fd, buf + offset, buf_size - offset);
if (n == -1) { return 0; }
offset += n;
}
return 1;
}
int write_all(int fd, uint8_t *buf, size_t buf_size) {
int n;
size_t offset = 0;
while (offset < buf_size) {
n = write(fd, buf + offset, buf_size - offset);
if (n == -1) { return 0; }
offset += n;
}
return 1;
}
void put_uint32(uint8_t *buf, uint32_t val) {
buf[0] = (uint8_t)(val >> 24);
buf[1] = (uint8_t)((val & 0x00ff0000) >> 16);
buf[2] = (uint8_t)((val & 0x0000ff00) >> 8);
buf[3] = (uint8_t)(val & 0x000000ff);
}
uint32_t to_uint32(uint8_t *buf) {
uint32_t val = 0;
val |= (((uint32_t)buf[0]) << 24);
val |= (((uint32_t)buf[1]) << 16);
val |= (((uint32_t)buf[2]) << 8);
val |= ((uint32_t)buf[3]);
return val;
}
void put_uint64(uint8_t *buf, uint64_t val) {
buf[0] = (uint8_t)(val >> 56);
buf[1] = (uint8_t)((val & 0x00ff000000000000) >> 48);
buf[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40);
buf[3] = (uint8_t)((val & 0x000000ff00000000) >> 32);
buf[4] = (uint8_t)((val & 0x00000000ff000000) >> 24);
buf[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16);
buf[6] = (uint8_t)((val & 0x000000000000ff00) >> 8);
buf[7] = (uint8_t)(val & 0x00000000000000ff);
}
/**
* Initialize this custom mutator
*
* @param[in] afl a pointer to the internal state object. Can be ignored for
* now.
* @param[in] seed A seed for this mutator - the same seed should always mutate
* in the same way.
* @return Pointer to the data object this custom mutator instance should use.
* There may be multiple instances of this mutator in one afl-fuzz run!
* Return NULL on error.
*/
atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed);
atnwalk_mutator_t *data =
(atnwalk_mutator_t *)malloc(sizeof(atnwalk_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
data->afl = afl;
data->prev_hits = 0;
data->fuzz_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
data->fuzz_size = BUF_SIZE_INIT;
data->post_process_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
data->post_process_size = BUF_SIZE_INIT;
return data;
}
unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data,
const unsigned char *buf, size_t buf_size) {
// afl_custom_fuzz_count is called exactly once before entering the
// 'stage-loop' for the current queue entry thus, we use it to reset the error
// count and to initialize stage variables (somewhat not intended by the API,
// but still better than rewriting the whole thing to have a custom mutator
// stage)
data->atnwalk_error_count = 0;
data->prev_timeouts = data->afl->total_tmouts;
// it might happen that on the last execution of the splice stage a new path
// is found we need to fix that here and count it
if (data->prev_hits) {
data->afl->stage_finds[STAGE_SPLICE] +=
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
}
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
data->stage_havoc_cur = 0;
data->stage_splice_cur = 0;
// 50% havoc, 50% splice
data->stage_havoc_max = data->afl->stage_max >> 1;
if (data->stage_havoc_max < HAVOC_MIN) { data->stage_havoc_max = HAVOC_MIN; }
data->stage_splice_max = data->stage_havoc_max;
return data->stage_havoc_max + data->stage_splice_max;
}
size_t fail_fatal(int fd_socket, uint8_t **out_buf) {
if (fd_socket != -1) { close(fd_socket); }
*out_buf = NULL;
return 0;
}
size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf,
size_t buf_size, uint8_t **out_buf) {
if (fd_socket != -1) { close(fd_socket); }
data->atnwalk_error_count++;
if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) {
data->afl->stage_max = data->afl->stage_cur;
}
*out_buf = buf;
return buf_size;
}
/**
* Perform custom mutations on a given input
*
* (Optional for now. Required in the future)
*
* @param[in] data pointer returned in afl_custom_init for this fuzz case
* @param[in] buf Pointer to input data to be mutated
* @param[in] buf_size Size of input data
* @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
* error.
* @param[in] add_buf Buffer containing the additional test case
* @param[in] add_buf_size Size of the additional test case
* @param[in] max_size Maximum size of the mutated output. The mutation must not
* produce data larger than max_size.
* @return Size of the mutated output.
*/
size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size,
uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size,
size_t max_size) {
struct sockaddr_un addr;
int fd_socket;
uint8_t ctrl_buf[8];
uint8_t wanted;
// let's display what's going on in a nice way
if (data->stage_havoc_cur == 0) {
data->afl->stage_name = (uint8_t *)"atnwalk - havoc";
}
if (data->stage_havoc_cur == data->stage_havoc_max) {
data->afl->stage_name = (uint8_t *)"atnwalk - splice";
}
// increase the respective havoc or splice counters
if (data->stage_havoc_cur < data->stage_havoc_max) {
data->stage_havoc_cur++;
data->afl->stage_cycles[STAGE_HAVOC]++;
} else {
// if there is nothing to splice, continue with havoc and skip splicing this
// time
if (data->afl->ready_for_splicing_count < 1) {
data->stage_havoc_max = data->afl->stage_max;
data->stage_havoc_cur++;
data->afl->stage_cycles[STAGE_HAVOC]++;
} else {
data->stage_splice_cur++;
data->afl->stage_cycles[STAGE_SPLICE]++;
}
}
// keep track of found new corpus seeds per stage
if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) {
if (data->stage_splice_cur <= 1) {
data->afl->stage_finds[STAGE_HAVOC] +=
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
} else {
data->afl->stage_finds[STAGE_SPLICE] +=
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
}
}
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
// check whether this input produces a lot of timeouts, if it does then
// abandon this queue entry
if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) {
data->afl->stage_max = data->afl->stage_cur;
return fail_gracefully(-1, data, buf, buf_size, out_buf);
}
// initialize the socket
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
return fail_fatal(fd_socket, out_buf);
}
// ask whether the server is alive
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
if (!write_all(fd_socket, ctrl_buf, 1)) {
return fail_fatal(fd_socket, out_buf);
}
// see whether the server replies as expected
if (!read_all(fd_socket, ctrl_buf, 1) ||
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
return fail_fatal(fd_socket, out_buf);
}
// tell the server what we want to do
wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
// perform a crossover if we are splicing
if (data->stage_splice_cur > 0) { wanted |= SERVER_CROSSOVER_BIT; }
// tell the server what we want and how much data will be sent
ctrl_buf[0] = wanted;
put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
if (!write_all(fd_socket, ctrl_buf, 5)) {
return fail_fatal(fd_socket, out_buf);
}
// send the data to mutate and encode
if (!write_all(fd_socket, buf, buf_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
if (wanted & SERVER_CROSSOVER_BIT) {
// since we requested crossover, we will first tell how much additional data
// is to be expected
put_uint32(ctrl_buf, (uint32_t)add_buf_size);
if (!write_all(fd_socket, ctrl_buf, 4)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// send the additional data for crossover
if (!write_all(fd_socket, add_buf, add_buf_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// lastly, a seed is required for crossover so send one
put_uint64(ctrl_buf, (uint64_t)rand());
if (!write_all(fd_socket, ctrl_buf, 8)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
}
// since we requested mutation, we need to provide a seed for that
put_uint64(ctrl_buf, (uint64_t)rand());
if (!write_all(fd_socket, ctrl_buf, 8)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// obtain the required buffer size for the data that will be returned
if (!read_all(fd_socket, ctrl_buf, 4)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
size_t new_size = (size_t)to_uint32(ctrl_buf);
// if the data is too large then we ignore this round
if (new_size > max_size) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
if (new_size > buf_size) {
// buf is too small, need to use data->fuzz_buf, let's see whether we need
// to reallocate
if (new_size > data->fuzz_size) {
data->fuzz_size = new_size << 1;
data->fuzz_buf = (uint8_t *)realloc(data->fuzz_buf, data->fuzz_size);
}
*out_buf = data->fuzz_buf;
} else {
// new_size fits into buf, so re-use it
*out_buf = buf;
}
// obtain the encoded data
if (!read_all(fd_socket, *out_buf, new_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
close(fd_socket);
return new_size;
}
/**
* A post-processing function to use right before AFL writes the test case to
* disk in order to execute the target.
*
* (Optional) If this functionality is not needed, simply don't define this
* function.
*
* @param[in] data pointer returned in afl_custom_init for this fuzz case
* @param[in] buf Buffer containing the test case to be executed
* @param[in] buf_size Size of the test case
* @param[out] out_buf Pointer to the buffer containing the test case after
* processing. External library should allocate memory for out_buf.
* The buf pointer may be reused (up to the given buf_size);
* @return Size of the output buffer after processing or the needed amount.
* A return of 0 indicates an error.
*/
size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf,
size_t buf_size, uint8_t **out_buf) {
struct sockaddr_un addr;
int fd_socket;
uint8_t ctrl_buf[8];
// initialize the socket
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
return fail_fatal(fd_socket, out_buf);
}
// ask whether the server is alive
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
if (!write_all(fd_socket, ctrl_buf, 1)) {
return fail_fatal(fd_socket, out_buf);
}
// see whether the server replies as expected
if (!read_all(fd_socket, ctrl_buf, 1) ||
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
return fail_fatal(fd_socket, out_buf);
}
// tell the server what we want and how much data will be sent
ctrl_buf[0] = SERVER_DECODE_BIT;
put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
if (!write_all(fd_socket, ctrl_buf, 5)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// send the data to decode
if (!write_all(fd_socket, buf, buf_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// obtain the required buffer size for the data that will be returned
if (!read_all(fd_socket, ctrl_buf, 4)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
size_t new_size = (size_t)to_uint32(ctrl_buf);
// need to use data->post_process_buf, let's see whether we need to reallocate
if (new_size > data->post_process_size) {
data->post_process_size = new_size << 1;
data->post_process_buf =
(uint8_t *)realloc(data->post_process_buf, data->post_process_size);
}
*out_buf = data->post_process_buf;
// obtain the decoded data
if (!read_all(fd_socket, *out_buf, new_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
close(fd_socket);
return new_size;
}
/**
* Deinitialize everything
*
* @param data The data ptr from afl_custom_init
*/
void afl_custom_deinit(atnwalk_mutator_t *data) {
free(data->fuzz_buf);
free(data->post_process_buf);
free(data);
}

View File

@ -1,22 +0,0 @@
#ifndef CUSTOM_MUTATOR_HELPERS
#define CUSTOM_MUTATOR_HELPERS
#include "config.h"
#include "types.h"
#include "afl-fuzz.h"
#include <stdlib.h>
#define INITIAL_GROWTH_SIZE (64)
/* Use in a struct: creates a name_buf and a name_size variable. */
#define BUF_VAR(type, name) \
type * name##_buf; \
size_t name##_size;
/* this filles in `&structptr->something_buf, &structptr->something_size`. */
#define BUF_PARAMS(struct, name) \
(void **)&struct->name##_buf, &struct->name##_size
#undef INITIAL_GROWTH_SIZE
#endif

View File

@ -3,14 +3,14 @@
#include <stdlib.h>
#include <string.h>
#include "custom_mutator_helpers.h"
#include "afl-fuzz.h"
#include "mangle.h"
#define NUMBER_OF_MUTATIONS 5
uint8_t * queue_input;
uint8_t *queue_input;
size_t queue_input_size;
afl_state_t * afl_struct;
afl_state_t *afl_struct;
run_t run;
honggfuzz_t global;
struct _dynfile_t dynfile;
@ -18,8 +18,8 @@ struct _dynfile_t dynfile;
typedef struct my_mutator {
afl_state_t *afl;
run_t * run;
u8 * mutator_buf;
run_t *run;
u8 *mutator_buf;
unsigned int seed;
unsigned int extras_cnt, a_extras_cnt;
@ -65,9 +65,9 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
/* When a new queue entry is added we check if there are new dictionary
entries to add to honggfuzz structure */
uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
const uint8_t *filename_new_queue,
const uint8_t *filename_orig_queue) {
void afl_custom_queue_new_entry(my_mutator_t *data,
const uint8_t *filename_new_queue,
const uint8_t *filename_orig_queue) {
if (run.global->mutate.dictionaryCnt >= 1024) return;
@ -97,7 +97,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
}
return 0;
return;
}

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
../examples/custom_mutator_helpers.h

View File

@ -1,6 +1,5 @@
// This simple example just creates random buffer <= 100 filled with 'A'
// needs -I /path/to/AFLplusplus/include
//#include "custom_mutator_helpers.h"
#include <stdint.h>
#include <stdlib.h>
@ -8,19 +7,17 @@
#include <stdio.h>
#include "radamsa.h"
#include "custom_mutator_helpers.h"
#include "afl-fuzz.h"
typedef struct my_mutator {
afl_t *afl;
u8 *mutator_buf;
afl_state_t *afl;
u8 *mutator_buf;
unsigned int seed;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed);
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));

View File

@ -5,6 +5,8 @@ This uses the symcc to find new paths into the target.
Note that this is a just a proof of concept example! It is better to use
the fuzzing helpers of symcc, symqemu, Fuzzolic, etc. rather than this.
Also the symqemu custom mutator is better than this.
To use this custom mutator follow the steps in the symcc repository
[https://github.com/eurecom-s3/symcc/](https://github.com/eurecom-s3/symcc/)
on how to build symcc and how to instrument a target binary (the same target

View File

@ -0,0 +1,14 @@
ifdef DEBUG
CFLAGS += -DDEBUG
endif
all: symqemu-mutator.so
CFLAGS += -O3 -funroll-loops
symqemu-mutator.so: symqemu.c
$(CC) -g $(CFLAGS) $(CPPFLAGS) -g -I../../include -shared -fPIC -o symqemu-mutator.so symqemu.c
clean:
rm -f symqemu-mutator.so *.o *~ core

View File

@ -0,0 +1,19 @@
# custum mutator: symqemu
This uses the symcc to find new paths into the target.
## How to build and use
To use this custom mutator follow the steps in the symqemu repository
[https://github.com/eurecom-s3/symqemu/](https://github.com/eurecom-s3/symqemu/)
on how to build symqemu-x86_x64 and put it in your `PATH`.
Just type `make` to build this custom mutator.
```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_DISABLE_TRIM=1 afl-fuzz ...```
## Options
`SYMQEMU_ALL=1` - use concolic solving on **all** queue items, not only interesting/favorite ones.
`SYMQEMU_LATE=1` - use concolic solving only after there have been no finds for 5 minutes.

View File

@ -0,0 +1,424 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include "config.h"
#include "debug.h"
#include "afl-fuzz.h"
#include "common.h"
afl_state_t *afl_struct;
static u32 debug = 0;
static u32 found_items = 0;
#define SYMQEMU_LOCATION "symqemu"
#define DBG(x...) \
if (debug) { fprintf(stderr, x); }
typedef struct my_mutator {
afl_state_t *afl;
u32 all;
u32 late;
u8 *mutator_buf;
u8 *out_dir;
u8 *target;
u8 *symqemu;
u8 *input_file;
u32 counter;
u32 seed;
u32 argc;
u8 **argv;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
if (getenv("AFL_DEBUG")) debug = 1;
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
char *path = getenv("PATH");
char *exec_name = "symqemu-x86_64";
char *token = strtok(path, ":");
char exec_path[4096];
while (token != NULL && data->symqemu == NULL) {
snprintf(exec_path, sizeof(exec_path), "%s/%s", token, exec_name);
if (access(exec_path, X_OK) == 0) {
data->symqemu = (u8 *)strdup(exec_path);
break;
}
token = strtok(NULL, ":");
}
if (!data->symqemu) FATAL("symqemu binary %s not found", exec_name);
DBG("Found %s\n", data->symqemu);
if (getenv("AFL_CUSTOM_MUTATOR_ONLY")) {
WARNF(
"the symqemu module is not very effective with "
"AFL_CUSTOM_MUTATOR_ONLY.");
}
if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
free(data);
perror("mutator_buf alloc");
return NULL;
}
data->target = getenv("AFL_CUSTOM_INFO_PROGRAM");
u8 *path_tmp = getenv("AFL_CUSTOM_INFO_OUT");
u32 len = strlen(path_tmp) + 32;
u8 *symqemu_path = malloc(len);
data->out_dir = malloc(len);
snprintf(symqemu_path, len, "%s/%s", path_tmp, SYMQEMU_LOCATION);
snprintf(data->out_dir, len, "%s/out", symqemu_path, path_tmp);
(void)mkdir(symqemu_path, 0755);
(void)mkdir(data->out_dir, 0755);
setenv("SYMCC_OUTPUT_DIR", data->out_dir, 1);
data->input_file = getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT");
u8 *tmp = NULL;
if ((tmp = getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) && *tmp) {
int argc = 0, index = 2;
for (u32 i = 0; i < strlen(tmp); ++i)
if (isspace(tmp[i])) ++argc;
data->argv = (u8 **)malloc((argc + 4) * sizeof(u8 **));
u8 *p = strdup(tmp);
do {
data->argv[index] = p;
while (*p && !isspace(*p))
++p;
if (*p) {
*p++ = 0;
while (isspace(*p))
++p;
}
if (strcmp(data->argv[index], "@@") == 0) {
if (!data->input_file) {
u32 ilen = strlen(symqemu_path) + 32;
data->input_file = malloc(ilen);
snprintf(data->input_file, ilen, "%s/.input", symqemu_path);
}
data->argv[index] = data->input_file;
}
DBG("%d: %s\n", index, data->argv[index]);
index++;
} while (*p);
data->argv[index] = NULL;
data->argc = index;
} else {
data->argv = (u8 **)malloc(8 * sizeof(u8 **));
data->argc = 2;
data->argv[2] = NULL;
}
data->argv[0] = data->symqemu;
data->argv[1] = data->target;
data->afl = afl;
data->seed = seed;
afl_struct = afl;
if (getenv("SYMQEMU_ALL")) { data->all = 1; }
if (getenv("SYMQEMU_LATE")) { data->late = 1; }
if (data->input_file) { setenv("SYMCC_INPUT_FILE", data->input_file, 1); }
DBG("out_dir=%s, target=%s, input_file=%s, argc=%u\n", data->out_dir,
data->target,
data->input_file ? (char *)data->input_file : (char *)"<stdin>",
data->argc);
if (debug) {
fprintf(stderr, "[");
for (u32 i = 0; i <= data->argc; ++i)
fprintf(stderr, " \"%s\"",
data->argv[i] ? (char *)data->argv[i] : "<NULL>");
fprintf(stderr, " ]\n");
}
return data;
}
/* No need to receive a splicing item */
void afl_custom_splice_optout(void *data) {
(void)(data);
}
/* Get unix time in milliseconds */
inline u64 get_cur_time(void) {
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000);
}
u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, size_t buf_size) {
if (likely((!afl_struct->queue_cur->favored && !data->all) ||
afl_struct->queue_cur->was_fuzzed)) {
return 0;
}
if (likely(data->late)) {
if (unlikely(get_cur_time() - afl_struct->last_find_time <=
10 * 60 * 1000)) {
return 0;
}
}
int pipefd[2];
struct stat st;
if (afl_struct->afl_env.afl_no_ui) {
ACTF("Sending to symqemu: %s", afl_struct->queue_cur->fname);
}
if (!(stat(afl_struct->queue_cur->fname, &st) == 0 && S_ISREG(st.st_mode) &&
st.st_size)) {
PFATAL("Couldn't find enqueued file: %s", afl_struct->queue_cur->fname);
}
if (afl_struct->fsrv.use_stdin) {
if (pipe(pipefd) == -1) {
PFATAL(
"Couldn't create a pipe for interacting with symqemu child process");
}
}
if (data->input_file) {
int fd = open(data->input_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
ssize_t s = write(fd, buf, buf_size);
close(fd);
DBG("wrote %zd/%zd to %s\n", s, buf_size, data->input_file);
}
int pid = fork();
if (pid == -1) return 0;
if (likely(pid)) {
if (!data->input_file || afl_struct->fsrv.use_stdin) {
close(pipefd[0]);
if (fcntl(pipefd[1], F_GETPIPE_SZ)) {
fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE);
}
ck_write(pipefd[1], buf, buf_size, data->input_file);
close(pipefd[1]);
}
pid = waitpid(pid, NULL, 0);
DBG("symqemu finished executing!\n");
} else /* (pid == 0) */ { // child
if (afl_struct->fsrv.use_stdin) {
close(pipefd[1]);
dup2(pipefd[0], 0);
}
DBG("exec=%s\n", data->target);
if (!debug) {
close(1);
close(2);
dup2(afl_struct->fsrv.dev_null_fd, 1);
dup2(afl_struct->fsrv.dev_null_fd, 2);
}
execvp((char *)data->argv[0], (char **)data->argv);
fprintf(stderr, "Executing: [");
for (u32 i = 0; i <= data->argc; ++i)
fprintf(stderr, " \"%s\"",
data->argv[i] ? (char *)data->argv[i] : "<NULL>");
fprintf(stderr, " ]\n");
FATAL("Failed to execute %s %s\n", data->argv[0], data->argv[1]);
exit(-1);
}
/* back in mother process */
struct dirent **nl;
s32 i, items = scandir(data->out_dir, &nl, NULL, NULL);
found_items = 0;
char source_name[4096];
if (items > 0) {
for (i = 0; i < (u32)items; ++i) {
// symqemu output files start with a digit
if (!isdigit(nl[i]->d_name[0])) continue;
struct stat st;
snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir,
nl[i]->d_name);
DBG("file=%s\n", source_name);
if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
++found_items;
}
free(nl[i]);
}
free(nl);
}
DBG("Done, found %u items!\n", found_items);
return found_items;
}
size_t afl_custom_fuzz(my_mutator_t *data, u8 *buf, size_t buf_size,
u8 **out_buf, u8 *add_buf, size_t add_buf_size,
size_t max_size) {
struct dirent **nl;
s32 done = 0, i, items = scandir(data->out_dir, &nl, NULL, NULL);
char source_name[4096];
if (items > 0) {
for (i = 0; i < (u32)items; ++i) {
// symqemu output files start with a digit
if (!isdigit(nl[i]->d_name[0])) continue;
struct stat st;
snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir,
nl[i]->d_name);
DBG("file=%s\n", source_name);
if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
int fd = open(source_name, O_RDONLY);
if (fd < 0) { goto got_an_issue; }
ssize_t r = read(fd, data->mutator_buf, MAX_FILE);
close(fd);
DBG("fn=%s, fd=%d, size=%ld\n", source_name, fd, r);
if (r < 1) { goto got_an_issue; }
done = 1;
--found_items;
unlink(source_name);
*out_buf = data->mutator_buf;
return (u32)r;
}
free(nl[i]);
}
free(nl);
}
got_an_issue:
*out_buf = NULL;
return 0;
}
/**
* Deinitialize everything
*
* @param data The data ptr from afl_custom_init
*/
void afl_custom_deinit(my_mutator_t *data) {
free(data->mutator_buf);
free(data);
}

View File

@ -3,6 +3,61 @@
This is the list of all noteworthy changes made in every public
release of the tool. See README.md for the general instruction manual.
### Version ++4.08a (dev)
- afl-fuzz:
- new mutation engine: mutations that favor discovery more paths are
prefered until no new finds for 10 minutes then switching to mutations
that favor triggering crashes. Modes and switch time can be configured
with `-P`. Also input mode for the target can be defined with `-a` to
be `text` or `binary` (defaults to `generic`)
- new custom mutator that has the new afl++ engine (so it can easily
incorporated into new custom mutators), and also comes with a standalone
command line tool! See custom_mutators/aflpp/standalone/
- display the state of the fuzzing run in the UI :-)
- fix timeout setting if '+' is used or a session is restarted
- afl-cmin/afl-cmin.bash:
- fixed a bug inherited from vanilla AFL where a coverage of
map[123] = 11 would be the same as map[1123] = 1
- warn on crashing inputs
- afl-cc:
- fixed an off-by-one instrumentation of iselect, hurting coverage a bit.
Thanks to @amykweon for spotting and fixing!
- @toka fixed a bug in laf-intel signed integer comparison splitting,
thanks a lot!!
- more LLVM compatability
- frida_mode:
- support for long form instrumentation on x86_x64 and arm64
### Version ++4.07c (release)
- afl-fuzz:
- reverse reading the seeds only on restarts (increases performance)
- new env `AFL_POST_PROCESS_KEEP_ORIGINAL` to keep the orignal
data before post process on finds (for atnwalk custom mutator)
- new env `AFL_IGNORE_PROBLEMS_COVERAGE` to ignore coverage from
loaded libs after forkserver initialization (required by Mozilla)
- afl-cc:
- added @responsefile support
- new env `AFL_LLVM_LTO_SKIPINIT` to support the AFL++ based WASM
(https://github.com/fgsect/WAFL) project
- error and print help if afl-clan-lto is used with lto=thin
- rewrote our PCGUARD pass to be compatible with LLVM 15+ shenanigans,
requires LLVM 13+ now instead of 10.0.1+
- fallback to native LLVM PCGUARD if our PCGUARD is unavailable
- fixed a crash in GCC CMPLOG
- afl-showmap:
- added custom mutator post_process and send support
- add `-I filelist` option, an alternative to `-i in_dir`
- afl-cmin + afl-cmin.bash:
- `-T threads` parallel task support, can be a huge speedup!
- qemu_mode:
- Persistent mode + QASAN support for ppc32 targets by @worksbutnottested
- a new grammar custom mutator atnwalk was submitted by @voidptr127 !
- two new custom mutators are now available:
- TritonDSE in custom_mutators/aflpp_tritondse
- SymQEMU in custom_mutators/symqemu
### Version ++4.06c (release)
- afl-fuzz:
- ensure temporary file descriptor is closed when not used
@ -211,7 +266,7 @@
afl-showmap and other tools.
- afl-cc:
- detect overflow reads on initial input buffer for asan
- new cmplog mode (incompatible with older afl++ versions)
- new cmplog mode (incompatible with older AFL++ versions)
- support llvm IR select instrumentation for default PCGUARD and LTO
- fix for shared linking on MacOS
- better selective instrumentation AFL_LLVM_{ALLOW|DENY}LIST

View File

@ -171,6 +171,14 @@ If you find an interesting or important question missing, submit it via
The more "unstable" edges there are, the harder it is for AFL++ to identify
valid new paths.
If you fuzz in persistent mode (`AFL_LOOP` or `LLVMFuzzerTestOneInput()`
harnesses, a large number of unstable edges can mean that the target keeps
internal state and therefore it is possible that crashes cannot be replayed.
In such a case do either **not** fuzz in persistent mode (remove `AFL_LOOP()`
from your harness or call `LLVMFuzzerTestOneInput()` harnesses with `@@`),
or set a low `AFL_LOOP` value, e.g. 100, and enable `AFL_PERSISTENT_RECORD`
in `config.h` with the same value.
A value above 90% is usually fine and a value above 80% is also still ok, and
even a value above 20% can still result in successful finds of bugs. However,
it is recommended that for values below 90% or 80% you should take
@ -229,7 +237,8 @@ If you find an interesting or important question missing, submit it via
If this is not a viable option, you can set `AFL_IGNORE_PROBLEMS=1` but then
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
degraded.
degraded. Note that there is additionally `AFL_IGNORE_PROBLEMS_COVERAGE` to
additionally tell AFL++ to ignore any coverage from the late loaded libaries.
</p></details>
<details>
@ -270,3 +279,54 @@ If you find an interesting or important question missing, submit it via
Solution: just do an `export AFL_MAP_SIZE=(the value in the warning)`.
</p></details>
<details>
<summary id="linker-errors">Linker errors.</summary><p>
If you compile C++ harnesses and see `undefined reference` errors for
variables named `__afl_...`, e.g.:
```
/usr/bin/ld: /tmp/test-d3085f.o: in function `foo::test()':
test.cpp:(.text._ZN3fooL4testEv[_ZN3fooL4testEv]+0x35): undefined reference to `foo::__afl_connected'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```
Then you use AFL++ macros like `__AFL_LOOP` within a namespace and this
will not work.
Solution: Move that harness portion to the global namespace, e.g. before:
```
#include <cstdio>
namespace foo {
static void test() {
while(__AFL_LOOP(1000)) {
foo::function();
}
}
}
int main(int argc, char** argv) {
foo::test();
return 0;
}
```
after:
```
#include <cstdio>
static void mytest() {
while(__AFL_LOOP(1000)) {
foo::function();
}
}
namespace foo {
static void test() {
mytest();
}
}
int main(int argc, char** argv) {
foo::test();
return 0;
}
```
</p></details>

View File

@ -3,9 +3,8 @@
## Linux on x86
An easy way to install AFL++ with everything compiled is available via docker:
You can use the [Dockerfile](../Dockerfile) (which has gcc-10 and clang-12 -
hence afl-clang-lto is available) or just pull directly from the Docker Hub
(for x86_64 and arm64):
You can use the [Dockerfile](../Dockerfile) or just pull directly from the
Docker Hub (for x86_64 and arm64):
```shell
docker pull aflplusplus/aflplusplus:
@ -21,14 +20,14 @@ development state of AFL++.
If you want to build AFL++ yourself, you have many options. The easiest choice
is to build and install everything:
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-12` with
whatever llvm version is available. We recommend llvm 12, 13 or 14.
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
whatever llvm version is available. We recommend llvm 13, 14, 15 or 16.
```shell
sudo apt-get update
sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools cargo libgtk-3-dev
# try to install llvm 12 and install the distro default if that fails
sudo apt-get install -y lld-12 llvm-12 llvm-12-dev clang-12 || sudo apt-get install -y lld llvm llvm-dev clang
# try to install llvm 14 and install the distro default if that fails
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 ninja-build # for QEMU mode
git clone https://github.com/AFLplusplus/AFLplusplus
@ -51,7 +50,7 @@ make source-only
These build targets exist:
* all: the main afl++ binaries and llvm/gcc instrumentation
* all: the main AFL++ binaries and llvm/gcc instrumentation
* binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode,
qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator,
libtokencap
@ -79,22 +78,20 @@ make STATIC=1
These build options exist:
* STATIC - compile AFL++ static
* CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md)
* ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for
debug purposes
* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes
* DEBUG - no optimization, -ggdb3, all warnings and -Werror
* LLVM_DEBUG - shows llvm deprecation warnings
* PROFILING - compile afl-fuzz with profiling information
* INTROSPECTION - compile afl-fuzz with mutation introspection
* NO_PYTHON - disable python support
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for
normal fuzzing
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
* NO_NYX - disable building nyx mode dependencies
* NO_CORESIGHT - disable building coresight (arm64 only)
* NO_UNICORN_ARM64 - disable building unicorn on arm64
* AFL_NO_X86 - if compiling on non-intel/amd platforms
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config
(e.g., Debian)
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)
e.g.: `make LLVM_CONFIG=llvm-config-14`

View File

@ -131,6 +131,11 @@ jitter, or is a hash map function etc., then it should not be instrumented.
To be able to exclude these functions (based on AFL++'s measured stability), the
following process will allow to identify functions with variable edges.
Note that this is only useful for non-persistent targets!
If a persistent target is unstable whereas when run non-persistent is fine,
then this means that the target is keeping internal state, which is bad for
fuzzing. Fuzz such targets **without** persistent mode.
Four steps are required to do this and it also requires quite some knowledge of
coding and/or disassembly and is effectively possible only with `afl-clang-fast`
`PCGUARD` and `afl-clang-lto` `LTO` instrumentation.

View File

@ -145,12 +145,15 @@ def deinit(): # optional for Python
- `fuzz` (optional):
This method performs custom mutations on a given input. It also accepts an
additional test case. Note that this function is optional - but it makes
sense to use it. You would only skip this if `post_process` is used to fix
checksums etc. so if you are using it, e.g., as a post processing library.
Note that a length > 0 *must* be returned!
The returned output buffer is under **your** memory management!
This method performs your custom mutations on a given input.
The add_buf is the contents of another queue item that can be used for
splicing - or anything else - and can also be ignored. If you are not
using this additional data then define `splice_optout` (see above).
This function is optional.
Returing a length of 0 is valid and is interpreted as skipping this
one mutation result.
For non-Python: the returned output buffer is under **your** memory
management!
- `describe` (optional):
@ -304,6 +307,34 @@ Note: for some distributions, you might also need the package `python[3]-apt`.
In case your setup is different, set the necessary variables like this:
`PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`.
### Helpers
For C/C++ custom mutators you get a pointer to `afl_state_t *afl` in the
`afl_custom_init()` which contains all information that you need.
Note that if you access it, you need to recompile your custom mutator if
you update AFL++ because the structure might have changed!
For mutators written in Python, Rust, GO, etc. there are a few environment
variables set to help you to get started:
`AFL_CUSTOM_INFO_PROGRAM` - the program name of the target that is executed.
If your custom mutator is used with modes like Qemu (`-Q`), this will still
contain the target program, not afl-qemu-trace.
`AFL_CUSTOM_INFO_PROGRAM_INPUT` - if the `-f` parameter is used with afl-fuzz
then this value is found in this environment variable.
`AFL_CUSTOM_INFO_PROGRAM_ARGV` - this contains the parameters given to the
target program and still has the `@@` identifier in there.
Note: If `AFL_CUSTOM_INFO_PROGRAM_INPUT` is empty and `AFL_CUSTOM_INFO_PROGRAM_ARGV`
is either empty or does not contain `@@` then the target gets the input via
`stdin`.
`AFL_CUSTOM_INFO_OUT` - This is the output directory for this fuzzer instance,
so if `afl-fuzz` was called with `-o out -S foobar`, then this will be set to
`out/foobar`.
### Custom Mutator Preparation
For C/C++ mutators, the source code must be compiled as a shared object:

View File

@ -156,7 +156,7 @@ Available options:
- LTO - LTO instrumentation
- NATIVE - clang's original pcguard based instrumentation
- NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
- PCGUARD - our own pcgard based instrumentation (default)
- PCGUARD - our own pcguard based instrumentation (default)
#### CMPLOG
@ -240,7 +240,9 @@ combined.
the default `0x10000`. A value of 0 or empty sets the map address to be
dynamic (the original AFL way, which is slower).
- `AFL_LLVM_MAP_DYNAMIC` sets the shared memory address to be dynamic.
- `AFL_LLVM_LTO_SKIPINIT` skips adding initialization code. Some global vars
(e.g. the highest location ID) are not injected. Needed to instrument with
[WAFL](https://github.com/fgsect/WAFL.git).
For more information, see
[instrumentation/README.lto.md](../instrumentation/README.lto.md).
@ -404,7 +406,8 @@ checks or alter some of the more exotic semantics of the tool:
- If afl-fuzz encounters an incorrect fuzzing setup during a fuzzing session
(not at startup), it will terminate. If you do not want this, then you can
set `AFL_IGNORE_PROBLEMS`.
set `AFL_IGNORE_PROBLEMS`. If you additionally want to also ignore coverage
from late loaded libraries, you can set `AFL_IGNORE_PROBLEMS_COVERAGE`.
- When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the
fuzzer to import test cases from other instances before doing anything else.
@ -616,6 +619,14 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
- Setting `AFL_INST_LIBS` causes the translator to also instrument the code
inside any dynamically linked libraries (notably including glibc).
- You can use `AFL_QEMU_INST_RANGES=0xaaaa-0xbbbb,0xcccc-0xdddd` to just
instrument specific memory locations, e.g. a specific library.
Excluding ranges takes priority over any included ranges or `AFL_INST_LIBS`.
- You can use `AFL_QEMU_EXCLUDE_RANGES=0xaaaa-0xbbbb,0xcccc-0xdddd` to **NOT**
instrument specific memory locations, e.g. a specific library.
Excluding ranges takes priority over any included ranges or `AFL_INST_LIBS`.
- It is possible to set `AFL_INST_RATIO` to skip the instrumentation on some
of the basic blocks, which can be useful when dealing with very complex
binaries.
@ -677,6 +688,8 @@ support.
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
code. Code is considered to be JIT if the executable segment is not backed by
a file.
* `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` - Don't instrument the code loaded late at
runtime. Strictly limits instrumentation to what has been included.
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
instrumentation (the default where available). Required to use
`AFL_FRIDA_INST_TRACE`.

View File

@ -8,6 +8,7 @@ Here are some good write-ups to show how to effectively use AFL++:
* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
* [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
* [https://bushido-sec.com/index.php/2023/06/19/the-art-of-fuzzing/](https://bushido-sec.com/index.php/2023/06/19/the-art-of-fuzzing/)
* [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
* [https://securitylab.github.com/research/fuzzing-software-2](https://securitylab.github.com/research/fuzzing-software-2)
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
@ -20,6 +21,14 @@ training, then we can highly recommend the following:
* [https://github.com/antonio-morales/Fuzzing101](https://github.com/antonio-morales/Fuzzing101)
Here is a good forkflow description (and tutorial) for qemu_mode:
* [https://airbus-seclab.github.io/AFLplusplus-blogpost/](https://airbus-seclab.github.io/AFLplusplus-blogpost/)
Here is good workflow description for frida_mode:
* [https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html](https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html)
If you are interested in fuzzing structured data (where you define what the
structure is), these links have you covered (some are outdated though):

View File

@ -7,6 +7,8 @@ variables.
In FRIDA mode, binary programs are instrumented, similarly to QEMU mode.
A tutorial can be found at [https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html](https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html)
## Current progress
As FRIDA mode is new, it is missing a lot of features. The design is such that
@ -178,11 +180,13 @@ Default is 256Mb.
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
code. Code is considered to be JIT if the executable segment is not backed by
a file.
* `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` - Don't instrument the code loaded late at
runtime. Strictly limits instrumentation to what has been included.
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
instrumentation (the default where available). Required to use
`AFL_FRIDA_INST_TRACE`.
* `AFL_FRIDA_INST_REGS_FILE` - File to write raw register contents at the start
of each block.
`AFL_FRIDA_INST_TRACE`.
* `AFL_FRIDA_INST_NO_CACHE` - Don't use a look-up table to cache real to
instrumented address block translations.
* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default, the child will

View File

@ -844,6 +844,12 @@ class Afl {
static setInstrumentLibraries() {
Afl.jsApiSetInstrumentLibraries();
}
/**
* See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
*/
static setInstrumentNoDynamicLoad() {
Afl.jsApiSetInstrumentNoDynamicLoad();
}
/**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/

View File

@ -19,6 +19,7 @@
js_api_set_instrument_jit;
js_api_set_instrument_libraries;
js_api_set_instrument_instructions;
js_api_set_instrument_no_dynamic_load;
js_api_set_instrument_no_optimize;
js_api_set_instrument_regs_file;
js_api_set_instrument_seed;

View File

@ -14,8 +14,6 @@ void entry_init(void);
void entry_start(void);
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output);
void entry_on_fork(void);
#endif

View File

@ -6,6 +6,7 @@
extern gboolean ranges_debug_maps;
extern gboolean ranges_inst_libs;
extern gboolean ranges_inst_jit;
extern gboolean ranges_inst_dynamic_load;
void ranges_config(void);
void ranges_init(void);

View File

@ -78,6 +78,7 @@ void entry_init(void) {
void entry_start(void) {
FVERBOSE("AFL_ENTRYPOINT reached");
if (persistent_start == 0) {
ranges_exclude();
@ -85,32 +86,7 @@ void entry_start(void) {
}
if (entry_point == 0) { entry_launch(); }
}
static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) {
UNUSED_PARAMETER(cpu_context);
UNUSED_PARAMETER(user_data);
entry_compiled = TRUE;
entry_launch();
}
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) {
UNUSED_PARAMETER(output);
FVERBOSE("AFL_ENTRYPOINT reached");
if (persistent_start == 0) {
ranges_exclude();
stalker_trust();
}
gum_stalker_iterator_put_callout(iterator, entry_callout, NULL, NULL);
}

View File

@ -169,7 +169,6 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
if (unlikely(begin)) { instrument_debug_start(instr->address, output); }
if (instr->address == entry_point) { entry_prologue(iterator, output); }
if (instr->address == persistent_start) { persistent_prologue(output); }
if (instr->address == persistent_ret) { persistent_epilogue(output); }

View File

@ -76,6 +76,45 @@ typedef struct {
} afl_log_code_asm_t;
typedef struct {
uint32_t b_imm8; /* br #XX (end) */
uint32_t restoration_prolog; /* ldp x16, x17, [sp], #0x90 */
uint32_t stp_x0_x1; /* stp x0, x1, [sp, #-0xa0] */
uint32_t ldr_x0_p_prev_loc_1; /* ldr x0, #0xXXXX */
uint32_t ldr_x1_ptr_x0; /* ldr x1, [x0] */
uint32_t ldr_x0_p_area_offset; /* ldr x0, #0xXXXX */
uint32_t eor_x0_x1_x0; /* eor x0, x1, x0 */
uint32_t ldr_x1_p_area_ptr; /* ldr x1, #0xXXXX */
uint32_t add_x0_x1_x0; /* add x0, x1, x0 */
uint32_t ldrb_w1_x0; /* ldrb w1, [x0] */
uint32_t add_w1_w1_1; /* add w1, w1, #1 */
uint32_t add_w1_w1_w1_lsr_8; /* add x1, x1, x1, lsr #8 */
uint32_t strb_w1_ptr_x0; /* strb w1, [x0] */
uint32_t ldr_x0_p_prev_loc_2; /* ldr x0, #0xXXXX */
uint32_t ldr_x1_p_area_offset_ror; /* ldr x1, #0xXXXX */
uint32_t str_x1_ptr_x0; /* str x1, [x0] */
uint32_t ldp_x0_x1; /* ldp x0, x1, [sp, #-0xa0] */
uint32_t b_end; /* skip the data */
uint64_t area_ptr;
uint64_t prev_loc_ptr;
uint64_t area_offset;
uint64_t area_offset_ror;
uint8_t end[0];
} afl_log_code_asm_long_t;
#pragma pack(pop)
typedef union {
@ -85,6 +124,13 @@ typedef union {
} afl_log_code;
typedef union {
afl_log_code_asm_long_t code;
uint8_t bytes[0];
} afl_log_code_long;
static const afl_log_code_asm_t template =
{
@ -119,6 +165,46 @@ static const afl_log_code_asm_t template =
;
static const afl_log_code_asm_long_t template_long =
{.b_imm8 = 0x1400001a,
.restoration_prolog = 0xa8c947f0, /* ldp x16, x17, [sp], #0x90 */
.stp_x0_x1 = 0xa93607e0, /* stp x0, x1, [sp, #-0xa0] */
.ldr_x0_p_prev_loc_1 = 0x58000220, /* ldr x0, #0xXXXX */
.ldr_x1_ptr_x0 = 0xf9400001, /* ldr x1, [x0] */
.ldr_x0_p_area_offset = 0x58000220, /* ldr x0, #0xXXXX */
.eor_x0_x1_x0 = 0xca000020, /* eor x0, x1, x0 */
.ldr_x1_p_area_ptr = 0x58000161, /* ldr x1, #0xXXXX */
.add_x0_x1_x0 = 0x8b000020, /* add x0, x1, x0 */
.ldrb_w1_x0 = 0x39400001, /* ldrb w1, [x0] */
.add_w1_w1_1 = 0x11000421, /* add w1, w1, #1 */
.add_w1_w1_w1_lsr_8 = 0x8b412021, /* add x1, x1, x1, lsr #8 */
.strb_w1_ptr_x0 = 0x39000001, /* strb w1, [x0] */
.ldr_x0_p_prev_loc_2 = 0x580000e0, /* ldr x0, #0xXXXX */
.ldr_x1_p_area_offset_ror = 0x58000141, /* ldr x1, #0xXXXX */
.str_x1_ptr_x0 = 0xf9000001, /* str x1, [x0] */
.ldp_x0_x1 = 0xa97607e0, /* ldp x0, x1, [sp, #-0xa0] */
.b_end = 0x14000009, /* skip the data */
.area_ptr = 0x0,
.prev_loc_ptr = 0x0,
.area_offset = 0x0,
.area_offset_ror = 0x0,
.end = {}
}
;
gboolean instrument_is_coverage_optimize_supported(void) {
return true;
@ -266,16 +352,22 @@ static gboolean instrument_coverage_in_range(gssize offset) {
}
static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
static bool instrument_patch_ardp(guint32 *patch, GumAddress insn,
GumAddress target) {
if (!PAGE_ALIGNED(target)) { FATAL("Target not page aligned"); }
if (!PAGE_ALIGNED(target)) {
FWARNF("Target not page aligned");
return false;
}
gssize distance = target - (GUM_ADDRESS(insn) & PAGE_MASK);
if (!instrument_coverage_in_range(distance)) {
FATAL("Patch out of range 0x%016lX->0x%016lX = 0x%016lX", insn, target,
distance);
FVERBOSE("Patch out of range 0x%016lX->0x%016lX = 0x%016lX", insn, target,
distance);
return false;
}
@ -283,6 +375,95 @@ static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
guint32 imm_high = ((distance >> 14) & 0x7FFFF) << 5;
*patch |= imm_low;
*patch |= imm_high;
return true;
}
bool instrument_write_inline(GumArm64Writer *cw, GumAddress code_addr,
guint64 area_offset, gsize area_offset_ror) {
afl_log_code code = {0};
code.code = template;
/*
* Given our map is allocated on a 64KB boundary and our map is a multiple of
* 64KB in size, then it should also end on a 64 KB boundary. It is followed
* by our previous_pc, so this too should be 64KB aligned.
*/
g_assert(PAGE_ALIGNED(instrument_previous_pc_addr));
g_assert(PAGE_ALIGNED(__afl_area_ptr));
if (!instrument_patch_ardp(
&code.code.adrp_x0_prev_loc1,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc1),
GUM_ADDRESS(instrument_previous_pc_addr))) {
return false;
}
code.code.mov_x0_curr_loc |= area_offset << 5;
if (!instrument_patch_ardp(
&code.code.adrp_x1_area_ptr,
code_addr + offsetof(afl_log_code, code.adrp_x1_area_ptr),
GUM_ADDRESS(__afl_area_ptr))) {
return false;
}
if (!instrument_patch_ardp(
&code.code.adrp_x0_prev_loc2,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc2),
GUM_ADDRESS(instrument_previous_pc_addr))) {
return false;
}
code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
if (instrument_suppress) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
} else {
size_t offset = offsetof(afl_log_code, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code) - offset);
}
return true;
}
bool instrument_write_inline_long(GumArm64Writer *cw, GumAddress code_addr,
guint64 area_offset, gsize area_offset_ror) {
afl_log_code_long code = {0};
code.code = template_long;
code.code.area_ptr = GUM_ADDRESS(__afl_area_ptr);
code.code.prev_loc_ptr = GUM_ADDRESS(instrument_previous_pc_addr);
code.code.area_offset = area_offset;
code.code.area_offset_ror = GUM_ADDRESS(area_offset_ror);
if (instrument_suppress) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code_long));
} else {
size_t offset = offsetof(afl_log_code_long, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code_long) - offset);
}
return true;
}
@ -312,6 +493,8 @@ void instrument_coverage_optimize(const cs_insn *instr,
}
// gum_arm64_writer_put_brk_imm(cw, 0x0);
// uint32_t jmp_dot = 0x14000000;
// gum_arm64_writer_put_bytes(cw, (guint8 *)&jmp_dot, sizeof(jmp_dot));
if (instrument_suppress) { instrument_coverage_suppress_init(); }
@ -343,47 +526,19 @@ void instrument_coverage_optimize(const cs_insn *instr,
}
code.code = template;
/*
* Given our map is allocated on a 64KB boundary and our map is a multiple of
* 64KB in size, then it should also end on a 64 KB boundary. It is followed
* by our previous_pc, so this too should be 64KB aligned.
*/
g_assert(PAGE_ALIGNED(instrument_previous_pc_addr));
g_assert(PAGE_ALIGNED(__afl_area_ptr));
instrument_patch_ardp(
&code.code.adrp_x0_prev_loc1,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc1),
GUM_ADDRESS(instrument_previous_pc_addr));
code.code.mov_x0_curr_loc |= area_offset << 5;
instrument_patch_ardp(
&code.code.adrp_x1_area_ptr,
code_addr + offsetof(afl_log_code, code.adrp_x1_area_ptr),
GUM_ADDRESS(__afl_area_ptr));
map_size_pow2 = util_log2(__afl_map_size);
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
instrument_patch_ardp(
&code.code.adrp_x0_prev_loc2,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc2),
GUM_ADDRESS(instrument_previous_pc_addr));
code.code = template;
code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
if (!instrument_write_inline(cw, code_addr, area_offset, area_offset_ror)) {
if (instrument_suppress) {
if (!instrument_write_inline_long(cw, code_addr, area_offset,
area_offset_ror)) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
FATAL("Failed to write inline instrumentation");
} else {
size_t offset = offsetof(afl_log_code, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code) - offset);
}
}

View File

@ -58,6 +58,7 @@ typedef union {
} jcc_insn;
static GHashTable *coverage_blocks = NULL;
static GHashTable *coverage_blocks_long = NULL;
gboolean instrument_is_coverage_optimize_supported(void) {
@ -127,6 +128,64 @@ typedef struct {
} afl_log_code_asm_t;
typedef struct {
// cur_location = (block_address >> 4) ^ (block_address << 8);
// shared_mem[cur_location ^ prev_location]++;
// prev_location = cur_location >> 1;
// mov QWORD PTR [rsp-0x88],rax
// lahf
// mov QWORD PTR [rsp-0x90],rax
// mov QWORD PTR [rsp-0x98],rbx
// mov rax, 0xXXXXXXXXXXXXXXXXX /* p_prev_loc */
// mov eax, dword ptr [rax] /* prev_loc */
// xor eax,0x3f77 /* cur_loc */
// mov rbx, 0xXXXXXXXXXXXXXXXXX /* map */
// add rax,rbx
// mov bl,BYTE PTR [rax]
// add bl,0x1
// adc bl,0x0
// mov BYTE PTR [rax],bl
// mov rax, 0xXXXXXXXXXXXXXXXXX /* p_prev_loc */
// mov dword ptr [rax], 0xXXXXXXXXX /* prev_loc */
// mov rbx,QWORD PTR [rsp-0x98]
// mov rax,QWORD PTR [rsp-0x90]
// sahf
// mov rax,QWORD PTR [rsp-0x88]
uint8_t mov_rax_rsp_88[8];
uint8_t lahf;
uint8_t mov_rax_rsp_90[8];
uint8_t mov_rbx_rsp_98[8];
uint8_t mov_rax_prev_loc_ptr1[10];
uint8_t mov_eax_prev_loc[2];
uint8_t xor_eax_curr_loc[5];
uint8_t mov_rbx_map_ptr[10];
uint8_t add_rax_rbx[3];
uint8_t mov_rbx_ptr_rax[2];
uint8_t add_bl_1[3];
uint8_t adc_bl_0[3];
uint8_t mov_ptr_rax_rbx[2];
uint8_t mov_rax_prev_loc_ptr2[10];
uint8_t mov_prev_loc_curr_loc_shr1[6];
uint8_t mov_rsp_98_rbx[8];
uint8_t mov_rsp_90_rax[8];
uint8_t sahf;
uint8_t mov_rsp_88_rax[8];
} afl_log_code_asm_long_t;
#pragma pack(pop)
static const afl_log_code_asm_t template =
@ -158,6 +217,41 @@ static const afl_log_code_asm_t template =
;
static const afl_log_code_asm_long_t template_long =
{
.mov_rax_rsp_88 = {0x48, 0x89, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
.lahf = 0x9f,
.mov_rax_rsp_90 = {0x48, 0x89, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF},
.mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
.mov_rax_prev_loc_ptr1 = {0x48, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF},
.mov_eax_prev_loc = {0x8b, 0x00},
.xor_eax_curr_loc = {0x35},
.mov_rbx_map_ptr = {0x48, 0xBB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF},
.add_rax_rbx = {0x48, 0x01, 0xd8},
.mov_rbx_ptr_rax = {0x8a, 0x18},
.add_bl_1 = {0x80, 0xc3, 0x01},
.adc_bl_0 = {0x80, 0xd3, 0x00},
.mov_ptr_rax_rbx = {0x88, 0x18},
.mov_rax_prev_loc_ptr2 = {0x48, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF},
.mov_prev_loc_curr_loc_shr1 = {0xc7, 0x00, 0xFF, 0xFF, 0xFF, 0xFF},
.mov_rsp_98_rbx = {0x48, 0x8B, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
.mov_rsp_90_rax = {0x48, 0x8B, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF},
.sahf = 0x9e,
.mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
}
;
typedef union {
afl_log_code_asm_t code;
@ -165,6 +259,13 @@ typedef union {
} afl_log_code;
typedef union {
afl_log_code_asm_long_t code;
uint8_t bytes[0];
} afl_log_code_long;
void instrument_coverage_optimize_init(void) {
FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr);
@ -182,16 +283,19 @@ static void instrument_coverage_switch_insn(GumStalkerObserver *self,
cs_x86 *x86;
cs_x86_op *op;
bool is_short = false;
bool is_long = false;
if (from_insn == NULL) { return; }
x86 = &from_insn->detail->x86;
op = x86->operands;
if (!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target))) {
is_short = g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target));
is_long =
g_hash_table_contains(coverage_blocks_long, GSIZE_TO_POINTER(*target));
return;
}
if (!is_short && !is_long) { return; }
switch (from_insn->id) {
@ -212,15 +316,41 @@ static void instrument_coverage_switch_insn(GumStalkerObserver *self,
break;
case X86_INS_RET:
instrument_cache_insert(start_address,
(guint8 *)*target + sizeof(afl_log_code));
if (is_short) {
instrument_cache_insert(start_address,
(guint8 *)*target + sizeof(afl_log_code));
} else if (is_long) {
instrument_cache_insert(start_address,
(guint8 *)*target + sizeof(afl_log_code_long));
} else {
FATAL("Something has gone wrong here!");
}
break;
default:
return;
}
*target = (guint8 *)*target + sizeof(afl_log_code);
if (is_short) {
*target = (guint8 *)*target + sizeof(afl_log_code);
} else if (is_long) {
*target = (guint8 *)*target + sizeof(afl_log_code_long);
} else {
FATAL("Something has gone wrong here!");
}
}
@ -270,22 +400,22 @@ static void instrument_coverage_suppress_init(void) {
}
coverage_blocks_long = g_hash_table_new(g_direct_hash, g_direct_equal);
if (coverage_blocks_long == NULL) {
FATAL("Failed to g_hash_table_new, errno: %d", errno);
}
}
static void instrument_coverage_write(GumAddress address,
GumStalkerOutput *output) {
bool instrument_write_inline(GumX86Writer *cw, GumAddress code_addr,
guint32 area_offset, guint32 area_offset_ror) {
afl_log_code code = {0};
GumX86Writer *cw = output->writer.x86;
guint64 area_offset = instrument_get_offset_hash(address);
gsize map_size_pow2;
gsize area_offset_ror;
GumAddress code_addr = cw->pc;
afl_log_code code = {0};
code.code = template;
/* mov_prev_loc_curr_loc_shr1 */
gssize prev_loc_value =
GPOINTER_TO_SIZE(instrument_previous_pc_addr) -
(code_addr + offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
@ -294,11 +424,7 @@ static void instrument_coverage_write(GumAddress address,
offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(gint) -
sizeof(guint32);
if (!instrument_coverage_in_range(prev_loc_value)) {
FATAL("Patch out of range (current_pc_value1): 0x%016lX", prev_loc_value);
}
if (!instrument_coverage_in_range(prev_loc_value)) { return false; }
*((gint *)&code.bytes[prev_loc_value_offset]) = (gint)prev_loc_value;
@ -311,11 +437,7 @@ static void instrument_coverage_write(GumAddress address,
gssize prev_loc_value_offset2 =
offsetof(afl_log_code, code.mov_eax_prev_loc) +
sizeof(code.code.mov_eax_prev_loc) - sizeof(gint);
if (!instrument_coverage_in_range(prev_loc_value)) {
FATAL("Patch out of range (current_pc_value1): 0x%016lX", prev_loc_value2);
}
if (!instrument_coverage_in_range(prev_loc_value)) { return false; }
*((gint *)&code.bytes[prev_loc_value_offset2]) = (gint)prev_loc_value2;
@ -338,12 +460,7 @@ static void instrument_coverage_write(GumAddress address,
(code_addr + offsetof(afl_log_code, code.lea_rbx_area_ptr) +
sizeof(code.code.lea_rbx_area_ptr)));
if (!instrument_coverage_in_range(lea_rbx_area_ptr_value)) {
FATAL("Patch out of range (lea_rbx_area_ptr_value): 0x%016lX",
lea_rbx_area_ptr_value);
}
if (!instrument_coverage_in_range(lea_rbx_area_ptr_value)) { return false; }
*((guint32 *)&code.bytes[lea_rbx_area_ptr_offset]) = lea_rbx_area_ptr_value;
@ -353,12 +470,100 @@ static void instrument_coverage_write(GumAddress address,
offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32);
map_size_pow2 = util_log2(__afl_map_size);
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
*((guint32 *)&code.bytes[curr_loc_shr_1_offset]) = (guint32)(area_offset_ror);
if (instrument_suppress) {
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
FATAL("Failed - g_hash_table_add");
}
}
gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
return true;
}
bool instrument_write_inline_long(GumX86Writer *cw, guint32 area_offset,
guint32 area_offset_ror) {
afl_log_code_long code = {0};
code.code = template_long;
/* mov_rax_prev_loc_ptr1 */
gssize mov_rax_prev_loc_ptr1_offset =
offsetof(afl_log_code_long, code.mov_rax_prev_loc_ptr1) +
sizeof(code.code.mov_rax_prev_loc_ptr1) - sizeof(gsize);
*((gsize *)&code.bytes[mov_rax_prev_loc_ptr1_offset]) =
GPOINTER_TO_SIZE(instrument_previous_pc_addr);
/* xor_eax_curr_loc */
gssize xor_eax_curr_loc_offset =
offsetof(afl_log_code_long, code.xor_eax_curr_loc) +
sizeof(code.code.xor_eax_curr_loc) - sizeof(guint32);
*((guint32 *)&code.bytes[xor_eax_curr_loc_offset]) = area_offset;
/* mov_rbx_map_ptr */
gsize mov_rbx_map_ptr_offset =
offsetof(afl_log_code_long, code.mov_rbx_map_ptr) +
sizeof(code.code.mov_rbx_map_ptr) - sizeof(gsize);
*((gsize *)&code.bytes[mov_rbx_map_ptr_offset]) =
GPOINTER_TO_SIZE(__afl_area_ptr);
/* mov_rax_prev_loc_ptr2 */
gssize mov_rax_prev_loc_ptr2_offset =
offsetof(afl_log_code_long, code.mov_rax_prev_loc_ptr2) +
sizeof(code.code.mov_rax_prev_loc_ptr2) - sizeof(gsize);
*((gsize *)&code.bytes[mov_rax_prev_loc_ptr2_offset]) =
GPOINTER_TO_SIZE(instrument_previous_pc_addr);
/* mov_prev_loc_curr_loc_shr1 */
gssize mov_prev_loc_curr_loc_shr1_offset =
offsetof(afl_log_code_long, code.mov_prev_loc_curr_loc_shr1) +
sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32);
*((guint32 *)&code.bytes[mov_prev_loc_curr_loc_shr1_offset]) =
(guint32)(area_offset_ror);
if (instrument_suppress) {
if (!g_hash_table_add(coverage_blocks_long, GSIZE_TO_POINTER(cw->code))) {
FATAL("Failed - g_hash_table_add");
}
}
gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code_long));
return true;
}
static void instrument_coverage_write(GumAddress address,
GumStalkerOutput *output) {
GumX86Writer *cw = output->writer.x86;
guint64 area_offset = (guint32)instrument_get_offset_hash(address);
gsize map_size_pow2;
guint32 area_offset_ror;
GumAddress code_addr = cw->pc;
map_size_pow2 = util_log2(__afl_map_size);
area_offset_ror = (guint32)util_rotate(instrument_get_offset_hash(address), 1,
map_size_pow2);
if (!instrument_write_inline(cw, code_addr, area_offset, area_offset_ror)) {
if (!instrument_write_inline_long(cw, area_offset, area_offset_ror)) {
FATAL("Failed to write inline instrumentation");
}
}
}
@ -380,17 +585,7 @@ void instrument_coverage_optimize(const cs_insn *instr,
}
if (instrument_suppress) {
instrument_coverage_suppress_init();
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
FATAL("Failed - g_hash_table_add");
}
}
if (instrument_suppress) { instrument_coverage_suppress_init(); }
instrument_coverage_write(GUM_ADDRESS(instr->address), output);

View File

@ -150,6 +150,12 @@ class Afl {
static setInstrumentLibraries() {
Afl.jsApiSetInstrumentLibraries();
}
/**
* See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
*/
static setInstrumentNoDynamicLoad() {
Afl.jsApiSetInstrumentNoDynamicLoad();
}
/**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
@ -342,6 +348,7 @@ Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_de
Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []);
Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []);
Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []);
Afl.jsApiSetInstrumentNoDynamicLoad = Afl.jsApiGetFunction("js_api_set_instrument_no_dynamic_load", "void", []);
Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []);
Afl.jsApiSetInstrumentRegsFile = Afl.jsApiGetFunction("js_api_set_instrument_regs_file", "void", ["pointer"]);
Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", "void", ["uint64"]);

View File

@ -156,6 +156,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_instructions(
}
__attribute__((visibility("default"))) void
js_api_set_instrument_no_dynamic_load(void) {
ranges_inst_dynamic_load = FALSE;
}
__attribute__((visibility("default"))) void js_api_set_instrument_no_optimize(
void) {

View File

@ -17,8 +17,8 @@ static gboolean lib_get_main_module(const GumModuleDetails *details,
GumDarwinModule **ret = (GumDarwinModule **)user_data;
GumDarwinModule *module = gum_darwin_module_new_from_memory(
details->path, mach_task_self(), details->range->base_address,
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
details->path, mach_task_self(), details->range->base_address,
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
FVERBOSE("Found main module: %s", module->name);

View File

@ -197,7 +197,7 @@ static void afl_print_env(void) {
}
__attribute__((visibility("default"))) void afl_frida_start(void) {
void afl_frida_config(void) {
FOKF(cRED "**********************");
FOKF(cRED "* " cYEL "******************" cRED " *");
@ -225,9 +225,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
js_start();
/* Initialize */
output_init();
embedded_init();
entry_init();
instrument_init();
@ -240,12 +238,35 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
ranges_init();
stats_init();
/* Start */
}
void afl_frida_run(void) {
stalker_start();
entry_start();
}
__attribute__((visibility("default"))) void afl_frida_start(void) {
afl_frida_config();
afl_frida_run();
}
typedef void *(*entry_func_t)(size_t a1, size_t a2, size_t a3, size_t a4,
size_t a5, size_t a6);
static void *on_entry(size_t a1, size_t a2, size_t a3, size_t a4, size_t a5,
size_t a6) {
intercept_unhook(GSIZE_TO_POINTER(entry_point));
afl_frida_run();
entry_func_t entry = (entry_func_t)entry_point;
return entry(a1, a2, a3, a4, a5, a6);
}
static int on_main(int argc, char **argv, char **envp) {
int ret;
@ -254,7 +275,17 @@ static int on_main(int argc, char **argv, char **envp) {
intercept_unhook_self();
afl_frida_start();
afl_frida_config();
if (entry_point == 0) {
afl_frida_run();
} else {
intercept_hook(GSIZE_TO_POINTER(entry_point), on_entry, NULL);
}
if (js_main_hook != NULL) {

View File

@ -18,6 +18,7 @@ typedef struct {
gboolean ranges_debug_maps = FALSE;
gboolean ranges_inst_libs = FALSE;
gboolean ranges_inst_jit = FALSE;
gboolean ranges_inst_dynamic_load = TRUE;
static GArray *module_ranges = NULL;
static GArray *libs_ranges = NULL;
@ -25,6 +26,7 @@ static GArray *jit_ranges = NULL;
static GArray *include_ranges = NULL;
static GArray *exclude_ranges = NULL;
static GArray *ranges = NULL;
static GArray *whole_memory_ranges = NULL;
static void convert_address_token(gchar *token, GumMemoryRange *range) {
@ -387,6 +389,21 @@ static GArray *collect_jit_ranges(void) {
}
static GArray *collect_whole_mem_ranges(void) {
GArray *result;
GumMemoryRange range;
result = g_array_new(false, false, sizeof(GumMemoryRange));
range.base_address = 0;
range.size = G_MAXULONG;
g_array_append_val(result, range);
return result;
}
static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra,
GumMemoryRange *rb) {
@ -574,11 +591,17 @@ void ranges_config(void) {
if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { ranges_debug_maps = TRUE; }
if (getenv("AFL_INST_LIBS") != NULL) { ranges_inst_libs = TRUE; }
if (getenv("AFL_FRIDA_INST_JIT") != NULL) { ranges_inst_jit = TRUE; }
if (getenv("AFL_FRIDA_INST_NO_DYNAMIC_LOAD") != NULL) {
ranges_inst_dynamic_load = FALSE;
}
if (ranges_debug_maps) { ranges_print_debug_maps(); }
include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES");
exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES");
whole_memory_ranges = collect_whole_mem_ranges();
}
@ -628,10 +651,20 @@ void ranges_init(void) {
print_ranges("step4", step4);
/*
* After step4, we have the total ranges to be instrumented, we now subtract
* that from the original ranges of the modules to configure stalker.
* After step 4 we have the total ranges to be instrumented, we now subtract
* that either from the original ranges of the modules or from the whole
* memory if AFL_INST_NO_DYNAMIC_LOAD to configure the stalker.
*/
step5 = subtract_ranges(module_ranges, step4);
if (ranges_inst_dynamic_load) {
step5 = subtract_ranges(module_ranges, step4);
} else {
step5 = subtract_ranges(whole_memory_ranges, step4);
}
print_ranges("step5", step5);
ranges = merge_ranges(step5);

View File

@ -67,3 +67,8 @@ debug:
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
--ex 'set disassembly-flavor intel' \
--args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
lldb:
lldb \
-O 'settings set target.env-vars DYLD_INSERT_LIBRARIES=$(ROOT)afl-frida-trace.so' \
-- $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)

View File

@ -178,6 +178,13 @@ class Afl {
Afl.jsApiSetInstrumentLibraries();
}
/**
* See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
*/
public static setInstrumentNoDynamicLoad(): void {
Afl.jsApiSetInstrumentNoDynamicLoad();
}
/**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
@ -443,6 +450,11 @@ class Afl {
"void",
[]);
private static readonly jsApiSetInstrumentNoDynamicLoad = Afl.jsApiGetFunction(
"js_api_set_instrument_no_dynamic_load",
"void",
[]);
private static readonly jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction(
"js_api_set_instrument_no_optimize",
"void",

View File

@ -184,6 +184,7 @@ struct queue_entry {
handicap, /* Number of queue cycles behind */
depth, /* Path depth */
exec_cksum, /* Checksum of the execution trace */
custom, /* Marker for custom mutators */
stats_mutated; /* stats: # of mutations performed */
u8 *trace_mini; /* Trace bytes, if kept */
@ -399,7 +400,8 @@ typedef struct afl_env_vars {
afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new,
afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems,
afl_keep_timeouts, afl_no_crash_readme, afl_ignore_timeouts,
afl_no_startup_calibration, afl_no_warn_instability;
afl_no_startup_calibration, afl_no_warn_instability,
afl_post_process_keep_original;
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
@ -492,7 +494,8 @@ typedef struct afl_state {
*orig_cmdline, /* Original command line */
*infoexec; /* Command to execute on a new crash */
u32 hang_tmout; /* Timeout used for hang det (ms) */
u32 hang_tmout, /* Timeout used for hang det (ms) */
stats_update_freq; /* Stats update frequency (execs) */
u8 havoc_stack_pow2, /* HAVOC_STACK_POW2 */
no_unlink, /* do not unlink cur_input */
@ -501,14 +504,12 @@ typedef struct afl_state {
custom_splice_optout, /* Custom mutator no splice buffer */
is_main_node, /* if this is the main node */
is_secondary_node, /* if this is a secondary instance */
pizza_is_served; /* pizza mode */
u32 stats_update_freq; /* Stats update frequency (execs) */
u8 schedule; /* Power schedule (default: EXPLORE)*/
u8 havoc_max_mult;
u8 skip_deterministic, /* Skip deterministic stages? */
pizza_is_served, /* pizza mode */
input_mode, /* target wants text inputs */
fuzz_mode, /* coverage/exploration or crash/exploitation mode */
schedule, /* Power schedule (default: EXPLORE)*/
havoc_max_mult, /* havoc multiplier */
skip_deterministic, /* Skip deterministic stages? */
use_splicing, /* Recombine input files? */
non_instrumented_mode, /* Run in non-instrumented mode? */
score_changed, /* Scoring for favorites changed? */
@ -595,7 +596,8 @@ typedef struct afl_state {
last_hang_time, /* Time for most recent hang (ms) */
longest_find_time, /* Longest time taken for a find */
exit_on_time, /* Delay to exit if no new paths */
sync_time; /* Sync time (ms) */
sync_time, /* Sync time (ms) */
switch_fuzz_mode; /* auto or fixed fuzz mode */
u32 slowest_exec_ms, /* Slowest testcase non hang in ms */
subseq_tmouts; /* Number of timeouts in a row */
@ -1103,7 +1105,6 @@ u32 count_bits(afl_state_t *, u8 *);
u32 count_bytes(afl_state_t *, u8 *);
u32 count_non_255_bytes(afl_state_t *, u8 *);
void simplify_trace(afl_state_t *, u8 *);
void classify_counts(afl_forkserver_t *);
#ifdef WORD_SIZE_64
void discover_word(u8 *ret, u64 *current, u64 *virgin);
#else
@ -1117,6 +1118,9 @@ u8 *describe_op(afl_state_t *, u8, size_t);
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
u8 has_new_bits(afl_state_t *, u8 *);
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
#ifndef AFL_SHOWMAP
void classify_counts(afl_forkserver_t *);
#endif
/* Extras */
@ -1192,11 +1196,14 @@ void fix_up_sync(afl_state_t *);
void check_asan_opts(afl_state_t *);
void check_binary(afl_state_t *, u8 *);
void check_if_tty(afl_state_t *);
void setup_signal_handlers(void);
void save_cmdline(afl_state_t *, u32, char **);
void read_foreign_testcases(afl_state_t *, int);
void write_crash_readme(afl_state_t *afl);
u8 check_if_text_buf(u8 *buf, u32 len);
#ifndef AFL_SHOWMAP
void setup_signal_handlers(void);
#endif
char *get_fuzzing_state(afl_state_t *afl);
/* CmpLog */
@ -1218,7 +1225,7 @@ double rand_next_percent(afl_state_t *afl);
static inline u32 rand_below(afl_state_t *afl, u32 limit) {
if (limit <= 1) return 0;
if (unlikely(limit <= 1)) return 0;
/* The boundary not being necessarily a power of 2,
we need to ensure the result uniformity. */
@ -1251,7 +1258,7 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) {
expand havoc mode */
static inline u32 rand_below_datalen(afl_state_t *afl, u32 limit) {
if (limit <= 1) return 0;
if (unlikely(limit <= 1)) return 0;
switch (rand_below(afl, 3)) {

2662
include/afl-mutations.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@
// Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators
#ifndef _WANT_ORIGINAL_AFL_ALLOC
// afl++ stuff without memory corruption checks - for speed
// AFL++ stuff without memory corruption checks - for speed
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
@ -322,7 +322,7 @@ static inline void DFL_ck_free(void *mem) {
static inline void *DFL_ck_realloc(void *orig, u32 size) {
void *ret;
u32 old_size = 0;
u32 old_size = 0;
if (!size) {
@ -392,7 +392,7 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
static inline u8 *DFL_ck_strdup(u8 *str) {
void *ret;
u32 size;
u32 size;
if (!str) return NULL;
@ -438,14 +438,14 @@ struct TRK_obj {
void *ptr;
char *file, *func;
u32 line;
u32 line;
};
#ifdef AFL_MAIN
struct TRK_obj *TRK[ALLOC_BUCKETS];
u32 TRK_cnt[ALLOC_BUCKETS];
u32 TRK_cnt[ALLOC_BUCKETS];
#define alloc_report() TRK_report()
@ -704,12 +704,11 @@ static inline void *afl_realloc(void **buf, size_t size_needed) {
*buf = NULL;
return NULL;
} else {
new_buf = newer_buf;
}
new_buf = newer_buf;
memset(((u8 *)new_buf) + current_size, 0, next_size - current_size);
new_buf->complete_size = next_size;
*buf = (void *)(new_buf->buf);
return *buf;

View File

@ -34,7 +34,7 @@
#define CMP_MAP_W 65536
#define CMP_MAP_H 32
#define CMP_MAP_RTN_H (CMP_MAP_H / 4)
#define CMP_MAP_RTN_H (CMP_MAP_H / 2)
#define SHAPE_BYTES(x) (x + 1)

View File

@ -115,6 +115,11 @@ u8 *stringify_mem_size(u8 *buf, size_t len, u64 val);
u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms);
/* Unsafe describe time delta as simple string.
Returns a pointer to buf for convenience. */
u8 *u_simplestring_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
/* Unsafe Describe integer. The buf sizes are not checked.
This is unsafe but fast.
Will return buf for convenience. */

View File

@ -26,7 +26,7 @@
/* Version string: */
// c = release, a = volatile github dev, e = experimental branch
#define VERSION "++4.06c"
#define VERSION "++4.08a"
/******************************************************
* *
@ -43,6 +43,12 @@
Default: 8MB (defined in bytes) */
#define DEFAULT_SHMEM_SIZE (8 * 1024 * 1024)
/* Default time until when no more coverage finds are happening afl-fuzz
switches to exploitation mode. It automatically switches back when new
coverage is found.
Default: 300 (seconds) */
#define STRATEGY_SWITCH_TIME 1000
/* Default file permission umode when creating files (default: 0600) */
#define DEFAULT_PERMISSION 0600
@ -81,7 +87,7 @@
will be kept and written to the crash/ directory as RECORD:... files.
Note that every crash will be written, not only unique ones! */
//#define AFL_PERSISTENT_RECORD
// #define AFL_PERSISTENT_RECORD
/* console output colors: There are three ways to configure its behavior
* 1. default: colored outputs fixed on: defined USE_COLOR && defined

View File

@ -37,6 +37,10 @@ static char *afl_environment_variables[] = {
"AFL_CRASH_EXITCODE",
"AFL_CUSTOM_MUTATOR_LIBRARY",
"AFL_CUSTOM_MUTATOR_ONLY",
"AFL_CUSTOM_INFO_PROGRAM",
"AFL_CUSTOM_INFO_PROGRAM_ARGV",
"AFL_CUSTOM_INFO_PROGRAM_INPUT",
"AFL_CUSTOM_INFO_OUT",
"AFL_CXX",
"AFL_CYCLE_SCHEDULES",
"AFL_DEBUG",
@ -65,6 +69,7 @@ static char *afl_environment_variables[] = {
"AFL_FRIDA_INST_INSN",
"AFL_FRIDA_INST_JIT",
"AFL_FRIDA_INST_NO_CACHE",
"AFL_FRIDA_INST_NO_DYNAMIC_LOAD",
"AFL_FRIDA_INST_NO_OPTIMIZE",
"AFL_FRIDA_INST_NO_PREFETCH",
"AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
@ -105,6 +110,7 @@ static char *afl_environment_variables[] = {
"AFL_HARDEN",
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
"AFL_IGNORE_PROBLEMS",
"AFL_IGNORE_PROBLEMS_COVERAGE",
"AFL_IGNORE_TIMEOUTS",
"AFL_IGNORE_UNKNOWN_ENVS",
"AFL_IMPORT_FIRST",
@ -159,8 +165,9 @@ static char *afl_environment_variables[] = {
"AFL_LLVM_SKIP_NEVERZERO",
"AFL_NO_AFFINITY",
"AFL_TRY_AFFINITY",
"AFL_LLVM_LTO_STARTID",
"AFL_LLVM_LTO_DONTWRITEID",
"AFL_LLVM_LTO_SKIPINIT"
"AFL_LLVM_LTO_STARTID",
"AFL_NO_ARITH",
"AFL_NO_AUTODICT",
"AFL_NO_BUILTIN",
@ -186,6 +193,7 @@ static char *afl_environment_variables[] = {
"AFL_PATH",
"AFL_PERFORMANCE_FILE",
"AFL_PERSISTENT_RECORD",
"AFL_POST_PROCESS_KEEP_ORIGINAL",
"AFL_PRELOAD",
"AFL_TARGET_ENV",
"AFL_PYTHON_MODULE",

View File

@ -151,6 +151,8 @@ typedef struct afl_forkserver {
bool uses_asan; /* Target uses ASAN? */
bool keep_coverage; /* use coverage feature */
bool debug; /* debug mode? */
bool uses_crash_exitcode; /* Custom crash exitcode specified? */
@ -160,6 +162,8 @@ typedef struct afl_forkserver {
u8 *shmem_fuzz; /* allocated memory for fuzzing */
u8 *coverage_map; /* for coverage feature */
char *cmplog_binary; /* the name of the cmplog binary */
/* persistent mode replay functionality */

View File

@ -7,7 +7,7 @@ For the GCC-based instrumentation, see
## 1) Introduction
! llvm_mode works with llvm versions 3.8 up to 13 !
! llvm_mode works with llvm versions 3.8 up to 17 - but 13+ is recommended !
The code in this directory allows you to instrument programs for AFL++ using
true compiler-level instrumentation, instead of the more crude assembly-level
@ -280,3 +280,27 @@ Please note that the default counter implementations are not thread safe!
Support for thread safe counters in mode LLVM CLASSIC can be activated with
setting `AFL_LLVM_THREADSAFE_INST=1`.
## 8) Source code coverage through instrumentation
Measuring source code coverage is a common task in fuzzing, but it is very
difficut to do in some situations (e.g. when using snapshot fuzzing).
When using the `AFL_LLVM_INSTRUMENT=llvm-codecov` option, afl-cc will use
native trace-pc-guard instrumentation but additionally select options that
are required to utilize the instrumentation for source code coverage.
In particular, it will switch the instrumentation to be per basic block
instead of instrumenting edges, disable all guard pruning and enable the
experimental pc-table support that allows the runtime to gather 100% of
instrumented basic blocks at start, including their locations.
Note: You must compile AFL with the `CODE_COVERAGE=1` option to enable the
respective parts in the AFL compiler runtime. Support is currently only
implemented for Nyx, but can in theory also work without Nyx.
Note: You might have to adjust `MAP_SIZE_POW2` in include/config.h to ensure
that your coverage map is large enough to hold all basic blocks of your
target program without any collisions.
More documentation on how to utilize this with Nyx will follow.

View File

@ -1,4 +1,4 @@
/* SanitizeCoverage.cpp ported to afl++ LTO :-) */
/* SanitizeCoverage.cpp ported to AFL++ LTO :-) */
#define AFL_LLVM_PASS
@ -19,8 +19,10 @@
#include "llvm/ADT/SmallVector.h"
#if LLVM_VERSION_MAJOR < 17
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/EHPersonalities.h"
#else
#include "llvm/IR/EHPersonalities.h"
#endif
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
@ -49,7 +51,9 @@
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#if LLVM_VERSION_MAJOR < 17
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
@ -234,7 +238,7 @@ class ModuleSanitizerCoverageLTO
SanitizerCoverageOptions Options;
// afl++ START
// AFL++ START
// const SpecialCaseList * Allowlist;
// const SpecialCaseList * Blocklist;
uint32_t autodictionary = 1;
@ -260,7 +264,7 @@ class ModuleSanitizerCoverageLTO
Value *MapPtrFixed = NULL;
std::ofstream dFile;
size_t found = 0;
// afl++ END
// AFL++ END
};
@ -404,7 +408,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
Int8Ty = IRB.getInt8Ty();
Int1Ty = IRB.getInt1Ty();
/* afl++ START */
/* AFL++ START */
char *ptr;
LLVMContext &Ctx = M.getContext();
Ct = &Ctx;
@ -978,7 +982,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
}
// afl++ END
// AFL++ END
SanCovTracePCIndir =
M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy);
@ -1002,10 +1006,11 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
for (auto &F : M)
instrumentFunction(F, DTCallback, PDTCallback);
// afl++ START
// AFL++ START
if (dFile.is_open()) dFile.close();
if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
if (!getenv("AFL_LLVM_LTO_SKIPINIT") &&
(!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr)) {
// yes we could create our own function, insert it into ctors ...
// but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
@ -1155,7 +1160,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
}
// afl++ END
// AFL++ END
// We don't reference these arrays directly in any of our runtime functions,
// so we need to prevent them from being dead stripped.
@ -1212,10 +1217,10 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
// (catchswitch blocks).
if (BB->getFirstInsertionPt() == BB->end()) return false;
// afl++ START
// AFL++ START
if (!Options.NoPrune && &F.getEntryBlock() == BB && F.size() > 1)
return false;
// afl++ END
// AFL++ END
if (Options.NoPrune || &F.getEntryBlock() == BB) return true;
@ -1257,10 +1262,10 @@ void ModuleSanitizerCoverageLTO::instrumentFunction(
// if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName()))
// return;
// afl++ START
// AFL++ START
if (!F.size()) return;
if (!isInInstrumentList(&F, FMNAME)) return;
// afl++ END
// AFL++ END
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
SplitAllCriticalEdges(
@ -1473,8 +1478,8 @@ GlobalVariable *ModuleSanitizerCoverageLTO::CreateFunctionLocalArrayInSection(
ArrayType *ArrayTy = ArrayType::get(Ty, NumElements);
auto Array = new GlobalVariable(
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
Constant::getNullValue(ArrayTy), "__sancov_gen_");
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
Constant::getNullValue(ArrayTy), "__sancov_gen_");
#if LLVM_VERSION_MAJOR >= 13
if (TargetTriple.supportsCOMDAT() &&
@ -1558,7 +1563,7 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage(
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
// afl++ START
// AFL++ START
if (BlockList.size()) {
int skip = 0;
@ -1580,7 +1585,7 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage(
}
// afl++ END
// AFL++ END
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
@ -1646,7 +1651,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F,
if (Options.TracePCGuard) {
// afl++ START
// AFL++ START
++afl_global_id;
if (dFile.is_open()) {
@ -1710,7 +1715,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F,
// done :)
inst++;
// afl++ END
// AFL++ END
/*
XXXXXXXXXXXXXXXXXXX

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,14 @@
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <dlfcn.h>
#ifdef __ANDROID__
#include "android-ashmem.h"
#endif
@ -105,6 +113,50 @@ u32 __afl_dictionary_len;
u64 __afl_map_addr;
u32 __afl_first_final_loc;
typedef struct afl_module_info_t afl_module_info_t;
struct afl_module_info_t {
// A unique id starting with 0
u32 id;
// Name and base address of the module
char *name;
uintptr_t base_address;
// PC Guard start/stop
u32 start;
u32 stop;
// PC Table begin/end
const uintptr_t *pcs_beg;
const uintptr_t *pcs_end;
u8 mapped;
afl_module_info_t *next;
};
typedef struct {
uintptr_t PC, PCFlags;
} PCTableEntry;
afl_module_info_t *__afl_module_info = NULL;
u32 __afl_pcmap_size = 0, __afl_pcmap_shmem = 1;
uintptr_t *__afl_pcmap_ptr = NULL;
// Maximum path length on Linux
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
// Maximum length of an uint32_t as string
#define START_STOP_MAX 10
/* 1 if we are running in afl, and the forkserver was started, else 0 */
u32 __afl_connected = 0;
@ -496,11 +548,12 @@ static void __afl_map_shm(void) {
if (__afl_map_size && __afl_map_size > MAP_SIZE) {
u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE");
if (!map_env || atoi((char *)map_env) < MAP_SIZE) {
u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE");
if (!map_env || atoi((char *)map_env) < MAP_SIZE) {
send_forkserver_error(FS_ERROR_MAP_SIZE);
_exit(1);
fprintf(stderr, "FS_ERROR_MAP_SIZE\n");
send_forkserver_error(FS_ERROR_MAP_SIZE);
_exit(1);
}
@ -512,13 +565,13 @@ static void __afl_map_shm(void) {
if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) {
if (__afl_map_addr)
if (__afl_map_addr)
send_forkserver_error(FS_ERROR_MAP_ADDR);
else
send_forkserver_error(FS_ERROR_SHMAT);
perror("shmat for map");
_exit(1);
_exit(1);
}
@ -678,6 +731,32 @@ static void __afl_map_shm(void) {
}
char *pcmap_id_str = getenv("__AFL_PCMAP_SHM_ID");
if (pcmap_id_str) {
__afl_pcmap_size = __afl_map_size * sizeof(void *);
u32 shm_id = atoi(pcmap_id_str);
__afl_pcmap_ptr = (uintptr_t *)shmat(shm_id, NULL, 0);
if (__afl_debug) {
fprintf(stderr, "DEBUG: Received %p via shmat for pcmap\n",
__afl_pcmap_ptr);
}
} else if (getenv("__AFL_CODE_COVERAGE") ||
getenv("AFL_DUMP_CODE_COVERAGE")) {
__afl_pcmap_size = __afl_map_size * sizeof(void *);
__afl_pcmap_ptr = (uintptr_t *)malloc(__afl_pcmap_size);
__afl_pcmap_shmem = 0;
}
}
/* unmap SHM. */
@ -686,6 +765,15 @@ static void __afl_unmap_shm(void) {
if (!__afl_already_initialized_shm) return;
if (__afl_pcmap_size) {
if (__afl_pcmap_shmem) { shmdt((void *)__afl_pcmap_ptr); }
__afl_pcmap_ptr = NULL;
__afl_pcmap_size = 0;
__afl_pcmap_shmem = 1;
}
char *id_str = getenv(SHM_ENV_VAR);
if (id_str) {
@ -1001,9 +1089,88 @@ static void __afl_start_snapshots(void) {
static void __afl_start_forkserver(void) {
if (__afl_already_initialized_forkserver) return;
if (__afl_already_initialized_forkserver) { return; }
__afl_already_initialized_forkserver = 1;
if (getenv("AFL_DUMP_CODE_COVERAGE")) {
if (__afl_module_info) {
int32_t cnt = 0;
afl_module_info_t *start = __afl_module_info;
while (start) {
++cnt;
start = start->next;
}
// Allocate per entry enough space for:
//
// 1. One path
// 2. Two pcguard start/stop offsets
// 3. Two spaces and a trailing newline
//
// This is a very conservative allocation so we can just YOLO the rest.
size_t bufsize = (PATH_MAX + START_STOP_MAX * 2 + 2 + 1) * cnt + 1;
char *buf = malloc(bufsize);
char *cur = buf;
if (!buf) { perror("malloc"); };
start = __afl_module_info;
while (start) {
size_t namelen = strlen(start->name);
memcpy(cur, start->name, namelen);
cur += namelen;
*cur = ' ';
cur += 1;
cur += sprintf(cur, "%u %u", start->start, start->stop);
*cur = '\n';
cur += 1;
start = start->next;
}
*cur = '\0';
FILE *f = fopen("modinfo.txt", "w");
if (!f) {
fprintf(stderr, "Error: Could not create modinfo.txt!");
exit(-1);
}
fprintf(f, "%s\n", buf);
fclose(f);
f = fopen("pcmap.dump", "w");
if (!f) {
fprintf(stderr, "Error: Could not create pcmap.dump!");
exit(-1);
}
fwrite(__afl_pcmap_ptr, __afl_map_size * sizeof(void *), 1, f);
fclose(f);
fprintf(stderr,
"[+] Created modinfo.txt and pcmap.dump for coverage analysis "
"purposes. Now run afl-showmap with '-V -b -o covmap.dump'.\n");
}
exit(-1);
}
struct sigaction orig_action;
sigaction(SIGTERM, NULL, &orig_action);
old_sigterm_handler = orig_action.sa_handler;
@ -1507,6 +1674,101 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
}
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
const uintptr_t *pcs_end) {
if (__afl_debug) {
fprintf(stderr, "DEBUG: __sanitizer_cov_pcs_init called\n");
}
// If for whatever reason, we cannot get dlinfo here, then pc_guard_init also
// couldn't get it and we'd end up attributing to the wrong module.
Dl_info dlinfo;
if (!dladdr(__builtin_return_address(0), &dlinfo)) {
fprintf(stderr,
"WARNING: Ignoring __sanitizer_cov_pcs_init callback due to "
"missing module info\n");
return;
}
afl_module_info_t *last_module_info = __afl_module_info;
while (last_module_info && last_module_info->next) {
last_module_info = last_module_info->next;
}
if (!last_module_info) {
fprintf(stderr,
"ERROR: __sanitizer_cov_pcs_init called with no module info?!\n");
abort();
}
last_module_info->pcs_beg = pcs_beg;
last_module_info->pcs_end = pcs_end;
// Now update the pcmap. If this is the last module coming in, after all
// pre-loaded code, then this will also map all of our delayed previous
// modules.
if (!__afl_pcmap_ptr) { return; }
for (afl_module_info_t *mod_info = __afl_module_info; mod_info;
mod_info = mod_info->next) {
if (mod_info->mapped) { continue; }
PCTableEntry *start = (PCTableEntry *)(mod_info->pcs_beg);
PCTableEntry *end = (PCTableEntry *)(mod_info->pcs_end);
u32 in_module_index = 0;
if (mod_info->start - in_module_index >= __afl_map_size) {
fprintf(stderr,
"ERROR: __sanitizer_cov_pcs_init out of bounds?! (%u >= %u)\n",
mod_info->start, __afl_map_size);
abort();
}
while (start < end) {
uintptr_t PC = start->PC;
// This is what `GetPreviousInstructionPc` in sanitizer runtime does
// for x86/x86-64. Needs more work for ARM and other archs.
PC = PC - 1;
// Calculate relative offset in module
PC = PC - mod_info->base_address;
__afl_pcmap_ptr[mod_info->start + in_module_index] = PC;
start++;
in_module_index++;
}
mod_info->mapped = 1;
if (__afl_debug) {
fprintf(stderr, "DEBUG: __sanitizer_cov_pcs_init initialized %u PCs\n",
in_module_index);
}
}
}
/* Init callback. Populates instrumentation IDs. Note that we're using
ID of 0 as a special value to indicate non-instrumented bits. That may
still touch the bitmap, but in a fairly harmless way. */
@ -1538,6 +1800,68 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
if (start == stop || *start) { return; }
u32 *orig_start = start;
afl_module_info_t *mod_info = NULL;
if (getenv("__AFL_CODE_COVERAGE") || getenv("AFL_DUMP_CODE_COVERAGE")) {
Dl_info dlinfo;
if (dladdr(__builtin_return_address(0), &dlinfo)) {
if (__afl_already_initialized_forkserver) {
fprintf(stderr, "[pcmap] Error: Module was not preloaded: %s\n",
dlinfo.dli_fname);
} else {
afl_module_info_t *last_module_info = __afl_module_info;
while (last_module_info && last_module_info->next) {
last_module_info = last_module_info->next;
}
mod_info = malloc(sizeof(afl_module_info_t));
mod_info->id = last_module_info ? last_module_info->id + 1 : 0;
mod_info->name = strdup(dlinfo.dli_fname);
mod_info->base_address = (uintptr_t)dlinfo.dli_fbase;
mod_info->start = 0;
mod_info->stop = 0;
mod_info->pcs_beg = NULL;
mod_info->pcs_end = NULL;
mod_info->mapped = 0;
mod_info->next = NULL;
if (last_module_info) {
last_module_info->next = mod_info;
} else {
__afl_module_info = mod_info;
}
if (__afl_debug) {
fprintf(stderr, "[pcmap] Module: %s Base Address: %p\n",
dlinfo.dli_fname, dlinfo.dli_fbase);
}
}
} else {
fprintf(stderr, "[pcmap] dladdr call failed\n");
}
}
x = getenv("AFL_INST_RATIO");
if (x) {
@ -1563,17 +1887,27 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
"[-] FATAL: forkserver is already up, but an instrumented dlopen() "
"library loaded afterwards. You must AFL_PRELOAD such libraries to "
"be able to fuzz them or LD_PRELOAD to run outside of afl-fuzz.\n"
"To ignore this set AFL_IGNORE_PROBLEMS=1 but this will be bad for "
"coverage.\n");
"To ignore this set AFL_IGNORE_PROBLEMS=1 but this will lead to "
"ambiguous coverage data.\n"
"In addition, you can set AFL_IGNORE_PROBLEMS_COVERAGE=1 to "
"ignore the additional coverage instead (use with caution!).\n");
abort();
} else {
u8 ignore_dso_after_fs = !!getenv("AFL_IGNORE_PROBLEMS_COVERAGE");
if (__afl_debug && ignore_dso_after_fs) {
fprintf(stderr, "Ignoring coverage from dynamically loaded code\n");
}
static u32 offset = 5;
while (start < stop) {
if (likely(inst_ratio == 100) || R(100) < inst_ratio) {
if (!ignore_dso_after_fs &&
(likely(inst_ratio == 100) || R(100) < inst_ratio)) {
*(start++) = offset;
@ -1615,6 +1949,19 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
}
if (mod_info) {
mod_info->start = *orig_start;
mod_info->stop = *(stop - 1);
if (__afl_debug) {
fprintf(stderr, "DEBUG: [pcmap] Start Index: %u Stop Index: %u\n",
mod_info->start, mod_info->stop);
}
}
if (__afl_debug) {
fprintf(stderr,

View File

@ -157,6 +157,9 @@ struct afl_cmptrs_pass : afl_base_pass {
/* We expect it to be a record type. */
if (TREE_CODE(t) != RECORD_TYPE) return false;
/* The type has an identifier. */
if (!TYPE_IDENTIFIER(t)) return false;
/* The type of the template is basic_string. */
if (strcmp(IDENTIFIER_POINTER(TYPE_IDENTIFIER(t)), "basic_string") != 0)
return false;
@ -201,7 +204,7 @@ struct afl_cmptrs_pass : afl_base_pass {
/* Now go back to the first data member. Its type should be a
record type named _Alloc_hider. */
c = TREE_TYPE(c);
if (!c || TREE_CODE(c) != RECORD_TYPE ||
if (!c || TREE_CODE(c) != RECORD_TYPE || !TYPE_IDENTIFIER(t) ||
strcmp(IDENTIFIER_POINTER(TYPE_IDENTIFIER(c)), "_Alloc_hider") != 0)
return false;

View File

@ -584,7 +584,7 @@ bool isInInstrumentList(llvm::Function *F, std::string Filename) {
}
// Calculate the number of average collisions that would occur if all
// location IDs would be assigned randomly (like normal afl/afl++).
// location IDs would be assigned randomly (like normal afl/AFL++).
// This uses the "balls in bins" algorithm.
unsigned long long int calculateCollisions(uint32_t edges) {

View File

@ -22,7 +22,9 @@ typedef long double max_align_t;
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#if LLVM_VERSION_MAJOR < 17
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)

View File

@ -53,7 +53,9 @@
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#if LLVM_VERSION_MAJOR < 17
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ValueTracking.h"
@ -744,7 +746,7 @@ static void registerAFLdict2filePass(const PassManagerBuilder &,
}
static RegisterPass<AFLdict2filePass> X("afl-dict2file",
"afl++ dict2file instrumentation pass",
"AFL++ dict2file instrumentation pass",
false, false);
static RegisterStandardPasses RegisterAFLdict2filePass(

View File

@ -45,7 +45,7 @@
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
//#include "llvm/Transforms/IPO/PassManagerBuilder.h"
// #include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"

View File

@ -38,7 +38,9 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#if LLVM_VERSION_MAJOR < 17
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ValueTracking.h"
@ -540,7 +542,7 @@ bool CmpLogRoutines::hookRtns(Module &M) {
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value *v3Pbitcast = IRB.CreateBitCast(
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
Value *v3Pcasted =
IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
args.push_back(v1Pcasted);
@ -606,7 +608,7 @@ bool CmpLogRoutines::hookRtns(Module &M) {
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value *v3Pbitcast = IRB.CreateBitCast(
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
Value *v3Pcasted =
IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
args.push_back(v1Pcasted);

View File

@ -39,7 +39,9 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#if LLVM_VERSION_MAJOR < 17
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ValueTracking.h"

View File

@ -623,7 +623,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt()));
Value *icmp = cur_lenchk_IRB.CreateICmpEQ(
sizedValue, ConstantInt::get(sizedValue->getType(), i));
sizedValue, ConstantInt::get(sizedValue->getType(), i));
cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb);
cur_lenchk_bb->getTerminator()->eraseFromParent();

View File

@ -60,7 +60,7 @@ using namespace llvm;
// uncomment this toggle function verification at each step. horribly slow, but
// helps to pinpoint a potential problem in the splitting code.
//#define VERIFY_TOO_MUCH 1
// #define VERIFY_TOO_MUCH 1
namespace {
@ -463,8 +463,12 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst *IcmpInst,
#else
ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
#endif
if (new_pred == CmpInst::ICMP_SGT || new_pred == CmpInst::ICMP_SLT) {
simplifySignedCompare(icmp_np, M, worklist);
}
worklist.push_back(icmp_np);
worklist.push_back(icmp_eq);
return true;
@ -740,17 +744,24 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
CmpInst *icmp_inv_cmp = nullptr;
BasicBlock *inv_cmp_bb =
BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb);
if (pred == CmpInst::ICMP_UGT || pred == CmpInst::ICMP_SGT ||
pred == CmpInst::ICMP_UGE || pred == CmpInst::ICMP_SGE) {
if (pred == CmpInst::ICMP_UGT) {
icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT,
op0_high, op1_high);
} else {
} else if (pred == CmpInst::ICMP_ULT) {
icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT,
op0_high, op1_high);
} else {
// Never gonna appen
if (!be_quiet)
fprintf(stderr,
"Error: split-compare: Equals or signed not removed: %d\n",
pred);
}
#if LLVM_MAJOR >= 16

View File

@ -1 +1 @@
2da7f08
c8a72dc

View File

@ -1 +1 @@
0569eff8a1
a1321713c7

View File

@ -356,7 +356,7 @@ fi
if ! command -v "$CROSS" > /dev/null ; then
if [ "$CPU_TARGET" = "$(uname -m)" ] ; then
echo "[+] Building afl++ qemu support libraries with CC=$CC"
echo "[+] Building AFL++ qemu support libraries with CC=$CC"
echo "[+] Building libcompcov ..."
make -C libcompcov && echo "[+] libcompcov ready"
echo "[+] Building unsigaction ..."
@ -371,7 +371,7 @@ if ! command -v "$CROSS" > /dev/null ; then
echo "[!] Cross compiler $CROSS could not be found, cannot compile libcompcov libqasan and unsigaction"
fi
else
echo "[+] Building afl++ qemu support libraries with CC=\"$CROSS $CROSS_FLAGS\""
echo "[+] Building AFL++ qemu support libraries with CC=\"$CROSS $CROSS_FLAGS\""
echo "[+] Building libcompcov ..."
make -C libcompcov CC="$CROSS $CROSS_FLAGS" && echo "[+] libcompcov ready"
echo "[+] Building unsigaction ..."

View File

@ -68,7 +68,11 @@ static int debug_fd = -1;
#define MAX_MAPPINGS 1024
static struct mapping { void *st, *en; } __compcov_ro[MAX_MAPPINGS];
static struct mapping {
void *st, *en;
} __compcov_ro[MAX_MAPPINGS];
static u32 __compcov_ro_cnt;

View File

@ -1762,7 +1762,7 @@ static FORCEINLINE void *win32direct_mmap(size_t size) {
static FORCEINLINE int win32munmap(void *ptr, size_t size) {
MEMORY_BASIC_INFORMATION minfo;
char *cptr = (char *)ptr;
char *cptr = (char *)ptr;
while (size) {

View File

@ -31,6 +31,8 @@
#include <strings.h>
#include <limits.h>
#include <assert.h>
#include <ctype.h>
#include <sys/stat.h>
#if (LLVM_MAJOR - 0 == 0)
#undef LLVM_MAJOR
@ -76,6 +78,7 @@ enum {
INSTRUMENT_OPT_NGRAM = 16,
INSTRUMENT_OPT_CALLER = 32,
INSTRUMENT_OPT_CTX_K = 64,
INSTRUMENT_OPT_CODECOV = 128,
};
@ -375,15 +378,316 @@ void parse_fsanitize(char *string) {
}
static u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0,
shared_linking = 0, preprocessor_only = 0, have_unroll = 0,
have_o = 0, have_pic = 0, have_c = 0, partial_linking = 0,
non_dash = 0;
#ifndef MAX_PARAMS_NUM
#define MAX_PARAMS_NUM 2048
#endif
static void process_params(u32 argc, char **argv) {
if (cc_par_cnt + argc >= MAX_PARAMS_NUM) {
FATAL("Too many command line parameters, please increase MAX_PARAMS_NUM.");
}
if (lto_mode && argc > 1) {
u32 idx;
for (idx = 1; idx < argc; idx++) {
if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1;
}
}
// for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
/* Process the argument list. */
u8 skip_next = 0;
while (--argc) {
u8 *cur = *(++argv);
if (skip_next) {
skip_next = 0;
continue;
}
if (cur[0] != '-') { non_dash = 1; }
if (!strncmp(cur, "--afl", 5)) continue;
if (lto_mode && !strncmp(cur, "-flto=thin", 10)) {
FATAL(
"afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or "
"use afl-clang-fast!");
}
if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
if (!strncmp(cur, "-fno-unroll", 11)) continue;
if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
!strcmp(cur, "--no-undefined")) {
continue;
}
if (compiler_mode == GCC_PLUGIN && !strcmp(cur, "-pipe")) { continue; }
if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
u8 *param = *(argv + 1);
if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
skip_next = 1;
continue;
}
}
if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) &&
!strncmp(cur, "-stdlib=", 8)) {
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
continue;
}
if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) {
have_instr_list = 1;
}
if (!strncmp(cur, "-fsanitize=", strlen("-fsanitize=")) &&
strchr(cur, ',')) {
parse_fsanitize(cur);
if (!cur || strlen(cur) <= strlen("-fsanitize=")) { continue; }
} else if ((!strncmp(cur, "-fsanitize=fuzzer-",
strlen("-fsanitize=fuzzer-")) ||
!strncmp(cur, "-fsanitize-coverage",
strlen("-fsanitize-coverage"))) &&
(strncmp(cur, "sanitize-coverage-allow",
strlen("sanitize-coverage-allow")) &&
strncmp(cur, "sanitize-coverage-deny",
strlen("sanitize-coverage-deny")) &&
instrument_mode != INSTRUMENT_LLVMNATIVE)) {
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
continue;
}
if (need_aflpplib || !strcmp(cur, "-fsanitize=fuzzer")) {
u8 *afllib = find_object("libAFLDriver.a", argv[0]);
if (!be_quiet) {
OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
}
if (!afllib) {
if (!be_quiet) {
WARNF(
"Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
"the flags - this will fail!");
}
} else {
cc_params[cc_par_cnt++] = afllib;
#ifdef __APPLE__
cc_params[cc_par_cnt++] = "-undefined";
cc_params[cc_par_cnt++] = "dynamic_lookup";
#endif
}
if (need_aflpplib) {
need_aflpplib = 0;
} else {
continue;
}
}
if (!strcmp(cur, "-m32")) bit_mode = 32;
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
if (!strcmp(cur, "-m64")) bit_mode = 64;
if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
asan_set = 1;
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
if (!strcmp(cur, "-x")) x_set = 1;
if (!strcmp(cur, "-E")) preprocessor_only = 1;
if (!strcmp(cur, "-shared")) shared_linking = 1;
if (!strcmp(cur, "-dynamiclib")) shared_linking = 1;
if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1;
if (!strcmp(cur, "-Wl,-r")) partial_linking = 1;
if (!strcmp(cur, "-Wl,-i")) partial_linking = 1;
if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1;
if (!strcmp(cur, "-r")) partial_linking = 1;
if (!strcmp(cur, "--relocatable")) partial_linking = 1;
if (!strcmp(cur, "-c")) have_c = 1;
if (!strncmp(cur, "-O", 2)) have_o = 1;
if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1;
if (*cur == '@') {
// response file support.
// we have two choices - move everything to the command line or
// rewrite the response files to temporary files and delete them
// afterwards. We choose the first for easiness.
// We do *not* support quotes in the rsp files to cope with spaces in
// filenames etc! If you need that then send a patch!
u8 *filename = cur + 1;
if (debug) { DEBUGF("response file=%s\n", filename); }
FILE *f = fopen(filename, "r");
struct stat st;
// Check not found or empty? let the compiler complain if so.
if (!f || fstat(fileno(f), &st) < 0 || st.st_size < 1) {
cc_params[cc_par_cnt++] = cur;
continue;
}
u8 *tmpbuf = malloc(st.st_size + 2), *ptr;
char **args = malloc(sizeof(char *) * (st.st_size >> 1));
int count = 1, cont = 0, cont_act = 0;
while (fgets(tmpbuf, st.st_size + 1, f)) {
ptr = tmpbuf;
// fprintf(stderr, "1: %s\n", ptr);
// no leading whitespace
while (isspace(*ptr)) {
++ptr;
cont_act = 0;
}
// no comments, no empty lines
if (*ptr == '#' || *ptr == '\n' || !*ptr) { continue; }
// remove LF
if (ptr[strlen(ptr) - 1] == '\n') { ptr[strlen(ptr) - 1] = 0; }
// remove CR
if (*ptr && ptr[strlen(ptr) - 1] == '\r') { ptr[strlen(ptr) - 1] = 0; }
// handle \ at end of line
if (*ptr && ptr[strlen(ptr) - 1] == '\\') {
cont = 1;
ptr[strlen(ptr) - 1] = 0;
}
// fprintf(stderr, "2: %s\n", ptr);
// remove whitespace at end
while (*ptr && isspace(ptr[strlen(ptr) - 1])) {
ptr[strlen(ptr) - 1] = 0;
cont = 0;
}
// fprintf(stderr, "3: %s\n", ptr);
if (*ptr) {
do {
u8 *value = ptr;
while (*ptr && !isspace(*ptr)) {
++ptr;
}
while (*ptr && isspace(*ptr)) {
*ptr++ = 0;
}
if (cont_act) {
u32 len = strlen(args[count - 1]) + strlen(value) + 1;
u8 *tmp = malloc(len);
snprintf(tmp, len, "%s%s", args[count - 1], value);
free(args[count - 1]);
args[count - 1] = tmp;
cont_act = 0;
} else {
args[count++] = strdup(value);
}
} while (*ptr);
}
if (cont) {
cont_act = 1;
cont = 0;
}
}
if (count) { process_params(count, args); }
// we cannot free args[]
free(tmpbuf);
continue;
}
cc_params[cc_par_cnt++] = cur;
}
}
/* Copy argv to cc_params, making the necessary edits. */
static void edit_params(u32 argc, char **argv, char **envp) {
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0,
preprocessor_only = 0, have_unroll = 0, have_o = 0, have_pic = 0,
have_c = 0, partial_linking = 0;
cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
cc_params = ck_alloc(MAX_PARAMS_NUM * sizeof(u8 *));
if (lto_mode) {
@ -641,10 +945,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
//#if LLVM_MAJOR >= 13
// // Use the old pass manager in LLVM 14 which the afl++ passes still
// use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
//#endif
// #if LLVM_MAJOR >= 13
// // Use the old pass manager in LLVM 14 which the AFL++ passes still
// use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
// #endif
if (lto_mode && !have_c) {
@ -701,7 +1005,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (instrument_mode == INSTRUMENT_PCGUARD) {
#if LLVM_MAJOR >= 11
#if LLVM_MAJOR >= 13
#if defined __ANDROID__ || ANDROID
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE;
@ -718,7 +1022,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} else {
#if LLVM_MAJOR >= 11 /* use new pass manager */
#if LLVM_MAJOR >= 13 /* use new pass manager */
#if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
#endif
@ -739,21 +1043,35 @@ static void edit_params(u32 argc, char **argv, char **envp) {
#if LLVM_MAJOR >= 4
if (!be_quiet)
SAYF(
"Using unoptimized trace-pc-guard, upgrade to llvm 10.0.1+ for "
"Using unoptimized trace-pc-guard, upgrade to LLVM 13+ for "
"enhanced version.\n");
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE;
#else
FATAL("pcguard instrumentation requires llvm 4.0.1+");
FATAL("pcguard instrumentation requires LLVM 4.0.1+");
#endif
#endif
} else if (instrument_mode == INSTRUMENT_LLVMNATIVE) {
#if LLVM_MAJOR >= 4
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
if (instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
#if LLVM_MAJOR >= 6
cc_params[cc_par_cnt++] =
"-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table";
#else
FATAL("pcguard instrumentation with pc-table requires LLVM 6.0.1+");
#endif
} else {
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
}
#else
FATAL("pcguard instrumentation requires llvm 4.0.1+");
FATAL("pcguard instrumentation requires LLVM 4.0.1+");
#endif
} else {
@ -816,159 +1134,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
if (!have_pic) cc_params[cc_par_cnt++] = "-fPIC";
}
}
/* Detect stray -v calls from ./configure scripts. */
/* Inspect the command line parameters. */
u8 skip_next = 0, non_dash = 0;
while (--argc) {
process_params(argc, argv);
u8 *cur = *(++argv);
if (skip_next) {
skip_next = 0;
continue;
}
if (cur[0] != '-') { non_dash = 1; }
if (!strncmp(cur, "--afl", 5)) continue;
if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
if (!strncmp(cur, "-fno-unroll", 11)) continue;
if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
!strcmp(cur, "--no-undefined")) {
continue;
}
if (compiler_mode == GCC_PLUGIN && !strcmp(cur, "-pipe")) { continue; }
if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
u8 *param = *(argv + 1);
if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
skip_next = 1;
continue;
}
}
if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) &&
!strncmp(cur, "-stdlib=", 8)) {
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
continue;
}
if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) {
have_instr_list = 1;
}
if (!strncmp(cur, "-fsanitize=", strlen("-fsanitize=")) &&
strchr(cur, ',')) {
parse_fsanitize(cur);
if (!cur || strlen(cur) <= strlen("-fsanitize=")) { continue; }
} else if ((!strncmp(cur, "-fsanitize=fuzzer-",
strlen("-fsanitize=fuzzer-")) ||
!strncmp(cur, "-fsanitize-coverage",
strlen("-fsanitize-coverage"))) &&
(strncmp(cur, "sanitize-coverage-allow",
strlen("sanitize-coverage-allow")) &&
strncmp(cur, "sanitize-coverage-deny",
strlen("sanitize-coverage-deny")) &&
instrument_mode != INSTRUMENT_LLVMNATIVE)) {
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
continue;
}
if (need_aflpplib || !strcmp(cur, "-fsanitize=fuzzer")) {
u8 *afllib = find_object("libAFLDriver.a", argv[0]);
if (!be_quiet) {
OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
}
if (!afllib) {
if (!be_quiet) {
WARNF(
"Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
"the flags - this will fail!");
}
} else {
cc_params[cc_par_cnt++] = afllib;
#ifdef __APPLE__
cc_params[cc_par_cnt++] = "-undefined";
cc_params[cc_par_cnt++] = "dynamic_lookup";
#endif
}
if (need_aflpplib) {
need_aflpplib = 0;
} else {
continue;
}
}
if (!strcmp(cur, "-m32")) bit_mode = 32;
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
if (!strcmp(cur, "-m64")) bit_mode = 64;
if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
asan_set = 1;
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
if (!strcmp(cur, "-x")) x_set = 1;
if (!strcmp(cur, "-E")) preprocessor_only = 1;
if (!strcmp(cur, "-shared")) shared_linking = 1;
if (!strcmp(cur, "-dynamiclib")) shared_linking = 1;
if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1;
if (!strcmp(cur, "-Wl,-r")) partial_linking = 1;
if (!strcmp(cur, "-Wl,-i")) partial_linking = 1;
if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1;
if (!strcmp(cur, "-r")) partial_linking = 1;
if (!strcmp(cur, "--relocatable")) partial_linking = 1;
if (!strcmp(cur, "-c")) have_c = 1;
if (!strncmp(cur, "-O", 2)) have_o = 1;
if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1;
cc_params[cc_par_cnt++] = cur;
}
if (!have_pic) { cc_params[cc_par_cnt++] = "-fPIC"; }
// in case LLVM is installed not via a package manager or "make install"
// e.g. compiled download or compiled from github then its ./lib directory
@ -1651,13 +1825,17 @@ int main(int argc, char **argv, char **envp) {
instrument_mode = INSTRUMENT_CLASSIC;
lto_mode = 1;
} else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL)
} else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL) {
instrument_mode = INSTRUMENT_AFL;
else
} else {
FATAL("main instrumentation mode already set with %s",
instrument_mode_string[instrument_mode]);
}
}
if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
@ -1672,7 +1850,8 @@ int main(int argc, char **argv, char **envp) {
}
if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) {
strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 ||
strncasecmp(ptr2, "native", strlen("native")) == 0) {
if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE)
instrument_mode = INSTRUMENT_LLVMNATIVE;
@ -1682,6 +1861,24 @@ int main(int argc, char **argv, char **envp) {
}
if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 ||
strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) {
if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) {
instrument_mode = INSTRUMENT_LLVMNATIVE;
instrument_opt_mode |= INSTRUMENT_OPT_CODECOV;
setenv("AFL_DONT_OPTIMIZE", "1", 1);
} else {
FATAL("main instrumentation mode already set with %s",
instrument_mode_string[instrument_mode]);
}
}
if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
@ -1843,7 +2040,7 @@ int main(int argc, char **argv, char **envp) {
if (!compiler_mode) {
// lto is not a default because outside of afl-cc RANLIB and AR have to
// be set to llvm versions so this would work
// be set to LLVM versions so this would work
if (have_llvm)
compiler_mode = LLVM;
else if (have_gcc_plugin)
@ -1862,6 +2059,17 @@ int main(int argc, char **argv, char **envp) {
}
/* if our PCGUARD implementation is not available then silently switch to
native LLVM PCGUARD */
if (compiler_mode == CLANG &&
(instrument_mode == INSTRUMENT_DEFAULT ||
instrument_mode == INSTRUMENT_PCGUARD) &&
find_object("SanitizerCoveragePCGUARD.so", argv[0]) == NULL) {
instrument_mode = INSTRUMENT_LLVMNATIVE;
}
if (compiler_mode == GCC) {
if (clang_mode) {
@ -1908,12 +2116,7 @@ int main(int argc, char **argv, char **envp) {
"-------------|\n"
"MODES: NCC PERSIST DICT LAF "
"CMPLOG SELECT\n"
" [LTO] llvm LTO: %s%s\n"
" PCGUARD DEFAULT yes yes yes yes yes "
" yes\n"
" CLASSIC yes yes yes yes yes "
" yes\n"
" [LLVM] llvm: %s%s\n"
" [LLVM] LLVM: %s%s\n"
" PCGUARD %s yes yes module yes yes "
"yes\n"
" CLASSIC %s no yes module yes yes "
@ -1922,16 +2125,21 @@ int main(int argc, char **argv, char **envp) {
" - CALLER\n"
" - CTX\n"
" - NGRAM-{2-16}\n"
" [LTO] LLVM LTO: %s%s\n"
" PCGUARD DEFAULT yes yes yes yes yes "
" yes\n"
" CLASSIC yes yes yes yes yes "
" yes\n"
" [GCC_PLUGIN] gcc plugin: %s%s\n"
" CLASSIC DEFAULT no yes no no no "
"yes\n"
" [GCC/CLANG] simple gcc/clang: %s%s\n"
" CLASSIC DEFAULT no no no no no "
"no\n\n",
have_lto ? "AVAILABLE" : "unavailable!",
compiler_mode == LTO ? " [SELECTED]" : "",
have_llvm ? "AVAILABLE" : "unavailable!",
compiler_mode == LLVM ? " [SELECTED]" : "",
have_lto ? "AVAILABLE" : "unavailable!",
compiler_mode == LTO ? " [SELECTED]" : "",
LLVM_MAJOR >= 7 ? "DEFAULT" : " ",
LLVM_MAJOR >= 7 ? " " : "DEFAULT",
have_gcc_plugin ? "AVAILABLE" : "unavailable!",
@ -1983,7 +2191,7 @@ int main(int argc, char **argv, char **envp) {
" (instrumentation/README.lto.md)\n"
" PERSIST: persistent mode support [code] (huge speed increase!)\n"
" (instrumentation/README.persistent_mode.md)\n"
" DICT: dictionary in the target [yes=automatic or llvm module "
" DICT: dictionary in the target [yes=automatic or LLVM module "
"pass]\n"
" (instrumentation/README.lto.md + "
"instrumentation/README.llvm.md)\n"
@ -2099,6 +2307,8 @@ int main(int argc, char **argv, char **envp) {
"bb\n"
" AFL_REAL_LD: use this lld linker instead of the compiled in "
"path\n"
" AFL_LLVM_LTO_SKIPINIT: don't inject initialization code "
"(used in WAFL mode)\n"
"If anything fails - be sure to read README.lto.md!\n");
#endif
@ -2145,6 +2355,15 @@ int main(int argc, char **argv, char **envp) {
"AFL_LLVM_CMPLOG and "
"AFL_LLVM_DICT2FILE+AFL_LLVM_DICT2FILE_NO_MAIN.\n\n");
if (LLVM_MAJOR < 13) {
SAYF(
"Warning: It is highly recommended to use at least LLVM version 13 "
"(or better, higher) rather than %d!\n\n",
LLVM_MAJOR);
}
exit(1);
}
@ -2239,7 +2458,8 @@ int main(int argc, char **argv, char **envp) {
"(requires LLVM 11 or higher)");
#endif
if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC)
if (instrument_opt_mode && instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
instrument_mode != INSTRUMENT_CLASSIC)
FATAL(
"CALLER, CTX and NGRAM instrumentation options can only be used with "
"the LLVM CLASSIC instrumentation mode.");

View File

@ -949,7 +949,7 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) {
/* Get unix time in milliseconds */
u64 get_cur_time(void) {
inline u64 get_cur_time(void) {
struct timeval tv;
struct timezone tz;
@ -1298,6 +1298,35 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
}
/* Unsafe describe time delta as simple string.
Returns a pointer to buf for convenience. */
u8 *u_simplestring_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
if (!event_ms) {
sprintf(buf, "00:00:00");
} else {
u64 delta;
s32 t_d, t_h, t_m, t_s;
delta = cur_ms - event_ms;
t_d = delta / 1000 / 60 / 60 / 24;
t_h = (delta / 1000 / 60 / 60) % 24;
t_m = (delta / 1000 / 60) % 60;
t_s = (delta / 1000) % 60;
sprintf(buf, "%d:%02d:%02d:%02d", t_d, t_h, t_m, t_s);
}
return buf;
}
/* Reads the map size from ENV */
u32 get_map_size(void) {

View File

@ -226,6 +226,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
/* Settings */
fsrv->use_stdin = true;
fsrv->no_unlink = false;
fsrv->keep_coverage = false;
fsrv->coverage_map = NULL;
fsrv->exec_tmout = EXEC_TIMEOUT;
fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
fsrv->mem_limit = MEM_LIMIT;
@ -276,6 +278,9 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->init_child_func = from->init_child_func;
// Note: do not copy ->add_extra_func or ->persistent_record*
fsrv_to->keep_coverage = false;
fsrv_to->coverage_map = NULL;
list_append(&fsrv_list, fsrv_to);
}
@ -489,7 +494,7 @@ static void report_error_and_exit(int error) {
break;
case FS_ERROR_OLD_CMPLOG:
FATAL(
"the -c cmplog target was instrumented with an too old afl++ "
"the -c cmplog target was instrumented with an too old AFL++ "
"version, you need to recompile it.");
break;
case FS_ERROR_OLD_CMPLOG_QEMU:
@ -987,7 +992,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
// workaround for recent afl++ versions
// workaround for recent AFL++ versions
if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND)
status = (status & 0xf0ffffff);
@ -1059,7 +1064,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
FATAL(
"Target's coverage map size of %u is larger than the one this "
"afl++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
"AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
" afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
"afl-fuzz",
tmp_map_size, fsrv->map_size, tmp_map_size);
@ -1175,6 +1180,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
}
if (unlikely(fsrv->keep_coverage)) {
fsrv->coverage_map = ck_alloc(fsrv->map_size);
}
return;
}
@ -1226,7 +1237,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
" fail, poke the Awesome Fuzzing Discord for troubleshooting "
"tips.\n");
} else {
@ -1271,7 +1282,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
" fail, poke the Awesome Fuzzing Discord for troubleshooting "
"tips.\n",
stringify_mem_size(val_buf, sizeof(val_buf), fsrv->mem_limit << 20),
fsrv->mem_limit - 1);
@ -1321,7 +1332,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
"Otherwise there is a horrible bug in the fuzzer.\n"
"Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
"Poke the Awesome Fuzzing Discord for troubleshooting tips.\n");
} else {
@ -1370,7 +1381,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
" fail, poke the Awesome Fuzzing Discord for troubleshooting "
"tips.\n",
getenv(DEFER_ENV_VAR)
? " - You are using deferred forkserver, but __AFL_INIT() is "
@ -1407,6 +1418,19 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) {
afl_nyx_runner_kill(fsrv);
#endif
if (unlikely(fsrv->keep_coverage)) {
// TODO maybe we should write that to out_dir
FILE *f = fopen("covmap.dump", "w");
if (!f) { PFATAL("creating covmap.dump failed"); }
fwrite(fsrv->coverage_map, fsrv->map_size, 1, f);
fclose(f);
OKF("Wrote coverage map to covmap.dump");
ck_free(fsrv->coverage_map);
fsrv->coverage_map = NULL;
}
}
/* Get the map size from the target forkserver */
@ -1565,7 +1589,22 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
enum NyxReturnValue ret_val =
fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner);
fsrv->total_execs++;
++fsrv->total_execs;
if (unlikely(fsrv->keep_coverage)) {
for (u32 i = 0; i < fsrv->map_size; ++i) {
if (unlikely(fsrv->trace_bits[i]) &&
likely(fsrv->coverage_map[i] < 255)) {
++fsrv->coverage_map[i];
}
}
}
switch (ret_val) {

View File

@ -533,6 +533,18 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
close(fd);
add_to_queue(afl, queue_fn, len, 0);
if (unlikely(afl->fuzz_mode) && likely(afl->switch_fuzz_mode)) {
if (afl->afl_env.afl_no_ui) {
ACTF("New coverage found, switching back to exploration mode.");
}
afl->fuzz_mode = 0;
}
#ifdef INTROSPECTION
if (afl->custom_mutators_count && afl->current_custom_fuzz) {

View File

@ -716,12 +716,25 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
}
// if (getenv("MYTEST")) afl->in_place_resume = 1;
if (nl_cnt) {
i = nl_cnt;
u32 done = 0;
if (unlikely(afl->in_place_resume)) {
i = nl_cnt;
} else {
i = 0;
}
do {
--i;
if (unlikely(afl->in_place_resume)) { --i; }
struct stat st;
u8 dfn[PATH_MAX];
@ -745,7 +758,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
free(nl[i]); /* not tracked */
read_testcases(afl, fn2);
ck_free(fn2);
continue;
goto next_entry;
}
@ -754,7 +767,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
ck_free(fn2);
continue;
goto next_entry;
}
@ -801,21 +814,23 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
}
/*
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
next_entry:
if (unlikely(afl->in_place_resume)) {
u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size,
HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
if (unlikely(i == 0)) { done = 1; }
}
} else {
*/
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
} while (i > 0);
}
} while (!done);
}
// if (getenv("MYTEST")) afl->in_place_resume = 0;
free(nl); /* not tracked */
if (!afl->queued_items && directory == NULL) {
@ -897,8 +912,10 @@ void perform_dry_run(afl_state_t *afl) {
if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) {
SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us\n" cRST,
q->len, q->bitmap_size, q->exec_us);
SAYF(cGRA
" len = %u, map size = %u, exec speed = %llu us, hash = "
"%016llx\n" cRST,
q->len, q->bitmap_size, q->exec_us, q->exec_cksum);
}
@ -995,7 +1012,7 @@ void perform_dry_run(afl_state_t *afl) {
" - Least likely, there is a horrible bug in the fuzzer. If "
"other options\n"
" fail, poke <afl-users@googlegroups.com> for "
" fail, poke the Awesome Fuzzing Discord for "
"troubleshooting tips.\n",
stringify_mem_size(val_buf, sizeof(val_buf),
afl->fsrv.mem_limit << 20),
@ -1024,7 +1041,7 @@ void perform_dry_run(afl_state_t *afl) {
" - Least likely, there is a horrible bug in the fuzzer. If "
"other options\n"
" fail, poke <afl-users@googlegroups.com> for "
" fail, poke the Awesome Fuzzing Discord for "
"troubleshooting tips.\n");
}
@ -1153,14 +1170,14 @@ void perform_dry_run(afl_state_t *afl) {
u32 duplicates = 0, i;
for (idx = 0; idx < afl->queued_items; idx++) {
for (idx = 0; idx < afl->queued_items - 1; idx++) {
q = afl->queue_buf[idx];
if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
u32 done = 0;
for (i = idx + 1;
i < afl->queued_items && !done && likely(afl->queue_buf[i]); i++) {
likely(i < afl->queued_items && afl->queue_buf[i] && !done); ++i) {
struct queue_entry *p = afl->queue_buf[i];
if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
@ -1183,6 +1200,13 @@ void perform_dry_run(afl_state_t *afl) {
p->disabled = 1;
p->perf_score = 0;
if (afl->debug) {
WARNF("Same coverage - %s is kept active, %s is disabled.",
q->fname, p->fname);
}
} else {
if (!q->was_fuzzed) {
@ -1196,7 +1220,14 @@ void perform_dry_run(afl_state_t *afl) {
q->disabled = 1;
q->perf_score = 0;
done = 1;
if (afl->debug) {
WARNF("Same coverage - %s is kept active, %s is disabled.",
p->fname, q->fname);
}
done = 1; // end inner loop because outer loop entry is disabled now
}
@ -1511,8 +1542,8 @@ double get_runnable_processes(void) {
processes well. */
FILE *f = fopen("/proc/stat", "r");
u8 tmp[1024];
u32 val = 0;
u8 tmp[1024];
u32 val = 0;
if (!f) { return 0; }
@ -2195,7 +2226,7 @@ void check_crash_handling(void) {
*BSD, so we can just let it slide for now. */
s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY);
u8 fchar;
u8 fchar;
if (fd < 0) { return; }
@ -2334,7 +2365,7 @@ void check_cpu_governor(afl_state_t *afl) {
FATAL("Suboptimal CPU scaling governor");
#elif defined __APPLE__
u64 min = 0, max = 0;
u64 min = 0, max = 0;
size_t mlen = sizeof(min);
if (afl->afl_env.afl_skip_cpufreq) return;

File diff suppressed because it is too large Load Diff

View File

@ -49,11 +49,13 @@ inline u32 select_next_queue_entry(afl_state_t *afl) {
u32 s = rand_below(afl, afl->queued_items);
double p = rand_next_percent(afl);
/*
fprintf(stderr, "select: p=%f s=%u ... p < prob[s]=%f ? s=%u : alias[%u]=%u"
" ==> %u\n", p, s, afl->alias_probability[s], s, s, afl->alias_table[s], p <
afl->alias_probability[s] ? s : afl->alias_table[s]);
*/
return (p < afl->alias_probability[s] ? s : afl->alias_table[s]);
}
@ -87,25 +89,28 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q,
void create_alias_table(afl_state_t *afl) {
u32 n = afl->queued_items, i = 0, a, g;
u32 n = afl->queued_items, i = 0, nSmall = 0, nLarge = n - 1;
double sum = 0;
double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
u32 *Small = (int *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
u32 *Large = (int *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
afl->alias_table =
(u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32));
afl->alias_probability = (double *)afl_realloc(
(void **)&afl->alias_probability, n * sizeof(double));
double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
int *S = (int *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
int *L = (int *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
if (!P || !S || !L || !afl->alias_table || !afl->alias_probability) {
if (!P || !Small || !Large || !afl->alias_table || !afl->alias_probability) {
FATAL("could not acquire memory for alias table");
}
memset((void *)afl->alias_table, 0, n * sizeof(u32));
memset((void *)afl->alias_probability, 0, n * sizeof(double));
memset((void *)afl->alias_table, 0, n * sizeof(u32));
memset((void *)Small, 0, n * sizeof(u32));
memset((void *)Large, 0, n * sizeof(u32));
if (likely(afl->schedule < RARE)) {
@ -166,7 +171,15 @@ void create_alias_table(afl_state_t *afl) {
for (i = 0; i < n; i++) {
// weight is always 0 for disabled entries
P[i] = (afl->queue_buf[i]->weight * n) / sum;
if (unlikely(afl->queue_buf[i]->disabled)) {
P[i] = 0;
} else {
P[i] = (afl->queue_buf[i]->weight * n) / sum;
}
}
@ -176,60 +189,81 @@ void create_alias_table(afl_state_t *afl) {
struct queue_entry *q = afl->queue_buf[i];
if (likely(!q->disabled)) { q->perf_score = calculate_score(afl, q); }
if (likely(!q->disabled)) {
sum += q->perf_score;
q->perf_score = calculate_score(afl, q);
sum += q->perf_score;
}
}
for (i = 0; i < n; i++) {
// perf_score is always 0 for disabled entries
P[i] = (afl->queue_buf[i]->perf_score * n) / sum;
if (unlikely(afl->queue_buf[i]->disabled)) {
P[i] = 0;
} else {
P[i] = (afl->queue_buf[i]->perf_score * n) / sum;
}
}
}
int nS = 0, nL = 0, s;
for (s = (s32)n - 1; s >= 0; --s) {
// Done collecting weightings in P, now create the arrays.
if (P[s] < 1) {
for (s32 j = (s32)(n - 1); j >= 0; j--) {
S[nS++] = s;
if (P[j] < 1) {
Small[nSmall++] = (u32)j;
} else {
L[nL++] = s;
Large[nLarge--] = (u32)j;
}
}
while (nS && nL) {
while (nSmall && nLarge != n - 1) {
a = S[--nS];
g = L[--nL];
afl->alias_probability[a] = P[a];
afl->alias_table[a] = g;
P[g] = P[g] + P[a] - 1;
if (P[g] < 1) {
u32 small = Small[--nSmall];
u32 large = Large[++nLarge];
S[nS++] = g;
afl->alias_probability[small] = P[small];
afl->alias_table[small] = large;
P[large] = P[large] - (1 - P[small]);
if (P[large] < 1) {
Small[nSmall++] = large;
} else {
L[nL++] = g;
Large[nLarge--] = large;
}
}
while (nL)
afl->alias_probability[L[--nL]] = 1;
while (nSmall) {
while (nS)
afl->alias_probability[S[--nS]] = 1;
afl->alias_probability[Small[--nSmall]] = 1;
}
while (nLarge != n - 1) {
afl->alias_probability[Large[++nLarge]] = 1;
}
afl->reinit_table = 0;
@ -264,7 +298,7 @@ void create_alias_table(afl_state_t *afl) {
*/
/*
fprintf(stderr, " entry alias probability perf_score weight
filename\n"); for (u32 i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u
filename\n"); for (i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u
%0.9f %0.9f %s\n", i, afl->alias_table[i], afl->alias_probability[i],
afl->queue_buf[i]->perf_score, afl->queue_buf[i]->weight,
afl->queue_buf[i]->fname);
@ -578,7 +612,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
}
if (likely(q->len > 4)) afl->ready_for_splicing_count++;
if (likely(q->len > 4)) { ++afl->ready_for_splicing_count; }
++afl->queued_items;
++afl->active_items;

View File

@ -28,8 +28,8 @@
#include "afl-fuzz.h"
#include "cmplog.h"
//#define _DEBUG
//#define CMPLOG_INTROSPECTION
// #define _DEBUG
// #define CMPLOG_INTROSPECTION
// CMP attribute enum
enum {
@ -379,7 +379,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
}
if (++afl->stage_cur % screen_update == 0) { show_stats(afl); };
if (unlikely(++afl->stage_cur % screen_update == 0)) { show_stats(afl); };
}
@ -571,7 +571,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
}
//#ifdef CMPLOG_SOLVE_TRANSFORM
// #ifdef CMPLOG_SOLVE_TRANSFORM
static int strntoll(const char *str, size_t sz, char **end, int base,
long long *out) {
@ -771,7 +771,7 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) {
#endif
//#endif
// #endif
static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u64 pattern, u64 repl, u64 o_pattern,
@ -790,7 +790,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u32 its_len = MIN(len - idx, taint_len);
if (afl->fsrv.total_execs - last_update > screen_update) {
if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
show_stats(afl);
last_update = afl->fsrv.total_execs;
@ -803,8 +803,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// o_pattern, pattern, repl, changed_val, idx, taint_len,
// hshape, attr);
//#ifdef CMPLOG_SOLVE_TRANSFORM
// reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
// #ifdef CMPLOG_SOLVE_TRANSFORM
// reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
if (afl->cmplog_enable_transform && (lvl & LVL3)) {
u8 *endptr;
@ -1120,7 +1120,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
//#endif
// #endif
// we only allow this for ascii2integer (above) so leave if this is the case
if (unlikely(pattern == o_pattern)) { return 0; }
@ -1275,7 +1275,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// 16 = modified float, 32 = modified integer (modified = wont match
// in original buffer)
//#ifdef CMPLOG_SOLVE_ARITHMETIC
// #ifdef CMPLOG_SOLVE_ARITHMETIC
if (!afl->cmplog_enable_arith || lvl < LVL3 || attr == IS_TRANSFORM) {
return 0;
@ -1440,8 +1440,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
//#endif /*
// CMPLOG_SOLVE_ARITHMETIC
// #endif /*
// CMPLOG_SOLVE_ARITHMETIC
return 0;
@ -1455,7 +1455,7 @@ static u8 cmp_extend_encodingN(afl_state_t *afl, struct cmp_header *h,
u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf,
u32 len, u8 do_reverse, u8 lvl, u8 *status) {
if (afl->fsrv.total_execs - last_update > screen_update) {
if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
show_stats(afl);
last_update = afl->fsrv.total_execs;
@ -1948,11 +1948,11 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
#ifndef CMPLOG_COMBINE
(void)(cbuf);
#endif
//#ifndef CMPLOG_SOLVE_TRANSFORM
// (void)(changed_val);
//#endif
// #ifndef CMPLOG_SOLVE_TRANSFORM
// (void)(changed_val);
// #endif
if (afl->fsrv.total_execs - last_update > screen_update) {
if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
show_stats(afl);
last_update = afl->fsrv.total_execs;
@ -1988,10 +1988,10 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
if (l0 >= 0x80 || ol0 >= 0x80) {
l0 -= 0x80;
l1 -= 0x80;
ol0 -= 0x80;
ol1 -= 0x80;
if (l0 >= 0x80) { l0 -= 0x80; }
if (l1 >= 0x80) { l1 -= 0x80; }
if (ol0 >= 0x80) { ol0 -= 0x80; }
if (ol1 >= 0x80) { ol1 -= 0x80; }
}
@ -2059,7 +2059,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
for (i = 0; i < its_len; ++i) {
if ((pattern[i] != buf[idx + i] && o_pattern[i] != orig_buf[idx + i]) ||
if ((pattern[i] != buf[idx + i] || o_pattern[i] != orig_buf[idx + i]) ||
*status == 1) {
break;
@ -2418,7 +2418,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
//#endif
// #endif
return 0;
@ -2592,6 +2592,8 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
// shape_len), check_if_text_buf((u8 *)&o->v1, shape_len), v0_len,
// o->v0, v1_len, o->v1);
// Note that this check differs from the line 1901, for RTN we are more
// opportunistic for adding to the dictionary than cmps
if (!memcmp(o->v0, orig_o->v0, v0_len) ||
(!found_one || check_if_text_buf((u8 *)&o->v0, v0_len) == v0_len))
maybe_add_auto(afl, o->v0, v0_len);
@ -2818,9 +2820,9 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
} else if ((lvl & LVL1)
//#ifdef CMPLOG_SOLVE_TRANSFORM
// #ifdef CMPLOG_SOLVE_TRANSFORM
|| ((lvl & LVL3) && afl->cmplog_enable_transform)
//#endif
// #endif
) {
if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) {

View File

@ -135,10 +135,19 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
if (new_mem != *mem && new_mem != NULL && new_size > 0) {
u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
memcpy(new_buf, new_mem, new_size);
/* if AFL_POST_PROCESS_KEEP_ORIGINAL is set then save the original memory
prior post-processing in new_mem to restore it later */
if (unlikely(afl->afl_env.afl_post_process_keep_original)) {
new_mem = *mem;
}
*mem = new_buf;
memcpy(*mem, new_mem, new_size);
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
}
@ -162,7 +171,18 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
/* everything as planned. use the potentially new data. */
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
len = new_size;
if (likely(!afl->afl_env.afl_post_process_keep_original)) {
len = new_size;
} else {
/* restore the original memory which was saved in new_mem */
*mem = new_mem;
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
}
}

View File

@ -108,6 +108,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->cmplog_lvl = 2;
afl->min_length = 1;
afl->max_length = MAX_FILE;
afl->switch_fuzz_mode = STRATEGY_SWITCH_TIME * 1000;
#ifndef NO_SPLICING
afl->use_splicing = 1;
#endif
@ -394,6 +395,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_statsd =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
} else if (!strncmp(env, "AFL_POST_PROCESS_KEEP_ORIGINAL",
afl_environment_variable_len)) {
afl->afl_env.afl_post_process_keep_original =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
} else if (!strncmp(env, "AFL_TMPDIR",
afl_environment_variable_len)) {

View File

@ -27,6 +27,45 @@
#include "envs.h"
#include <limits.h>
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
"finished..."};
char *get_fuzzing_state(afl_state_t *afl) {
u64 cur_ms = get_cur_time();
u64 last_find = cur_ms - afl->last_find_time;
u64 cur_run_time = cur_ms - afl->start_time;
u64 cur_total_run_time = afl->prev_run_time + cur_run_time;
if (unlikely(cur_run_time < 60 * 3 * 1000 ||
cur_total_run_time < 60 * 5 * 1000)) {
return fuzzing_state[0];
} else {
u64 last_find_100 = 100 * last_find;
u64 percent_cur = last_find_100 / cur_run_time;
u64 percent_total = last_find_100 / cur_total_run_time;
if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
return fuzzing_state[3];
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
return fuzzing_state[2];
} else {
return fuzzing_state[1];
}
}
}
/* Write fuzzer setup file */
void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
@ -1282,7 +1321,11 @@ void show_stats_normal(afl_state_t *afl) {
}
/* Last line */
SAYF(SET_G1 "\n" bSTG bLB bH30 bH20 bH2 bRB bSTOP cRST RESET_G1);
SAYF(SET_G1 "\n" bSTG bLB bH cCYA bSTOP " strategy:" cPIN
" %s " bSTG bH10 cCYA bSTOP " state:" cPIN
" %s " bSTG bH2 bRB bSTOP cRST RESET_G1,
afl->fuzz_mode == 0 ? "explore" : "exploit", get_fuzzing_state(afl));
#undef IB
@ -2260,7 +2303,12 @@ void show_init_stats(afl_state_t *afl) {
stringify_int(IB(0), min_us), stringify_int(IB(1), max_us),
stringify_int(IB(2), avg_us));
if (afl->timeout_given != 1) {
if (afl->timeout_given == 3) {
ACTF("Applying timeout settings from resumed session (%u ms).",
afl->fsrv.exec_tmout);
} else if (afl->timeout_given != 1) {
/* Figure out the appropriate timeout. The basic idea is: 5x average or
1x max, rounded up to EXEC_TM_ROUND ms and capped at 1 second.
@ -2302,11 +2350,6 @@ void show_init_stats(afl_state_t *afl) {
afl->timeout_given = 1;
} else if (afl->timeout_given == 3) {
ACTF("Applying timeout settings from resumed session (%u ms).",
afl->fsrv.exec_tmout);
} else {
ACTF("-t option specified. We'll use an exec timeout of %u ms.",

View File

@ -124,10 +124,19 @@ static void usage(u8 *argv0, int more_help) {
"\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n"
"Required parameters:\n"
" -i dir - input directory with test cases\n"
" -i dir - input directory with test cases (or '-' to resume, "
"also see \n"
" AFL_AUTORESUME)\n"
" -o dir - output directory for fuzzer findings\n\n"
"Execution control settings:\n"
" -P strategy - set fix mutation strategy: explore (focus on new "
"coverage),\n"
" exploit (focus on triggering crashes). You can also "
"set a\n"
" number of seconds after without any finds it switches "
"to\n"
" exploit mode, and back on new coverage (default: %u)\n"
" -p schedule - power schedules compute a seed's performance score:\n"
" fast(default), explore, exploit, seek, rare, mmopt, "
"coe, lin\n"
@ -156,6 +165,8 @@ static void usage(u8 *argv0, int more_help) {
"\n"
"Mutator settings:\n"
" -a - target input format, \"text\" or \"binary\" (default: "
"generic)\n"
" -g minlength - set min length of generated fuzz input (default: 1)\n"
" -G maxlength - set max length of generated fuzz input (default: "
"%lu)\n"
@ -211,7 +222,8 @@ static void usage(u8 *argv0, int more_help) {
" -e ext - file extension for the fuzz test input file (if "
"needed)\n"
"\n",
argv0, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE, FOREIGN_SYNCS_MAX);
argv0, STRATEGY_SWITCH_TIME, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE,
FOREIGN_SYNCS_MAX);
if (more_help > 1) {
@ -259,6 +271,8 @@ static void usage(u8 *argv0, int more_help) {
"AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
"AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected\n"
"AFL_IGNORE_PROBLEMS_COVERAGE: if set in addition to AFL_IGNORE_PROBLEMS - also\n"
" ignore those libs for coverage\n"
"AFL_IGNORE_TIMEOUTS: do not process or save any timeouts\n"
"AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
"AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
@ -292,6 +306,8 @@ static void usage(u8 *argv0, int more_help) {
PERSISTENT_MSG
"AFL_POST_PROCESS_KEEP_ORIGINAL: save the file as it was prior post-processing to the queue,\n"
" but execute the post-processed one\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_TARGET_ENV: pass extra environment variables to target\n"
"AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
@ -326,7 +342,7 @@ static void usage(u8 *argv0, int more_help) {
}
#ifdef USE_PYTHON
SAYF("Compiled with %s module support, see docs/custom_mutator.md\n",
SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
(char *)PYTHON_VERSION);
#else
SAYF("Compiled without Python module support.\n");
@ -489,14 +505,63 @@ int main(int argc, char **argv_orig, char **envp) {
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
while (
(opt = getopt(
argc, argv,
"+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YZ")) >
0) {
// still available: HjJkKqruvwz
while ((opt = getopt(argc, argv,
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
"T:UV:WXx:YZ")) > 0) {
switch (opt) {
case 'a':
if (!stricmp(optarg, "text") || !stricmp(optarg, "ascii") ||
!stricmp(optarg, "txt") || !stricmp(optarg, "asc")) {
afl->input_mode = 1;
} else if (!stricmp(optarg, "bin") || !stricmp(optarg, "binary")) {
afl->input_mode = 2;
} else {
FATAL("-a input mode needs to be \"text\" or \"binary\".");
}
break;
case 'P':
if (!stricmp(optarg, "explore") || !stricmp(optarg, "exploration")) {
afl->fuzz_mode = 0;
afl->switch_fuzz_mode = 0;
} else if (!stricmp(optarg, "exploit") ||
!stricmp(optarg, "exploitation")) {
afl->fuzz_mode = 1;
afl->switch_fuzz_mode = 0;
} else {
if ((afl->switch_fuzz_mode = (u32)atoi(optarg)) > INT_MAX) {
FATAL(
"Parameter for option -P must be \"explore\", \"exploit\" or a "
"number!");
} else {
afl->switch_fuzz_mode *= 1000;
}
}
break;
case 'g':
afl->min_length = atoi(optarg);
break;
@ -1216,6 +1281,10 @@ int main(int argc, char **argv_orig, char **envp) {
}
WARNF(
"Note that the MOpt mode is not maintained and is not as effective "
"as normal havoc mode.");
} break;
case 'h':
@ -1276,16 +1345,16 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
"Eißfeldt, Andrea Fioraldi and Dominik Maier");
OKF("afl++ is open source, get it at "
OKF("AFL++ is maintained by Marc \"van Hauser\" Heuse, Dominik Maier, Andrea "
"Fioraldi and Heiko \"hexcoder\" Eißfeldt");
OKF("AFL++ is open source, get it at "
"https://github.com/AFLplusplus/AFLplusplus");
OKF("NOTE: afl++ >= v3 has changed defaults and behaviours - see README.md");
OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md");
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
OKF("afl++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)");
OKF("AFL++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)");
OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz");
}
@ -1525,29 +1594,6 @@ int main(int argc, char **argv_orig, char **envp) {
}
if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
if (afl->custom_only) {
FATAL("Custom mutators are incompatible with MOpt (-L)");
}
u32 custom_fuzz = 0;
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
if (el->afl_custom_fuzz) { custom_fuzz = 1; }
});
if (custom_fuzz) {
WARNF("afl_custom_fuzz is incompatible with MOpt (-L)");
}
}
if (afl->afl_env.afl_max_det_extras) {
s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras);
@ -1764,16 +1810,6 @@ int main(int argc, char **argv_orig, char **envp) {
check_if_tty(afl);
if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; }
if (afl->afl_env.afl_custom_mutator_only) {
/* This ensures we don't proceed to havoc/splice */
afl->custom_only = 1;
/* Ensure we also skip all deterministic steps */
afl->skip_deterministic = 1;
}
get_core_count(afl);
atexit(at_exit);
@ -1822,8 +1858,107 @@ int main(int argc, char **argv_orig, char **envp) {
printf("DEBUG: rand %06d is %u\n", counter, rand_below(afl, 65536));
#endif
if (!getenv("AFL_CUSTOM_INFO_PROGRAM")) {
setenv("AFL_CUSTOM_INFO_PROGRAM", argv[optind], 1);
}
if (!getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT") && afl->fsrv.out_file) {
setenv("AFL_CUSTOM_INFO_PROGRAM_INPUT", afl->fsrv.out_file, 1);
}
if (!getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) {
u8 envbuf[8096] = "", tmpbuf[8096] = "";
for (s32 i = optind + 1; i < argc; ++i) {
strcpy(tmpbuf, envbuf);
if (strchr(argv[i], ' ') && !strchr(argv[i], '"') &&
!strchr(argv[i], '\'')) {
if (!strchr(argv[i], '\'')) {
snprintf(envbuf, sizeof(tmpbuf), "%s '%s'", tmpbuf, argv[i]);
} else {
snprintf(envbuf, sizeof(tmpbuf), "%s \"%s\"", tmpbuf, argv[i]);
}
} else {
snprintf(envbuf, sizeof(tmpbuf), "%s %s", tmpbuf, argv[i]);
}
}
setenv("AFL_CUSTOM_INFO_PROGRAM_ARGV", envbuf + 1, 1);
}
if (!getenv("AFL_CUSTOM_INFO_OUT")) {
setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR
}
setup_custom_mutators(afl);
if (afl->afl_env.afl_custom_mutator_only) {
if (!afl->custom_mutators_count) {
if (afl->shm.cmplog_mode) {
WARNF(
"No custom mutator loaded, using AFL_CUSTOM_MUTATOR_ONLY is "
"pointless and only allowed now to allow experiments with CMPLOG.");
} else {
FATAL(
"No custom mutator loaded but AFL_CUSTOM_MUTATOR_ONLY specified.");
}
}
/* This ensures we don't proceed to havoc/splice */
afl->custom_only = 1;
/* Ensure we also skip all deterministic steps */
afl->skip_deterministic = 1;
}
if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
if (afl->custom_only) {
FATAL("Custom mutators are incompatible with MOpt (-L)");
}
u32 custom_fuzz = 0;
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
if (el->afl_custom_fuzz) { custom_fuzz = 1; }
});
if (custom_fuzz) {
WARNF("afl_custom_fuzz is incompatible with MOpt (-L)");
}
}
write_setup_file(afl, argc, argv);
setup_cmdline_file(afl, argv + optind);
@ -1975,6 +2110,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {
u32 old_map_size = map_size;
map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
@ -1986,6 +2122,18 @@ int main(int argc, char **argv_orig, char **envp) {
afl->first_trace = ck_realloc(afl->first_trace, map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size);
if (old_map_size < map_size) {
memset(afl->var_bytes + old_map_size, 0, map_size - old_map_size);
memset(afl->top_rated + old_map_size, 0, map_size - old_map_size);
memset(afl->clean_trace + old_map_size, 0, map_size - old_map_size);
memset(afl->clean_trace_custom + old_map_size, 0,
map_size - old_map_size);
memset(afl->first_trace + old_map_size, 0, map_size - old_map_size);
memset(afl->map_tmp_buf + old_map_size, 0, map_size - old_map_size);
}
}
afl->argv = use_argv;
@ -2013,6 +2161,7 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("Re-initializing maps to %u bytes", new_map_size);
u32 old_map_size = map_size;
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
@ -2025,6 +2174,18 @@ int main(int argc, char **argv_orig, char **envp) {
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
if (old_map_size < new_map_size) {
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace_custom + old_map_size, 0,
new_map_size - old_map_size);
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
}
afl_fsrv_kill(&afl->fsrv);
afl_shm_deinit(&afl->shm);
afl->fsrv.map_size = new_map_size;
@ -2075,6 +2236,7 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
u32 old_map_size = map_size;
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
@ -2087,6 +2249,18 @@ int main(int argc, char **argv_orig, char **envp) {
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
if (old_map_size < new_map_size) {
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace_custom + old_map_size, 0,
new_map_size - old_map_size);
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
}
afl_fsrv_kill(&afl->fsrv);
afl_fsrv_kill(&afl->cmplog_fsrv);
afl_shm_deinit(&afl->shm);
@ -2209,6 +2383,7 @@ int main(int argc, char **argv_orig, char **envp) {
max_ms = afl->queue_buf[entry]->exec_us;
afl->fsrv.exec_tmout = max_ms;
afl->timeout_given = 1;
}
@ -2578,13 +2753,31 @@ int main(int argc, char **argv_orig, char **envp) {
} while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);
u64 cur_time = get_cur_time();
if (likely(afl->switch_fuzz_mode && afl->fuzz_mode == 0) &&
unlikely(cur_time > afl->last_find_time + afl->switch_fuzz_mode)) {
if (afl->afl_env.afl_no_ui) {
ACTF(
"No new coverage found for %llu seconds, switching to exploitation "
"strategy.",
afl->switch_fuzz_mode / 1000);
}
afl->fuzz_mode = 1;
}
if (likely(!afl->stop_soon && afl->sync_id)) {
if (likely(afl->skip_deterministic)) {
if (unlikely(afl->is_main_node)) {
if (unlikely(get_cur_time() >
if (unlikely(cur_time >
(afl->sync_time >> 1) + afl->last_sync_time)) {
if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) {
@ -2597,7 +2790,7 @@ int main(int argc, char **argv_orig, char **envp) {
} else {
if (unlikely(get_cur_time() > afl->sync_time + afl->last_sync_time)) {
if (unlikely(cur_time > afl->sync_time + afl->last_sync_time)) {
if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); }

View File

@ -2,7 +2,7 @@
american fuzzy lop++ - wrapper for llvm 11+ lld
-----------------------------------------------
Written by Marc Heuse <mh@mh-sec.de> for afl++
Written by Marc Heuse <mh@mh-sec.de> for AFL++
Maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
@ -210,7 +210,7 @@ static void edit_params(int argc, char **argv) {
if (strcmp(argv[i], "--afl") == 0) {
if (!be_quiet) OKF("afl++ test command line flag detected, exiting.");
if (!be_quiet) OKF("AFL++ test command line flag detected, exiting.");
exit(0);
}

View File

@ -30,8 +30,10 @@
*/
#define AFL_MAIN
#define AFL_SHOWMAP
#include "config.h"
#include "afl-fuzz.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
@ -62,15 +64,20 @@
#include <sys/types.h>
#include <sys/resource.h>
static afl_state_t *afl;
static char *stdin_file; /* stdin file */
static u8 *in_dir = NULL, /* input folder */
*out_file = NULL, *at_file = NULL; /* Substitution string for @@ */
*out_file = NULL, /* output file or directory */
*at_file = NULL, /* Substitution string for @@ */
*in_filelist = NULL; /* input file list */
static u8 outfile[PATH_MAX];
static u8 *in_data, /* Input data */
*coverage_map; /* Coverage map */
static u8 *in_data; /* Input data */
static u8 *coverage_map; /* Coverage map */
static u64 total; /* tuple content information */
static u32 tcnt, highest; /* tuple content information */
@ -91,7 +98,8 @@ static bool quiet_mode, /* Hide non-essential messages? */
no_classify, /* do not classify counts */
debug, /* debug mode */
print_filenames, /* print the current filename */
wait_for_gdb;
wait_for_gdb, /* wait for gdb to allow attaching */
code_cov; /* code coverage cmdline parameter */
static volatile u8 stop_soon, /* Ctrl-C pressed? */
child_crashed; /* Child crashed? */
@ -105,8 +113,9 @@ static sharedmem_t *shm_fuzz;
static const u8 count_class_human[256] = {
[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4,
[8] = 5, [16] = 6, [32] = 7, [128] = 8
[0] = 0, [1] = 1, [2] = 2, [3] = 3,
[4 ... 7] = 4, [8 ... 15] = 5, [16 ... 31] = 6, [32 ... 127] = 7,
[128 ... 255] = 8
};
@ -136,7 +145,39 @@ static void kill_child() {
}
static void classify_counts(afl_forkserver_t *fsrv) {
/* dummy functions */
u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
(void)afl;
(void)mem;
return a + b;
}
void show_stats(afl_state_t *afl) {
(void)afl;
}
void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
(void)afl;
(void)q;
}
fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
u32 i) {
(void)afl;
(void)fsrv;
(void)i;
return 0;
}
void classify_counts(afl_forkserver_t *fsrv) {
u8 *mem = fsrv->trace_bits;
const u8 *map = binary_mode ? count_class_binary : count_class_human;
@ -205,7 +246,15 @@ static void analyze_results(afl_forkserver_t *fsrv) {
total += fsrv->trace_bits[i];
if (fsrv->trace_bits[i] > highest) highest = fsrv->trace_bits[i];
if (!coverage_map[i]) { coverage_map[i] = 1; }
if (code_cov) {
if (coverage_map[i] < 255 && fsrv->trace_bits[i]) { coverage_map[i]++; }
} else {
coverage_map[i] |= fsrv->trace_bits[i];
}
}
@ -290,7 +339,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
if (cmin_mode) {
fprintf(f, "%u%u\n", fsrv->trace_bits[i], i);
fprintf(f, "%u%03u\n", i, fsrv->trace_bits[i]);
} else {
@ -308,12 +357,143 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
}
#if 0
static u32 write_results_to_file32(u32 *map, u8 *outfile) {
s32 fd;
u32 i, ret = 0;
if (!outfile || !*outfile) {
FATAL("Output filename not set (Bug in AFL++?)");
}
if (!strncmp(outfile, "/dev/", 5)) {
fd = open(outfile, O_WRONLY);
if (fd < 0) { PFATAL("Unable to open '%s'", out_file); }
} else if (!strcmp(outfile, "-")) {
fd = dup(1);
if (fd < 0) { PFATAL("Unable to open stdout"); }
} else {
unlink(outfile); /* Ignore errors */
fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", outfile); }
}
if (binary_mode) {
for (i = 0; i < map_size; i++) {
if (map[i]) { ret++; }
}
ck_write(fd, map, map_size, outfile);
close(fd);
} else {
FILE *f = fdopen(fd, "w");
if (!f) { PFATAL("fdopen() failed"); }
for (i = 0; i < map_size; i++) {
if (!map[i]) { continue; }
ret++;
total += map[i];
if (highest < map[i]) { highest = map[i]; }
fprintf(f, "%06u:%u\n", i, map[i]);
}
fclose(f);
}
return ret;
}
#endif
void pre_afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *mem, u32 len) {
static u8 buf[MAX_FILE];
u32 sent = 0;
if (unlikely(afl->custom_mutators_count)) {
ssize_t new_size = len;
u8 *new_mem = mem;
u8 *new_buf = NULL;
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
if (el->afl_custom_post_process) {
new_size =
el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
if (unlikely(!new_buf || new_size <= 0)) {
return;
} else {
new_mem = new_buf;
len = new_size;
}
}
});
if (new_mem != mem && new_mem != NULL) {
mem = buf;
memcpy(mem, new_mem, new_size);
}
if (unlikely(afl->custom_mutators_count)) {
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
if (el->afl_custom_fuzz_send) {
el->afl_custom_fuzz_send(el->data, mem, len);
sent = 1;
}
});
}
}
if (likely(!sent)) { afl_fsrv_write_to_testcase(fsrv, mem, len); }
}
/* Execute target application. */
static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
u32 len) {
afl_fsrv_write_to_testcase(fsrv, mem, len);
pre_afl_fsrv_write_to_testcase(fsrv, mem, len);
if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
@ -324,9 +504,9 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
}
if (fsrv->trace_bits[0] == 1) {
if (fsrv->trace_bits[0]) {
fsrv->trace_bits[0] = 0;
fsrv->trace_bits[0] -= 1;
have_coverage = true;
} else {
@ -555,9 +735,9 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
}
if (fsrv->trace_bits[0] == 1) {
if (fsrv->trace_bits[0]) {
fsrv->trace_bits[0] = 0;
fsrv->trace_bits[0] -= 1;
have_coverage = true;
} else {
@ -781,6 +961,103 @@ u32 execute_testcases(u8 *dir) {
}
u32 execute_testcases_filelist(u8 *fn) {
u32 done = 0;
u8 buf[4096];
u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
FILE *f;
if (!be_quiet) { ACTF("Reading from '%s'...", fn); }
if ((f = fopen(fn, "r")) == NULL) { FATAL("could not open '%s'", fn); }
while (fgets(buf, sizeof(buf), f) != NULL) {
struct stat st;
u8 *fn2 = buf, *fn3;
while (*fn2 == ' ') {
++fn2;
}
while (*fn2 &&
(fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' ||
fn2[strlen(fn2) - 1] == ' ')) {
fn2[strlen(fn2) - 1] = 0;
}
if (debug) { printf("Getting coverage for '%s'\n", fn2); }
if (!*fn2) { continue; }
if (lstat(fn2, &st) || access(fn2, R_OK)) {
WARNF("Unable to access '%s'", fn2);
continue;
}
++done;
if (!S_ISREG(st.st_mode) || !st.st_size) { continue; }
if ((fn3 = strrchr(fn2, '/'))) {
++fn3;
} else {
fn3 = fn2;
}
if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) {
WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2,
stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
}
if (!collect_coverage) {
snprintf(outfile, sizeof(outfile), "%s/%s", out_file, fn3);
}
if (read_file(fn2)) {
if (wait_for_gdb) {
fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
fprintf(stderr, "exec: kill -CONT %d\n", getpid());
kill(0, SIGSTOP);
}
showmap_run_target_forkserver(fsrv, in_data, in_len);
ck_free(in_data);
if (child_crashed && debug) { WARNF("crashed: %s", fn2); }
if (collect_coverage)
analyze_results(fsrv);
else
tcnt = write_results_to_file(fsrv, outfile);
}
}
return done;
}
/* Show banner. */
static void show_banner(void) {
@ -823,6 +1100,7 @@ static void usage(u8 *argv0) {
" With -C, -o is a file, without -C it must be a "
"directory\n"
" and each bitmap will be written there individually.\n"
" -I filelist - alternatively to -i, -I is a list of files\n"
" -C - collect coverage, writes all edges to -o and gives a "
"summary\n"
" Must be combined with -i.\n"
@ -835,6 +1113,10 @@ static void usage(u8 *argv0) {
"This tool displays raw tuple data captured by AFL instrumentation.\n"
"For additional help, consult %s/README.md.\n\n"
"If you use -i/-I mode, then custom mutator post_process send send "
"functionality\n"
"is supported.\n\n"
"Environment variables used:\n"
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
"AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
@ -893,10 +1175,17 @@ int main(int argc, char **argv_orig, char **envp) {
if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) {
while ((opt = getopt(argc, argv, "+i:I:o:f:m:t:AeqCZOH:QUWbcrshVXY")) > 0) {
switch (opt) {
case 'V':
code_cov = true;
collect_coverage = true;
quiet_mode = true;
setenv("__AFL_CODE_COVERAGE", "1", 1);
break;
case 's':
no_classify = true;
break;
@ -911,6 +1200,11 @@ int main(int argc, char **argv_orig, char **envp) {
in_dir = optarg;
break;
case 'I':
if (in_filelist) { FATAL("Multiple -I options not supported"); }
in_filelist = optarg;
break;
case 'o':
if (out_file) { FATAL("Multiple -o options not supported"); }
@ -1081,7 +1375,7 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'Y': // fallthough
case 'Y': // fallthrough
#ifdef __linux__
case 'X': /* NYX mode */
@ -1133,10 +1427,12 @@ int main(int argc, char **argv_orig, char **envp) {
if (optind == argc || !out_file) { usage(argv[0]); }
if (in_dir) {
if (in_dir && in_filelist) { FATAL("you can only specify either -i or -I"); }
if (in_dir || in_filelist) {
if (!out_file && !collect_coverage)
FATAL("for -i you need to specify either -C and/or -o");
FATAL("for -i/-I you need to specify either -C and/or -o");
}
@ -1193,7 +1489,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
if (in_dir) {
if (in_dir || in_filelist) {
/* If we don't have a file name chosen yet, use a safe default. */
u8 *use_dir = ".";
@ -1213,6 +1509,14 @@ int main(int argc, char **argv_orig, char **envp) {
// If @@ are in the target args, replace them and also set use_stdin=false.
detect_file_args(argv + optind, stdin_file, &fsrv->use_stdin);
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
fsrv->out_file = stdin_file;
fsrv->out_fd =
open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", stdin_file); }
} else {
// If @@ are in the target args, replace them and also set use_stdin=false.
@ -1266,6 +1570,8 @@ int main(int argc, char **argv_orig, char **envp) {
}
afl = calloc(1, sizeof(afl_state_t));
if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
@ -1297,7 +1603,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
#ifdef __linux__
if (!fsrv->nyx_mode && in_dir) {
if (!fsrv->nyx_mode && (in_dir || in_filelist)) {
(void)check_binary_signatures(fsrv->target_path);
@ -1378,28 +1684,66 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv->map_size = map_size;
} else {
afl_fsrv_start(fsrv, use_argv, &stop_soon,
(get_afl_env("AFL_DEBUG_CHILD") ||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
? 1
: 0);
}
if (in_dir) {
if (in_dir || in_filelist) {
afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
afl->afl_env.afl_custom_mutator_library =
getenv("AFL_CUSTOM_MUTATOR_LIBRARY");
afl->afl_env.afl_python_module = getenv("AFL_PYTHON_MODULE");
setup_custom_mutators(afl);
} else {
if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) {
WARNF(
"Custom mutator environment detected, this is only supported in "
"-i/-I mode!\n");
}
}
if (in_dir || in_filelist) {
DIR *dir_in, *dir_out = NULL;
u8 *dn = NULL;
if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
if (in_filelist) {
// if a queue subdirectory exists switch to that
u8 *dn = alloc_printf("%s/queue", in_dir);
if ((dir_in = opendir(dn)) != NULL) {
if (!be_quiet) ACTF("Reading from file list '%s'...", in_filelist);
closedir(dir_in);
in_dir = dn;
} else {
} else
// if a queue subdirectory exists switch to that
dn = alloc_printf("%s/queue", in_dir);
ck_free(dn);
if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
if ((dir_in = opendir(dn)) != NULL) {
closedir(dir_in);
in_dir = dn;
} else {
ck_free(dn);
}
if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
}
if (!collect_coverage) {
@ -1415,18 +1759,18 @@ int main(int argc, char **argv_orig, char **envp) {
} else {
if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL)
if ((coverage_map = (u8 *)malloc((map_size + 64))) == NULL) {
FATAL("coult not grab memory");
}
edges_only = false;
raw_instr_output = true;
}
atexit(at_exit_handler);
fsrv->out_file = stdin_file;
fsrv->out_fd =
open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
if (get_afl_env("AFL_DEBUG")) {
@ -1442,20 +1786,26 @@ int main(int argc, char **argv_orig, char **envp) {
}
afl_fsrv_start(fsrv, use_argv, &stop_soon,
(get_afl_env("AFL_DEBUG_CHILD") ||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
? 1
: 0);
map_size = fsrv->map_size;
if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
if (execute_testcases(in_dir) == 0) {
if (in_dir) {
FATAL("could not read input testcases from %s", in_dir);
if (execute_testcases(in_dir) == 0) {
FATAL("could not read input testcases from %s", in_dir);
}
} else {
if (execute_testcases_filelist(in_filelist) == 0) {
FATAL("could not read input testcases from %s", in_filelist);
}
}

View File

@ -24,7 +24,7 @@
int main(int argc, char **argv) {
int fd = 0;
int fd = 0, cnt;
char buff[8];
char *buf = buff;
@ -32,7 +32,6 @@ int main(int argc, char **argv) {
if (argc == 2) {
buf = argv[1];
printf("Input %s - ", buf);
} else {
@ -47,15 +46,19 @@ int main(int argc, char **argv) {
}
if (read(fd, buf, sizeof(buf)) < 1) {
if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) {
printf("Hum?\n");
return 1;
}
buf[cnt] = 0;
}
if (getenv("AFL_DEBUG")) fprintf(stderr, "test-instr: %s\n", buf);
// we support three input cases (plus a 4th if stdin is used but there is no
// input)
switch (buf[0]) {

View File

@ -28,7 +28,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
rm -f test-instr.plain.0 test-instr.plain.1
SKIP=
TUPLES=`echo 1|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'`
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 12 && {
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 22 && {
$ECHO "$GREEN[+] ${AFL_GCC} run reported $TUPLES instrumented locations which is fine"
} || {
$ECHO "$RED[!] ${AFL_GCC} instrumentation produces weird numbers: $TUPLES"
@ -152,7 +152,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
}
rm -f test-instr.plain.0 test-instr.plain.1
TUPLES=`echo 1|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'`
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 12 && {
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 22 && {
$ECHO "$GREEN[+] ${AFL_CLANG} run reported $TUPLES instrumented locations which is fine"
} || {
$ECHO "$RED[!] ${AFL_CLANG} instrumentation produces weird numbers: $TUPLES"

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