Compare commits

...

750 Commits

Author SHA1 Message Date
f596a297c4 Merge pull request #1832 from AFLplusplus/dev
v4.08c release
2023-08-10 08:42:17 +00:00
3721c65a0b v4.08c release 2023-08-10 10:41:55 +02:00
fa44d8f79f Merge pull request #1831 from AFLplusplus/dev
push to stable
2023-08-09 18:29:25 +00:00
55d696fbae code format 2023-08-09 17:14:13 +02:00
b4bd33961c Merge pull request #1821 from junwha0511/crashing-seeds-as-new-crash
Implement an option for treating crashing seeds as new crash
2023-08-09 14:39:25 +00:00
7f3b0a9503 Merge pull request #1829 from devnexen/fix_build_fuzzqueen
afl-fuzz-redqueen.c fix build, also forgotten math lib for ilog* calls
2023-08-09 14:33:23 +00:00
d9cadb2e7d -c - support 2023-08-09 16:31:30 +02:00
18d9234dfe Revert "-c - support"
This reverts commit 5618062cb5.
2023-08-09 16:29:56 +02:00
5618062cb5 -c - support 2023-08-09 16:28:04 +02:00
2c376f8994 afl-fuzz-redqueen.c fix build, also forgotten math lib for ilog* calls 2023-08-08 21:24:05 +01:00
a0aaae9b17 Merge pull request #1825 from devnexen/cpp_no_exceptions
disable exceptions on LLVM/GCC plugins, decreasing further the librar…
2023-08-06 13:45:40 +00:00
5b55cf84c1 disable exceptions on LLVM/GCC plugins, decreasing further the libraries's binaries size in the process. 2023-08-05 14:21:56 +01:00
2ce5113530 Merge pull request #1822 from jschwartzentruber/nyx-log
Add AFL_NYX_LOG to redirect NYX hprintf messages to a file.
2023-08-04 21:13:07 +00:00
247d8539fe Add AFL_NYX_LOG to redirect NYX hprintf messages to a file. 2023-08-04 15:39:57 -04:00
738a6c0731 Merge pull request #1824 from schumilo/dev
Nyx mode - minor changes
2023-08-04 10:50:46 +00:00
c2a0a24594 add someone else to the "list of contributors" :-) 2023-08-04 12:20:44 +02:00
08a6fd7c29 update the old nyx env var naming scheme
(to have a more consistent naming overall)
2023-08-04 12:13:06 +02:00
1fd1f0d8ce fix typo in nyx_mode/README.md 2023-08-04 11:54:58 +02:00
4f3aa90a5f update QEMU-Nyx submodule 2023-08-04 11:52:39 +02:00
fcdfe9e990 Define AFL_CRASHING_SEEDS_AS_NEW_CRASH as env variable
- and fix typo

Signed-off-by: Junwha <qbit@unist.ac.kr>
2023-08-04 18:36:58 +09:00
0a28bce016 update docs 2023-08-04 09:45:11 +02:00
79640acbf1 nits 2023-08-04 09:25:19 +02:00
4a9264444f Merge pull request #1823 from schumilo/dev
Nyx mode updates
2023-08-04 09:12:27 +02:00
5d78a6f592 update nyx mode readme (NYX_AUX_BUFFER_SIZE) 2023-08-03 14:43:16 +02:00
8f31086a7f make nyx aux buffer size configurable 2023-08-03 14:40:10 +02:00
641c551ba0 update Nyx submodules 2023-08-03 13:46:54 +02:00
a61e1ffe4d Add AFL_CRASHING_SEEDS_AS_NEW_CRASH to doc
Signed-off-by: Junwha <qbit@unist.ac.kr>
2023-08-02 19:21:41 +09:00
1429c9724e Add option for treating crashing input as new crash
Signed-off-by: Junwha Hong <qbit@unist.ac.kr>
2023-08-02 19:07:38 +09:00
0265b39c13 Merge pull request #1819 from jschwartzentruber/cxx-use-cppflags
C++ compilation should use CPPFLAGS
2023-08-01 09:55:10 +02:00
82635dc656 Use CPPFLAGS for C++ too. 2023-07-31 11:50:33 -04:00
f75c430365 Go back to correct unicornafl version 2023-07-30 22:02:18 +00:00
d0782a7f03 Various fixes for warnings, extends #1818 2023-07-30 21:59:57 +00:00
168ade3b70 Fix format specifiers (#1818)
* Update afl-mutations.h

Fix bug: compilation cannot pass when DEBUG macro is enabled

* Update afl-fuzz-one.c

Fix bug: compilation cannot pass when DEBUG macro is enabled
2023-07-30 23:51:24 +02:00
f87ba7ed63 doc fix 2023-07-28 15:18:12 +02:00
57c9dfda1f Merge pull request #1815 from mark0-cn/dev
fix the file descriptor without determining null
2023-07-28 13:19:21 +02:00
bd1648e707 fix the file descriptor without determining null 2023-07-28 17:32:59 +08:00
705cdf45fc temp cmplog fixes 2023-07-23 13:05:10 +02:00
5f813bbb86 improve cmplog level 3 2023-07-21 18:02:30 +02:00
4113b6ccad take care of uninstrumented mode for fuzz state and mode 2023-07-18 09:56:28 +02:00
7f17a94349 Merge pull request #1798 from AFLplusplus/dev
push to stable
2023-07-15 09:42:04 +02:00
2b8e528a3b interesting32_float 2023-07-13 17:12:55 +02:00
127c345161 nts 2023-07-13 14:26:32 +02:00
1132b08d7d Update afl-common.c typo 2023-07-13 13:37:47 +02:00
534b3eba14 qemu_get_symbol_addr.sh 2023-07-13 10:10:30 +02:00
2a34e84507 nits 2023-07-12 16:08:22 +02:00
a46d27fad5 nits 2023-07-10 18:29:21 +02:00
b547a6ab0d nits 2023-07-10 17:43:21 +02:00
e10e0e01e9 Merge pull request #1804 from WorksButNotTested/frida-fix
Increase dummy map size
2023-07-10 09:16:48 +02:00
a560e42a4d Increase dummy map size 2023-07-10 07:31:19 +01:00
20dcb40c53 fix cmin -T 2023-07-08 13:31:06 +02:00
d30272a64e Merge pull request #1801 from fuzzah/remove-extra-limits-h
remove extra limits.h in afl-ld-lto for BSD
2023-07-07 16:26:57 +02:00
e71de2f2b8 remove extra limits.h in afl-ld-lto for BSD 2023-07-07 16:57:45 +03:00
877b2bcab6 add limits.h to afl-ld-lto 2023-07-07 15:03:31 +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
497ff5ff79 Merge pull request #1795 from AFLplusplus/dev
push to stable
2023-07-03 10:53:02 +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
3426189c06 Merge pull request #1791 from AFLplusplus/dev
push to stable
2023-06-30 13:18:57 +03: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
641d02ab72 Merge pull request #1780 from AFLplusplus/dev
push to stable
2023-06-29 18:00:46 +03: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
a326c23210 Merge pull request #1706 from AFLplusplus/dev
push to stable, 4.06c release
2023-04-17 10:26:33 +02:00
7f734c96d1 v4.06c release 2023-04-17 10:25:10 +02:00
4d29e484b7 update nyx readme 2023-04-16 18:47:50 +02:00
56f7e3aa08 hidden -Y option for nyx, code format 2023-04-16 12:42:32 +02:00
87b9dc4ba0 Merge pull request #1702 from schumilo/dev
add Nyx support in afl-showmap, afl-tmin, afl-cmin and afl-analyze
2023-04-16 12:24:10 +02:00
d0b86bf055 pass absolute paths to libnyx 2023-04-16 06:23:38 +02:00
0a699d885b add some documentation 2023-04-16 06:19:39 +02:00
61aeb44863 remove redundant access() call 2023-04-16 05:19:09 +02:00
d213071e13 bump packer version 2023-04-16 05:16:01 +02:00
6d4234b305 bump libnyx version 2023-04-16 05:14:32 +02:00
059d470e8d improved Nyx tmp dir handling (additional sanity checks) 2023-04-16 04:42:09 +02:00
47833bcf9e fix remove_nyx_tmp_workdir function 2023-04-16 04:28:19 +02:00
2f6242d3f8 update docs 2023-04-15 12:28:39 +02:00
120d009e7d wasm support 2023-04-15 11:36:58 +02:00
e12acaa203 fix custom mutator C examples 2023-04-15 10:12:20 +02:00
8f6d9d66ef fix post_process 2023-04-15 09:11:33 +02:00
2b81d2d63f Merge pull request #1703 from YSaxon/patch-1
Fixing typo: & (background) to && (and)
2023-04-14 17:43:18 +02:00
50678ed369 Fixing typo: & (background) to && (and) 2023-04-14 11:24:10 -04:00
9764483693 remove warning 2023-04-14 16:27:32 +02:00
0c4f0dd4c4 oss-fuzz fix for LLVMFuzzerTestOneInput driver 2023-04-14 16:09:55 +02:00
b5f7f42cd0 update qemuafl, info in afl-plot 2023-04-14 10:22:00 +02:00
c34c3e2f5f add some sanity checks and remove duplicate nyx_shutdown calls 2023-04-14 06:24:46 +02:00
4f6ec6cb08 add NYX_REUSE_SNAPSHOT env-var option 2023-04-14 06:21:43 +02:00
a96cdc649f switch to latest libnyx API 2023-04-14 05:59:12 +02:00
e2fedce6ec bump libnyx version 2023-04-14 04:40:26 +02:00
afc47868ee bump QEMU-Nyx version
The QEMU-Nyx compile script does not set "--enable-gtk" anymore.
So it is no longer necessary to patch the compile_qemu_nyx.sh script manually.
2023-04-14 04:39:15 +02:00
eefd98f374 add Nyx support in various tools (like afl-cmin) 2023-04-14 02:25:33 +02:00
2adf5aac0f libfuzzer driver nits 2023-04-13 15:32:06 +02:00
f756734ad2 fix attempt at post_process implementation 2023-04-13 12:07:27 +02:00
6cc8d607fb remove -z option, use -p mmopt instead 2023-04-13 11:44:39 +02:00
824385f52c make llvm 17 work 2023-04-12 14:03:29 +02:00
d304f4e4f1 update lto doc 2023-04-12 11:24:56 +02:00
4f2d9eeaaa Merge pull request #1700 from AFLplusplus/dev
push to stable
2023-04-12 10:54:08 +02:00
743ae50775 nits 2023-04-12 10:53:23 +02:00
a5a122a533 Merge pull request #1698 from neuschaefer/nodefer
afl-cc: Don't offer __AFL_INIT() etc. in GCC/CLANG modes
2023-04-10 17:50:11 +02:00
1589e17213 Merge pull request #1697 from devnexen/llvm_instr_warning_fix
LLVM instrumentation disable build warning.
2023-04-10 14:35:56 +02:00
9e3e1a5512 afl-cc: Don't offer __AFL_INIT() etc. in GCC/CLANG modes
instrumentation/README.persistent_mode.md documents in the section about
deferred forkserver initialization:

> With the location selected, add this code in the appropriate spot:
>
> ```c
> #ifdef __AFL_HAVE_MANUAL_CONTROL
>   __AFL_INIT();
> #endif
> ```
>
> You don't need the #ifdef guards, but including them ensures that the program
> will keep working normally when compiled with a tool other than afl-clang-fast/
> afl-clang-lto/afl-gcc-fast.
>
> Finally, recompile the program with afl-clang-fast/afl-clang-lto/afl-gcc-fast
> (afl-gcc or afl-clang will *not* generate a deferred-initialization binary) -
> and you should be all set!


This strongly implies that you can compile a program that uses __AFL_INIT()
under an `#ifdef __AFL_HAVE_MANUAL_CONTROL` guard with afl-gcc/-clang.

However, this currently fails:

  $ cat example.c
  #include <stdio.h>

  int main(void) {
  #ifdef __AFL_HAVE_MANUAL_CONTROL
  	__AFL_INIT();
  #endif

  	puts("Hello");
  }
  $ afl-gcc example.c -o example
  afl-cc++4.06a by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: GCC-GCC
  [!] WARNING: You are using outdated instrumentation, install LLVM and/or gcc-plugin and use afl-clang-fast/afl-clang-lto/afl-gcc-fast instead!
  afl-as++4.06a by Michal Zalewski
  [+] Instrumented 1 locations (64-bit, non-hardened mode, ratio 100%).
  /usr/bin/ld: /tmp/ccuJHcpt.o: in function `main':
  /home/jn/dev/fuzz/AFLplusplus/example.c:5: undefined reference to `__afl_manual_init'
  collect2: error: ld returned 1 exit status


The issue here is an inconsistency in afl-gcc (i.e. afl-cc operating in GCC mode):

 - afl-cc defines __AFL_HAVE_MANUAL_CONTROL and __AFL_INIT unconditionally
 - __AFL_INIT relies on __afl_manual_init, which is defined in afl-compiler-rt.o
 - afl-cc doesn't link afl-compiler-rt in GCC or CLANG mode


Since afl-gcc/-clang is documented as not supporting deferred forkserver
initialization, this patch omits the definitions of __AFL_HAVE_MANUAL_CONTROL
and related macros in GCC/CLANG mode.

This restores the ability to compile a deferred-forkserver program under
afl-gcc, if it can also be compiled under gcc.

[ In case someone reads this an feels adventurous enough (as I did) to
  think about enabling deferred forkserver under afl-gcc: Whether the
  deferred forkserver actually works can be verified by placing a
  usleep(100000) or similar at the start of main (before __AFL_INIT()),
  and watching the execution speed. It doesn't work. ]
2023-04-10 13:47:19 +02:00
a0818c4fce LLVM instrumentation disable build warning.
Since clang 16 is the version for Ubuntu 23 04/Fedora 38 and is easy enough to fix..
2023-04-10 12:38:26 +01:00
0782ed3841 remove pointer to removed doc 2023-04-09 10:33:39 +02:00
0911525194 Merge pull request #1694 from neuschaefer/dev
afl-cc: Avoid casts of string literals to char*, in definition of __AFL_INIT() etc.
2023-04-08 17:33:41 +02:00
0eace0212e afl-cc: Avoid casts of string literals to char*, in definition of __AFL_INIT() etc.
With the right -W options, compilers may complain about the cast of
string literals (for PERSIST_SIG and DEFER_SIG) to (char*), and they're
right to do so, because string literals are constant. Since some
projects enable -Werror, this can lead to a broken build with afl-cc.

Let's simply cast to (const char *), which preserves the constness of
the string literal.
2023-04-08 17:24:02 +02:00
c1af004451 afl-whatsup tput 2023-04-08 15:29:43 +02:00
abd6b06fa4 Merge pull request #1693 from hardik05/patch-1
display instance name
2023-04-08 14:42:08 +02:00
35151cefe8 display instance name 2023-04-08 17:57:08 +05:30
75d7a09469 show custom mutator name in UI 2023-04-08 13:48:07 +02:00
f9851dbfbb hopefully better -z algorithm 2023-04-08 13:00:57 +02:00
400c5e92cb renaming 2023-04-07 09:41:22 +02:00
fcb5eda5d0 nit 2023-04-05 16:34:08 +02:00
d67ee17778 fix 2023-04-05 13:30:06 +02:00
dba93705a7 better new weighting 2023-04-05 13:07:22 +02:00
36127fb197 add -z switch 2023-04-05 12:59:20 +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
5fea071ae9 Merge pull request #1692 from nj00001/dev
fix getOperand out of range
2023-04-03 10:33:59 +02:00
a01138e1c8 fix getOperand out of range
This commit fixes a sloppy function call that should normally check the number of insn's Operand before calling insn's getOperand method. The fix is that if it is 0 it should continue the loop.
I solved problem https://github.com/AFLplusplus/AFLplusplus/issues/1688#issue-1648543691 using this modification
2023-04-03 15:32:52 +08:00
71e2aa5d2b more fix 2023-04-02 13:42:08 +02:00
21203c2ea6 fix 2023-04-02 12:39:02 +02:00
319b2e8e6f fix ui layout with slow targets in pizza mode 2023-04-02 12:08:54 +02:00
e46e0bce44 allow pizza mode to be disabled 2023-04-02 12:03:45 +02:00
4d02d8e43d fix buffer overflow in pizza mode :( 2023-04-02 11:52:36 +02:00
be96253f52 nits 2023-03-31 11:02:27 +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
2d0d1e267e better aflpp driver 2023-03-30 14:07:33 +02:00
145748a7e0 prepare new mutation strategies 2023-03-30 14:00:45 +02:00
a061e1304d further magma adaption 2023-03-30 10:18: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
dbdf2d79f2 magma support 2023-03-29 10:57:57 +02:00
48816417ee introspection 2023-03-29 10:13:18 +02:00
661b626c87 Merge pull request #1686 from tuliom/minor-fixes
Minor fixes
2023-03-28 19:29:04 +02:00
214e24fff0 fix arm64 build 2023-03-28 17:23:07 +02:00
67e8c4f100 Fix unsupported operands in .custom-format.py
Python 3.11 complains that int and str are unsupported operand types for
operator +.
2023-03-28 12:15:20 -03:00
5d9c1bc3a3 [afs-as] Allow debugging arguments after the input file
Clang may call as with extra debugging arguments after the input file,
e.g. as --64 -o /tmp/hello-617ff5.o /tmp/hello-6b6f52.s -g -gdwarf-4
2023-03-28 12:15:20 -03:00
c594a58583 Stop using removed pipeline extensions
LLVM commit 7ae6838defb21737963b1dd8ff9de7e87052c74f removed the
following extensions:

- PassManagerBuilder::EP_OptimizerLast
- PassManagerBuilder::EP_EnabledOnOptLevel0
- PassManagerBuilder::EP_FullLinkTimeOptimizationLast
2023-03-28 12:15:20 -03:00
01236f47bc nits 2023-03-28 16:50:05 +02:00
b1bfc1ae76 time_wo_finds in fuzzer_stats 2023-03-27 17:52:01 +02:00
0faa323f12 Merge pull request #1683 from cdown/cdown/2023-03-26/ver
Clarify confusing version message
2023-03-27 13:04:38 +02:00
2d3c5cc6d8 Clarify confusing version message
When running, the following gets printed in quick succession on startup:

    afl-fuzz++4.00c based on afl by Michal Zalewski and a large online community
    [...]
    [+] NOTE: This is v3.x which changes defaults and behaviours - see README.md

Don't assert that this is v3, just that v3+ changes defaults and
behaviours.
2023-03-26 20:44:57 -04:00
7101192865 Merge pull request #1682 from AFLplusplus/dev
push to stable
2023-03-26 13:36:31 +02:00
19f9612910 fix frida mode 2023-03-26 12:14:35 +02:00
d955409178 disable frida in the ci for the moment it is working nowhere 2023-03-25 20:37:08 +01:00
9bc5abc4ec reduce CI resources 2023-03-25 12:14:08 +01:00
64fd01d46c Merge pull request #1681 from AFLplusplus/dev
Push to stable
2023-03-25 10:47:58 +01:00
b2f9802f9f Merge pull request #1680 from yuawn/add_check_for_n_fuzz_update
add check for n_fuzz update
2023-03-25 10:47:02 +01:00
e24ae96361 add likely() to cksum check 2023-03-25 09:45:02 +00:00
0f62e0b167 add check for n_fuzz update 2023-03-25 09:28:35 +00:00
478f0bbc1e ci test 2023-03-21 16:23:51 +01:00
3d7bad99b6 Merge pull request #1678 from dmitris/patch-1
nit: fix minor typos
2023-03-21 16:22:57 +01:00
5c5b73df82 nit: fix minor typos
change "cannot be build" to "cannot be built"
2023-03-21 13:32:59 +01:00
24503fba5f Merge pull request #1668 from AFLplusplus/dev
push to stable
2023-03-17 12:47:33 +01:00
d80cedcf02 Merge pull request #1677 from AFLplusplus/classify
Classify
2023-03-17 11:01:17 +01:00
bd3855fe5d improve ci time 2023-03-15 10:18:33 +01:00
84274f2e5d more ci repair attempts 2023-03-15 10:16:46 +01:00
988028bb3b fix ci 2023-03-15 09:45:49 +01:00
ac4dd1605e fix ci 2023-03-15 09:44:11 +01:00
7ab689ef0e fix qemu_mode 2023-03-13 10:12:45 +01:00
e32e825372 macos ci debug 2023-03-10 15:26:38 +01:00
c3cf918bcb macos ci debug 2023-03-10 15:16:55 +01:00
af77dab666 macos ci debug 2023-03-10 15:12:15 +01:00
1d4f779d4d debug macos ci 2023-03-10 11:10:09 +01:00
4c7c78d926 enhance tests for macos 2023-03-10 10:59:52 +01:00
aabfe781fd enhance tests for macos 2023-03-10 10:22:35 +01:00
7a650e4866 Merge pull request #1672 from AFLplusplus/dev
Dev
2023-03-10 09:25:07 +01:00
30483919eb code format 2023-03-09 17:37:29 +01:00
5221938945 various fixes 2023-03-09 17:36:13 +01:00
dc7ef967d8 fix attempt at lsan 2023-03-09 14:56:38 +01:00
1385c24a7d fix qemuafl name range 2023-03-09 14:41:24 +01:00
cd57641705 fast schedules n_fuzz update after classify 2023-03-09 14:25:45 +01:00
e0866f51c7 support LLVMFuzzerTestOneInput -1 return 2023-03-09 13:57:03 +01:00
aa125f8246 Merge pull request #1667 from amitelka/feature/opt_statsfile_update_interval
Added env variable to allow custom interval update of fuzzer_stats file
2023-03-06 11:51:56 +01:00
b571e88bd3 Fixed according to CR 2023-03-06 12:40:54 +02:00
2f128e0dbd Revert "Merge pull request #1665 from devnexen/llvm_inst_mem_leaks"
This reverts commit e5f8c7a612, reversing
changes made to e6a05382b8.
2023-03-06 10:13:35 +01:00
e5f8c7a612 Merge pull request #1665 from devnexen/llvm_inst_mem_leaks
llvm instrumentation trying to delete all static data
2023-03-06 10:09:17 +01:00
e6a05382b8 fix IGNORE_PROBLEMS and update qemuafl 2023-03-06 09:59:52 +01:00
cb8296bdb0 fix ci 2023-03-06 09:25:14 +01:00
6b75fe1831 fix ci 2023-03-06 09:16:32 +01:00
a30664c563 fix ci 2023-03-06 09:15:05 +01:00
7034348c57 Changed warning message to use const instead of magic 2023-03-05 20:44:18 +02:00
e9e440d7f3 Fixed according to PR comment, moved cli flag to an env variable 2023-03-05 20:25:39 +02:00
5e7f8a51e0 Added minimum interval of 1 sec to avoid undefined behaviour in interval 2023-03-05 18:27:07 +02:00
403d95d2d2 auto code format fixes 2023-03-05 18:21:35 +02:00
07cf27cddc Added flag -u to allow custom interval to update fuzzer_stats file 2023-03-05 18:16:21 +02:00
bc61c90fb6 llvm instrumentation trying to delete all static data
at module end of pass with llvm_shutdown and is concurrent safe.
2023-03-04 14:46:38 +00:00
6af195916c Merge pull request #1662 from kobrineli/fix-exit-on-time
Fix exit on time
2023-03-03 08:26:44 +01:00
7c07437941 Fix. 2023-03-02 17:42:34 +03:00
85fa17451d Fix exit on time. 2023-03-02 17:04:43 +03:00
12262d3a63 Merge pull request #1661 from AFLplusplus/weight
fix item weighting
2023-03-02 13:56:07 +01:00
2ff0ff7a90 Merge pull request #1659 from AFLplusplus/dev
update docs
2023-02-28 11:03:39 +01:00
d8ba0caab3 update docs 2023-02-28 11:03:09 +01:00
86bf009792 div hits 2023-02-27 18:34:35 +01:00
ea14f3fd40 Merge pull request #1653 from AFLplusplus/dev
push to stable
2023-02-25 09:20:47 +01:00
2b5c9954f6 Merge pull request #1654 from tokatoka/typo
Redqueen typo
2023-02-25 08:53:59 +01:00
65d4d10762 Update afl-fuzz-redqueen.c 2023-02-24 23:14:40 +09:00
2bea77e28a fix custom python splice optout 2023-02-23 17:09:06 +01:00
add2eb42c0 nits 2023-02-23 15:26:41 +01:00
ffdb5ec9b1 improve cmplog ci 2023-02-23 14:32:54 +01:00
eb5c1ee4f3 Merge pull request #1650 from AFLplusplus/autotoken
Autotoken
2023-02-23 11:49:28 +01:00
eeccb2da69 nits 2023-02-23 11:45:26 +01:00
0c0a6c3bfa regression fix 2023-02-23 11:22:40 +01:00
a293281b9b Merge pull request #1652 from wtdcode/fix-clang-rt
Also install libclang-rt-dev
2023-02-23 10:41:05 +01:00
8a8e350f34 Also install libclang-rt-dev 2023-02-22 22:48:03 +01:00
c33f8751e3 Merge pull request #1651 from AFLplusplus/dev
Dev
2023-02-21 01:11:00 +01:00
6f4b5ae083 nit 2023-02-21 01:07:02 +01:00
91b7f1c9f2 fix regression 2023-02-21 01:05:46 +01:00
b786558dea Revert "LLVM cmplog factoring custom Instruction iterator with added restriction"
This reverts commit 8bc3fa1df2.
2023-02-20 15:43:54 +01:00
ebaac23a51 clarify AFL_NO_STARTUP_CALIBRATION 2023-02-20 11:42:40 +01:00
9da3a2ed45 fixes 2023-02-16 13:11:11 +01:00
1faf6f6731 fix 2023-02-16 07:47:36 +01:00
7f2bafbb8b remove some debug 2023-02-15 11:54:39 +01:00
ae94499503 fix 2023-02-15 11:48:49 +01:00
04356ecbbe fix 2023-02-15 11:28:43 +01:00
2090f17a9b opt 2023-02-15 11:23:42 +01:00
668f5e1fa9 debug output 2023-02-15 09:32:32 +01:00
a7c43484e1 bettern custom mut warning 2023-02-15 07:45:45 +01:00
b352e3d1cc Merge pull request #1646 from devnexen/llvm_custom_unique_refactoring
LLVM cmplog factoring custom Instruction iterator with added restriction
2023-02-14 05:42:45 +01:00
8bc3fa1df2 LLVM cmplog factoring custom Instruction iterator with added restriction 2023-02-13 23:00:15 +00:00
80eabd6e8a AFL_LLVM_DICT2FILE_NO_MAIN support 2023-02-13 11:34:14 +01:00
5a0100c6ee add to readme 2023-02-13 10:01:02 +01:00
54fa78d32c autodisable and better performance 2023-02-13 09:52:57 +01:00
61439859ce cleanup 2023-02-13 08:26:30 +01:00
240f6421d8 optimize performance 2023-02-13 08:23:47 +01:00
7eaef449a1 remove ALTERNATIVE_TOKENIZE 2023-02-13 08:14:04 +01:00
3881ccd0b7 enable arm64 container build again 2023-02-13 07:16:47 +01:00
6030df2f56 Merge pull request #1639 from apach301/fix-score-calculation
Increase fuzz_level for mopt_common_fuzzing
2023-02-12 17:55:48 +01:00
141c324eb9 revert perfscore 0 fix attempt 2023-02-12 17:55:16 +01:00
bac8d25bc2 Merge pull request #1643 from YSaxon/dev
Cmplog should search for unprefixed target in PATH, not PWD
2023-02-12 17:48:31 +01:00
d3cdeabf92 Add myself to contributors :) 2023-02-09 22:04:18 +00:00
673a0a3866 add test for unprefixed path 2023-02-09 22:02:47 +00:00
f2be73186e cmplog exec with target_path 2023-02-09 21:37:35 +00:00
025f617d6a Merge pull request #1640 from marcellomaugeri/stable
Fix typo in Nyx-mode
2023-02-08 17:04:41 +01:00
c86d06849b Update forkserver.h
Fix typo
2023-02-08 15:54:27 +01:00
05b1189a55 Update afl-forkserver.c
Fix typo
2023-02-08 15:53:49 +01:00
846e910e0c Validate -M and -p power schedule options 2023-02-08 13:50:03 +03:00
ab26356bf7 Increase fuzz_level for mopt_common_fuzzing
Change performance score calculation for lin and quad power schedules
2023-02-07 19:50:31 +03:00
03e6d33a40 fix perfscore 0 check 2023-02-07 15:27:31 +01:00
6596284cc4 endless loop fix 2023-02-06 17:59:17 +01:00
dbfa23b40a fixes 2023-02-06 16:38:52 +01:00
1a9f96858b Merge pull request #1635 from stulle123/patch-1
Add Qemu Deferred Initialization Example for Binary-Only Targets
2023-02-06 15:27:54 +01:00
24e36212d5 Rename fuzzing harness 2023-02-06 09:04:33 -05:00
ca2e8a1bf6 Add Qemu deferred initialization example 2023-02-06 08:38:20 -05:00
ca063c92d2 more options 2023-02-06 08:52:12 +01:00
8a2547073c more options 2023-02-06 08:51:20 +01:00
e612028255 dict fix 2023-02-05 14:19:10 +01:00
f99656e22b create from thin air, max mutation 2023-02-05 13:15:06 +01:00
90f61552f7 changes 2023-02-04 15:39:03 +01:00
ec87abda93 readme 2023-02-04 14:37:28 +01:00
e1434bcfcd more autotoken options 2023-02-04 14:34:47 +01:00
53c19a807c code indent 2023-02-04 14:09:50 +01:00
3a6dea420f Merge pull request #1634 from nataraj-hates-MS-for-stealing-github/stable
Explicitly print error code if sched_setaffinity fails
2023-02-04 13:55:29 +01:00
df9ef84f5e Explicitly print error code if sched_setaffinity fails 2023-02-03 14:32:17 +00:00
25b4b32627 small fix to compiler rt 2023-02-02 12:13:48 +01:00
4946e9cc3a small fix to compiler rt 2023-02-02 12:08:45 +01:00
f01bf77604 Merge pull request #1632 from AFLplusplus/dev
push to stable
2023-02-02 09:32:19 +01:00
91ccbf3f68 fix 2023-02-01 17:16:51 +01:00
686382c328 Merge pull request #1631 from WorksButNotTested/arm64
Arm64
2023-01-31 09:00:20 +01:00
0d55feb11d Add support for disabling branch suppression 2023-01-31 07:00:02 +00:00
31727f36a8 Changes to revert broken branch suppression fix 2023-01-31 06:23:00 +00:00
b5d8d4c866 comment 2023-01-29 10:07:33 +01:00
b81bc8eb6f fix warning 2023-01-28 12:14:57 +01:00
47f35d29ac fix 2023-01-27 14:32:18 +01:00
4a54555a1a Merge pull request #1628 from AFLplusplus/dev
Dev
2023-01-27 13:40:48 +01:00
3e8a691a81 Merge pull request #1627 from AFLplusplus/dev
push to stable
2023-01-27 11:46:59 +01:00
33eba1fc56 update changelog 2023-01-27 10:17:16 +01:00
4ec26fc7cb update UNICORNAFL_VERSION 2023-01-27 09:51:47 +01:00
5db7be5ee2 Updated unicorn, added while to build sh 2023-01-27 01:33:05 +01:00
614265897c ignored llvm testcase files 2023-01-27 00:31:16 +01:00
f4a13585a1 better asan defaults everwhere 2023-01-26 12:21:47 +01:00
e332d37d4e update unicorn 2023-01-26 12:08:38 +01:00
90a259d523 new sanitizer option handling 2023-01-25 15:36:19 +01:00
322e5e2fb6 Merge pull request #1623 from WorksButNotTested/osx
Fix FRIDA mode for OSX x64
2023-01-25 15:02:57 +01:00
1b4e1d75b3 cmplog decision updates 2023-01-25 13:52:22 +01:00
c52a0a15c8 Fix FRIDA mode for OSX arm64 2023-01-25 12:37:38 +00:00
c5a84a124c fixes 2023-01-25 13:33:17 +01:00
16f71bfa24 Merge pull request #1621 from devnexen/llvm_16_upd
LLVM plugin 16+ support proposal.
2023-01-25 10:26:16 +01:00
b0898de377 Fix FRIDA mode for OSX x64 2023-01-25 08:24:34 +00:00
0251b9bfd8 llvm15 pcguard_init earlier constructor 2023-01-24 14:56:14 +01:00
5837322310 erase the switch instruction from the current parent 2023-01-23 22:56:04 +00:00
4063a3eb4c nit 2023-01-23 12:50:57 +01:00
8bc7b3cf26 add CFI variant for gcc 2023-01-23 12:45:21 +01:00
afd2ea90df LLVM plugin 16+ support proposal.
- Lifting the standard to C++17.
- Beyond the cosmetic changes, it boils down to BasicBlock::getInstList being
  no longer available (and reading the header it is no accident).
2023-01-20 22:12:35 +00:00
bd2cb4cd1c more default tokens 2023-01-20 12:22:29 +01:00
67cfe4f6d4 nits 2023-01-19 22:24:24 +01:00
628b4b6002 enhance examples 2023-01-19 17:24:56 +01:00
86d3c65559 nit 2023-01-19 15:59:57 +01:00
afff6f642c optimize 2023-01-19 13:41:48 +01:00
eeca3a0b29 lots of fixes 2023-01-19 11:52:19 +01:00
151a8facae autotokens: stats 2023-01-18 23:16:18 +01:00
45567791c6 autotokens: define disable splice 2023-01-18 23:09:16 +01:00
17752465e6 nit 2023-01-18 22:31:55 +01:00
14d8eb9e40 autotoken: splicing; splice_optout 2023-01-18 22:17:14 +01:00
8fe5e29104 ignore timeout env option 2023-01-18 14:56:26 +01:00
22f757a169 fix 2023-01-18 14:33:06 +01:00
0db662db7b fix 2023-01-18 14:21:44 +01:00
70f4b456fa fixes 2023-01-18 13:58:27 +01:00
a41fd5cc5c alternate tokenize, options 2023-01-18 11:46:28 +01:00
efe57c9368 more whitespace 2023-01-17 09:57:23 +01:00
33f41e3974 autotokens: print stats at exit 2023-01-17 09:52:35 +01:00
4b915207c4 autotokens - much better tokenizer 2023-01-16 17:05:04 +01:00
8cc1c6c54e nits 2023-01-16 10:18:08 +01:00
10b82c7277 fixes 2023-01-15 18:17:28 +01:00
35801bed7a dictionary support 2023-01-15 13:47:31 +01:00
5163a49350 fix input file deletion 2023-01-15 08:26:15 +01:00
7abbc8d740 ensure out fd is closed in shmem mode 2023-01-15 08:18:11 +01:00
9548af52b2 texts 2023-01-14 09:30:25 +01:00
e3dadbfe0f autotokens 2023-01-13 18:27:22 +01:00
75fb918a37 skip buiding arm64 container :( 2023-01-12 11:46:52 +01:00
c3d7612c97 fix macos ci 2023-01-12 09:56:40 +01:00
e2acba57bf Merge pull request #1614 from devnexen/gotcpu_macos_arm64
afl-gotcpu disable thread_affinity api on macos arm64.
2023-01-12 09:55:14 +01:00
e4b7c4e6c9 afl-gotcpu disable thread_affinity api on macos arm64. 2023-01-11 21:26:24 +00:00
e4ff0ebd56 4.06a init 2023-01-05 13:52:32 +01:00
3b6fcd911a Merge pull request #1610 from AFLplusplus/dev
push to stable
2023-01-05 13:51:20 +01:00
a3b56e7280 rust custom mutator: mark external fns unsafe 2023-01-05 12:25:02 +00:00
57e7408774 add update info to changelog 2023-01-05 12:15:54 +00:00
462e55da0c Updated rust custom mutator bindgen, fixed clippy lints 2023-01-05 12:12:01 +00:00
a8b6365a90 LibAFL custom mutator: unused variables with underscores 2023-01-05 11:49:58 +00:00
aa39921e49 Update LibAFL custom mutator to latest 2023-01-05 11:47:37 +00:00
885a6fc106 4.05c release 2023-01-05 12:43:53 +01:00
db9fc49ef8 Add pip to docker 2023-01-05 07:03:45 +00:00
94d1740390 Fix automatic unicornafl bindings install for python 2023-01-05 06:48:07 +00:00
1c91d8ca79 code format 2023-01-04 17:08:29 +01:00
081c480e36 fix 2023-01-04 15:18:14 +01:00
8d9620eca2 try afl-showmap fix for qemu 2023-01-04 10:21:35 +01:00
35f09e11a4 welcome 2023 2023-01-03 09:38:07 +01:00
026404c452 Merge pull request #1608 from ahpaleus/custom-format-pip
Support for clang-format from pip in the .custom-format.py
2022-12-30 15:03:23 +01:00
ffe89e8f2d fix makefile typo 2022-12-29 10:25:18 +01:00
31d4dc8a38 Merge pull request #1607 from ahpaleus/argv-persistent-fuzzing
Argv_fuzz feature persistent fuzzing + cleanup
2022-12-28 17:54:32 +01:00
e847b9948d prevent weighting < 1 2022-12-28 17:40:56 +01:00
1bcc9bfa91 clang-format pip 2022-12-28 13:05:44 +01:00
8817da8ae4 Removed a modified file from pr 2022-12-28 11:10:38 +01:00
1149b13185 undo custom-format 2022-12-28 11:07:49 +01:00
fd27b2c9be makefile cleanup 2022-12-28 11:04:53 +01:00
5670c847bd readme update 2022-12-28 11:00:14 +01:00
99c67defb4 readme cleanup 2022-12-28 10:58:44 +01:00
209527907f makefile update 2022-12-28 10:50:05 +01:00
489f2d4d97 makefile update 2022-12-28 10:49:31 +01:00
0710e4f17c makefile update 2022-12-28 10:47:08 +01:00
c090abb00d makefile update 2022-12-28 10:44:02 +01:00
107ebb7d49 makefile update 2022-12-28 10:40:17 +01:00
4ff37da709 makefile update 2022-12-28 10:34:56 +01:00
86ec1b9d71 makefile update 2022-12-28 09:55:14 +01:00
c0c985a278 minor changes 2022-12-28 09:48:10 +01:00
f28f6adbce update 2022-12-28 09:41:22 +01:00
51e0707d4d readme update 2022-12-28 09:27:22 +01:00
3188cac1d0 cleanup 2022-12-27 16:57:30 +01:00
b189640a92 cleanup 2022-12-27 16:54:36 +01:00
3d031f93a6 update 2022-12-27 16:15:52 +01:00
3a134edd88 makefile update 2022-12-27 15:51:50 +01:00
6e5c08b653 makefile update 2022-12-27 15:50:53 +01:00
67ae1d5839 makefile update 2022-12-27 15:49:22 +01:00
b4000dda8d Merge branch 'argv-persistent-fuzzing' of github.com:ahpaleus/AFLplusplus into argv-persistent-fuzzing 2022-12-27 15:48:17 +01:00
0062a14aa3 makefile update 2022-12-27 15:48:06 +01:00
4626435dbf Merge branch 'AFLplusplus:stable' into argv-persistent-fuzzing 2022-12-27 15:47:22 +01:00
a0eee2bd92 makefile update 2022-12-27 15:44:49 +01:00
6fe38b2138 argv fuzz persistent 2022-12-27 15:39:47 +01:00
342081d5ee make CI green 2022-12-23 16:33:00 +01:00
65729a2637 Merge pull request #1606 from devnexen/afl_untracer_fbsd_upd
afl-untracer freebsd 13.1 and above update.
2022-12-23 15:22:25 +01:00
401811a97d afl-untracer freebsd 13.1 and above update.
with the new kern.elf*.allow_wx setting, we try
 to make sure we still can make the maps w/x,
fixing few build warnings while at it.
2022-12-23 12:47:16 +00:00
60dc37a8cf Merge pull request #1592 from AFLplusplus/dev
Dev
2022-12-20 14:31:09 +01:00
0165ca8c6c hide queue introspection behind define 2022-12-20 13:36:56 +01:00
96f05c7f69 fix fork server timeout in afl-showmap 2022-12-20 10:21:36 +01:00
195bf87f18 Merge pull request #1603 from devnexen/solaris_fuzz_run_fix
fix Solaris/Illumos build
2022-12-20 10:04:03 +01:00
e30c20cd28 fix Solaris/Illumos build 2022-12-16 20:44:49 +00:00
e26c173041 code format 2022-12-13 09:13:52 +01:00
85b44bb730 add cmplog envs 2022-12-12 18:35:05 +01:00
42e6f98005 Merge pull request #1601 from devnexen/silent_more_clang15_warnings
Silent more deprecation warning for clang 15 and onwards
2022-12-08 01:21:43 +01:00
e02753fd7d Silent more deprecation warning for clang 15 and onwards 2022-12-07 19:48:20 +00:00
bf1617d354 fix warning 2022-12-05 16:15:29 +01:00
149366507d update qemuafl 2022-12-04 04:09:12 +01:00
9239ab01df Merge pull request #1598 from WorksButNotTested/arm64
Arm64
2022-12-01 22:09:01 +01:00
0885dda767 Fix branch suppression for ARM64 2022-12-01 18:19:47 +00:00
6dd9764cf6 Bump FRIDA version 2022-12-01 18:19:41 +00:00
b5f2a17235 Merge pull request #1596 from a-shvedov/patch-1
Update README.md
2022-11-26 22:22:07 +01:00
32a331ab43 Update README.md 2022-11-26 10:34:14 +03:00
28af7cb9bd Merge pull request #1593 from WorksButNotTested/arm
Fixes to make things easier to build for ARM
2022-11-24 00:58:25 +01:00
9734d0b3c0 Fixes to make things easier to build for ARM 2022-11-23 18:18:26 +00:00
4124a272d8 crash fix for queue analysis feature 2022-11-23 10:27:30 +01:00
a16726039f shorten text 2022-11-21 13:28:07 +01:00
6655d66a9b Merge pull request #1588 from anfedotoff/dev
Add CASR as third party tool in docs.
2022-11-21 13:24:33 +01:00
2c39c51263 casr-afl short description in fuzzing_in_depth. 2022-11-21 15:18:19 +03:00
ef0921d858 Add CASR as third party tool in docs. 2022-11-21 12:59:23 +03:00
b7c87350cf Make env description extra clear 2022-11-18 17:04:16 +01:00
f667279b70 Merge pull request #1583 from kobrineli/fix-argv-fuzz
Fix argv-fuzz.
2022-11-18 12:30:44 +01:00
26a5bd625c write queue statistics 2022-11-18 12:23:18 +01:00
d7e788a3c0 Exit on read error. 2022-11-18 13:35:51 +03:00
170e8122ae Merge pull request #1584 from WorksButNotTested/cmplog
Fix cmplog block ID generation to use hashes rather than bit-shifts
2022-11-18 11:11:05 +01:00
ad6a4cf1c2 Fix cmplog block ID generation to use hashes rather than bit-shifts 2022-11-18 08:11:26 +00:00
ba788591dc Handle read() error. 2022-11-17 17:38:45 +03:00
8f9726d4a9 Fix delim. 2022-11-17 17:27:13 +03:00
3d07f0ab79 Handle empty input. 2022-11-17 14:14:11 +03:00
4b7126c46c nits 2022-11-17 10:58:20 +01:00
903b5607bc Fix argv-fuzz. 2022-11-16 18:19:50 +03:00
8cdc48f73a Merge pull request #1579 from AFLplusplus/dev
push to stable
2022-11-15 09:27:54 +01:00
e5c725c4e0 custom mutator fix 2022-11-14 22:47:34 +01:00
1cc2029179 update changelog 2022-11-14 21:50:31 +01:00
46beedadd7 Merge pull request #1580 from guyf2010/dev
Add option for random cmplog colorization
2022-11-14 21:48:50 +01:00
3cc5019fe4 fix warnings 2022-11-14 21:45:08 +01:00
57257ce656 fix python 2022-11-14 21:41:07 +01:00
e2ebebce83 fix python 2022-11-14 21:37:08 +01:00
4a7cd53f64 custom_send example 2022-11-14 21:26:17 +01:00
7f7cbe9623 Ensure random colorization always changes byte 2022-11-14 12:19:44 +00:00
189255d3f4 cmplog random replacement code formatting 2022-11-13 14:57:53 +00:00
bb81fb784e Add option for random cmplog colorization 2022-11-13 14:37:33 +00:00
c5f8869778 afl_custom_fuzz_send added 2022-11-11 10:46:45 +01:00
b2f12c3712 llvm debug 2022-11-10 16:12:37 +01:00
2323952d62 update for llvm16 compile instructions 2022-11-10 15:06:02 +01:00
dfc6d0fbf7 nits 2022-11-10 14:49:14 +01:00
c24939e812 Merge pull request #1576 from AFLplusplus/persistent_mode_always
Persistent mode always
2022-11-10 14:46:01 +01:00
b868758cd7 more llvm16 fixes 2022-11-10 12:06:00 +01:00
513a6ce7b6 try llvm 16 fix 2022-11-10 11:55:29 +01:00
c1562a7cde Didn't mean to change that 2022-11-09 03:34:37 +01:00
0496390526 fmt 2022-11-09 02:32:13 +00:00
d65cf10bad Always enable persistent mode, no env/bincheck needed 2022-11-09 03:28:06 +01:00
21372473a1 warn for -t none 2022-11-02 15:21:46 +01:00
a8c1ba0d59 Merge pull request #1570 from edmcman/showmap-timeout
Fix -t none in afl-showmap
2022-11-02 15:19:56 +01:00
1bc7cf759d Use a long timeout instead of 0 for afl-showmap -t none 2022-11-02 08:30:24 -04:00
c058ce37bb remove python2 reference 2022-11-01 14:05:31 +01:00
9dab653563 update unicorn 2022-10-30 15:26:43 +01:00
6553e24b22 add env 2022-10-30 15:26:17 +01:00
2d640558a0 Merge pull request #1573 from AFLplusplus/dev
push to stable
2022-10-29 15:12:07 +02:00
ec19a9b068 fix 2022-10-29 13:55:05 +02:00
c0eaf6f47a nits 2022-10-29 11:15:23 +02:00
0b6007a49c fix fork server kill signals for qemu, unicorn and nyx mode 2022-10-29 10:00:36 +02:00
2da6b6bf42 Add braces 2022-10-28 08:04:06 -04:00
15a26d3303 Fix -t none in afl-showmap 2022-10-27 12:12:55 -04:00
340647c5f1 Merge pull request #1568 from AFLplusplus/dev
fix usecase
2022-10-25 23:26:42 +02:00
a6a26d8153 fix usecase 2022-10-25 22:13:31 +02:00
a075cddef6 Merge pull request #1561 from AFLplusplus/dev
push to stable
2022-10-24 20:46:31 +02:00
05e0825d66 changelog update 2022-10-24 20:06:57 +02:00
02502c1a54 Merge pull request #1563 from nbars/stable
Fix child reaping on fuzzer termination
2022-10-24 20:01:36 +02:00
2cbe49c6eb Update usage messages 2022-10-24 18:08:29 +02:00
102b749c07 AFL_FORK_SERVER_KILL_SIGNAL backwards compatiblity
If `AFL_KILL_SIGNAL` is set, `AFL_FORK_SERVER_KILL_SIGNAL` is set
to the same value.
2022-10-24 17:54:03 +02:00
7512316b46 Add AFL_FORK_SERVER_KILL_SIGNAL environment variable.
The AFL_FORK_SERVER_KILL_SIGNAL variable allows to configure the signal
used to kill the fork server on termination.
2022-10-21 12:47:00 +02:00
f84ea69660 Fix child reaping on fuzzer termination
This commit contains the following changes:
    - Call `waitpid()` on the child and the fork server when terminating the
      fuzzer; thus, we do not end up with zombies.
    - Rename `fsrv.kill_signal` to `fsrv.child_kill_signal`, since the
      documentation states that the signal is used to terminate the *child*.
    - Use SIGTERM instead of fsrv.(child)_kill_signal, thus the fork server
      can always reap the child.
2022-10-20 18:08:07 +02:00
e9ecfed81d Merge pull request #1562 from edmcman/dev
Fix -rpath argument
2022-10-20 15:00:23 +02:00
0e908d5b1e Fix -rpath argument 2022-10-20 08:26:55 -04:00
5ccf389414 nits 2022-10-19 10:41:40 +02:00
96ee3fb899 nits 2022-10-19 10:28:53 +02:00
ca9854a924 nits 2022-10-19 10:17:12 +02:00
9a77a6fa92 nits 2022-10-19 08:50:17 +02:00
23580e2cb6 Fix afl-showmap usage output (#1560) 2022-10-18 18:55:59 +02:00
089e773d1e update qemuafl 2022-10-17 17:47:37 +02:00
26d4771678 Fix exit_on_time (#1555) 2022-10-15 12:06:11 +02:00
d1e1bbc713 Merge pull request #1553 from AFLplusplus/dev
4.05a init
2022-10-12 17:09:49 +02:00
77ebab64d3 Merge pull request #1554 from WorksButNotTested/be8
Be8
2022-10-12 08:19:28 +02:00
939575de4b Bump to FRIDA 16.0.1 2022-10-11 18:15:51 +01:00
7461c52278 Fixes for x64 2022-10-11 18:15:51 +01:00
fac6491ad0 Bump FRIDA version 2022-10-11 18:15:51 +01:00
4bb4d6ebfd ARM branch suppression 2022-10-11 18:15:51 +01:00
23e477caa7 Updates following FRIDA API changes 2022-10-11 18:15:51 +01:00
182013a26f 4.05a init fix 2022-10-11 15:44:26 +02:00
bd27adf9af v4.05a init 2022-10-11 15:41:51 +02:00
cbfa5207ba Merge pull request #1551 from AFLplusplus/dev
push to stable
2022-10-11 15:40:55 +02:00
bac6ba8907 v4.04c 2022-10-11 15:39:27 +02:00
de9d1ff4a0 doc fixes 2022-10-11 12:43:06 +02:00
e6e82948bf fastexit + code format 2022-10-11 08:53:49 +02:00
c5008362c6 Merge pull request #1543 from quinox/feat-make-on-gentoo
Support building LTO on Gentoo
2022-10-10 17:08:01 +02:00
db4fa9319d Fix #1548 2022-10-10 14:37:16 +02:00
680e6e91a1 Support building LTO on Gentoo 2022-10-08 09:51:26 +02:00
2107ece114 auto shmem fuzzing (#1541)
* auto shmem fuzzing

* print warning when forcing shmem fuzzing

* typos

* Shmem always

* typo fix

* fixes

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-10-07 15:40:04 +02:00
5e04c9693b fix qemu_mode speed bug 2022-10-04 08:39:07 +02:00
9e4137a3eb Enabled tricore arch for unicornafl 2022-10-03 22:58:21 +02:00
jma
97fb0b5099 fix Rust speedtest example dependency (#1542) 2022-10-03 12:06:43 +02:00
9c6aebba05 typos 2022-10-03 11:04:23 +02:00
3e0fe86465 Merge pull request #1539 from devnexen/reallocarr
libdislocator adding netbsd's reallocarr
2022-10-01 18:27:02 +02:00
0eeddda2c8 libdislocator adding netbsd's reallocarr 2022-10-01 16:12:32 +01:00
586aec7116 Fixed typo in README.llvm.md (#1538)
Co-authored-by: van Hauser <vh@thc.org>
2022-09-29 12:42:04 +02:00
7e0171006a Merge pull request #1537 from AFLplusplus/dev
push to stable
2022-09-28 22:56:28 +02:00
96b7742611 enhancements to afl-persistent-config and afl-system-config 2022-09-28 21:36:25 +02:00
3c21e9f0d1 another attempt at stand-alone map fix 2022-09-27 15:51:16 +02:00
0f72a7473f Fix docs for fuzz_count in python 2022-09-27 13:45:39 +00:00
1ce0dcac3f fix standalone running with shared libs 2022-09-26 11:55:03 +02:00
77f253c1b9 fix custom mutator build scripts 2022-09-26 03:43:45 +02:00
ed54532f29 make gcc_plugin compilable for gcc 3.6.0 2022-09-23 23:19:10 +02:00
6ed40d5a08 4.04a init 2022-09-20 18:12:37 +02:00
ad4b727476 Merge pull request #1527 from AFLplusplus/dev
push to stable
2022-09-20 17:37:20 +02:00
41fe8b6ab9 update qemuafl 2022-09-20 12:58:20 +02:00
38ab1eda6e 4.03c 2022-09-19 12:15:10 +02:00
6afca4f073 fix help links 2022-09-17 14:05:24 +02:00
9cfe1d1394 afl-cmin -A 2022-09-17 13:44:34 +02:00
badd9694d2 Merge pull request #1525 from AFLplusplus/dev
push to stable
2022-09-17 11:58:41 +02:00
0623a73a5c fix docs 2022-09-17 11:56:39 +02:00
2e8a459d0b Merge pull request #1523 from lszekeres/stable
Fix null pointers.
2022-09-17 11:53:54 +02:00
02db8685f1 Fix null pointers. 2022-09-16 23:04:47 -04:00
2f0cc088b5 Merge pull request #1522 from AFLplusplus/dev
fix unicornafl
2022-09-16 14:42:07 +02:00
05b1e49bc2 fix unicornafl 2022-09-16 12:29:45 +02:00
9d45e8d810 Merge pull request #1521 from AFLplusplus/dev
update unicorn
2022-09-16 11:54:37 +02:00
5435d5c175 update unicorn 2022-09-16 11:54:12 +02:00
869138aa41 Merge pull request #1519 from AFLplusplus/dev
push to stable
2022-09-16 11:51:17 +02:00
5bf8bffd4a changelog 2022-09-16 10:57:54 +02:00
af5e8370af fix LLVMFuzzerRunDriver 2022-09-16 10:57:13 +02:00
9d9d2cada9 Typo 2022-09-16 10:53:53 +02:00
4e73828645 Added unicorn changes to changelog 2022-09-15 18:24:26 +02:00
d610821679 Re-enabled unicorn for aarch64 2022-09-15 18:23:07 +02:00
453d554fb5 Correctly multi-process unicorn builds 2022-09-15 17:33:07 +02:00
9a0cee6ce1 add temporary fix for uc until unicorn publishes a new release 2022-09-15 17:15:15 +02:00
2125950a81 undo tmp changes in unicorn_mode 2022-09-15 15:50:51 +02:00
8e3aee8a1a Fixed unicorn_mode for aarch64, update unicorn 2022-09-15 15:43:00 +02:00
636025df9a forgot correct callback 2022-09-15 10:32:34 +02:00
b7a2c7e698 try LLVMFuzzerRunDriver support 2022-09-15 10:13:46 +02:00
a7877416a8 update changelog 2022-09-15 10:00:05 +02:00
061bd75953 Merge pull request #1518 from nikic/fix-lto
Fix LTO with LLVM 15
2022-09-15 09:58:03 +02:00
b27a4a3689 Fix loading and registeration of LTO pass for new pass manager 2022-09-14 15:54:29 +02:00
a194a82bcd Fixed typo in README.lto.md (#1517)
typo fixed
2022-09-14 15:05:30 +02:00
5452d4652b Fix naming clash between AFL's sancov LTO pass and upstream sancov pass
There was some confusion here due to name reuse. The
initializeModuleSanitizerCoverageLegacyPassPass() function was
actually calling the initialization of the upstream pass (which
no longer supports legacy PM and thus fails to build on LLVM 15).
The intention was to call the LTO initialization here.

Fix this by renaming symbols to avoid collision.
2022-09-14 11:36:05 +02:00
9b6ad933cd Allow building LTO component with LLVM 15 2022-09-14 11:35:55 +02:00
36c46b9579 Fix LLVM 15 build
By removing ModuleSanitizerCoverageLegacyPass, which is completely
unused.

There was some confusing between the initialization function for
the upstream sancov pass and AFLs own implementation.
2022-09-14 10:58:22 +02:00
08f44f4e5d code format 2022-09-10 19:09:32 +02:00
f12ee5c7d2 Merge pull request #1512 from devnexen/libdislocator_attrs
libdislocator apply few attributes for few compiler optimisations.
2022-09-10 18:45:47 +02:00
258f4ee529 libdislocator apply few attributes for few compiler optimisations. 2022-09-10 11:43:19 +01:00
c06c297933 Merge pull request #1511 from tocic/fix/docs_typos
Fix typos in docs
2022-09-10 10:06:20 +02:00
ffad6f3f09 Fix typos in docs 2022-09-10 07:41:19 +03:00
3e30b700dd Dockerfile enhancements 2022-09-09 10:20:30 +02:00
05ac236a6b update changelog 2022-09-07 17:10:03 +02:00
6bb2500707 Merge pull request #1509 from CodeLogicError/stable
analyze_run_target return dataconversion
2022-09-07 17:07:15 +02:00
d06f8b2a93 analyze_run_target return dataconversion
analyze_run_target create u64 data and return u32
2022-09-07 19:59:20 +08:00
0fe39e4768 egrep -> grep -e 2022-09-05 13:57:32 +02:00
0c122aeee6 Merge pull request #1505 from tokatoka/stable
Fix my name in Changelog.md
2022-08-31 10:45:47 +02:00
3a31c5c985 update qemuafl 2022-08-30 16:07:35 +02:00
644b544bc0 fix my name 2022-08-30 13:05:22 +02:00
147654f871 Merge pull request #1504 from AFLplusplus/dev
pcguard off-by-one fix
2022-08-26 23:52:44 +02:00
2775271b17 pcguard off-by-one fix 2022-08-26 18:27:38 +02:00
413e68ab6d Merge pull request #1499 from AFLplusplus/dev
push to stable
2022-08-25 15:56:36 +02:00
eb5a914ef6 fix pizza mode 2022-08-25 15:52:46 +02:00
88ff8aa81e fix gcc_mode cmplog 2022-08-25 08:47:30 +02:00
804e845a94 Merge pull request #1500 from kobrineli/fix-dummy-mapsize
Change map size dummy value.
2022-08-19 13:46:15 +02:00
47d5dbbead Fix. 2022-08-19 14:33:15 +03:00
4ebde72f28 Change map size dummy value. 2022-08-19 14:33:15 +03:00
b4cb3784a5 add malloc check 2022-08-19 13:17:01 +02:00
7b2145b914 shorter calibration 2022-08-19 09:16:17 +02:00
361263b0f2 better no dry run 2022-08-18 08:06:17 +02:00
eeab1afd57 alt no cal 2022-08-17 12:50:15 +02:00
843ef46b21 fix docs 2022-08-16 10:05:52 +02:00
d7abf6936c fix afl-cmin 2022-08-16 09:46:11 +02:00
2462c61df9 fix new map size extraction for afl-gcc 2022-08-15 19:22:46 +02:00
ba14c353c0 get map size from binaries within afl-cmin* 2022-08-15 18:31:45 +02:00
f00d83afbc filter pipe in gcc_mode 2022-08-15 17:38:53 +02:00
4e98071385 better handling of -fsanitize=..,...,.. lists 2022-08-14 14:40:26 +02:00
1a3b463c4c add build report 2022-08-14 13:00:55 +02:00
dae5843b0e Merge pull request #1496 from devnexen/libtokencap_update_hotsummer
libtokencap annotate overriden calls to pyt them together in a special
2022-08-14 12:49:52 +02:00
3200e6515b add AFL_NO_STARTUP_CALIBRATION feature 2022-08-14 12:30:23 +02:00
130b1f7864 libtokencap annotate overriden calls to pyt them together in a special
elf (sub)section and improve their locality.
2022-08-13 07:23:34 +01:00
89d6e306f2 Merge pull request #1494 from WorksButNotTested/armhf
Armhf
2022-08-11 20:19:28 +02:00
2c8228dbe4 Changes to allow cross-compilation of pngtest 2022-08-11 17:55:23 +01:00
b5002d74b4 Fixed warnings about format strings 2022-08-11 17:55:23 +01:00
ddea91de1d Fixed makefile formatting 2022-08-11 17:55:23 +01:00
39dadab065 fix qemu_mode 2022-08-10 09:05:13 +02:00
e377ee3c57 Merge pull request #1491 from WorksButNotTested/unstable
Fix unstable test makefile
2022-08-09 10:51:07 +02:00
38fba71546 add env var 2022-08-09 10:49:05 +02:00
3c811de917 update qemuafl 2022-08-09 10:19:16 +02:00
63b12c5f86 Fix unstable test makefile 2022-08-09 08:25:00 +01:00
79a69b14ef 4.03a 2022-08-08 15:30:48 +02:00
273 changed files with 15734 additions and 4762 deletions

View File

@ -3,10 +3,10 @@
# american fuzzy lop++ - custom code formatter
# --------------------------------------------
#
# Written and maintaned by Andrea Fioraldi <andreafioraldi@gmail.com>
# Written and maintained by Andrea Fioraldi <andreafioraldi@gmail.com>
#
# Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -18,24 +18,57 @@
import subprocess
import sys
import os
import re
# import re # TODO: for future use
import shutil
import importlib.metadata
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use
CURRENT_LLVM = os.getenv('LLVM_VERSION', 16)
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
def check_clang_format_pip_version():
"""
Check if the correct version of clang-format is installed via pip.
Returns:
bool: True if the correct version of clang-format is installed,
False otherwise.
"""
# Check if clang-format is installed
if importlib.util.find_spec('clang_format'):
# Check if the installed version is the expected LLVM version
if importlib.metadata.version('clang-format')\
.startswith(str(CURRENT_LLVM)+'.'):
return True
else:
# Return False, because the clang-format version does not match
return False
else:
# If the 'clang_format' package isn't installed, return False
return False
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use
with open(".clang-format") as f:
fmt = f.read()
CURRENT_LLVM = os.getenv('LLVM_VERSION', 14)
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
CLANG_FORMAT_PIP = check_clang_format_pip_version()
if shutil.which(CLANG_FORMAT_BIN) is None:
CLANG_FORMAT_BIN = f"clang-format-{CURRENT_LLVM}"
if shutil.which(CLANG_FORMAT_BIN) is None:
if shutil.which(CLANG_FORMAT_BIN) is None \
and CLANG_FORMAT_PIP is False:
print(f"[!] clang-format-{CURRENT_LLVM} is needed. Aborted.")
print(f"Run `pip3 install \"clang-format=={CURRENT_LLVM}.*\"` \
to install via pip.")
exit(1)
if CLANG_FORMAT_PIP:
CLANG_FORMAT_BIN = shutil.which("clang-format")
COLUMN_LIMIT = 80
for line in fmt.split("\n"):
line = line.split(":")
@ -54,43 +87,43 @@ def custom_format(filename):
for line in src.split("\n"):
if line.lstrip().startswith("#"):
if line[line.find("#") + 1 :].lstrip().startswith("define"):
if line[line.find("#") + 1:].lstrip().startswith("define"):
in_define = True
if (
"/*" in line
and not line.strip().startswith("/*")
and line.endswith("*/")
and len(line) < (COLUMN_LIMIT - 2)
"/*" in line
and not line.strip().startswith("/*")
and line.endswith("*/")
and len(line) < (COLUMN_LIMIT - 2)
):
cmt_start = line.rfind("/*")
line = (
line[:cmt_start]
+ " " * (COLUMN_LIMIT - 2 - len(line))
+ line[cmt_start:]
line[:cmt_start]
+ " " * (COLUMN_LIMIT - 2 - len(line))
+ line[cmt_start:]
)
define_padding = 0
if last_line is not None and in_define and last_line.endswith("\\"):
last_line = last_line[:-1]
define_padding = max(0, len(last_line[last_line.rfind("\n") + 1 :]))
define_padding = max(0, len(last_line[last_line.rfind("\n") + 1:]))
if (
last_line is not None
and last_line.strip().endswith("{")
and line.strip() != ""
last_line is not None
and last_line.strip().endswith("{")
and line.strip() != ""
):
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
elif (
last_line is not None
and last_line.strip().startswith("}")
and line.strip() != ""
last_line is not None
and last_line.strip().startswith("}")
and line.strip() != ""
):
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
elif (
line.strip().startswith("}")
and last_line is not None
and last_line.strip() != ""
line.strip().startswith("}")
and last_line is not None
and last_line.strip() != ""
):
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line

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
@ -23,34 +23,36 @@ jobs:
- name: debug
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
- name: update
run: sudo apt-get update && sudo apt-get upgrade -y
run: sudo apt-get update
# && sudo apt-get upgrade -y
- name: install packages
run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build
#run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip
run: sudo apt-get install -y -m -f build-essential git libtool libtool-bin automake flex bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip
- name: compiler installed
run: gcc -v; echo; clang -v
- name: install gcc plugin
run: sudo apt-get install -y -m -f --install-suggests $(readlink /usr/bin/gcc)-plugin-dev
- name: build afl++
run: make distrib ASAN_BUILD=1
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

133
.gitignore vendored
View File

@ -1,100 +1,107 @@
.test
.test2
.sync_tmp
.vscode
!coresight_mode
!coresight_mode/coresight-trace
*.dSYM
*.o
*.o.tmp
*.pyc
*.so
*.swp
*.pyc
*.dSYM
as
a.out
ld
in
out
core*
compile_commands.json
.sync_tmp
.test
.test2
.vscode
afl-analyze
afl-analyze.8
afl-as
afl-as.8
afl-c++
afl-c++.8
afl-cc
afl-cc.8
afl-clang
afl-clang++
afl-clang-fast
afl-clang-fast++
afl-clang-lto
afl-clang-lto++
afl-fuzz
afl-g++
afl-gcc
afl-gcc-fast
afl-g++-fast
afl-gotcpu
afl-ld
afl-ld-lto
afl-cs-proxy
afl-qemu-trace
afl-showmap
afl-tmin
afl-analyze.8
afl-as.8
afl-clang-fast++.8
afl-clang-fast.8
afl-clang-lto.8
afl-clang-lto
afl-clang-lto++
afl-clang-lto++.8
afl-clang-lto.8
afl-cmin.8
afl-cmin.bash.8
afl-cs-proxy
afl-frida-trace.so
afl-fuzz
afl-fuzz.8
afl-c++.8
afl-cc.8
afl-gcc.8
afl-g++
afl-g++.8
afl-gcc
afl-gcc.8
afl-gcc-fast
afl-gcc-fast.8
afl-g++-fast
afl-g++-fast.8
afl-gotcpu
afl-gotcpu.8
afl-plot.8
afl-showmap.8
afl-system-config.8
afl-tmin.8
afl-whatsup.8
afl-persistent-config.8
afl-c++
afl-cc
afl-ld
afl-ld-lto
afl-lto
afl-lto++
afl-lto++.8
afl-lto.8
afl-persistent-config.8
afl-plot.8
afl-qemu-trace
afl-showmap
afl-showmap.8
afl-system-config.8
afl-tmin
afl-tmin.8
afl-whatsup.8
a.out
as
compile_commands.json
core*
examples/afl_frida/afl-frida
examples/afl_frida/frida-gum-example.c
examples/afl_frida/frida-gum.h
examples/afl_frida/libtestinstr.so
examples/afl_network_proxy/afl-network-client
examples/afl_network_proxy/afl-network-server
examples/aflpp_driver/libAFLDriver.a
examples/aflpp_driver/libAFLQemuDriver.a
gmon.out
in
ld
libAFLDriver.a
libAFLQemuDriver.a
out
qemu_mode/libcompcov/compcovtest
qemu_mode/qemu-*
qemu_mode/qemuafl
unicorn_mode/samples/*/\.test-*
unicorn_mode/samples/*/output/
test/.afl_performance
test-instr
test/output
test/test-c
test/test-cmplog
test/test-compcov
test/test-instr.ts
test/test-persistent
test/unittests/unit_hash
test/unittests/unit_list
test/unittests/unit_maybe_alloc
test/unittests/unit_preallocable
test/unittests/unit_list
test/unittests/unit_rand
test/unittests/unit_hash
examples/afl_network_proxy/afl-network-server
examples/afl_network_proxy/afl-network-client
examples/afl_frida/afl-frida
examples/afl_frida/libtestinstr.so
examples/afl_frida/frida-gum-example.c
examples/afl_frida/frida-gum.h
examples/aflpp_driver/libAFLDriver.a
examples/aflpp_driver/libAFLQemuDriver.a
libAFLDriver.a
libAFLQemuDriver.a
test/.afl_performance
gmon.out
afl-frida-trace.so
unicorn_mode/samples/*/output/
unicorn_mode/samples/*/\.test-*
utils/afl_network_proxy/afl-network-client
utils/afl_network_proxy/afl-network-server
utils/plot_ui/afl-plot-ui
*.o.tmp
utils/afl_proxy/afl-proxy
utils/optimin/build
utils/optimin/optimin
utils/persistent_mode/persistent_demo
utils/persistent_mode/persistent_demo_new
utils/persistent_mode/test-instr
!coresight_mode
!coresight_mode/coresight-trace
vuln_prog
utils/plot_ui/afl-plot-ui
vuln_prog

View File

@ -6,21 +6,32 @@
#
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
# Only available on specific ARM64 boards
ENV NO_CORESIGHT=1
# Possible but unlikely in a docker container
ENV NO_NYX=1
### Only change these if you know what you are doing:
# LLVM 15 does not look good so we stay at 14 to still have LTO
ENV LLVM_VERSION=14
# GCC 12 is producing compile errors for some targets so we stay at GCC 11
ENV GCC_VERSION=11
### No changes beyond the point unless you know what you are doing :)
ARG DEBIAN_FRONTEND=noninteractive
ENV NO_ARCH_OPT=1
ENV IS_DOCKER=1
RUN apt-get update && apt-get full-upgrade -y && \
apt-get install -y --no-install-recommends wget ca-certificates && \
apt-get install -y --no-install-recommends wget ca-certificates apt-utils && \
rm -rf /var/lib/apt/lists/*
ENV LLVM_VERSION=14
ENV GCC_VERSION=11
RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \
wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key
@ -28,15 +39,15 @@ RUN apt-get update && \
apt-get -y install --no-install-recommends \
make cmake automake meson ninja-build bison flex \
git xz-utils bzip2 wget jupp nano bash-completion less vim joe ssh psmisc \
python3 python3-dev python3-setuptools python-is-python3 \
python3 python3-dev python3-pip python-is-python3 \
libtool libtool-bin libglib2.0-dev \
apt-utils apt-transport-https gnupg dialog \
gnuplot-nox libpixman-1-dev \
apt-transport-https gnupg dialog \
gnuplot-nox libpixman-1-dev bc \
gcc-${GCC_VERSION} g++-${GCC_VERSION} gcc-${GCC_VERSION}-plugin-dev gdb lcov \
clang-${LLVM_VERSION} clang-tools-${LLVM_VERSION} libc++1-${LLVM_VERSION} \
libc++-${LLVM_VERSION}-dev libc++abi1-${LLVM_VERSION} libc++abi-${LLVM_VERSION}-dev \
libclang1-${LLVM_VERSION} libclang-${LLVM_VERSION}-dev \
libclang-common-${LLVM_VERSION}-dev libclang-cpp${LLVM_VERSION} \
libclang-common-${LLVM_VERSION}-dev libclang-rt-${LLVM_VERSION}-dev libclang-cpp${LLVM_VERSION} \
libclang-cpp${LLVM_VERSION}-dev liblld-${LLVM_VERSION} \
liblld-${LLVM_VERSION}-dev liblldb-${LLVM_VERSION} liblldb-${LLVM_VERSION}-dev \
libllvm${LLVM_VERSION} libomp-${LLVM_VERSION}-dev libomp5-${LLVM_VERSION} \
@ -56,6 +67,8 @@ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0
RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path
ENV PATH=$PATH:/etc/cargo/bin
RUN apt clean -y
ENV LLVM_CONFIG=llvm-config-${LLVM_VERSION}
ENV AFL_SKIP_CPUFREQ=1
ENV AFL_TRY_AFFINITY=1
@ -64,10 +77,6 @@ ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov && \
(cd afl-cov && make install) && rm -rf afl-cov
# Build currently broken
ENV NO_CORESIGHT=1
ENV NO_UNICORN_ARM64=1
WORKDIR /AFLplusplus
COPY . .
@ -85,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$(__git_ps1) \$ '"'" >> ~/.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
@ -91,19 +91,23 @@ ifneq "$(SYS)" "Darwin"
#ifeq "$(HAVE_MARCHNATIVE)" "1"
# SPECIAL_PERFORMANCE += -march=native
#endif
# OS X does not like _FORTIFY_SOURCE=2
ifndef DEBUG
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
endif
#ifndef DEBUG
# CFLAGS_OPT += -D_FORTIFY_SOURCE=1
#endif
else
# On some odd MacOS system configurations, the Xcode sdk path is not set correctly
SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib
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
LDFLAGS = -lkstat -lrt -lsocket -lnsl
endif
ifdef STATIC
@ -146,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
@ -181,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
@ -195,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))
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
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
@ -210,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
@ -221,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
@ -232,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
@ -251,17 +255,17 @@ endif
ifneq "$(findstring FreeBSD, $(SYS))" ""
override CFLAGS += -pthread
override LDFLAGS += -lpthread
override LDFLAGS += -lpthread -lm
endif
ifneq "$(findstring NetBSD, $(SYS))" ""
override CFLAGS += -pthread
override LDFLAGS += -lpthread
override LDFLAGS += -lpthread -lm
endif
ifneq "$(findstring OpenBSD, $(SYS))" ""
override CFLAGS += -pthread
override LDFLAGS += -lpthread
override LDFLAGS += -lpthread -lm
endif
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
@ -309,6 +313,17 @@ endif
.PHONY: all
all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done
-$(MAKE) -C utils/aflpp_driver
@echo
@echo
@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-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
@echo
.PHONY: llvm
llvm:
@ -347,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)"
@ -355,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)"
@ -367,9 +382,11 @@ 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
@echo LLVM_DEBUG - shows llvm deprecation warnings
@echo PROFILING - compile afl-fuzz with profiling information
@echo INTROSPECTION - compile afl-fuzz with mutation introspection
@echo NO_PYTHON - disable python support
@ -377,10 +394,11 @@ help:
@echo NO_NYX - disable building nyx mode dependencies
@echo "NO_CORESIGHT - disable building coresight (arm64 only)"
@echo NO_UNICORN_ARM64 - disable building unicorn on arm64
@echo "WAFL_MODE - enable for WASM fuzzing with https://github.com/fgsect/WAFL"
@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
@ -414,12 +432,12 @@ test_python:
@echo "[+] $(PYTHON_VERSION) support seems to be working."
else
test_python:
@echo "[-] You seem to need to install the package python3-dev, python2-dev or python-dev (and perhaps python[23]-apt), but it is optional so we continue"
@echo "[-] You seem to need to install the package python3-dev or python-dev (and perhaps python[3]-apt), but it is optional so we continue"
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)
@ -441,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)
@ -535,8 +553,8 @@ ifndef AFL_NO_X86
test_build: afl-cc afl-gcc afl-as afl-showmap
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
-ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -q -m none -o .test-instr0 ./test-instr < /dev/null
-echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
@rm -f test-instr
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
@echo
@ -581,6 +599,7 @@ clean:
-$(MAKE) -C utils/argv_fuzzing clean
-$(MAKE) -C utils/plot_ui clean
-$(MAKE) -C qemu_mode/unsigaction clean
-$(MAKE) -C qemu_mode/fastexit clean
-$(MAKE) -C qemu_mode/libcompcov clean
-$(MAKE) -C qemu_mode/libqasan clean
-$(MAKE) -C frida_mode clean
@ -616,25 +635,25 @@ distrib: all
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
endif
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
endif
-$(MAKE) -C utils/afl_network_proxy
-$(MAKE) -C utils/socket_fuzzing
-$(MAKE) -C utils/argv_fuzzing
# -$(MAKE) -C utils/plot_ui
-$(MAKE) -C frida_mode
ifneq "$(SYS)" "Darwin"
ifeq "$(ARCH)" "aarch64"
ifndef NO_CORESIGHT
ifeq "$(ARCH)" "aarch64"
ifndef NO_CORESIGHT
-$(MAKE) -C coresight_mode
endif
endif
endif
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
-cd nyx_mode && ./build_nyx_support.sh
endif
endif
endif
-cd qemu_mode && sh ./build_qemu_support.sh
ifeq "$(ARCH)" "aarch64"
ifndef NO_UNICORN_ARM64
@ -647,8 +666,10 @@ endif
.PHONY: binary-only
binary-only: test_shm test_python ready $(PROGS)
ifneq "$(SYS)" "Darwin"
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
endif
-$(MAKE) -C utils/afl_network_proxy
-$(MAKE) -C utils/socket_fuzzing
-$(MAKE) -C utils/argv_fuzzing
@ -674,24 +695,65 @@ endif
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
endif
endif
@echo
@echo
@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"
ifneq "$(SYS)" "Darwin"
ifeq "$(ARCH)" "aarch64"
ifndef NO_CORESIGHT
@test -e afl-cs-proxy && echo "[+] coresight_mode successfully built" || echo "[-] coresight_mode could not be built, it is optional and experimental, see coresight_mode/README.md for what is needed"
endif
endif
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
@test -e libnyx.so && echo "[+] nyx_mode successfully built" || echo "[-] nyx_mode could not be built, it is optional, see nyx_mode/README.md for what is needed"
endif
endif
@test -e afl-qemu-trace && echo "[+] qemu_mode successfully built" || echo "[-] qemu_mode could not be built, see docs/INSTALL.md for what is needed"
ifeq "$(ARCH)" "aarch64"
ifndef NO_UNICORN_ARM64
@test -e unicorn_mode/unicornafl/build_python/libunicornafl.so && echo "[+] unicorn_mode successfully built" || echo "[-] unicorn_mode could not be built, it is optional, see unicorn_mode/README.md for what is needed"
endif
else
@test -e unicorn_mode/unicornafl/build_python/libunicornafl.so && echo "[+] unicorn_mode successfully built" || echo "[-] unicorn_mode could not be built, it is optional, see unicorn_mode/README.md for what is needed"
endif
endif
@echo
.PHONY: source-only
source-only: all
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
endif
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
endif
# -$(MAKE) -C utils/plot_ui
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
-cd nyx_mode && ./build_nyx_support.sh
endif
endif
@echo
@echo
@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-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"
endif
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
@test -e libnyx.so && echo "[+] nyx_mode successfully built" || echo "[-] nyx_mode could not be built, it is optional, see nyx_mode/README.md for what is needed"
endif
endif
@echo
%.8: %
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
@echo .TH $* 8 $(BUILD_DATE) "AFL++" > $@
@echo .SH NAME >> $@
@echo .B $* >> $@
@echo >> $@
@ -703,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

@ -11,7 +11,7 @@
# from Laszlo Szekeres.
#
# Copyright 2015 Google Inc. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -28,15 +28,17 @@ MAN_PATH ?= $(PREFIX)/share/man/man8
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
CFLAGS ?= -O3 -g -funroll-loops
# -D_FORTIFY_SOURCE=1
CFLAGS_SAFE := -Wall -Iinclude -Wno-pointer-sign \
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
-DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
-Wno-unused-function
override CFLAGS += $(CFLAGS_SAFE)
CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11
CXXFLAGS ?= -O3 -g -funroll-loops
# -D_FORTIFY_SOURCE=1
CXXEFLAGS := $(CXXFLAGS) $(CPPFLAGS) -Wall -std=c++11
CC ?= gcc
CXX ?= g++
@ -59,7 +61,7 @@ ifeq "$(findstring Foundation,$(shell $(CC) --version))" ""
endif
PLUGIN_BASE = "$(shell $(CC) -print-file-name=plugin)"
PLUGIN_FLAGS = -fPIC -fno-rtti -I$(PLUGIN_BASE)/include -I$(PLUGIN_BASE)
PLUGIN_FLAGS = -fPIC -fno-rtti -fno-exceptions -I$(PLUGIN_BASE)/include -I$(PLUGIN_BASE)
HASH=\#
GCCVER = $(shell $(CC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}')
@ -175,7 +177,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 +189,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

@ -45,11 +45,13 @@ endif
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' )
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 | egrep -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 )
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[5-9]' && echo 1 || echo 0 )
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
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[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_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)
LLVM_STDCXX = gnu++11
@ -68,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"
@ -81,25 +89,18 @@ ifeq "$(LLVM_NEW_API)" "1"
LLVM_TOO_OLD=0
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_MAJOR)" "15"
$(info [!] llvm_mode detected llvm 15, which is currently broken for LTO plugins.)
LLVM_LTO = 0
LLVM_HAVE_LTO = 0
ifeq "$(LLVM_NEWER_API)" "1"
$(info [+] llvm_mode detected llvm 16+, enabling c++17)
LLVM_STDCXX = c++17
endif
ifeq "$(LLVM_HAVE_LTO)" "1"
$(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
LLVM_LTO = 1
#TEST_MMAP = 1
endif
ifeq "$(LLVM_LTO)" "0"
$(info [+] llvm_mode detected llvm < 11 or llvm 15, afl-lto LTO will not be build.)
$(info [+] llvm_mode detected llvm < 11, afl-lto LTO will not be build.)
endif
ifeq "$(LLVM_APPLE_XCODE)" "1"
@ -220,6 +221,17 @@ ifeq "$(LLVM_LTO)" "1"
ifeq "$(AFL_REAL_LD)" ""
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
else ifneq "$(shell command -v ld.lld 2>/dev/null)" ""
AFL_REAL_LD = $(shell command -v ld.lld)
TMP_LDLDD_VERSION = $(shell $(AFL_REAL_LD) --version | awk '{ print $$2 }')
ifeq "$(LLVMVER)" "$(TMP_LDLDD_VERSION)"
$(warning ld.lld found in a weird location ($(AFL_REAL_LD)), but its the same version as LLVM so we will allow it)
else
$(warning ld.lld found in a weird location ($(AFL_REAL_LD)) and its of a different version than LLMV ($(TMP_LDLDD_VERSION) vs. $(LLVMVER)) - cannot enable LTO mode)
AFL_REAL_LD=
LLVM_LTO = 0
endif
undefine TMP_LDLDD_VERSION
else
$(warning ld.lld not found, cannot enable LTO mode)
LLVM_LTO = 0
@ -235,7 +247,7 @@ AFL_CLANG_FUSELD=
ifeq "$(LLVM_LTO)" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FUSELD=1
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(LLVM_BINDIR)/ld.lld -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(AFL_REAL_LD) -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_LDPATH=1
endif
else
@ -250,26 +262,36 @@ else
AFL_CLANG_DEBUG_PREFIX =
endif
CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
CFLAGS_SAFE := -Wall -g -Wno-cast-qual -Wno-variadic-macros -Wno-pointer-sign -I ./include/ -I ./instrumentation/ \
CFLAGS ?= -O3 -funroll-loops -fPIC
# -D_FORTIFY_SOURCE=1
CFLAGS_SAFE := -Wall -g -Wno-cast-qual -Wno-variadic-macros -Wno-pointer-sign \
-I ./include/ -I ./instrumentation/ \
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
-DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
-Wno-deprecated -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
-DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \
-DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" \
-DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
-DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function \
$(AFL_CLANG_DEBUG_PREFIX)
-DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \
-DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
-DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) \
-Wno-unused-function $(AFL_CLANG_DEBUG_PREFIX)
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
$(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
endif
CXXFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
CXXFLAGS ?= -O3 -funroll-loops -fPIC
# -D_FORTIFY_SOURCE=1
override CXXFLAGS += -Wall -g -I ./include/ \
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros \
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros -Wno-deprecated-copy-with-dtor \
-DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR)
ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" ""
@ -278,9 +300,14 @@ endif
ifneq "$(LLVM_CONFIG)" ""
CLANG_CFL += -I$(shell dirname $(LLVM_CONFIG))/../include
endif
CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS) -Wno-deprecated-declarations
CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fno-exceptions -fPIC $(CXXFLAGS) $(CPPFLAGS) -Wno-deprecated-declarations
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
# wasm fuzzing: disable thread-local storage and unset LLVM debug flag
ifdef WAFL_MODE
$(info Compiling libraries for use with WAVM)
CLANG_CPPFL += -DNDEBUG -DNO_TLS
endif
# User teor2345 reports that this is required to make things work on MacOS X.
ifeq "$(SYS)" "Darwin"
@ -399,7 +426,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
@ -492,7 +519,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" >> ./$@
@ -506,8 +533,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.02c](https://github.com/AFLplusplus/AFLplusplus/releases)
Release version: [4.08c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 4.02c
GitHub version: 4.08c
Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@ -12,12 +12,13 @@ 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>
* Andrea Fioraldi <andreafioraldi@gmail.com>
* Heiko "hexcoder-" Eissfeldt <heiko.eissfeldt@hexco.de>
* frida_mode is maintained by @Worksbutnottested
* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
Originally developed by Michał "lcamtuf" Zalewski.
Originally developed by Michal "lcamtuf" Zalewski.
AFL++ is a superior fork to Google's AFL - more speed, more and better
mutations, more and better instrumentation, custom module support, etc.
@ -228,6 +229,7 @@ Thank you! (For people sending pull requests - please add yourself to this list
Thomas Rooijakkers David Carlier
Ruben ten Hove Joey Jiao
fuzzah @intrigus-lgtm
Yaakov Saxon Sergej Schumilo
```
</details>

View File

@ -2,19 +2,20 @@
## Should
- makefiles should show provide a build summary success/failure
- better documentation for custom mutators
- 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
- parallel builds for source-only targets
- get rid of check_binary, replace with more forkserver communication
- first fuzzer should be a main automatically? not sure.
## Maybe
- forkserver tells afl-fuzz if cmplog is supported and if so enable
it by default, with AFL_CMPLOG_NO=1 (?) set to skip?
- afl_custom_fuzz_splice_optin()
- afl_custom_splice()
- cmdline option from-to range for mutations

225
afl-cmin
View File

@ -103,30 +103,38 @@ 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 (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" \
" -X - use Nyx mode\n" \
"\n" \
"Minimization settings:\n" \
" -A - allow crashes and timeouts (not recommended)\n" \
" -C - keep crashing inputs, reject everything else\n" \
" -e - solve for edge coverage only, ignore hit counts\n" \
"\n" \
"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" \
"AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \
"AFL_FORK_SERVER_KILL_SIGNAL: Signal delivered to fork server processes on\n" \
" termination (default: SIGTERM). If this is not set and AFL_KILL_SIGNAL is\n" \
" set, this will be set to the same value as AFL_KILL_SIGNAL.\n" \
"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" \
"AFL_CMIN_ALLOW_ANY: write tuples for crashing inputs also\n" \
"AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \
"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
}
@ -141,22 +149,29 @@ BEGIN {
redirected = 0
}
print "corpus minimization tool for afl++ (awk version)\n"
print "corpus minimization tool for AFL++ (awk version)\n"
# defaults
extra_par = ""
AFL_CMIN_CRASHES_ONLY = ""
AFL_CMIN_ALLOW_ANY = ""
# process options
Opterr = 1 # default is to diagnose
Optind = 1 # skip ARGV[0]
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCOQU?")) != -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"}
@ -186,6 +201,10 @@ BEGIN {
AFL_CMIN_CRASHES_ONLY = "AFL_CMIN_CRASHES_ONLY=1 "
continue
} else
if (_go_c == "A") {
AFL_CMIN_ALLOW_ANY = "AFL_CMIN_ALLOW_ANY=1 "
continue
} else
if (_go_c == "e") {
extra_par = extra_par " -e"
continue
@ -207,6 +226,12 @@ BEGIN {
extra_par = extra_par " -U"
unicorn_mode = 1
continue
} else
if (_go_c == "X" || _go_c == "Y") {
if (nyx_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
extra_par = extra_par " -X"
nyx_mode = 1
continue
} else
if (_go_c == "?") {
exit 1
@ -215,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
@ -234,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
@ -281,9 +315,12 @@ BEGIN {
exit 1
}
if (target_bin && !exists_and_is_executable(target_bin)) {
"command -v "target_bin" 2>/dev/null" | getline tnew
if (!nyx_mode && target_bin && !exists_and_is_executable(target_bin)) {
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
@ -291,7 +328,18 @@ BEGIN {
target_bin = tnew
}
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) {
if (0 == system ( "grep -aq AFL_DUMP_MAP_SIZE " target_bin )) {
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
}
}
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode && !nyx_mode) {
if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) {
print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr"
exit 1
@ -314,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"
@ -329,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")) {
@ -356,8 +422,10 @@ 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
if (statversion ~ /GNU coreutils/) {
cmd = "stat --version 2>/dev/null"
cmd | getline statversion
close(cmd)
if (statversion ~ /GNU coreutils/ || statversion ~ /BusyBox/) {
stat_format = "-c '%s %n'" # GNU
} else {
stat_format = "-f '%z %N'" # *BSD, MacOS
@ -375,6 +443,7 @@ BEGIN {
infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i]
i++
}
close(cmdline)
in_count = i
first_file = infilesSmallToBigFull[0]
@ -399,10 +468,10 @@ BEGIN {
print "[*] Testing the target binary..."
if (!stdin_file) {
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
system(AFL_MAP_SIZE "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
} else {
system("cp \""in_dir"/"first_file"\" "stdin_file)
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
system(AFL_MAP_SIZE "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
}
first_count = 0
@ -411,6 +480,7 @@ BEGIN {
while ((getline < runtest) > 0) {
++first_count
}
close(runtest)
if (first_count) {
print "[+] OK, "first_count" tuples recorded."
@ -423,33 +493,90 @@ BEGIN {
}
}
if (in_count < threads) {
threads = in_count
print "[!] WARNING: less inputs than threads, reducing threads to "threads" and likely the overhead of threading makes things slower..."
}
# Let's roll!
#############################
# 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_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_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) {
print "[!] Exit code "retval" != 0 received from afl-showmap, 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
}
}
#######################################################
@ -473,6 +600,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
@ -534,6 +670,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:eOQUCh" 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:eOQUCh" opt; do
;;
"f")
STDIN_FILE="$OPTARG"
F_ARG=1
;;
"m")
MEM_LIMIT="$OPTARG"
@ -80,6 +83,9 @@ while getopts "+i:o:f:m:t:eOQUCh" opt; do
"e")
EXTRA_PAR="$EXTRA_PAR -e"
;;
"A")
export AFL_CMIN_ALLOW_ANY=1
;;
"C")
export AFL_CMIN_CRASHES_ONLY=1
;;
@ -91,10 +97,21 @@ while getopts "+i:o:f:m:t:eOQUCh" opt; do
EXTRA_PAR="$EXTRA_PAR -Q"
QEMU_MODE=1
;;
"Y")
EXTRA_PAR="$EXTRA_PAR -X"
NYX_MODE=1
;;
"X")
EXTRA_PAR="$EXTRA_PAR -X"
NYX_MODE=1
;;
"U")
EXTRA_PAR="$EXTRA_PAR -U"
UNICORN_MODE=1
;;
"T")
T_ARG="$OPTARG"
;;
"?")
exit 1
;;
@ -119,15 +136,18 @@ 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)
-X - use Nyx mode
Minimization settings:
-A - allow crashing and timeout inputs
-C - keep crashing inputs, reject everything else
-e - solve for edge coverage only, ignore hit counts
@ -138,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
@ -184,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
@ -202,20 +229,32 @@ if [ ! "$TIMEOUT" = "none" ]; then
fi
if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
if [ "$NYX_MODE" = "" ]; then
if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
TNEW="`which "$TARGET_BIN" 2>/dev/null`"
TNEW="`which "$TARGET_BIN" 2>/dev/null`"
if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then
echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2
exit 1
fi
TARGET_BIN="$TNEW"
if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then
echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2
exit 1
fi
TARGET_BIN="$TNEW"
fi
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
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" && {
export AFL_MAP_SIZE=$MAPSIZE
echo "[+] Setting AFL_MAP_SIZE=$MAPSIZE"
}
}
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" -a "$NYX_MODE" = "" ]; then
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
@ -272,14 +311,41 @@ 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."
if [ -n "$THREADS" ]; then
if [ "$IN_COUNT" -lt "$THREADS" ]; then
THREADS=$IN_COUNT
echo "[!] WARNING: less inputs than threads, reducing threads to $THREADS and likely the overhead of threading makes things slower..."
fi
fi
FIRST_FILE=`ls "$IN_DIR" | head -1`
# Make sure that we're not dealing with a directory.
@ -328,6 +394,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!
#############################
@ -336,6 +414,7 @@ fi
echo "[*] Obtaining traces for input files in '$IN_DIR'..."
if [ "$THREADS" = "" ]; then
(
CUR=0
@ -359,17 +438,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 #
@ -410,6 +530,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

@ -111,12 +111,12 @@ kernel.sched_latency_ns=250000000
EOF
}
egrep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null || echo Error: /etc/default/grub with GRUB_CMDLINE_LINUX_DEFAULT is not present, cannot set boot options
egrep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null && {
egrep '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | egrep -q hardened_usercopy=off || {
grep -E -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null || echo Error: /etc/default/grub with GRUB_CMDLINE_LINUX_DEFAULT is not present, cannot set boot options
grep -E -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null && {
grep -E '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | grep -E -q 'noibrs pcid nopti' || {
echo "Configuring performance boot options"
LINE=`egrep '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | sed 's/^GRUB_CMDLINE_LINUX_DEFAULT=//' | tr -d '"'`
OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
LINE=`grep -E '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | sed 's/^GRUB_CMDLINE_LINUX_DEFAULT=//' | tr -d '"'`
OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
echo Setting boot options in /etc/default/grub to GRUB_CMDLINE_LINUX_DEFAULT=\"$OPTIONS\"
sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"$OPTIONS\"|" /etc/default/grub
}

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
@ -287,9 +296,9 @@ $PLOT_EG
_EOF_
) | gnuplot
) | gnuplot || echo "Note: if you see errors concerning 'unknown or ambiguous terminal type' then you need to use a gnuplot that has png support compiled in."
echo "[?] You can also use -g flag to view the plots in an GUI window, and interact with the plots (if you have built afl-plot-ui). Run \"afl-plot-h\" to know more."
echo "[?] You can also use -g flag to view the plots in an GUI window, and interact with the plots (if you have built afl-plot-ui). Run \"afl-plot -h\" to know more."
fi

View File

@ -47,9 +47,9 @@ if [ "$PLATFORM" = "Linux" ] ; then
} > /dev/null
echo Settings applied.
echo
dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
dmesg | grep -E -q 'noibrs pcid nopti' || {
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
echo
}
echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed.
@ -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

@ -6,7 +6,7 @@
# Originally written by Michal Zalewski
#
# Copyright 2015 Google Inc. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -70,10 +70,10 @@ if [ -d queue ]; then
fi
RED=`tput setaf 9 1 1`
GREEN=`tput setaf 2 1 1`
BLUE=`tput setaf 4 1 1`
YELLOW=`tput setaf 11 1 1`
RED=`tput setaf 9 1 1 2>/dev/null`
GREEN=`tput setaf 2 1 1 2>/dev/null`
BLUE=`tput setaf 4 1 1 2>/dev/null`
YELLOW=`tput setaf 11 1 1 2>/dev/null`
NC=`tput sgr0`
RESET="$NC"
@ -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
@ -141,7 +142,8 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
. "$TMP"
DIR=$(dirname "$i")
DIR=${DIR##*/}
RUN_UNIX=$run_time
RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
@ -154,7 +156,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
if [ "$SUMMARY_ONLY" = "" ]; then
echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
echo ">>> $afl_banner instance: $DIR ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
echo
fi
@ -189,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))
@ -300,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,19 +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 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.
@ -37,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
@ -47,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,166 @@
#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);
if (data->afl->fsrv.dev_urandom_fd < 0) { PFATAL("Unable to open /dev/urandom"); }
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

@ -0,0 +1,26 @@
ifdef debug
CPPLAGS += -fsanitize=address
CXXFLAGS += -Wall
CC := clang
CXX := clang++
endif
ifdef DEBUG
CPPFLAGS += -fsanitize=address
CXXFLAGS += -Wall
CC := clang
CXX := clang++
endif
all: autotokens.so
afl-fuzz-queue.o: ../../src/afl-fuzz-queue.c
$(CC) -D_STANDALONE_MODULE=1 -I../../include -g -O3 $(CPPFLAGS) -fPIC -c -o ./afl-fuzz-queue.o ../../src/afl-fuzz-queue.c
afl-common.o: ../../src/afl-common.c
$(CC) -I../../include -g -O3 $(CPPFLAGS) -DBIN_PATH=\"dummy\" -Wno-pointer-sign -fPIC -c -o ./afl-common.o ../../src/afl-common.c
autotokens.so: afl-fuzz-queue.o afl-common.o autotokens.cpp
$(CXX) -Wno-deprecated -g -O3 $(CXXFLAGS) $(CPPFLAGS) -shared -fPIC -o autotokens.so -I../../include autotokens.cpp ./afl-fuzz-queue.o ../../src/afl-performance.o ./afl-common.o
clean:
rm -f autotokens.so *.o *~ core

View File

@ -0,0 +1,34 @@
# Autotokens
This implements an improved autotoken grammar fuzzing idea presented in
[Token-Level Fuzzing][https://www.usenix.org/system/files/sec21-salls.pdf].
It is a grammar fuzzer without actually knowing the grammar, but only works
with text based inputs.
It is recommended to run with together in an instance with `CMPLOG`.
If you have a dictionary (`-x`) this improves this custom grammar mutator.
If **not** running with `CMPLOG`, it is possible to set
`AFL_CUSTOM_MUTATOR_ONLY` to concentrate on grammar bug classes.
Do **not** set `AFL_DISABLE_TRIM` with this custom mutator!
## Configuration via environment variables
`AUTOTOKENS_ONLY_FAV` - only use this mutator on favorite queue items
`AUTOTOKENS_COMMENT` - what character or string starts a comment which will be
removed. Default: `/* ... */`
`AUTOTOKENS_FUZZ_COUNT_SHIFT` - reduce the number of fuzzing performed, shifting
the value by this number, e.g. 1.
`AUTOTOKENS_AUTO_DISABLE` - disable this module if the seeds are not ascii
(or no input and no (ascii) dictionary)
`AUTOTOKENS_LEARN_DICT` - learn from dictionaries?
0 = none
1 = only -x or autodict
2 = -x, autodict and `CMPLOG`
`AUTOTOKENS_CHANGE_MIN` - minimum number of mutations (1-256, default 8)
`AUTOTOKENS_CHANGE_MAX` - maximum number of mutations (1-4096, default 64)
`AUTOTOKENS_CREATE_FROM_THIN_AIR` - if only one small start file is present and
a dictionary loaded then create one initial
structure based on the dictionary.

File diff suppressed because it is too large Load Diff

View File

@ -1,342 +0,0 @@
#ifndef CUSTOM_MUTATOR_HELPERS
#define CUSTOM_MUTATOR_HELPERS
#include "config.h"
#include "types.h"
#include <stdlib.h>
#define INITIAL_GROWTH_SIZE (64)
#define RAND_BELOW(limit) (rand() % (limit))
/* 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 fills in `&structptr->something_buf, &structptr->something_size`. */
#define BUF_PARAMS(struct, name) \
(void **)&struct->name##_buf, &struct->name##_size
typedef struct {
} afl_t;
static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
static s8 interesting_8[] = {INTERESTING_8};
static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
switch (RAND_BELOW(12)) {
case 0: {
/* Flip a single bit somewhere. Spooky! */
s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
break;
}
case 1: {
/* Set byte to interesting value. */
u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
out_buf[(RAND_BELOW(end - begin) + begin)] = val;
break;
}
case 2: {
/* Set word to interesting value, randomly choosing endian. */
if (end - begin < 2) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 1) break;
switch (RAND_BELOW(2)) {
case 0:
*(u16 *)(out_buf + byte_idx) =
interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
break;
case 1:
*(u16 *)(out_buf + byte_idx) =
SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
break;
}
break;
}
case 3: {
/* Set dword to interesting value, randomly choosing endian. */
if (end - begin < 4) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 3) break;
switch (RAND_BELOW(2)) {
case 0:
*(u32 *)(out_buf + byte_idx) =
interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
break;
case 1:
*(u32 *)(out_buf + byte_idx) =
SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
break;
}
break;
}
case 4: {
/* Set qword to interesting value, randomly choosing endian. */
if (end - begin < 8) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 7) break;
switch (RAND_BELOW(2)) {
case 0:
*(u64 *)(out_buf + byte_idx) =
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
break;
case 1:
*(u64 *)(out_buf + byte_idx) = SWAP64(
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
break;
}
break;
}
case 5: {
/* Randomly subtract from byte. */
out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
break;
}
case 6: {
/* Randomly add to byte. */
out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
break;
}
case 7: {
/* Randomly subtract from word, random endian. */
if (end - begin < 2) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 1) break;
if (RAND_BELOW(2)) {
*(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
} else {
u16 num = 1 + RAND_BELOW(ARITH_MAX);
*(u16 *)(out_buf + byte_idx) =
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
}
break;
}
case 8: {
/* Randomly add to word, random endian. */
if (end - begin < 2) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 1) break;
if (RAND_BELOW(2)) {
*(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
} else {
u16 num = 1 + RAND_BELOW(ARITH_MAX);
*(u16 *)(out_buf + byte_idx) =
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
}
break;
}
case 9: {
/* Randomly subtract from dword, random endian. */
if (end - begin < 4) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 3) break;
if (RAND_BELOW(2)) {
*(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
} else {
u32 num = 1 + RAND_BELOW(ARITH_MAX);
*(u32 *)(out_buf + byte_idx) =
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
}
break;
}
case 10: {
/* Randomly add to dword, random endian. */
if (end - begin < 4) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 3) break;
if (RAND_BELOW(2)) {
*(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
} else {
u32 num = 1 + RAND_BELOW(ARITH_MAX);
*(u32 *)(out_buf + byte_idx) =
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
}
break;
}
case 11: {
/* Just set a random byte to a random value. Because,
why not. We use XOR with 1-255 to eliminate the
possibility of a no-op. */
out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
break;
}
}
}
/* This function calculates the next power of 2 greater or equal its argument.
@return The rounded up power of 2 (if no overflow) or 0 on overflow.
*/
static inline size_t next_pow2(size_t in) {
if (in == 0 || in > (size_t)-1)
return 0; /* avoid undefined behaviour under-/overflow */
size_t out = in - 1;
out |= out >> 1;
out |= out >> 2;
out |= out >> 4;
out |= out >> 8;
out |= out >> 16;
return out + 1;
}
/* This function makes sure *size is > size_needed after call.
It will realloc *buf otherwise.
*size will grow exponentially as per:
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
Will return NULL and free *buf if size_needed is <1 or realloc failed.
@return For convenience, this function returns *buf.
*/
static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
/* No need to realloc */
if (likely(size_needed && *size >= size_needed)) return *buf;
/* No initial size was set */
if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
/* grow exponentially */
size_t next_size = next_pow2(size_needed);
/* handle overflow */
if (!next_size) { next_size = size_needed; }
/* alloc */
*buf = realloc(*buf, next_size);
*size = *buf ? next_size : 0;
return *buf;
}
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
size_t *size2) {
void * scratch_buf = *buf1;
size_t scratch_size = *size1;
*buf1 = *buf2;
*size1 = *size2;
*buf2 = scratch_buf;
*size2 = scratch_size;
}
#undef INITIAL_GROWTH_SIZE
#endif

View File

@ -0,0 +1,63 @@
//
// This is an example on how to use afl_custom_send
// It writes each mutated data set to /tmp/foo
// You can modify this to send to IPC, shared memory, etc.
//
// cc -O3 -fPIC -shared -g -o custom_send.so -I../../include custom_send.c
// cd ../..
// afl-cc -o test-instr test-instr.c
// AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/examples/custom_send.so \
// afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
//
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "afl-fuzz.h"
typedef struct my_mutator {
afl_state_t *afl;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
data->afl = afl;
return data;
}
void afl_custom_fuzz_send(my_mutator_t *data, uint8_t *buf, size_t buf_size) {
int fd = open("/tmp/foo", O_CREAT | O_NOFOLLOW | O_TRUNC | O_RDWR, 0644);
if (fd >= 0) {
(void)write(fd, buf, buf_size);
close(fd);
}
return;
}
void afl_custom_deinit(my_mutator_t *data) {
free(data);
}

View File

@ -6,8 +6,8 @@
Dominik Maier <mail@dmnk.co>
*/
// You need to use -I /path/to/AFLplusplus/include
#include "custom_mutator_helpers.h"
// You need to use -I/path/to/AFLplusplus/include -I.
#include "afl-fuzz.h"
#include <stdint.h>
#include <stdlib.h>
@ -26,19 +26,14 @@ static const char *commands[] = {
typedef struct my_mutator {
afl_t *afl;
afl_state_t *afl;
// any additional data here!
size_t trim_size_current;
int trimmming_steps;
int cur_step;
// Reused buffers:
BUF_VAR(u8, fuzz);
BUF_VAR(u8, data);
BUF_VAR(u8, havoc);
BUF_VAR(u8, trim);
BUF_VAR(u8, post_process);
u8 *mutated_out, *post_process_buf, *trim_buf;
} my_mutator_t;
@ -53,7 +48,7 @@ typedef struct my_mutator {
* There may be multiple instances of this mutator in one afl-fuzz run!
* Return NULL on error.
*/
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); // needed also by surgical_havoc_mutate()
@ -65,6 +60,27 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
}
if ((data->mutated_out = (u8 *)malloc(MAX_FILE)) == NULL) {
perror("afl_custom_init malloc");
return NULL;
}
if ((data->post_process_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
perror("afl_custom_init malloc");
return NULL;
}
if ((data->trim_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
perror("afl_custom_init malloc");
return NULL;
}
data->afl = afl;
return data;
@ -96,29 +112,14 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
// the fuzzer
size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
// maybe_grow is optimized to be quick for reused buffers.
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
if (!mutated_out) {
*out_buf = NULL;
perror("custom mutator allocation (maybe_grow)");
return 0; /* afl-fuzz will very likely error out after this. */
}
memcpy(data->mutated_out, buf, buf_size);
// Randomly select a command string to add as a header to the packet
memcpy(mutated_out, commands[rand() % 3], 3);
memcpy(data->mutated_out, commands[rand() % 3], 3);
// Mutate the payload of the packet
int i;
for (i = 0; i < 8; ++i) {
if (mutated_size > max_size) { mutated_size = max_size; }
// Randomly perform one of the (no len modification) havoc mutations
surgical_havoc_mutate(mutated_out, 3, mutated_size);
}
*out_buf = mutated_out;
*out_buf = data->mutated_out;
return mutated_size;
}
@ -142,24 +143,16 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
size_t buf_size, uint8_t **out_buf) {
uint8_t *post_process_buf =
maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
if (!post_process_buf) {
if (buf_size + 5 > MAX_FILE) { buf_size = MAX_FILE - 5; }
perror("custom mutator realloc failed.");
*out_buf = NULL;
return 0;
memcpy(data->post_process_buf + 5, buf, buf_size);
data->post_process_buf[0] = 'A';
data->post_process_buf[1] = 'F';
data->post_process_buf[2] = 'L';
data->post_process_buf[3] = '+';
data->post_process_buf[4] = '+';
}
memcpy(post_process_buf + 5, buf, buf_size);
post_process_buf[0] = 'A';
post_process_buf[1] = 'F';
post_process_buf[2] = 'L';
post_process_buf[3] = '+';
post_process_buf[4] = '+';
*out_buf = post_process_buf;
*out_buf = data->post_process_buf;
return buf_size + 5;
@ -195,13 +188,6 @@ int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
data->cur_step = 0;
if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
perror("init_trim grow");
return -1;
}
memcpy(data->trim_buf, buf, buf_size);
data->trim_size_current = buf_size;
@ -282,27 +268,11 @@ int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
u8 **out_buf, size_t max_size) {
if (buf_size == 0) {
*out_buf = buf; // in-place mutation
*out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
if (!*out_buf) {
if (buf_size <= sizeof(size_t)) { return buf_size; }
perror("custom havoc: maybe_grow");
return 0;
}
**out_buf = rand() % 256;
buf_size = 1;
} else {
// We reuse buf here. It's legal and faster.
*out_buf = buf;
}
size_t victim = rand() % buf_size;
size_t victim = rand() % (buf_size - sizeof(size_t));
(*out_buf)[victim] += rand() % 10;
return buf_size;
@ -369,9 +339,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data,
void afl_custom_deinit(my_mutator_t *data) {
free(data->post_process_buf);
free(data->havoc_buf);
free(data->data_buf);
free(data->fuzz_buf);
free(data->mutated_out);
free(data->trim_buf);
free(data);

View File

@ -45,9 +45,8 @@
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
and return the original `len`.
NOTE: the following is currently NOT true, we abort in this case!
2) If you want to skip this test case altogether and have AFL generate a
new one, return 0 or set `*out_buf = NULL`.
new one, return 0.
Use this sparingly - it's faster than running the target program
with patently useless inputs, but still wastes CPU time.
@ -59,8 +58,6 @@
Note that the buffer will *not* be freed for you. To avoid memory leaks,
you need to free it or reuse it on subsequent calls (as shown below).
*** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
Alright. The example below shows a simple postprocessor that tries to make
sure that all input files start with "GIF89a".
@ -72,7 +69,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alloc-inl.h"
#include "afl-fuzz.h"
/* Header that must be present at the beginning of every test case: */
@ -80,8 +77,7 @@
typedef struct post_state {
unsigned char *buf;
size_t size;
size_t size;
} post_state_t;
@ -95,15 +91,6 @@ void *afl_custom_init(void *afl) {
}
state->buf = calloc(sizeof(unsigned char), 4096);
if (!state->buf) {
free(state);
perror("calloc");
return NULL;
}
return state;
}
@ -113,6 +100,10 @@ void *afl_custom_init(void *afl) {
size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
unsigned int len, unsigned char **out_buf) {
/* we do in-place modification as we do not increase the size */
*out_buf = in_buf;
/* Skip execution altogether for buffers shorter than 6 bytes (just to
show how it's done). We can trust len to be sane. */
@ -120,34 +111,7 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
/* Do nothing for buffers that already start with the expected header. */
if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
*out_buf = in_buf;
return len;
}
/* Allocate memory for new buffer, reusing previous allocation if
possible. Note we have to use afl-fuzz's own realloc!
Note that you should only do this if you need to grow the buffer,
otherwise work with in_buf, and assign it to *out_buf instead. */
*out_buf = afl_realloc(out_buf, len);
/* If we're out of memory, the most graceful thing to do is to return the
original buffer and give up on modifying it. Let AFL handle OOM on its
own later on. */
if (!*out_buf) {
*out_buf = in_buf;
return len;
}
if (len > strlen(HEADER))
memcpy(*out_buf + strlen(HEADER), in_buf + strlen(HEADER),
len - strlen(HEADER));
if (!memcmp(in_buf, HEADER, strlen(HEADER))) { return len; }
/* Insert the new header. */
@ -162,7 +126,6 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
/* Gets called afterwards */
void afl_custom_deinit(post_state_t *data) {
free(data->buf);
free(data);
}

View File

@ -30,7 +30,7 @@
#include <string.h>
#include <zlib.h>
#include <arpa/inet.h>
#include "alloc-inl.h"
#include "afl-fuzz.h"
/* A macro to round an integer up to 4 kB. */
@ -53,7 +53,7 @@ void *afl_custom_init(void *afl) {
}
state->buf = calloc(sizeof(unsigned char), 4096);
state->buf = calloc(sizeof(unsigned char), MAX_FILE);
if (!state->buf) {
free(state);
@ -80,21 +80,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
}
/* This is not a good way to do it, if you do not need to grow the buffer
then just work with in_buf instead for speed reasons.
But we want to show how to grow a buffer, so this is how it's done: */
unsigned int pos = 8;
unsigned char *new_buf = afl_realloc(out_buf, UP4K(len));
if (!new_buf) {
*out_buf = in_buf;
return len;
}
memcpy(new_buf, in_buf, len);
unsigned int pos = 8;
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
don't have that, we can bail out. */
@ -124,7 +110,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
if (real_cksum != file_cksum) {
*(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
*(uint32_t *)(data->buf + pos + 8 + chunk_len) = real_cksum;
}
@ -134,7 +120,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
}
*out_buf = new_buf;
*out_buf = data->buf;
return len;
}

View File

@ -1,6 +1,6 @@
// This simple example just creates random buffer <= 100 filled with 'A'
// needs -I /path/to/AFLplusplus/include
#include "custom_mutator_helpers.h"
#include "afl-fuzz.h"
#include <stdint.h>
#include <stdlib.h>
@ -13,14 +13,14 @@
typedef struct my_mutator {
afl_t *afl;
afl_state_t *afl;
// Reused buffers:
BUF_VAR(u8, fuzz);
u8 *fuzz_buf;
} 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));
@ -31,6 +31,14 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
}
data->fuzz_buf = (u8 *)malloc(MAX_FILE);
if (!data->fuzz_buf) {
perror("afl_custom_init malloc");
return NULL;
}
data->afl = afl;
return data;
@ -44,18 +52,10 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
int size = (rand() % 100) + 1;
if (size > max_size) size = max_size;
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size);
if (!mutated_out) {
*out_buf = NULL;
perror("custom mutator allocation (maybe_grow)");
return 0; /* afl-fuzz will very likely error out after this. */
memset(data->fuzz_buf, _FIXED_CHAR, size);
}
memset(mutated_out, _FIXED_CHAR, size);
*out_buf = mutated_out;
*out_buf = data->fuzz_buf;
return size;
}

View File

@ -11,7 +11,7 @@
# Adapted for AFLplusplus by Dominik Maier <mail@dmnk.co>
#
# Copyright 2017 Battelle Memorial Institute. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -125,7 +125,7 @@ else
}
fi
test -d json-c/.git || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
test -e json-c/.git || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
echo "[+] Got json-c."
test -e json-c/.libs/libjson-c.a || {

View File

@ -14,7 +14,7 @@
# <andreafioraldi@gmail.com>
#
# Copyright 2017 Battelle Memorial Institute. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -119,7 +119,7 @@ else
}
fi
test -f grammar_mutator/.git || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
test -e grammar_mutator/.git || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
echo "[+] Got grammar mutator."
cd "grammar_mutator" || exit 1

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

@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "62614ce1016c86e3f00f35b56399292ceabd486b" }
libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "266677bb88abe75165430f34e7de897c35560504" }
custom_mutator = { path = "../rust/custom_mutator", features = ["afl_internals"] }
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib

View File

@ -1,5 +1,4 @@
#![cfg(unix)]
#![allow(unused_variables)]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
@ -18,10 +17,12 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
Mutator,
},
state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State},
prelude::UsesInput,
state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State, UsesState},
Error,
};
#[allow(clippy::identity_op)]
const MAX_FILE: usize = 1 * 1024 * 1024;
static mut AFL: Option<&'static afl_state> = None;
@ -64,24 +65,32 @@ impl<'de> Deserialize<'de> for AFLCorpus {
}
}
impl Corpus<BytesInput> for AFLCorpus {
impl UsesState for AFLCorpus {
type State = AFLState;
}
impl Corpus for AFLCorpus {
#[inline]
fn count(&self) -> usize {
afl().queued_items as usize
}
#[inline]
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
fn add(&mut self, _testcase: Testcase<BytesInput>) -> Result<usize, Error> {
unimplemented!();
}
#[inline]
fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> {
fn replace(
&mut self,
_idx: usize,
_testcase: Testcase<BytesInput>,
) -> Result<Testcase<Self::Input>, Error> {
unimplemented!();
}
#[inline]
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
fn remove(&mut self, _idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
unimplemented!();
}
@ -92,7 +101,7 @@ impl Corpus<BytesInput> for AFLCorpus {
entries.entry(idx).or_insert_with(|| {
let queue_buf = std::slice::from_raw_parts_mut(afl().queue_buf, self.count());
let entry = queue_buf[idx].as_mut().unwrap();
let fname = CStr::from_ptr((entry.fname as *mut i8).as_ref().unwrap())
let fname = CStr::from_ptr((entry.fname.cast::<i8>()).as_ref().unwrap())
.to_str()
.unwrap()
.to_owned();
@ -127,9 +136,10 @@ pub struct AFLState {
}
impl AFLState {
#[must_use]
pub fn new(seed: u32) -> Self {
Self {
rand: StdRand::with_seed(seed as u64),
rand: StdRand::with_seed(u64::from(seed)),
corpus: AFLCorpus::default(),
metadata: SerdeAnyMap::new(),
max_size: MAX_FILE,
@ -153,7 +163,11 @@ impl HasRand for AFLState {
}
}
impl HasCorpus<BytesInput> for AFLState {
impl UsesInput for AFLState {
type Input = BytesInput;
}
impl HasCorpus for AFLState {
type Corpus = AFLCorpus;
#[inline]
@ -208,7 +222,7 @@ impl CustomMutator for LibAFLBaseCustomMutator {
tokens.push(data.to_vec());
}
if !tokens.is_empty() {
state.add_metadata(Tokens::new(tokens));
state.add_metadata(Tokens::from(tokens));
}
Ok(Self {
state,
@ -220,7 +234,7 @@ impl CustomMutator for LibAFLBaseCustomMutator {
fn fuzz<'b, 's: 'b>(
&'s mut self,
buffer: &'b mut [u8],
add_buff: Option<&[u8]>,
_add_buff: Option<&[u8]>,
max_size: usize,
) -> Result<Option<&'b [u8]>, Self::Error> {
self.state.set_max_size(max_size);

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

@ -1,12 +1,12 @@
[package]
name = "custom_mutator-sys"
version = "0.1.0"
version = "0.1.1"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[build-dependencies]
bindgen = "0.56"
bindgen = "0.63"

View File

@ -15,8 +15,8 @@ fn main() {
// The input header we would like to generate
// bindings for.
.header("wrapper.h")
.whitelist_type("afl_state_t")
.blacklist_type(r"u\d+")
.allowlist_type("afl_state_t")
.blocklist_type(r"u\d+")
.opaque_type(r"_.*")
.opaque_type("FILE")
.opaque_type("in_addr(_t)?")

View File

@ -1,5 +1,7 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::too_many_lines)]
#![allow(clippy::used_underscore_binding)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

View File

@ -2,7 +2,7 @@
name = "custom_mutator"
version = "0.1.0"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -20,7 +20,7 @@
//! This binding is panic-safe in that it will prevent panics from unwinding into AFL++. Any panic will `abort` at the boundary between the custom mutator and AFL++.
//!
//! # Access to AFL++ internals
//! This crate has an optional feature "afl_internals", which gives access to AFL++'s internal state.
//! This crate has an optional feature "`afl_internals`", which gives access to AFL++'s internal state.
//! The state is passed to [`CustomMutator::init`], when the feature is activated.
//!
//! _This is completely unsafe and uses automatically generated types extracted from the AFL++ source._
@ -115,7 +115,7 @@ pub mod wrappers {
impl<M: RawCustomMutator> FFIContext<M> {
fn from(ptr: *mut c_void) -> ManuallyDrop<Box<Self>> {
assert!(!ptr.is_null());
ManuallyDrop::new(unsafe { Box::from_raw(ptr as *mut Self) })
ManuallyDrop::new(unsafe { Box::from_raw(ptr.cast::<Self>()) })
}
fn into_ptr(self: Box<Self>) -> *const c_void {
@ -141,27 +141,28 @@ pub mod wrappers {
}
/// panic handler called for every panic
fn panic_handler(method: &str, panic_info: Box<dyn Any + Send + 'static>) -> ! {
fn panic_handler(method: &str, panic_info: &Box<dyn Any + Send + 'static>) -> ! {
use std::ops::Deref;
let cause = panic_info
.downcast_ref::<String>()
.map(String::deref)
.unwrap_or_else(|| {
let cause = panic_info.downcast_ref::<String>().map_or_else(
|| {
panic_info
.downcast_ref::<&str>()
.copied()
.unwrap_or("<cause unknown>")
});
eprintln!("A panic occurred at {}: {}", method, cause);
},
String::deref,
);
eprintln!("A panic occurred at {method}: {cause}");
abort()
}
/// Internal function used in the macro
#[cfg(not(feature = "afl_internals"))]
#[must_use]
pub fn afl_custom_init_<M: RawCustomMutator>(seed: u32) -> *const c_void {
match catch_unwind(|| FFIContext::<M>::new(seed).into_ptr()) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_init", err),
Err(err) => panic_handler("afl_custom_init", &err),
}
}
@ -176,7 +177,7 @@ pub mod wrappers {
FFIContext::<M>::new(afl, seed).into_ptr()
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_init", err),
Err(err) => panic_handler("afl_custom_init", &err),
}
}
@ -196,32 +197,27 @@ pub mod wrappers {
) -> usize {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
if buf.is_null() {
panic!("null buf passed to afl_custom_fuzz")
}
if out_buf.is_null() {
panic!("null out_buf passed to afl_custom_fuzz")
}
assert!(!buf.is_null(), "null buf passed to afl_custom_fuzz");
assert!(!out_buf.is_null(), "null out_buf passed to afl_custom_fuzz");
let buff_slice = slice::from_raw_parts_mut(buf, buf_size);
let add_buff_slice = if add_buf.is_null() {
None
} else {
Some(slice::from_raw_parts(add_buf, add_buf_size))
};
match context.mutator.fuzz(buff_slice, add_buff_slice, max_size) {
Some(buffer) => {
*out_buf = buffer.as_ptr();
buffer.len()
}
None => {
// return the input buffer with 0-length to let AFL skip this mutation attempt
*out_buf = buf;
0
}
if let Some(buffer) = context.mutator.fuzz(buff_slice, add_buff_slice, max_size) {
*out_buf = buffer.as_ptr();
buffer.len()
} else {
// return the input buffer with 0-length to let AFL skip this mutation attempt
*out_buf = buf;
0
}
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_fuzz", err),
Err(err) => panic_handler("afl_custom_fuzz", &err),
}
}
@ -237,9 +233,8 @@ pub mod wrappers {
) -> u32 {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
if buf.is_null() {
panic!("null buf passed to afl_custom_fuzz")
}
assert!(!buf.is_null(), "null buf passed to afl_custom_fuzz");
let buf_slice = slice::from_raw_parts(buf, buf_size);
// see https://doc.rust-lang.org/nomicon/borrow-splitting.html
let ctx = &mut **context;
@ -247,37 +242,39 @@ pub mod wrappers {
mutator.fuzz_count(buf_slice)
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_fuzz_count", err),
Err(err) => panic_handler("afl_custom_fuzz_count", &err),
}
}
/// Internal function used in the macro
pub fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
pub unsafe fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
data: *mut c_void,
filename_new_queue: *const c_char,
filename_orig_queue: *const c_char,
) -> bool {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
if filename_new_queue.is_null() {
panic!("received null filename_new_queue in afl_custom_queue_new_entry");
}
assert!(
!filename_new_queue.is_null(),
"received null filename_new_queue in afl_custom_queue_new_entry"
);
let filename_new_queue = Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename_new_queue) }.to_bytes(),
));
let filename_orig_queue = if !filename_orig_queue.is_null() {
let filename_orig_queue = if filename_orig_queue.is_null() {
None
} else {
Some(Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename_orig_queue) }.to_bytes(),
)))
} else {
None
};
context
.mutator
.queue_new_entry(filename_new_queue, filename_orig_queue)
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_queue_new_entry", err),
Err(err) => panic_handler("afl_custom_queue_new_entry", &err),
}
}
@ -292,7 +289,7 @@ pub mod wrappers {
ManuallyDrop::into_inner(FFIContext::<M>::from(data));
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_deinit", err),
Err(err) => panic_handler("afl_custom_deinit", &err),
}
}
@ -306,13 +303,13 @@ pub mod wrappers {
buf.extend_from_slice(res.as_bytes());
buf.push(0);
// unwrapping here, as the error case should be extremely rare
CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
CStr::from_bytes_with_nul(buf).unwrap().as_ptr()
} else {
null()
}
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_introspection", err),
Err(err) => panic_handler("afl_custom_introspection", &err),
}
}
@ -329,18 +326,18 @@ pub mod wrappers {
buf.extend_from_slice(res.as_bytes());
buf.push(0);
// unwrapping here, as the error case should be extremely rare
CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
CStr::from_bytes_with_nul(buf).unwrap().as_ptr()
} else {
null()
}
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_describe", err),
Err(err) => panic_handler("afl_custom_describe", &err),
}
}
/// Internal function used in the macro
pub fn afl_custom_queue_get_<M: RawCustomMutator>(
pub unsafe fn afl_custom_queue_get_<M: RawCustomMutator>(
data: *mut c_void,
filename: *const c_char,
) -> u8 {
@ -348,12 +345,12 @@ pub mod wrappers {
let mut context = FFIContext::<M>::from(data);
assert!(!filename.is_null());
context.mutator.queue_get(Path::new(OsStr::from_bytes(
u8::from(context.mutator.queue_get(Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename) }.to_bytes(),
))) as u8
))))
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_queue_get", err),
Err(err) => panic_handler("afl_custom_queue_get", &err),
}
}
}
@ -373,7 +370,7 @@ macro_rules! _define_afl_custom_init {
};
}
/// An exported macro to defined afl_custom_init meant for insternal usage
/// An exported macro to defined `afl_custom_init` meant for internal usage
#[cfg(not(feature = "afl_internals"))]
#[macro_export]
macro_rules! _define_afl_custom_init {
@ -444,7 +441,7 @@ macro_rules! export_mutator {
}
#[no_mangle]
pub extern "C" fn afl_custom_queue_new_entry(
pub unsafe extern "C" fn afl_custom_queue_new_entry(
data: *mut ::std::os::raw::c_void,
filename_new_queue: *const ::std::os::raw::c_char,
filename_orig_queue: *const ::std::os::raw::c_char,
@ -457,7 +454,7 @@ macro_rules! export_mutator {
}
#[no_mangle]
pub extern "C" fn afl_custom_queue_get(
pub unsafe extern "C" fn afl_custom_queue_get(
data: *mut ::std::os::raw::c_void,
filename: *const ::std::os::raw::c_char,
) -> u8 {
@ -520,9 +517,10 @@ mod sanity_test {
export_mutator!(ExampleMutator);
}
#[allow(unused_variables)]
/// A custom mutator.
/// [`CustomMutator::handle_error`] will be called in case any method returns an [`Result::Err`].
#[allow(unused_variables)]
#[allow(clippy::missing_errors_doc)]
pub trait CustomMutator {
/// The error type. All methods must return the same error type.
type Error: Debug;
@ -537,7 +535,7 @@ pub trait CustomMutator {
.map(|v| !v.is_empty())
.unwrap_or(false)
{
eprintln!("Error in custom mutator: {:?}", err)
eprintln!("Error in custom mutator: {err:?}");
}
}
@ -759,8 +757,7 @@ mod truncate_test {
let actual_output = truncate_str_unicode_safe(input, *max_len);
assert_eq!(
&actual_output, expected_output,
"{:#?} truncated to {} bytes should be {:#?}, but is {:#?}",
input, max_len, expected_output, actual_output
"{input:#?} truncated to {max_len} bytes should be {expected_output:#?}, but is {actual_output:#?}"
);
}
}

View File

@ -2,7 +2,7 @@
name = "example_mutator"
version = "0.1.0"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -2,7 +2,7 @@
name = "example_lain"
version = "0.1.0"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

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,10 +3,172 @@
This is the list of all noteworthy changes made in every public
release of the tool. See README.md for the general instruction manual.
## Staying informed
### Version ++4.08c (release)
- 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
- -l X option to enable base64 transformation solving
- allow to disable CMPLOG with '-c -' (e.g. afl.rs enforces '-c 0' on
every instance which is counterproductive).
- 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
- adjust threads if less inputs than threads specified
- 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
- renamed utils/get_symbol_addr.sh to utils/frida_get_symbol_addr.sh
- qemu_mode:
- added qemu_mode/utils/qemu_get_symbol_addr.sh
### 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
- added `AFL_NO_WARN_INSTABILITY`
- added time_wo_finds to fuzzer_stats
- fixed a crash in pizza (1st april easter egg) mode. Sorry for
everyone who was affected!
- allow pizza mode to be disabled when AFL_PIZZA_MODE is set to -1
- option `-p mmopt` now also selects new queue items more often
- fix bug in post_process custom mutator implementation
- print name of custom mutator in UI
- slight changes that improve fuzzer performance
- afl-cc:
- add CFI sanitizer variant to gcc targets
- llvm 16 + 17 support (thanks to @devnexen!)
- support llvm 15 native pcguard changes
- support for LLVMFuzzerTestOneInput -1 return
- LTO autoken and llvm_mode: added AFL_LLVM_DICT2FILE_NO_MAIN support
- qemu_mode:
- fix _RANGES envs to allow hyphens in the filenames
- basic riscv support
- frida_mode:
- added `AFL_FRIDA_STATS_INTERVAL`
- fix issue on MacOS
- unicorn_mode:
- updated and minor issues fixed
- nyx_mode support for all tools
- better sanitizer default options support for all tools
- new custom module: autotoken, a grammar free fuzzer for text inputs
- fixed custom mutator C examples
- more minor fixes and cross-platform support
### Version ++4.05c (release)
- MacOS: libdislocator, libtokencap etc. do not work with modern
MacOS anymore, but could be patched to work, see this issue if you
want to make the effort and send a PR:
https://github.com/AFLplusplus/AFLplusplus/issues/1594
- afl-fuzz:
- added afl_custom_fuzz_send custom mutator feature. Now your can
send fuzz data to the target as you need, e.g. via IPC.
- cmplog mode now has a -l R option for random colorization, thanks
to guyf2010 for the PR!
- queue statistics are written every 30 minutes to
out/NAME/queue_data if compiled with INTROSPECTION
- new env: AFL_FORK_SERVER_KILL_SIGNAL
- afl-showmap/afl-cmin
- `-t none` now translates to `-t 120000` (120 seconds)
- unicorn_mode updated
- updated rust custom mutator dependencies and LibAFL custom mutator
- overall better sanitizer default setting handling
- several minor bugfixes
### Version ++4.04c (release)
- fix gramatron and grammar_mutator build scripts
- enhancements to the afl-persistent-config and afl-system-config
scripts
- afl-fuzz:
- force writing all stats on exit
- ensure targets are killed on exit
- `AFL_FORK_SERVER_KILL_SIGNAL` added
- afl-cc:
- make gcc_mode (afl-gcc-fast) work with gcc down to version 3.6
- qemu_mode:
- fixed 10x speed degredation in v4.03c, thanks to @ele7enxxh for
reporting!
- added qemu_mode/fastexit helper library
- unicorn_mode:
- Enabled tricore arch (by @jma-qb)
- Updated Capstone version in Rust bindings
- llvm-mode:
- AFL runtime will always pass inputs via shared memory, when possible,
ignoring the command line.
### Version ++4.03c (release)
- Building now gives a build summary what succeeded and what not
- afl-fuzz:
- added AFL_NO_STARTUP_CALIBRATION to start fuzzing at once instead
of calibrating all initial seeds first. Good for large queues
and long execution times, especially in CIs.
- default calibration cycles set to 7 from 8, and only add 5 cycles
to variables queue items instead of 12.
- afl-cc:
- fixed off-by-one bug in our pcguard implemenation, thanks for
@tokatoka for reporting
- fix for llvm 15 and reenabling LTO, thanks to nikic for the PR!
- better handling of -fsanitize=..,...,.. lists
- support added for LLVMFuzzerRunDriver()
- fix gcc_mode cmplog
- obtain the map size of a target with setting AFL_DUMP_MAP_SIZE=1
note that this will exit the target before main()
- qemu_mode:
- added AFL_QEMU_TRACK_UNSTABLE to log the addresses of unstable
edges (together with AFL_DEBUG=1 afl-fuzz). thanks to
worksbutnottested!
- afl-analyze broke at some point, fix by CodeLogicError, thank you!
- afl-cmin/afl-cmin.bash now have an -A option to allow also crashing
and timeout inputs
- unicorn_mode:
- updated upstream unicorn version
- fixed builds for aarch64
- build now uses all available cores
Want to stay in the loop on major new features? Join our mailing list by
sending a mail to <afl-users+subscribe@googlegroups.com>.
### Version ++4.02c (release)
- afl-cc:
@ -22,7 +184,6 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- change post_process hook to allow returning NULL and 0 length to
tell afl-fuzz to skip this mutated input
### Version ++4.01c (release)
- fixed */build_...sh scripts to work outside of git
- new custom_mutator: libafl with token fuzzing :)
@ -113,7 +274,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
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>
@ -255,3 +264,69 @@ If you find an interesting or important question missing, submit it via
Solution: `git pull ; make clean install` of AFL++.
</p></details>
<details>
<summary id="afl-map-size-warning">AFL++ map size warning.</summary><p>
When you run a large instrumented program stand-alone or via afl-showmap
you might see a warning like the following:
```
Warning: AFL++ tools might need to set AFL_MAP_SIZE to 223723 to be able to run this instrumented program if this crashes!
```
Depending how the target works it might also crash afterwards.
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/... version release `-12` with
whatever llvm version is available!
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,21 +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

@ -419,8 +419,8 @@ the process. Be sure to consult this file especially if any UI elements are
highlighted in red.
The fuzzing process will continue until you press Ctrl-C. At a minimum, you want
to allow the fuzzer to complete one queue cycle, which may take anywhere from a
couple of hours to a week or so.
to allow the fuzzer to at least one queue cycle without any new finds, which may
take anywhere from a couple of hours to a week or so.
There are three subdirectories created within the output directory and updated
in real-time:
@ -483,6 +483,7 @@ directory. This includes:
- `fuzzer_pid` - PID of the fuzzer process
- `cycles_done` - queue cycles completed so far
- `cycles_wo_finds` - number of cycles without any new paths found
- `time_wo_finds` - longest time in seconds no new path was found
- `execs_done` - number of execve() calls attempted
- `execs_per_sec` - overall number of execs per second
- `corpus_count` - total number of entries in the queue

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

@ -48,6 +48,7 @@ C/C++:
```c
void *afl_custom_init(afl_state_t *afl, unsigned int seed);
unsigned int afl_custom_fuzz_count(void *data, const unsigned char *buf, size_t buf_size);
void afl_custom_splice_optout(void *data);
size_t afl_custom_fuzz(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, unsigned char *add_buf, size_t add_buf_size, size_t max_size);
const char *afl_custom_describe(void *data, size_t max_description_len);
size_t afl_custom_post_process(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf);
@ -57,6 +58,7 @@ int afl_custom_post_trim(void *data, unsigned char success);
size_t afl_custom_havoc_mutation(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, size_t max_size);
unsigned char afl_custom_havoc_mutation_probability(void *data);
unsigned char afl_custom_queue_get(void *data, const unsigned char *filename);
void (*afl_custom_fuzz_send)(void *data, const u8 *buf, size_t buf_size);
u8 afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue);
const char* afl_custom_introspection(my_mutator_t *data);
void afl_custom_deinit(void *data);
@ -68,9 +70,12 @@ Python:
def init(seed):
pass
def fuzz_count(buf, add_buf, max_size):
def fuzz_count(buf):
return cnt
def splice_optout()
pass
def fuzz(buf, add_buf, max_size):
return mutated_out
@ -98,6 +103,9 @@ def havoc_mutation_probability():
def queue_get(filename):
return True
def fuzz_send(buf):
pass
def queue_new_entry(filename_new_queue, filename_orig_queue):
return False
@ -110,7 +118,7 @@ def deinit(): # optional for Python
### Custom Mutation
- `init`:
- `init` (optional in Python):
This method is called when AFL++ starts up and is used to seed RNG and set
up buffers and state.
@ -128,13 +136,24 @@ def deinit(): # optional for Python
for a specific queue entry, use this function. This function is most useful
if `AFL_CUSTOM_MUTATOR_ONLY` is **not** used.
- `splice_optout` (optional):
If this function is present, no splicing target is passed to the `fuzz`
function. This saves time if splicing data is not needed by the custom
fuzzing function.
This function is never called, just needs to be present to activate.
- `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!
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):
@ -168,6 +187,18 @@ def deinit(): # optional for Python
to the target, e.g. if it is too short, too corrupted, etc. If so,
return a NULL buffer and zero length (or a 0 length string in Python).
NOTE: Do not make any random changes to the data in this function!
PERFORMANCE for C/C++: If possible make the changes in-place (so modify
the `*data` directly, and return it as `*outbuf = data`.
- `fuzz_send` (optional):
This method can be used if you want to send data to the target yourself,
e.g. via IPC. This replaces some usage of utils/afl_proxy but requires
that you start the target with afl-fuzz.
Example: [custom_mutators/examples/custom_send.c](custom_mutators/examples/custom_send.c)
- `queue_new_entry` (optional):
This methods is called after adding a new test case to the queue. If the
@ -179,7 +210,7 @@ def deinit(): # optional for Python
discovered if compiled with INTROSPECTION. The custom mutator can then
return a string (const char *) that reports the exact mutations used.
- `deinit`:
- `deinit` (optional in Python):
The last method to be called, deinitializing the state.
@ -269,13 +300,41 @@ sudo apt install python-dev
```
Then, AFL++ can be compiled with Python support. The AFL++ Makefile detects
Python 2 and 3 through `python-config` if it is in the PATH and compiles
`afl-fuzz` with the feature if available.
Python3 through `python-config`/`python3-config` if it is in the PATH and
compiles `afl-fuzz` with the feature if available.
Note: for some distributions, you might also need the package `python[23]-apt`.
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

@ -129,6 +129,9 @@ subset of the settings discussed in section 1, with the exception of:
write all constant string comparisons to this file to be used later with
afl-fuzz' `-x` option.
- An option to `AFL_LLVM_DICT2FILE` is `AFL_LLVM_DICT2FILE_NO_MAIN=1` which
skill not parse `main()`.
- `TMPDIR` and `AFL_KEEP_ASSEMBLY`, since no temporary assembly files are
created.
@ -153,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
@ -237,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).
@ -354,9 +359,15 @@ checks or alter some of the more exotic semantics of the tool:
- Setting `AFL_KEEP_TIMEOUTS` will keep longer running inputs if they reach
new coverage
- On the contrary, if you are not interested in any timeouts, you can set
`AFL_IGNORE_TIMEOUTS` to get a bit of speed instead.
- `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behavior which
does not allow crashes or timeout seeds in the initial -i corpus.
- `AFL_CRASHING_SEEDS_AS_NEW_CRASH` will treat crashing seeds as new crash. these
crashes will be written to crashes folder as op:dry_run, and orig:<seed_file_name>.
- `AFL_EXIT_ON_TIME` causes afl-fuzz to terminate if no new paths were found
within a specified period of time (in seconds). May be convenient for some
types of automated jobs.
@ -378,10 +389,10 @@ checks or alter some of the more exotic semantics of the tool:
valid terminal was detected (for virtual consoles).
- Setting `AFL_FORKSRV_INIT_TMOUT` allows you to specify a different timeout
to wait for the forkserver to spin up. The default is the `-t` value times
`FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the
default would wait for `1000` milliseconds. Setting a different time here is
useful if the target has a very slow startup time, for example, when doing
to wait for the forkserver to spin up. The specified value is the new timeout, in milliseconds.
The default is the `-t` value times `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the default would wait for `1000` milliseconds.
The `AFL_FORKSRV_INIT_TMOUT` value does not get multiplied. It overwrites the initial timeout afl-fuzz waits for the target to come up with a constant time.
Setting a different time here is useful if the target has a very slow startup time, for example, when doing
full-system fuzzing or emulation, but you don't want the actual runs to wait
too long for timeouts.
@ -398,7 +409,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.
@ -409,11 +421,22 @@ checks or alter some of the more exotic semantics of the tool:
the afl-fuzz -g/-G command line option to control the minimum/maximum
of fuzzing input generated.
- `AFL_KILL_SIGNAL`: Set the signal ID to be delivered to child processes on
timeout. Unless you implement your own targets or instrumentation, you
- `AFL_KILL_SIGNAL`: Set the signal ID to be delivered to child processes
on timeout. Unless you implement your own targets or instrumentation, you
likely don't have to set it. By default, on timeout and on exit, `SIGKILL`
(`AFL_KILL_SIGNAL=9`) will be delivered to the child.
- `AFL_FORK_SERVER_KILL_SIGNAL`: Set the signal ID to be delivered to the
fork server when AFL++ is terminated. Unless you implement your
fork server, you likely do not have to set it. By default, `SIGTERM`
(`AFL_FORK_SERVER_KILL_SIGNAL=15`) will be delivered to the fork server.
If only `AFL_KILL_SIGNAL` is provided, `AFL_FORK_SERVER_KILL_SIGNAL` will
be set to same value as `AFL_KILL_SIGNAL` to provide backward compatibility.
If `AFL_FORK_SERVER_KILL_SIGNAL` is also set, it takes precedence.
NOTE: Uncatchable signals, such as `SIGKILL`, cause child processes of
the fork server to be orphaned and leaves them in a zombie state.
- `AFL_MAP_SIZE` sets the size of the shared map that afl-analyze, afl-fuzz,
afl-showmap, and afl-tmin create to gather instrumentation data from the
target. This must be equal or larger than the size the target was compiled
@ -455,13 +478,19 @@ checks or alter some of the more exotic semantics of the tool:
normally done when starting up the forkserver and causes a pretty
significant performance drop.
- `AFL_NO_SNAPSHOT` will advice afl-fuzz not to use the snapshot feature if
- `AFL_NO_SNAPSHOT` will advise afl-fuzz not to use the snapshot feature if
the snapshot lkm is loaded.
- Setting `AFL_NO_UI` inhibits the UI altogether and just periodically prints
some basic stats. This behavior is also automatically triggered when the
output from afl-fuzz is redirected to a file or to a pipe.
- Setting `AFL_NO_STARTUP_CALIBRATION` will skip the initial calibration
of all starting seeds, and start fuzzing at once. Use with care, this
degrades the fuzzing performance!
- Setting `AFL_NO_WARN_INSTABILITY` will suppress instability warnings.
- In QEMU mode (-Q) and FRIDA mode (-O), `AFL_PATH` will be searched for
afl-qemu-trace and afl-frida-trace.so.
@ -470,7 +499,7 @@ checks or alter some of the more exotic semantics of the tool:
some targets keep inherent state due which a detected crash test case does
not crash the target again when the test case is given. To be able to still
re-trigger these crashes, you can use the `AFL_PERSISTENT_RECORD` variable
with a value of how many previous fuzz cases to keep prio a crash. If set to
with a value of how many previous fuzz cases to keep prior a crash. If set to
e.g., 10, then the 9 previous inputs are written to out/default/crashes as
RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008 and
RECORD:000000,cnt:000009 being the crash case. NOTE: This option needs to be
@ -558,8 +587,15 @@ checks or alter some of the more exotic semantics of the tool:
constructors in your target, you can set `AFL_EARLY_FORKSERVER`.
Note that this is not a compile time option but a runtime option :-)
- Set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to 0
to disable although it is 1st of April.
- Set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to -1
to disable although it is 1st of April. 0 is the default and means enable
on the 1st of April automatically.
- If you need a specific interval to update fuzzer_stats file, you can
set `AFL_FUZZER_STATS_UPDATE_INTERVAL` to the interval in seconds you'd
the file to be updated.
Note that will not be exact and with slow targets it can take seconds
until there is a slice for the time test.
## 5) Settings for afl-qemu-trace
@ -587,6 +623,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.
@ -648,6 +692,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`.
@ -691,8 +737,8 @@ support.
* `AFL_FRIDA_STALKER_ADJACENT_BLOCKS` - Configure the number of adjacent blocks
to fetch when generating instrumented code. By fetching blocks in the same
order they appear in the original program, rather than the order of execution
should help reduce locallity and adjacency. This includes allowing us to
vector between adjancent blocks using a NOP slide rather than an immediate
should help reduce locality and adjacency. This includes allowing us to
vector between adjacent blocks using a NOP slide rather than an immediate
branch.
* `AFL_FRIDA_STALKER_IC_ENTRIES` - Configure the number of inline cache entries
stored along-side branch instructions which provide a cache to avoid having to

View File

@ -201,10 +201,10 @@ afl-clang-fast's.
### RetroWrite
RetroWrite is a static binary rewriter that can be combined with AFL++. If you
have an x86_64 binary that still has its symbols (i.e., not stripped binary), is
compiled with position independent code (PIC/PIE), and does not contain C++
exceptions, then the RetroWrite solution might be for you. It decompiles to ASM
files which can then be instrumented with afl-gcc.
have an x86_64 or arm64 binary that does not contain C++ exceptions and - if
x86_64 - still has it's symbols and compiled with position independent code
(PIC/PIE), then the RetroWrite solution might be for you.
It decompiles to ASM files which can then be instrumented with afl-gcc.
Binaries that are statically instrumented for fuzzing using RetroWrite are close
in performance to compiler-instrumented binaries and outperform the QEMU-based
@ -291,7 +291,7 @@ its IPT performance is just 6%!
There are many binary-only fuzzing frameworks. Some are great for CTFs but don't
work with large binaries, others are very slow but have good path discovery,
some are very hard to set-up...
some are very hard to set up...
* Jackalope:
[https://github.com/googleprojectzero/Jackalope](https://github.com/googleprojectzero/Jackalope)

View File

@ -523,7 +523,7 @@ mode!) and switch the input directory with a dash (`-`):
afl-fuzz -i - -o output -- bin/target -someopt @@
```
Adding a dictionary is helpful. You have to following options:
Adding a dictionary is helpful. You have the following options:
* See the directory
[dictionaries/](../dictionaries/), if something is already included for your
@ -534,6 +534,8 @@ dictionaries/FORMAT.dict`.
* With `afl-clang-fast`, you can set
`AFL_LLVM_DICT2FILE=/full/path/to/new/file.dic` to automatically generate a
dictionary during target compilation.
Adding `AFL_LLVM_DICT2FILE_NO_MAIN=1` to not parse main (usually command line
parameter parsing) is often a good idea too.
* You also have the option to generate a dictionary yourself during an
independent run of the target, see
[utils/libtokencap/README.md](../utils/libtokencap/README.md).
@ -626,6 +628,10 @@ from other fuzzers in the campaign first.
If you have a large corpus, a corpus from a previous run or are fuzzing in a CI,
then also set `export AFL_CMPLOG_ONLY_NEW=1` and `export AFL_FAST_CAL=1`.
If the queue in the CI is huge and/or the execution time is slow then you can
also add `AFL_NO_STARTUP_CALIBRATION=1` to skip the initial queue calibration
phase and start fuzzing at once - but only do this if the calibration phase
would be too long for your fuzz run time.
You can also use different fuzzers. If you are using AFL spinoffs or AFL
conforming fuzzers, then just use the same -o directory and give it a unique
@ -669,7 +675,7 @@ The syncing process itself is very simple. As the `-M main-$HOSTNAME` instance
syncs to all `-S` secondaries as well as to other fuzzers, you have to copy only
this directory to the other machines.
Lets say all servers have the `-o out` directory in /target/foo/out, and you
Let's say all servers have the `-o out` directory in /target/foo/out, and you
created a file `servers.txt` which contains the hostnames of all participating
servers, plus you have an ssh key deployed to all of them, then run:
@ -897,11 +903,23 @@ then color-codes the input based on which sections appear to be critical and
which are not; while not bulletproof, it can often offer quick insights into
complex file formats.
`casr-afl` from [CASR](https://github.com/ispras/casr) tools provides
comfortable triaging for crashes found by AFL++. Reports are clustered and
contain severity and other information.
```shell
casr-afl -i /path/to/afl/out/dir -o /path/to/casr/out/dir
```
## 5. CI fuzzing
Some notes on continuous integration (CI) fuzzing - this fuzzing is different to
normal fuzzing campaigns as these are much shorter runnings.
If the queue in the CI is huge and/or the execution time is slow then you can
also add `AFL_NO_STARTUP_CALIBRATION=1` to skip the initial queue calibration
phase and start fuzzing at once. But only do that if the calibration time is
too long for your overall available fuzz run time.
1. Always:
* LTO has a much longer compile time which is diametrical to short fuzzing -
hence use afl-clang-fast instead.
@ -921,7 +939,7 @@ normal fuzzing campaigns as these are much shorter runnings.
3. Also randomize the afl-fuzz runtime options, e.g.:
* 65% for `AFL_DISABLE_TRIM`
* 50% for `AFL_KEEP_TIMEOUTS`
* 50% use a dictionary generated by `AFL_LLVM_DICT2FILE`
* 50% use a dictionary generated by `AFL_LLVM_DICT2FILE` + `AFL_LLVM_DICT2FILE_NO_MAIN=1`
* 40% use MOpt (`-L 0`)
* 40% for `AFL_EXPAND_HAVOC_NOW`
* 20% for old queue processing (`-Z`)

View File

@ -3,6 +3,8 @@
In the following, we describe a variety of ideas that could be implemented for
future AFL++ versions.
**NOTE:** Our GSoC participation is concerning [libafl](https://github.com/AFLplusplus/libafl), not AFL++.
## Analysis software
Currently analysis is done by using afl-plot, which is rather outdated. A GTK or
@ -16,17 +18,6 @@ and Y axis, zoom factor, log scaling on-off, etc.
Mentor: vanhauser-thc
## WASM Instrumentation
Currently, AFL++ can be used for source code fuzzing and traditional binaries.
With the rise of WASM as a compile target, however, a novel way of
instrumentation needs to be implemented for binaries compiled to Webassembly.
This can either be done by inserting instrumentation directly into the WASM AST,
or by patching feedback into a WASM VM of choice, similar to the current Unicorn
instrumentation.
Mentor: any
## Support other programming languages
Other programming languages also use llvm hence they could be (easily?)

View File

@ -1,5 +1,10 @@
# Tools that help fuzzing with AFL++
## AFL++ and other development languages
* [afl-rs](https://github.com/rust-fuzz/afl.rs) - AFL++ for RUST
* [WASM](https://github.com/fgsect/WAFL) - AFL++ for WASM
## Speeding up fuzzing
* [libfiowrapper](https://github.com/marekzmyslowski/libfiowrapper) - if the
@ -62,3 +67,5 @@
generates builds of debian packages suitable for AFL.
* [afl-fid](https://github.com/FoRTE-Research/afl-fid) - a set of tools for
working with input data.
* [CASR](https://github.com/ispras/casr) - a set of tools for crash triage and
analysis.

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

@ -8,6 +8,7 @@
"__afl_auto_first";
"__afl_auto_init";
"__afl_auto_second";
"__afl_connected";
"__afl_coverage_discard";
"__afl_coverage_interesting";
"__afl_coverage_off";
@ -53,4 +54,5 @@
"__sanitizer_cov_trace_pc_guard";
"__sanitizer_cov_trace_pc_guard_init";
"__sanitizer_cov_trace_switch";
"LLVMFuzzerTestOneInput";
};

View File

@ -1,3 +1,4 @@
PWD:=$(shell pwd)/
ROOT:=$(PWD)../
INC_DIR:=$(PWD)include/
@ -32,7 +33,7 @@ CFLAGS+=-fPIC \
-ffunction-sections \
ifdef IS_ANDROID
CFLAGS+=-DANDROID
CFLAGS+=-DANDROID
endif
AFL_CFLAGS:=-Wno-unused-parameter \
@ -47,7 +48,7 @@ LDFLAGS+= -static-libstdc++ \
-DANDROID \
-llog \
-shared
else
else
LDFLAGS+=-shared \
-lpthread \
-lresolv
@ -57,7 +58,10 @@ ifdef DEBUG
CFLAGS+=-Werror \
-Wall \
-Wextra \
-Wpointer-arith
-Wpointer-arith \
-Wno-unknown-pragmas \
-Wno-pointer-to-int-cast \
-Wno-int-to-pointer-cast
else
CFLAGS+=-Wno-pointer-arith
endif
@ -95,6 +99,25 @@ ifeq "$(shell uname)" "Darwin"
OS:=macos
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-deprecated-declarations
GUM_ARCH:=""
ifeq "$(ARCH)" "arm64"
TARGET_CC= \
"clang" \
"-target" \
"arm64-apple-macos10.9"
TARGET_CXX= \
"clang++" \
"-target" \
"arm64-apple-macos10.9"
else
TARGET_CC= \
"clang" \
"-target" \
"x86_64-apple-macos10.9"
TARGET_CXX= \
"clang++" \
"-target" \
"x86_64-apple-macos10.9"
endif
else
ifdef DEBUG
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-prio-ctor-dtor
@ -103,7 +126,7 @@ endif
LDFLAGS+= -z noexecstack \
-Wl,--gc-sections \
-Wl,--exclude-libs,ALL \
-ldl
-ldl
LDSCRIPT:=-Wl,--version-script=$(PWD)frida.map
endif
@ -118,7 +141,7 @@ endif
ifdef IS_ANDROID
OS:=android
ifdef IS_x86
ARCH:=x86
ARCH:=x86
endif
ifdef IS_x86
ARCH:=x86_64
@ -142,7 +165,7 @@ ifndef OS
$(error "Operating system unsupported")
endif
GUM_DEVKIT_VERSION=15.2.1
GUM_DEVKIT_VERSION=16.0.11
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
@ -188,6 +211,9 @@ all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QE
32:
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
arm:
CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
@ -206,7 +232,7 @@ $(FRIDA_MAKEFILE): | $(BUILD_DIR)
.PHONY: $(GUM_DEVIT_LIBRARY)
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE)
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH)
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH) FRIDA_V8=disabled
$(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
echo "#include <stdio.h>" > $@
@ -245,46 +271,46 @@ TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
else ifeq "$(ARCH)" "arm64"
CFLAGS+=-I $(FRIDA_DIR)build/frida_thin-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
ifeq "$(OS)" "android"
CFLAGS += -static-libstdc++
CFLAGS += -static-libstdc++
endif
else
CFLAGS+=-I $(FRIDA_DIR)build/frida_thin-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
endif
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libunwind.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libelf.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libz.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
ifeq "$(OS)" "android"
CFLAGS += -static-libstdc++

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
@ -86,7 +88,7 @@ To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`.
## Scripting
One of the more powerful features of FRIDA mode is it's support for
One of the more powerful features of FRIDA mode is its support for
configuration by JavaScript, rather than using environment variables. For
details of how this works, see [Scripting.md](Scripting.md).
@ -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
@ -193,6 +197,13 @@ instrumented address block translations.
backpatching information. By default, the child will report applied
backpatches to the parent so that they can be applied and then be inherited by
the next child on fork.
* `AFL_FRIDA_INST_NO_SUPPRESS` - Disable deterministic branch suppression.
Deterministic branch suppression skips the preamble which generates coverage
information at the start of each block, if the block is reached by a
deterministic branch. This reduces map polution, and may improve performance
when all the executing blocks have been prefetched and backpatching applied.
However, in the event that backpatching is incomplete, this may incur a
performance penatly as branch instructions are disassembled on each branch.
* `AFL_FRIDA_INST_SEED` - Sets the initial seed for the hash function used to
generate block (and hence edge) IDs. Setting this to a constant value may be
useful for debugging purposes, e.g., investigating unstable edges.

View File

@ -2,7 +2,7 @@
FRIDA now supports the ability to configure itself using JavaScript. This allows
the user to make use of the convenience of FRIDA's scripting engine (along with
it's support for debug symbols and exports) to configure all of the things which
its support for debug symbols and exports) to configure all of the things which
were traditionally configured using environment variables.
By default, FRIDA mode will look for the file `afl.js` in the current working
@ -95,7 +95,7 @@ Afl.print("done");
## Stripped binaries
Lastly, if the binary you attempting to fuzz has no symbol information and no
Lastly, if the binary you're attempting to fuzz has no symbol information and no
exports, then the following approach can be used.
```js
@ -390,7 +390,7 @@ Consider the [following](test/js/test2.c) test code...
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
@ -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,9 +19,11 @@
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;
js_api_set_instrument_suppress_disable;
js_api_set_instrument_trace;
js_api_set_instrument_trace_unique;
js_api_set_instrument_unstable_coverage_file;

View File

@ -54,10 +54,12 @@ __attribute__((visibility("default"))) void afl_persistent_hook(
__attribute__((visibility("default"))) void afl_persistent_hook(
GumCpuContext *regs, uint8_t *input_buf, uint32_t input_buf_len) {
// do a length check matching the target!
memcpy((void *)regs->r[0], input_buf, input_buf_len);
regs->r[1] = input_buf_len;
}
#else

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

@ -15,6 +15,7 @@ extern guint64 instrument_hash_zero;
extern char *instrument_coverage_unstable_filename;
extern gboolean instrument_coverage_insn;
extern char *instrument_regs_filename;
extern gboolean instrument_suppress;
extern gboolean instrument_use_fixed_seed;
extern guint64 instrument_fixed_seed;

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

@ -204,10 +204,7 @@ static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
gsize address = context->pc;
register uintptr_t k = (uintptr_t)address;
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1;
register uintptr_t k = instrument_get_offset_hash(GUM_ADDRESS(address));
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS)
__afl_cmp_map->headers[k].hits = 0;

View File

@ -188,10 +188,7 @@ static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
gsize address = ctx_read_reg(context, X86_REG_RIP);
register uintptr_t k = (uintptr_t)address;
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 7;
register uintptr_t k = instrument_get_offset_hash(GUM_ADDRESS(address));
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS)
__afl_cmp_map->headers[k].hits = 0;

View File

@ -193,10 +193,7 @@ static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
gsize address = ctx_read_reg(context, X86_REG_EIP);
register uintptr_t k = (uintptr_t)address;
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1;
register uintptr_t k = instrument_get_offset_hash(GUM_ADDRESS(address));
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS)
__afl_cmp_map->headers[k].hits = 0;

View File

@ -7,6 +7,8 @@
gsize ctx_read_reg(GumArmCpuContext *ctx, arm_reg reg) {
UNUSED_PARAMETER(ctx);
UNUSED_PARAMETER(reg);
FFATAL("ctx_read_reg unimplemented for this architecture");
}

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

@ -27,6 +27,7 @@ gboolean instrument_optimize = false;
gboolean instrument_unique = false;
guint64 instrument_hash_zero = 0;
guint64 instrument_hash_seed = 0;
gboolean instrument_suppress = false;
gboolean instrument_use_fixed_seed = FALSE;
guint64 instrument_fixed_seed = 0;
@ -168,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); }
@ -290,6 +290,7 @@ void instrument_config(void) {
(getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE"));
instrument_coverage_insn = (getenv("AFL_FRIDA_INST_INSN") != NULL);
instrument_regs_filename = getenv("AFL_FRIDA_INST_REGS_FILE");
instrument_suppress = (getenv("AFL_FRIDA_INST_NO_SUPPRESS") == NULL);
instrument_debug_config();
instrument_coverage_config();
@ -321,6 +322,9 @@ void instrument_init(void) {
FOKF(cBLU "Instrumentation" cRST " - " cGRN "instructions:" cYEL " [%c]",
instrument_coverage_insn ? 'X' : ' ');
FOKF(cBLU "Instrumentation" cRST " - " cGRN "suppression:" cYEL " [%c]",
instrument_suppress ? 'X' : ' ');
if (instrument_tracing && instrument_optimize) {
WARNF("AFL_FRIDA_INST_TRACE implies AFL_FRIDA_INST_NO_OPTIMIZE");

View File

@ -1,6 +1,7 @@
#include "frida-gumjs.h"
#include "instrument.h"
#include "stalker.h"
#include "util.h"
#if defined(__arm__)
@ -8,12 +9,13 @@
#define PAGE_MASK (~(GUM_ADDRESS(0xfff)))
#define PAGE_ALIGNED(x) ((GUM_ADDRESS(x) & PAGE_MASK) == GUM_ADDRESS(x))
gboolean instrument_cache_enabled = FALSE;
gsize instrument_cache_size = 0;
gboolean instrument_cache_enabled = FALSE;
gsize instrument_cache_size = 0;
static GHashTable *coverage_blocks = NULL;
extern __thread guint64 instrument_previous_pc;
__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_SIZE];
__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_INITIAL_SIZE];
#pragma pack(push, 1)
typedef struct {
@ -22,7 +24,24 @@ typedef struct {
// shared_mem[cur_location ^ prev_location]++;
// prev_location = cur_location >> 1;
/* We can remove this branch when we add support for branch suppression */
// str r0, [sp, #-128] ; 0xffffff80
// str r1, [sp, #-132] ; 0xffffff7c
// ldr r0, [pc, #-20] ; 0xf691b29c
// ldrh r1, [r0]
// movw r0, #33222 ; 0x81c6
// eor r0, r0, r1
// ldr r1, [pc, #-40] ; 0xf691b298
// add r1, r1, r0
// ldrb r0, [r1]
// add r0, r0, #1
// add r0, r0, r0, lsr #8
// strb r0, [r1]
// movw r0, #49379 ; 0xc0e3
// ldr r1, [pc, #-64] ; 0xf691b29c
// strh r0, [r1]
// ldr r1, [sp, #-132] ; 0xffffff7c
// ldr r0, [sp, #-128] ; 0xffffff80
uint32_t b_code; /* b imm */
uint8_t *shared_mem;
uint64_t *prev_location;
@ -115,6 +134,46 @@ gboolean instrument_is_coverage_optimize_supported(void) {
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address, void *from_insn,
gpointer *target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(from_address);
UNUSED_PARAMETER(start_address);
UNUSED_PARAMETER(from_insn);
if (!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target))) {
return;
}
*target =
(guint8 *)*target + G_STRUCT_OFFSET(afl_log_code_asm_t, str_r0_sp_rz);
}
static void instrument_coverage_suppress_init(void) {
static gboolean initialized = false;
if (initialized) { return; }
initialized = true;
GumStalkerObserver *observer = stalker_get_observer();
GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer);
iface->switch_callback = instrument_coverage_switch;
coverage_blocks = g_hash_table_new(g_direct_hash, g_direct_equal);
if (coverage_blocks == NULL) {
FATAL("Failed to g_hash_table_new, errno: %d", errno);
}
}
static void patch_t3_insn(uint32_t *insn, uint16_t val) {
uint32_t orig = GUINT32_FROM_LE(*insn);
@ -135,14 +194,17 @@ void instrument_coverage_optimize(const cs_insn *instr,
guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
gsize map_size_pow2;
gsize area_offset_ror;
GumAddress code_addr = 0;
// gum_arm64_writer_put_brk_imm(cw, 0x0);
code_addr = cw->pc;
instrument_coverage_suppress_init();
block_start = GSIZE_TO_POINTER(GUM_ADDRESS(cw->code));
if (!g_hash_table_add(coverage_blocks, block_start)) {
FATAL("Failed - g_hash_table_add");
}
code.code = template;
g_assert(PAGE_ALIGNED(__afl_area_ptr));
@ -211,7 +273,19 @@ void instrument_flush(GumStalkerOutput *output) {
gpointer instrument_cur(GumStalkerOutput *output) {
return gum_arm_writer_cur(output->writer.arm);
gpointer curr = NULL;
if (output->encoding == GUM_INSTRUCTION_SPECIAL) {
curr = gum_thumb_writer_cur(output->writer.thumb);
} else {
curr = gum_arm_writer_cur(output->writer.arm);
}
return curr;
}

View File

@ -22,7 +22,7 @@ gboolean instrument_cache_enabled = FALSE;
gsize instrument_cache_size = 0;
static GHashTable *coverage_blocks = NULL;
__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_SIZE];
__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_INITIAL_SIZE];
#pragma pack(push, 1)
typedef struct {
@ -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;
@ -156,26 +242,55 @@ static gboolean instrument_is_deterministic(const cs_insn *from_insn) {
}
cs_insn *instrument_disassemble(gconstpointer address) {
csh capstone;
cs_insn *insn = NULL;
cs_open(CS_ARCH_ARM64, GUM_DEFAULT_CS_ENDIAN, &capstone);
cs_option(capstone, CS_OPT_DETAIL, CS_OPT_ON);
cs_disasm(capstone, address, 16, GPOINTER_TO_SIZE(address), 1, &insn);
cs_close(&capstone);
return insn;
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn *from_insn,
gpointer *target) {
gpointer start_address, void *from_insn,
gpointer *target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(from_address);
UNUSED_PARAMETER(start_address);
gsize fixup_offset;
cs_insn *insn = NULL;
gboolean deterministic = FALSE;
gsize fixup_offset;
if (!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target)) &&
!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target + 4))) {
!g_hash_table_contains(coverage_blocks,
GSIZE_TO_POINTER((guint8 *)*target + 4))) {
return;
}
if (instrument_is_deterministic(from_insn)) { return; }
insn = instrument_disassemble(from_insn);
deterministic = instrument_is_deterministic(insn);
cs_free(insn, 1);
/*
* If the branch is deterministic, then we should start execution at the
* begining of the block. From here, we will branch and skip the coverage
* code and jump right to the target code of the instrumented block.
* Otherwise, if the branch is non-deterministic, then we need to branch
* part way into the block to where the coverage instrumentation starts.
*/
if (deterministic) { return; }
/*
* Since each block is prefixed with a restoration prologue, we need to be
@ -208,7 +323,7 @@ static void instrument_coverage_switch(GumStalkerObserver *self,
*/
fixup_offset = GUM_RESTORATION_PROLOG_SIZE +
G_STRUCT_OFFSET(afl_log_code_asm_t, restoration_prolog);
*target += fixup_offset;
*target = (guint8 *)*target + fixup_offset;
}
@ -237,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;
}
@ -254,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;
}
@ -283,8 +493,10 @@ 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));
instrument_coverage_suppress_init();
if (instrument_suppress) { instrument_coverage_suppress_init(); }
code_addr = cw->pc;
@ -304,45 +516,31 @@ void instrument_coverage_optimize(const cs_insn *instr,
block_start =
GSIZE_TO_POINTER(GUM_ADDRESS(cw->code) - GUM_RESTORATION_PROLOG_SIZE);
if (!g_hash_table_add(coverage_blocks, block_start)) {
if (instrument_suppress) {
FATAL("Failed - g_hash_table_add");
if (!g_hash_table_add(coverage_blocks, block_start)) {
FATAL("Failed - g_hash_table_add");
}
}
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)) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
if (!instrument_write_inline_long(cw, code_addr, area_offset,
area_offset_ror)) {
FATAL("Failed to write inline instrumentation");
}
}
}

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,33 +259,43 @@ 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);
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn *from_insn,
gpointer *target) {
static void instrument_coverage_switch_insn(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn *from_insn,
gpointer *target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(from_address);
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,70 @@ static void instrument_coverage_switch(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!");
}
}
cs_insn *instrument_disassemble(gconstpointer address) {
csh capstone;
cs_insn *insn = NULL;
cs_open(CS_ARCH_X86, GUM_CPU_MODE, &capstone);
cs_option(capstone, CS_OPT_DETAIL, CS_OPT_ON);
cs_disasm(capstone, address, 16, GPOINTER_TO_SIZE(address), 1, &insn);
cs_close(&capstone);
return insn;
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address, void *from_insn,
gpointer *target) {
if (from_insn == NULL) { return; }
cs_insn *insn = instrument_disassemble(from_insn);
instrument_coverage_switch_insn(self, from_address, start_address, insn,
target);
cs_free(insn, 1);
}
@ -241,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) +
@ -265,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;
@ -282,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;
@ -309,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;
@ -324,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");
}
}
}
@ -351,13 +585,7 @@ void instrument_coverage_optimize(const cs_insn *instr,
}
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

@ -83,11 +83,11 @@ gboolean instrument_is_coverage_optimize_supported(void) {
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn *from_insn,
gpointer *target) {
static void instrument_coverage_switch_insn(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn *from_insn,
gpointer *target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(from_address);
@ -130,6 +130,35 @@ static void instrument_coverage_switch(GumStalkerObserver *self,
}
cs_insn *instrument_disassemble(gconstpointer address) {
csh capstone;
cs_insn *insn = NULL;
cs_open(CS_ARCH_X86, GUM_CPU_MODE, &capstone);
cs_option(capstone, CS_OPT_DETAIL, CS_OPT_ON);
cs_disasm(capstone, address, 16, GPOINTER_TO_SIZE(address), 1, &insn);
cs_close(&capstone);
return insn;
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address, void *from_insn,
gpointer *target) {
if (from_insn == NULL) { return; }
cs_insn *insn = instrument_disassemble(from_insn);
instrument_coverage_switch_insn(self, from_address, start_address, insn,
target);
cs_free(insn, 1);
}
static void instrument_coverage_suppress_init(void) {
static gboolean initialized = false;
@ -174,13 +203,17 @@ void instrument_coverage_optimize(const cs_insn *instr,
code.code = template;
instrument_coverage_suppress_init();
if (instrument_suppress) {
// gum_x86_writer_put_breakpoint(cw);
instrument_coverage_suppress_init();
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
// gum_x86_writer_put_breakpoint(cw);
FATAL("Failed - g_hash_table_add");
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
FATAL("Failed - g_hash_table_add");
}
}

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`
*/
@ -170,6 +176,12 @@ class Afl {
static setInstrumentSeed(seed) {
Afl.jsApiSetInstrumentSeed(seed);
}
/*
* See `AFL_FRIDA_INST_NO_SUPPRESS`
*/
static setInstrumentSuppressDisable() {
Afl.jsApiSetInstrumentSuppressDisable();
}
/**
* See `AFL_FRIDA_INST_TRACE_UNIQUE`.
*/
@ -336,9 +348,11 @@ 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"]);
Afl.jsApiSetInstrumentSuppressDisable = Afl.jsApiGetFunction("js_api_set_instrument_suppress_disable", "void", []);
Afl.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []);
Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []);
Afl.jsApiSetInstrumentUnstableCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_unstable_coverage_file", "void", ["pointer"]);

View File

@ -18,10 +18,8 @@ static GumScriptScheduler *scheduler;
static GMainContext *context;
static GMainLoop *main_loop;
static void js_msg(GumScript *script, const gchar *message, GBytes *data,
gpointer user_data) {
static void js_msg(const gchar *message, GBytes *data, gpointer user_data) {
UNUSED_PARAMETER(script);
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(user_data);
FOKF("%s", message);
@ -124,8 +122,8 @@ void js_start(void) {
main_loop = g_main_loop_new(context, true);
g_main_context_push_thread_default(context);
gum_script_backend_create(backend, "example", source, cancellable, create_cb,
&error);
gum_script_backend_create(backend, "example", source, NULL, cancellable,
create_cb, &error);
while (g_main_context_pending(context))
g_main_context_iteration(context, FALSE);

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) {
@ -289,6 +296,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_cache_size(
}
__attribute__((visibility("default"))) void
js_api_set_instrument_suppress_disable(void) {
instrument_suppress = false;
}
__attribute__((visibility("default"))) void js_api_set_js_main_hook(
const js_main_hook_t hook) {

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

@ -77,7 +77,9 @@ static int on_dlclose(void *handle) {
range = &g_array_index(ranges, gum_range_t, i);
base = range->range.base_address;
limit = base + range->range.size;
FVERBOSE("Reserving range: 0x%016lx, 0x%016lX", base, limit);
FVERBOSE("Reserving range: 0x%016" G_GINT64_MODIFIER
"x, 0x%016" G_GINT64_MODIFIER "X",
base, limit);
mem = gum_memory_allocate(GSIZE_TO_POINTER(base), range->range.size,
page_size, GUM_PAGE_NO_ACCESS);
if (mem == NULL) { FATAL("Failed to allocate %p (%d)", mem, errno); }

View File

@ -29,7 +29,6 @@ gboolean prefetch_enable = TRUE;
gboolean prefetch_backpatch = TRUE;
static prefetch_data_t *prefetch_data = NULL;
static int prefetch_shm_id = -1;
static GHashTable *cant_prefetch = 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

@ -13,6 +13,7 @@ void starts_arch_init(void) {
void stats_write_arch(stats_data_t *data) {
UNUSED_PARAMETER(data);
FFATAL("Stats not supported on this architecture");
}

View File

@ -35,7 +35,7 @@ endif
endif
ADDR_BIN:=$(ROOT)frida_mode/build/addr
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/frida_get_symbol_addr.sh
AFL_FRIDA_BASE_ADDR:=$(shell $(ADDR_BIN))
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput $(AFL_FRIDA_BASE_ADDR))

View File

@ -11,7 +11,7 @@ QEMU_OUT:=$(BUILD_DIR)qemu-out
FRIDA_OUT:=$(BUILD_DIR)frida-out
ADDR_BIN:=$(ROOT)frida_mode/build/addr
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/frida_get_symbol_addr.sh
AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so

View File

@ -11,7 +11,7 @@ QEMU_OUT:=$(BUILD_DIR)qemu-out
FRIDA_OUT:=$(BUILD_DIR)frida-out
ADDR_BIN:=$(ROOT)frida_mode/build/addr
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/frida_get_symbol_addr.sh
AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so

View File

@ -2,8 +2,9 @@ PWD:=$(shell pwd)/
ROOT:=$(PWD)../../../
BUILD_DIR:=$(PWD)build/
TEST_CMPLOG_BASENAME=compcovtest
TEST_CMPLOG_SRC=$(PWD)cmplog.c
TEST_CMPLOG_OBJ=$(BUILD_DIR)compcovtest
TEST_CMPLOG_OBJ=$(BUILD_DIR)$(TEST_CMPLOG_BASENAME)
TEST_BIN:=$(PWD)../../build/test
@ -13,7 +14,7 @@ CMP_LOG_INPUT:=$(TEST_DATA_DIR)in
QEMU_OUT:=$(BUILD_DIR)qemu-out
FRIDA_OUT:=$(BUILD_DIR)frida-out
.PHONY: all 32 clean qemu frida frida-nocmplog format
.PHONY: all 32 clean qemu frida frida-nocmplog frida-unprefixedpath format
all: $(TEST_CMPLOG_OBJ)
make -C $(ROOT)frida_mode/
@ -64,6 +65,18 @@ frida-nocmplog: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
-- \
$(TEST_CMPLOG_OBJ) @@
frida-unprefixedpath: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
PATH=$(BUILD_DIR) $(ROOT)afl-fuzz \
-O \
-i $(TEST_DATA_DIR) \
-o $(FRIDA_OUT) \
-c 0 \
-l 3AT \
-Z \
-- \
$(TEST_CMPLOG_BASENAME) @@
debug: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
gdb \
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \

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