Compare commits

...

622 Commits
win ... 4.02c

Author SHA1 Message Date
3e2986dd78 Merge pull request #1489 from AFLplusplus/dev
push to stable
2022-08-08 15:27:07 +02:00
1f06b55a8b 4.02c 2022-08-08 15:26:56 +02:00
7b6ee28291 code format 2022-08-06 09:07:49 +02:00
94fe62ad8d Merge pull request #1467 from WorksButNotTested/droid
Android Fixes
2022-08-06 09:02:02 +02:00
608ea5f8ab Add support for Android SHM 2022-08-05 20:57:54 +01:00
00b5d3792d Changes to abstract shared memory 2022-08-05 20:56:14 +01:00
e9cb939956 Fixes to formatting 2022-08-05 20:56:14 +01:00
7b6743f14c Android fixes 2022-08-05 20:56:14 +01:00
4b9c560b07 Merge pull request #1486 from WorksButNotTested/be8
Be8
2022-08-04 21:36:59 +02:00
9d5a2d1b8e Add support for using hook on ARM32 2022-08-04 18:46:29 +01:00
1e524d1f43 Added support for ARM32 inline assembly 2022-08-04 18:46:29 +01:00
7c50ec5d05 Added support for ARM32 persistent mode 2022-08-04 18:46:29 +01:00
7bdb22c70c Added build of FRIDA mode shared library to enable embedding 2022-08-04 18:46:29 +01:00
3562de440e Changes to add option for absolute coverage data 2022-08-04 18:46:29 +01:00
98e8838755 Fix formatting 2022-08-04 18:46:29 +01:00
a2f3c3ee51 Merge pull request #1478 from AFLplusplus/dev
Push to stable
2022-08-03 11:08:10 +02:00
6056d4b140 fix pcguard vector select instrumentation 2022-08-03 10:06:52 +02:00
d745da0c93 Merge pull request #1484 from WorksButNotTested/regs
Regs
2022-07-29 22:50:25 +02:00
4fdd64d6d6 Added framework for logging register contents at the end of each basic block 2022-07-29 19:33:31 +01:00
f2b7104cd6 Fix endianness of coverage data on big endian systems 2022-07-29 17:23:30 +01:00
c6af98bc35 fix 2022-07-25 11:49:49 +02:00
67fabcb0be update compile options 2022-07-25 11:15:14 +02:00
7b7914e1d6 code format 2022-07-25 09:09:29 +02:00
9551be3f8e Merge pull request #1482 from yuawn/fix_usage_message
Fix usage message
2022-07-25 08:47:48 +02:00
f22d28333b code format with clang-format-14 2022-07-24 10:41:50 +00:00
d8d6ea93cf fix sentence & code format 2022-07-24 10:30:21 +00:00
0540d30274 fix message overflow 2022-07-24 10:23:33 +00:00
9657b700b1 Fix some OSX incompatibilities on AARCH64 (#1479)
Co-authored-by: Your Name <you@example.com>
2022-07-21 19:48:21 +02:00
6c26434a63 fix pizza mode 2022-07-21 13:41:43 +02:00
42c677aa7b fix compilation for llvm 10.0 2022-07-19 23:03:20 +02:00
0373628adf fix custom mutator examples 2022-07-19 17:28:57 +02:00
d090232452 remove debug 2022-07-19 17:06:23 +02:00
4d20b2d28b fix 2022-07-19 17:04:53 +02:00
c67f98865e fix 2022-07-19 14:53:43 +02:00
ca4a8c0f92 post_process 0/NULL return support 2022-07-19 12:24:03 +02:00
c57988e672 Merge pull request #1469 from AFLplusplus/dev
push to stable
2022-07-15 10:12:35 +02:00
b847e0f414 clang format 14 2022-07-12 09:04:54 +02:00
338f1ae2f8 fix mawk bug 2022-07-11 21:42:03 +02:00
1f4b45b5bf nit 2022-07-11 12:32:17 +02:00
30736ab7d6 nit 2022-07-11 12:16:33 +02:00
46fed1f43f Merge pull request #1472 from llzmb/docs_quality_assurance_5
Fix formatting, punctuation, and typos of docs
2022-07-11 11:53:03 +02:00
662662c15d Fix formatting, punctuation, and typos 2022-07-11 11:33:51 +02:00
d088c26045 Merge pull request #1470 from WorksButNotTested/frida
Updated FRIDA version
2022-07-08 19:47:53 +02:00
3d2a095f2e Updated FRIDA version 2022-07-08 18:22:05 +01:00
9abae56a37 Merge pull request #1453 from rhtenhove/dev
improve CI and container image build
2022-07-08 18:46:21 +02:00
1f17aa082d Dont codeql submodules 2022-07-08 08:32:17 -04:00
c7c7476453 disable formatter 2022-07-07 17:10:42 +00:00
b883faa942 Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2022-07-07 17:07:57 +00:00
b1e0d6e640 fix macos ci 2022-07-07 18:39:21 +02:00
ada61204f3 Merge pull request #1468 from waugustus/add-missing-dependencies
add missing dependencies for "make source-only"
2022-07-07 15:17:35 +02:00
72344a2f5f move the apt call 2022-07-07 18:48:02 +08:00
0bb8cc46b4 build nyx in docker 2022-07-07 12:47:12 +02:00
05080f32ee fixes 2022-07-07 11:10:12 +02:00
32c4be4773 add missing dependencies for "make source-only" 2022-07-07 17:01:36 +08:00
1759859ae2 fix double free on exit for -c 0 on src cmplog 2022-07-07 09:03:46 +02:00
e6f27c2645 add missing laf compare split predicates 2022-07-07 00:34:30 +02:00
c90dd00fc9 no longer need this line 2022-07-04 22:38:28 +00:00
0da935183f allow unset env var 2022-07-04 22:36:06 +00:00
4848c8d24c use env as base 2022-07-04 22:30:03 +00:00
250000ee79 simpler format bin selector 2022-07-04 22:27:55 +00:00
fc520a2bde fix 2022-07-04 21:57:42 +02:00
6c9c8fdc65 check code formatting (#5) 2022-07-04 14:32:48 -04:00
24458ae285 nits 2022-07-04 18:13:21 +02:00
36a0ab1193 Merge pull request #1466 from rhtenhove/cpubind
feat: show bound cpu
2022-07-04 10:01:39 +02:00
1334851e7c cmplog support for gcc_plugin by adacore 2022-07-04 09:59:47 +02:00
b077a7963b feat: show bound cpu 2022-06-30 21:11:22 +00:00
3e65e1a029 fix test using test specific build 2022-06-28 15:59:56 +00:00
e21738a248 init new dev release 2022-06-28 14:30:03 +02:00
4094750803 Merge pull request #1438 from AFLplusplus/dev
push to stable
2022-06-28 14:18:44 +02:00
92352951d7 nits 2022-06-28 11:52:05 +02:00
bb509765df added back missing memcpy to python mutators 2022-06-28 11:45:22 +02:00
6705953a49 Python mutators: Gracious error handling for illegal return type (#1464)
* python types error handling

* reverted example change

* more python

* format
2022-06-28 10:23:20 +02:00
b3edb657c2 check python too 2022-06-28 01:50:39 +00:00
a1889db9bf simpler jobs 2022-06-27 16:17:02 -04:00
c83635e1d2 Merge pull request #1462 from bostick/patch-1
Update afl-system-config
2022-06-27 19:18:28 +02:00
fd404194f2 Update afl-system-config
System Integration Protection -> System Integrity Protection
2022-06-27 11:38:33 -04:00
5fa7861149 no need for that line anymore 2022-06-27 15:37:15 +00:00
e969972c97 gcta 2022-06-27 15:35:41 +00:00
80e829f79d revert more and global replace 2022-06-27 15:30:35 +00:00
73db4fe993 use actor 2022-06-27 15:13:16 +00:00
22c3b519fa reverts, fixes and even smaller image (#3) 2022-06-27 11:05:17 -04:00
88077d4136 prepare release 2022-06-27 08:44:35 +02:00
cfb0257c99 nits 2022-06-27 08:37:21 +02:00
9a93688e3e nits 2022-06-27 08:32:06 +02:00
48c2d51689 nits 2022-06-27 08:31:03 +02:00
1dac69b1eb use container; more is built + tested; use make -i (#2) 2022-06-24 09:26:09 -04:00
0da7ddb738 concurrency and caching (#1)
* use concurrency

* run here too

* allow test failure

* only push on push

* fix coresight mode build

* support but disable coresight

* woops

* no unicorn for arm

* update codeql and fix makefile

* forgot those

* disable forward cache

* fix needing buildx

Co-authored-by: Ruben ten Hove <ruben.tenhove@tno.nl>
2022-06-22 06:36:35 -04:00
6e960f78d6 arm needs qemu indeed 2022-06-21 22:01:30 +02:00
3282023047 check for package instead of if in docker 2022-06-21 21:36:02 +02:00
c7db5b67f9 just disable nyx 2022-06-21 21:30:43 +02:00
fc98d53e27 separate platforms 2022-06-21 18:54:54 +02:00
a5822c7c2f various changes 2022-06-21 18:52:43 +02:00
01cb84051a secure apt key; fix multilib 2022-06-21 16:54:47 +02:00
d9c2487c3e reduce layers, size and complexity 2022-06-21 10:30:30 -04:00
a7f3f87f41 Merge pull request #1450 from jrozner/add-22.04-to-ci
Update workflows to ubuntu 22.04
2022-06-21 07:48:49 +02:00
1a4c0d2ecd nits 2022-06-20 17:59:14 +02:00
eb37cec76e Update workflows to ubuntu 22.04
22.04 is the most recent LTS release and the official docker container
is running on it. It probably makes sense to run the unit tests on that
as well.
2022-06-19 11:42:31 -07:00
5ed993d74e Merge pull request #1440 from rhtenhove/dev
require value in env variables
2022-06-18 21:48:58 +02:00
5d5d1f70fc Merge pull request #1447 from rhtenhove/more-tags
fixes github actions
2022-06-18 21:48:10 +02:00
85b1ce00a8 fully qualified names 2022-06-18 08:35:25 -04:00
51a88b17b3 add tagged releases 2022-06-18 08:31:37 -04:00
b0e58baca2 add stable tag to docs 2022-06-18 08:21:25 -04:00
f23cac854a fix image build and push 2022-06-18 08:19:04 -04:00
0c3ba7d227 clarity 2022-06-18 07:23:06 -04:00
605f2bf969 code format 2022-06-18 09:14:44 +02:00
dc3e2e8200 update docs 2022-06-18 09:06:27 +02:00
47d4f16189 Merge pull request #1442 from rhtenhove/more-tags
Push both stable and dev
2022-06-18 08:58:49 +02:00
74f70d0c74 update name 2022-06-18 02:55:27 +02:00
be79ee7072 stable==latest 2022-06-18 02:52:57 +02:00
bf6a0159a9 formatting 2022-06-18 02:37:11 +02:00
fc3b483450 revert previous changes 2022-06-18 02:35:40 +02:00
0dd1c39b5a check for empty env var as well 2022-06-18 02:35:31 +02:00
60702fef7a Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2022-06-18 00:41:50 +02:00
a96f9a349a Merge pull request #1441 from rhtenhove/noreadme
Allow to skip README.txt creation in crashes/
2022-06-18 00:25:03 +02:00
4fdd1129f0 feat: push both dev and stable 2022-06-17 21:21:34 +02:00
4990823840 formatting 2022-06-17 21:08:37 +02:00
3d1a57deed feat: allow to skip readme creation on crash 2022-06-17 21:03:46 +02:00
47d8947471 require value in env 2022-06-17 12:10:11 -04:00
80892b8fc5 typos 2022-06-14 14:57:31 +02:00
ba21e20695 typo 2022-06-14 14:56:10 +02:00
5b471986b8 add line feed at end 2022-06-14 14:52:48 +02:00
da1b041098 update changelog 2022-06-12 08:24:32 +02:00
95aa81045b Merge pull request #1437 from Scepticz/patch-2
Fix Byte Decrement Havoc Mutation
2022-06-12 07:48:27 +02:00
b595727f2f Fix Byte Decrement Havoc Mutation
While looking at the source code of the havoc mutations I realized that there seems to be a typo / copy+paste error with the SUBBYTE_ mutation. It is currently incrementing, instead of decrementing the value.

Alternative Fix: Change the documentation to "/* Decrease byte by minus 1. */" to make it work as documented :-P
2022-06-10 18:38:37 +02:00
d798a90f04 uc update 2022-06-09 10:11:41 +02:00
35d49c7c5c fix 2022-06-08 12:46:08 +02:00
83f32c5248 honor AFL_MAP_SIZE well outside of afl++ 2022-06-08 10:56:11 +02:00
683dcc4710 remove existing shared modules when installing 2022-06-06 19:26:18 +02:00
59bb4a6cc4 Merge pull request #1431 from devnexen/malloc_good_size_apple_libdislocator
libdislocator, introduces malloc_good_size for Darwin.
2022-06-03 06:55:10 +02:00
6afccdebcd libdislocator, introduces malloc_good_size for Darwin. 2022-06-02 21:48:15 +01:00
7413316496 Merge pull request #1430 from devnexen/libdislocator_macos
libdislocator on macOS to get memory block size is malloc_size is
2022-06-01 07:32:45 +02:00
ad2a1b0574 libdislocator on macOS to get memory block size is malloc_size is
instead.
2022-05-31 21:07:02 +01:00
942b85bb77 clarify gpl3 2022-05-31 11:10:37 +02:00
50c6031cc3 remove optimin 2022-05-31 09:24:28 +02:00
066d65d846 Fix wrong memchr size in android (#1429)
Need to fix this otherwise ASAN will always complain about heap buffer overflows and refuse to run.

Co-authored-by: van Hauser <vh@thc.org>
2022-05-27 17:55:21 +02:00
1441503c43 afl-cmin: avoid messages with \r when redirection is used 2022-05-27 15:26:24 +02:00
c96238d85f Add AFL_SYNC_TIME variable for synchronization time tuning (#1425)
* Add AFL_SYNC_TIME variable for synchronization time tuning

* Documentation for AFL_SYNC_TIME variable
2022-05-27 12:52:31 +02:00
4103ee43e2 Add automaton parser (#1426)
* have compilable program

* enable read in file

* add hashmap usage

* add build hashmap; WIP; test if constructed correctly tomorrow

* add testcase to test hashmap

* add sorted symbols list

* build symbols dictionary

* clean up DEBUG

* successfully find automaton path

* fix all memory leaks

* test if automaton same with example

* able to iterate through files in a folder

* finish testing on one random queue
wip
- change macro values
- add bound checking

* add bound checking to program length

* add bound checking to program walk length

* add boundary check to terminal number, terminal lengths and program length

* commit test makefile

* add makefile

* able to add seeds to gramatron

* remove useless argument in automaton_parser

* add automaton parser to gramfuzz

* change build

* revert test.c to original state

* add makefile to test.c for testing
2022-05-26 16:21:59 +02:00
ba3c7bfe40 Merge pull request #1420 from AFLplusplus/dev
push to stable
2022-05-23 13:44:42 +02:00
5ad760a77b update changelog 2022-05-23 10:53:37 +02:00
6dfc9aaab0 disable LTO for llvm 15 :-( 2022-05-23 10:52:34 +02:00
ffdbe8a2fb Merge pull request #1411 from glandium/implicit-int
Fix build failures with clang 15
2022-05-19 11:21:32 +02:00
c5083f8982 todo 2022-05-19 11:21:09 +02:00
ca721404ef Merge pull request #1415 from che30122/dev
afl->cmplog_binary memory leak problem
2022-05-18 10:32:35 +02:00
c563faa076 fix mem leak 2022-05-17 16:47:01 +08:00
a2eb1f1412 Merge pull request #1404 from AFLplusplus/dev
push to stable
2022-05-16 12:34:38 +02:00
c08eeb95ca Merge pull request #1410 from WorksButNotTested/dynamic
A few updates
2022-05-16 11:15:21 +02:00
7c755a675f Merge pull request #1412 from HexRabbit/fix_make_deps
Fix missing dependency
2022-05-16 10:24:20 +02:00
4c0281adc8 Fix missing dependency
add `instrumentation/afl-llvm-common.o` to `SanitizerCoverageLTO.so`'s
dependency list
2022-05-16 16:10:07 +08:00
022f364661 Avoid implicit-int error in x86 test with clang 15
See 2cb2cd242c
2022-05-13 07:23:38 +09:00
3dc72ffb6b Added test for prefetch validation 2022-05-12 16:54:40 +01:00
ca361e1b6a Validate address space before prefetching 2022-05-12 16:54:40 +01:00
b36d0adb46 Update version of FRIDA 2022-05-12 16:54:40 +01:00
2a4d77abc6 Update nyx submodules (#1408) 2022-05-12 13:29:30 +02:00
dfe03a346a update unicorn 2022-05-12 09:11:25 +02:00
1605291154 Docker image update to ubuntu jammy LTS (#1406)
which brings gcc 12 and the llvm 14 suite.
2022-05-11 14:40:14 +02:00
f180109d1a Merge pull request #1405 from yuawn/fix_llvm_version
Fix LLVM version in Dockerfile comment
2022-05-11 11:29:01 +02:00
927cb770f0 fix LLVM version 2022-05-11 09:17:21 +00:00
82c6c8e563 update changelog 2022-05-10 12:18:34 +02:00
79099a01f8 fix effector map calculation 2022-05-10 11:05:43 +02:00
7c8246f18f fix 2022-05-09 14:30:40 +02:00
51942b605d support post_process's own return buffer 2022-05-09 13:18:14 +02:00
47dae21f4a Merge pull request #1401 from devnexen/fbsd_largepage
large shared segment optimisation (in TEST_MMAP mode)
2022-05-08 12:47:25 +02:00
ba12c7fc09 Merge pull request #1400 from devnexen/frida_android_bfix
frida module android build fix.
2022-05-08 12:46:33 +02:00
229a45c6a6 large shared segment optimisation (in TEST_MMAP mode)
for FreeBSD supporting such feature.

Grabbing the first kind which fit the needed size otherwise
falling back to the classic shared segment allocation.
2022-05-06 19:02:21 +01:00
45219dee80 frida module android build fix. 2022-05-06 15:56:03 +01:00
13e0fd3e1a pcguard fix for most current llvm 15 changes 2022-05-03 13:01:48 +02:00
68e8467859 fix 2022-05-02 14:11:25 +02:00
293e255734 fix mopt random selection 2022-05-02 13:09:34 +02:00
0b228fb0f5 fix token usage in normal and MOpt mode 2022-05-02 08:17:06 +02:00
01594dc416 Properly null CmpLog map in deinit (#1395)
Co-authored-by: van Hauser <vh@thc.org>
2022-04-28 09:42:49 +02:00
46d5452c86 update afl-sharedmem.c 2022-04-28 15:35:25 +08:00
c7bb0a9638 Merge pull request #1392 from AFLplusplus/dev
push to stable
2022-04-25 10:14:19 +02:00
ee409d18a6 code format 2022-04-25 10:14:04 +02:00
5d5aa430d2 add changelog 2022-04-25 09:10:59 +02:00
5792d492ed Merge pull request #1375 from wtdcode/fix_uc_static
Fix unicornafl static build
2022-04-25 09:09:18 +02:00
9ac3c53104 fix my name 2022-04-24 20:52:31 +02:00
ee50f41d29 Merge origin/dev 2022-04-24 20:13:40 +02:00
aeeca164b5 Bump unicornafl 2022-04-24 20:12:42 +02:00
b2c96f66ee unicorn 2022-04-22 10:29:56 +02:00
7f26d13345 try repeating write 2022-04-22 10:28:21 +02:00
5798c686b2 Merge pull request #1393 from jschwartzentruber/dev-wasm
instrumentation fixes for wasm
2022-04-21 10:16:41 +02:00
f53e6a6cf2 fix instrumentation for -Werror,-Wunused-but-set-variable
`used` is so it isn't optimized out. `unused` is to avoid the warning.
2022-04-20 15:39:28 -04:00
630eb943a5 use passthrough mode for wasm 2022-04-20 15:38:37 -04:00
4f42ecd815 remove WIP code 2022-04-18 13:16:10 +02:00
1d00bde6c5 code format 2022-04-18 13:14:20 +02:00
b1da7500b2 fix msg 2022-04-18 13:14:20 +02:00
223c52827a Merge pull request #1388 from mlichvar/cmin-args
afl-cmin: quote program arguments
2022-04-18 12:26:26 +02:00
e1c4a4ea7e Merge pull request #1382 from AdaCore/pr/gcc_deny_list_fix
Fix GCC plugin crash when using deny/allow list
2022-04-18 10:44:42 +02:00
b092ee4986 Merge pull request #1385 from Cornul11/update_citation
Updated citation file.
2022-04-18 10:43:38 +02:00
494c55df15 Merge pull request #1389 from yuawn/dev
update llvm version in INSTALL.md
2022-04-18 10:41:08 +02:00
35cf1fa906 Merge pull request #1390 from devnexen/map_name_libdislocator
libdislocator, new option to name an anonymous address range.
2022-04-18 10:40:27 +02:00
6e790552fe libdislocator, new option to name an anonymous address range.
For performance matter tough, disabled by default.
2022-04-15 17:34:19 +01:00
8971c9a5ce update llvm version in INSTALL.md 2022-04-14 11:26:54 +00:00
57db3e7f4f afl-cmin: quote program arguments
Quote the program arguments in the system() function to allow them to
contain spaces.
2022-04-13 13:47:51 +02:00
0540382c41 Fix persistant sample build 2022-04-13 00:43:47 +02:00
2263989e12 Fix linkage 2022-04-12 22:57:43 +02:00
6aa470d641 Sync unicornafl 2022-04-12 22:57:36 +02:00
0db57c3eec Merge origin/dev 2022-04-12 21:16:34 +02:00
ce1fc4b27d updated citation 2022-04-11 19:30:06 +02:00
5d4b0938d5 link https://github.com/fuzzah/exeptor 2022-04-08 23:28:13 +02:00
c208dcf9c5 Merge pull request #1383 from AFLplusplus/keep_tout
Keep timeouts option
2022-04-08 23:12:33 +02:00
d8317182ef update fuzzing in depth 2022-04-08 23:10:35 +02:00
e9288bcfad add AFL_KEEP_TIMEOUTS 2022-04-08 22:44:10 +02:00
396de6fc9c Fix GCC plugin crash when using deny/allow list
The provided function declaration F may not have valid location
information. Return an empty string in this case as the two callers are
already using this convention to filter out functions from being
instrumented when deny/allow list are used.
2022-04-08 09:50:08 +02:00
891f4d3c8e correct counting for tmouts 2022-04-08 09:31:39 +02:00
9933a6f3ab update grammar mutator 2022-04-07 10:21:52 +02:00
3261e86a3a save timeouts 2022-04-07 09:43:51 +02:00
3ccebbf9c5 Typo 2022-04-06 17:30:27 +02:00
9c2c35b233 Merge pull request #1381 from f0rki/no-build-nyx
add make flag to avoid building nyx mode
2022-04-06 14:31:42 +02:00
bf5b90f95a added NO_NYX flag to docs and help message 2022-04-06 14:20:36 +02:00
8385bc794a make flag to avoid building nyx mode 2022-04-06 11:54:35 +02:00
ac80678592 Merge pull request #1380 from AFLplusplus/dev
fix cmplog
2022-04-06 10:24:07 +02:00
3c5edab724 add cmplog icmp testcase to CI 2022-04-06 10:10:39 +02:00
9887f636ba Merge pull request #1376 from verifsec/patch-1
[wontfix] make error @SIMPLE_FILES
2022-04-06 09:45:15 +02:00
fc48951468 Merge pull request #1379 from devnexen/network_client_mem_leak
network client mem leak fix.
2022-04-06 09:43:34 +02:00
0e9d0ebbfe fix cmplog! 2022-04-06 09:36:57 +02:00
84e03e4a4d network client mem leak fix. 2022-04-05 22:54:36 +01:00
044d3e823e [wantfix] make error @SIMPLE_FILES
Hi there!
I tried to compile with SIMPLE_FILES, but got  an error message.
Please have a look through it.
Sincerely.

```
src/afl-fuzz-bitmap.c: In function ‘save_if_interesting’:
src/afl-fuzz-bitmap.c:706:39: error: ‘afl_state_t’ {aka ‘struct afl_state’} has no member named ‘last_kill_signal’
  706 |                afl->saved_crashes, afl->last_kill_signal);
      |                                       ^~
make: *** [GNUmakefile:437: afl-fuzz] Error 1
```
2022-04-05 17:38:34 +09:00
3fc03d4b6b Fix unicornafl static build
Signed-off-by: lazymio <mio@lazym.io>
2022-04-04 11:45:49 +02:00
15b43e6ce1 fix pizza mode 2022-04-03 19:14:59 +02:00
d9fa6af1b1 pizza mode on 1st of april 2022-04-03 09:50:18 +02:00
ef5543680a Merge pull request #1374 from CarloMara/stable
Add new mode to AFLplusplus
2022-04-03 09:31:23 +02:00
881aef21fd Merge pull request #1362 from AFLplusplus/dev
push to stable
2022-04-03 09:30:23 +02:00
26f3ec28ee Fix dyslexia and clang format 2022-04-02 13:11:39 +02:00
657e4cc812 Fix layout 2022-04-01 14:56:27 +02:00
29f0bb1c6a Add basic support for Italian users 2022-04-01 13:23:01 +02:00
c4363dd8b3 Merge pull request #1373 from rwmjones/no-circular-links
GNUmakefile.llvm: Avoid creating circular links
2022-04-01 09:42:06 +02:00
ff5882f415 Merge pull request #1372 from devnexen/frida_arm64_build_fix
frida mode fix arm64 build
2022-03-31 19:38:05 +02:00
7f56a93f5d GNUmakefile.llvm: Avoid creating circular links
Building into a DESTDIR gives circular links such as:

lrwxrwxrwx. 1 rjones rjones 17 Mar 31 18:09 /home/rjones/rpmbuild/BUILDROOT/american-fuzzy-lop-4.00c-3.git285a5cb3.fc37.x86_64/usr/lib64/afl/afl-compiler-rt.o -> afl-compiler-rt.o

I have to admit I've no idea what the original link command is trying
to achieve, but it's clearly wrong and deleting it fixes the problem.

Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
2022-03-31 18:20:43 +01:00
2d7ac5f69c frida mode fix arm64 build 2022-03-31 18:11:24 +01:00
285a5cb38b Some scan-build fixes 2022-03-31 15:36:26 +00:00
51dbd0e957 ignore unused variable to let make DEBUG=1 distrib succeed 2022-03-30 20:46:57 +02:00
772e33d550 avoid compiler warning (format-truncation), needed for make DEBUG=1 all 2022-03-30 20:32:51 +02:00
77a3abfa5e remove debug 2022-03-30 17:09:00 +02:00
a436ef47e5 fix instrumentlist for LTO with clang < 13 2022-03-30 09:16:47 +02:00
b34751efbf fix qemu sigunaction tests 2022-03-29 10:34:08 +02:00
d2ea1141eb cleanup 2022-03-27 11:35:38 +02:00
3f0d642f9b fix unicornafl test 2022-03-26 19:13:49 +00:00
7598efb8e6 Merge pull request #1363 from clchrlls/stable
fix installation packages commands for debian 10
2022-03-23 17:20:03 +01:00
0dca6ee038 put back the title of the page deleted by mistake 2022-03-23 17:11:22 +01:00
a601b56627 reverted to simply changing gcc version retrieval 2022-03-23 17:09:31 +01:00
ce0db35f18 Not sure the fix is needed only for debian 10 2022-03-23 15:03:56 +01:00
d012358748 missing column 2022-03-23 15:02:47 +01:00
d4734f6d9b fix installation packages for debian 10 2022-03-23 14:57:24 +01:00
bcf123e1ee update qemu mode 2022-03-23 09:30:16 +01:00
9a87e83bf4 Merge pull request #1359 from fuzzah/fix-1333-afl-target-env
fix early return in AFL_TARGET_ENV
2022-03-21 22:47:19 +01:00
c2ae24ab96 fix early return in AFL_TARGET_ENV 2022-03-21 22:58:17 +03:00
13c8a27faa Merge pull request #1355 from rwmjones/document-linker-scripts
docs: Document linker scripts change required in some projects
2022-03-19 15:58:11 +01:00
a133aa9106 docs: Document linker scripts change required in some projects
AFL instrumentation modifies the binary to export extra symbols which
must be visible if the main binary dlopen()s an instrumented DLL.
This change was required by nbdkit since it uses a linker script to
limit the symbols exported from the main binary:

355cacb812

Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
2022-03-18 15:52:50 +00:00
fa2b040476 fix LTO with cmplog and laf 2022-03-18 15:00:24 +01:00
69c9a176eb our own PCGUARD mode not for llvm 10.0.1 2022-03-18 12:57:51 +01:00
bdfac291ba fix split pass loading 2022-03-18 08:47:45 +01:00
90fd61d14a forgot one pass 2022-03-17 19:43:14 +01:00
3d1be62c96 merge fixes 2022-03-17 16:39:40 +01:00
d1f59435ca Merge pull request #1353 from AFLplusplus/newpm2
new pass manager
2022-03-17 16:30:44 +01:00
1bea949f34 Merge branch 'dev' into newpm2 2022-03-17 16:30:29 +01:00
3c11a37757 fixes for llvm < 11 2022-03-17 15:48:06 +01:00
e4f201707f make LTO pass work too plus some fixes 2022-03-17 14:35:15 +01:00
59eaed2f70 make pcguard work 2022-03-17 13:52:48 +01:00
1a65df2bee Merge pull request #1352 from cd80/patch-1
fix typo in error message when using LD_PRELOAD
2022-03-17 08:46:15 +01:00
c08304ad3d fix typo for error message when using LD_PRELOAD 2022-03-17 14:36:41 +09:00
2b8fea083e test 2022-03-15 07:35:37 +01:00
34d7a6357e Merge pull request #1347 from WorksButNotTested/cache
Add global caching of block translation to instrumentation
2022-03-08 11:44:15 +01:00
ae9897ff7b Merge pull request #1346 from mchesser/patches
Fix Shm trim bug and OOB accesses during Redqueen mutations.
2022-03-07 09:52:34 +01:00
d297738255 nits 2022-03-07 09:37:19 +01:00
981a04eb27 new compiler performance options 2022-03-07 08:13:24 +01:00
2a00f32666 Fix buffer overrun in rtn_extended_encoding
`idx + i` can range from `0` to `buf.len`, but the memcpy may try and write to offsets from `idx + i` to `idx + 2 * i`.
2022-03-07 15:26:54 +10:30
c2229b506e Fix off by one bounds check
`is_hex` reads two bytes but caller previously only ensured that one byte was in bounds.
2022-03-07 14:35:25 +10:30
70cc32dc6d Fix issue with trim in shared memory mode 2022-03-07 14:28:45 +10:30
5385cc7618 sancov will be only for llvm11+ 2022-03-04 15:03:26 +01:00
2eeba2dbf0 code format 2022-03-04 09:41:21 +01:00
09123d8617 Merge pull request #1344 from schumilo/dev
support Nyx crash logs
2022-03-04 09:37:21 +01:00
713b069f40 fix compile error on non linux targets 2022-03-04 06:01:49 +01:00
0f7419fc91 write nyx crash logs to AFL++ work directory 2022-03-04 05:41:40 +01:00
7c9b7c0bc0 update submodules 2022-03-04 05:35:27 +01:00
544b68044a fix broken code format 2022-03-04 03:36:52 +01:00
33e43b11f8 port instrumentation/afl-llvm-dict2file 2022-03-03 18:24:26 +01:00
a2d54218ad ported cmplog-routines-pass 2022-03-03 17:27:50 +01:00
899fa59ab6 port cmplog-switches-pass 2022-03-03 17:11:41 +01:00
f2831419f5 ported cmplog-instructions-pass 2022-03-03 08:55:05 +01:00
d325fa5db8 code format 2022-03-01 20:13:57 +01:00
7e67545b9d code format 2022-03-01 20:01:12 +01:00
d84a8da1e9 allow for -c0 also for src targets 2022-03-01 19:30:17 +01:00
f70760896c Revert "Merge branch 'newpm2' into dev"
This reverts commit fee1acf7e6, reversing
changes made to 675d17d737.
2022-03-01 19:21:31 +01:00
c9504867da Merge pull request #1342 from martinclauss/patch-1
Update fuzzing_in_depth.md
2022-03-01 16:27:09 +01:00
744ad172e1 Update fuzzing_in_depth.md
add libdesock as an additional way to ease the fuzzing for network servers (#1341)
2022-03-01 15:42:04 +01:00
5e9286b9ea todo list for llvm 2022-02-28 17:43:58 +01:00
d22532d8d3 Merge pull request #1340 from AFLplusplus/dev
Dev
2022-02-28 17:42:40 +01:00
cd02f635db remove file 2022-02-28 17:42:11 +01:00
819a1539a6 Merge pull request #1337 from devnexen/llvm_13_plus_fix
Fix build for the LLVM pass for LLVM >= 13
2022-02-27 17:25:42 +01:00
ba7ec51232 Merge pull request #1339 from adamdoupe/dev
Clarify in docs that AFL_TARGET_ENV will apply to QEMU in QEMU mode.
2022-02-27 17:25:02 +01:00
1840c27b6f Clarify in docs that AFL_TARGET_ENV will apply to QEMU in QEMU mode, and note that QEMU_SET_ENV should be used instead in QEMU mode. Closes #1328 2022-02-26 22:20:58 +00:00
e996112fbc Fix build for the LLVM pass for LLVM >= 13
Due to change of inheritance for more modern LLVM versions, the overridable
members are not the same.
2022-02-24 14:50:44 +00:00
9b799aeddd Merge pull request #1335 from AFLplusplus/dev
Dev
2022-02-22 13:59:04 +01:00
fee1acf7e6 Merge branch 'newpm2' into dev 2022-02-22 13:58:49 +01:00
675d17d737 Merge pull request #1334 from Teemperor/llvm14
Fix compilation against LLVM 14
2022-02-22 13:51:39 +01:00
05119990b6 LLVM 14 fixes 2022-02-22 11:13:00 +01:00
914eb79cbc todo list 2022-02-21 10:32:43 +01:00
92db443635 Revert "remove new llvm pass manager :("
This reverts commit 55ed2a443c.
2022-02-20 19:51:43 +01:00
852c036cae Add global caching of block translation to instrumentation 2022-02-18 17:39:21 +00:00
a5943dc782 Merge pull request #1332 from WorksButNotTested/module
Module
2022-02-18 11:04:45 +01:00
fc7bf33fb1 Reserved used address space on dlclose to prevent re-use 2022-02-18 08:21:36 +00:00
fcd06fa99c Added test for running python 2022-02-18 08:20:51 +00:00
5f45f380c3 Changes to default CMOV instrumentation to off 2022-02-18 08:10:19 +00:00
cb1256499f Added instrumentation for CMOV instructions 2022-02-18 08:01:34 +00:00
dd8ad4dfa3 Changes to simplify coverage code 2022-02-18 07:55:26 +00:00
8fc249d210 Fix sample script for Unicornafl2 (#1329)
* Fix the sample script for Unicornafl2

* Make it compatible with unicornafl1

* Sync to the latest unicornafl

* Update UNICORNAFL_VERSION

* Sync to latest unicornafl to resolve linkage problem

* Switch to ucafl2
2022-02-14 18:01:37 +01:00
1d4f1e4879 Merge pull request #1326 from AFLplusplus/dev
push to stable
2022-02-10 12:12:02 +01:00
de7058b75b typo 2022-02-10 10:40:11 +01:00
5e8da2b85c Adapt to my MacOS 2022-02-09 20:36:16 +01:00
056ebbff15 add AFL_EARLY_FORKSERVER support 2022-02-08 20:36:06 +01:00
cf853fb249 reintroduce AFL_PERSISTENT and AFL_DEFER_FORKSRV 2022-02-08 20:15:48 +01:00
fa628865c1 remove debug msg 2022-02-08 18:43:23 +01:00
05a36f10ba import mozilla afl-cc patch 2022-02-08 18:33:59 +01:00
cbf3d1bdee Merge pull request #1325 from devnexen/openbsd_sysconf_upd
afl-system-config update proposal for OpenBSD.
2022-02-08 13:40:21 +01:00
64cc345ec2 afl-system-config update proposal for OpenBSD.
The vast majority of security features can t be disabled but we can
act of allocation config.
2022-02-08 11:25:19 +00:00
8dbc4a1423 Merge pull request #1324 from WorksButNotTested/compile
Fix initialization in non-persistent mode
2022-02-08 12:17:20 +01:00
452eb9f75b Fix initialization in non-persistent mode 2022-02-08 08:58:35 +00:00
a5dc067331 nits 2022-02-07 12:22:57 +01:00
27dc0e09e0 Merge pull request #1323 from yuawn/dev
Add GCC hot attribute to hot functions
2022-02-06 11:51:54 +01:00
bcd802e6fd code format 2022-02-06 08:54:30 +00:00
958a059477 add GCC hot attribute to hot functions 2022-02-06 08:54:14 +00:00
c8bfce21ab Merge pull request #1322 from yuawn/dev
fix -G description
2022-02-06 09:13:40 +01:00
d178b325ab fix -G description 2022-02-06 05:34:44 +00:00
077a3e32e0 fix accidental broken frida mode 2022-02-05 10:57:58 +01:00
fa3c0d8a37 change -y to -g/-G and add env var alternatives 2022-02-05 10:36:37 +01:00
d5b9cd4b73 add afl-fuzz -y fuzz length support 2022-02-05 08:27:17 +01:00
ce5032cc29 debug CI 2022-02-05 07:32:20 +01:00
04d693721b force persistent and deferred also for tools 2022-02-05 07:25:12 +01:00
9eb66cccf4 typo 2022-02-04 15:06:53 +01:00
9b72fe4880 typo 2022-02-04 13:59:11 +01:00
1a89d428c9 same for defered forkserver 2022-02-04 12:12:23 +01:00
d4c01c057b test support for forced persistent mode 2022-02-04 12:09:07 +01:00
80543a809e small doc update 2022-02-01 20:15:45 +01:00
104c0e29e9 small doc update 2022-02-01 20:14:41 +01:00
7d36609722 libafl custom mut readme 2022-02-01 15:53:05 +01:00
119a0e0dce fix build scripts 2022-02-01 14:16:49 +01:00
f336aa463b Merge pull request #1307 from WorksButNotTested/arm64
ARM64
2022-02-01 11:09:39 +01:00
5f6bbc7dea Changes to fix persistent_ret demo 2022-02-01 08:13:28 +00:00
17fc44d995 Fix libunwind libraries when building from source 2022-02-01 08:13:28 +00:00
jon
055af82026 Make default coverage code branchless 2022-02-01 08:13:28 +00:00
e2f76dd41e AARCH64 branch suppression 2022-02-01 08:13:28 +00:00
1c79b82ab8 Add AARCH64 support for setting ic_entries 2022-02-01 08:13:28 +00:00
jon
c38b05c80a Fixed build from source on OSX 2022-02-01 08:13:28 +00:00
bb186a2ece Bump FRIDA version 2022-02-01 08:13:18 +00:00
60e126c615 mention arm64 docker image 2022-01-31 09:24:04 +01:00
dd9003e59b nits for nyx build script 2022-01-31 09:00:01 +01:00
2d9325aed9 Merge pull request #1319 from AFLplusplus/dev
push to stable
2022-01-30 20:59:24 +01:00
53eb5ba2fb update changelog 2022-01-30 20:59:00 +01:00
267dd634f1 Merge pull request #1318 from moyix/stable
Build docker images for arm64 as well as x86.
2022-01-30 20:55:55 +01:00
7ab7862e4d Build docker images for arm64 as well as x86.
This involves:

* A small change to the Dockerfile, so that it checks the target
  architecture and only installs gcc-multilib on x86_64.
* Updates to the GitHub Actions workflow build_aflplusplus_docker.yaml
  to build for both linux/amd64 and linux/arm64.

These changes should allow Mac M1 users to get a working version of
AFL++ by doing "docker pull aflplusplus/aflplusplus".
2022-01-30 14:20:30 -05:00
59a7337bf1 fix ci for mac 2022-01-30 18:02:09 +01:00
c75124aefa debug ci 2022-01-30 17:53:28 +01:00
2861f695ba debug ci 2022-01-30 17:19:22 +01:00
43a7c0d601 make build_... scripts work without afl++ git checkout 2022-01-30 14:50:15 +01:00
311649f458 make fPIC default 2022-01-29 22:16:16 +01:00
a5eafbff6c Merge pull request #1315 from devnexen/afl_fuzz_non_linux
afl fuzz enable getpgid on other platforms.
2022-01-29 21:43:53 +01:00
1d339527bb afl fuzz enable getpgid on other platforms. 2022-01-29 19:32:36 +00:00
707b1701c3 Add cmake in installation instructions (#1313) 2022-01-29 16:32:55 +01:00
b2465a05eb Merge pull request #1311 from AFLplusplus/libafl_mutator
LibAFL basic (just havoc + tokens) custom mutator
2022-01-27 09:00:57 +01:00
aa5f59b501 libafl_base custom mutator 2022-01-26 21:45:30 +01:00
08c39c1552 fix cfg in macro_rules in rust custom mutator 2022-01-26 21:44:07 +01:00
f75535807a 4.01a init 2022-01-26 11:11:42 +01:00
143c9d175e Merge pull request #1301 from AFLplusplus/dev
v4.00c release
2022-01-26 11:00:55 +01:00
b0758ac8db 4.00c readiness 2022-01-26 09:55:12 +01:00
77c06408c3 resized logo 2022-01-26 09:26:03 +01:00
6bf52c1434 svg logo 2022-01-26 09:24:37 +01:00
eebc2f4f1e adapt test harness to unicornafl for uc2 2022-01-26 01:33:58 +01:00
016bdc36bb code-format 2022-01-25 19:54:46 +01:00
ed72b9ec1d Merge pull request #1308 from schumilo/dev
add autodict capability to Nyx mode
2022-01-25 19:51:05 +01:00
615a8ff986 close autodict file even if fstat fails (Nyx mode) 2022-01-25 19:33:47 +01:00
026096ccf3 add AFL autodict capability to Nyx mode 2022-01-25 19:13:26 +01:00
87f2789e98 fix unicorn python test path 2022-01-25 18:05:35 +01:00
d9ed784298 ensure all fuzz targets are killed on exit 2022-01-25 14:51:02 +01:00
0fd6315dfb nit 2022-01-25 13:32:45 +01:00
28a1765781 fix atexit for rt 2022-01-25 12:41:22 +01:00
0b5ad8ee84 nits 2022-01-25 09:44:12 +01:00
3a78db2ade update sub gits 2022-01-25 09:11:06 +01:00
605b0e6465 fix libqasan repeated line 2022-01-24 18:35:16 +01:00
7270cbe756 try fix 2022-01-24 10:32:07 +01:00
a790bf6cc2 fix citation 2022-01-23 19:32:38 +01:00
86983f4060 fix citation 2022-01-23 19:31:33 +01:00
319c7457ff fix citation 2022-01-23 19:31:04 +01:00
e9be58b69c add citation 2022-01-23 19:28:48 +01:00
61d79f85c5 code format 2022-01-23 19:20:32 +01:00
9baa402344 update refs 2022-01-23 18:39:55 +01:00
04e3b5a6d3 update commit ids 2022-01-23 18:38:04 +01:00
227b42b1d0 unicorn fixes 2022-01-22 19:44:07 +01:00
ac169c3087 fix makefiles for uc2 c examples 2022-01-22 17:22:00 +01:00
3609912f41 new logo 2022-01-22 10:31:50 +01:00
6d2b8e3ed2 Merge pull request #1303 from schumilo/dev
update Nyx mode submodules
2022-01-22 00:35:07 +01:00
06ee6b1986 update Nyx custom harness:
use a coverage bitmap that is smaller than 64k
2022-01-21 21:07:28 +01:00
0090b3a3f0 update Nyx submodules 2022-01-21 21:03:07 +01:00
452a4cf5be Merge pull request #1302 from llzmb/docs_quality_assurance_4
Docs content - quality assurance - Unicorn mode
2022-01-21 16:33:02 +01:00
f63d2b0f55 Fix typo, add link 2022-01-21 16:27:17 +01:00
29235a7935 Fix punctuation, formatting, and line length 2022-01-21 16:18:25 +01:00
ac0e855907 Merge pull request #1259 from dmell/unicorn_docs
Adjustments to unicorn docs and speedtest sample
2022-01-21 14:09:23 +01:00
f7a5ea667b update changelog 2022-01-21 13:23:11 +01:00
fce512db40 update grammar mutator 2022-01-21 13:20:16 +01:00
b427a53a6b Merge pull request #1299 from llzmb/docs_quality_assurance_3
Docs content - quality assurance - 3rd run
2022-01-21 13:08:20 +01:00
2bb86863e6 Merge branch 'dev' into docs_quality_assurance_3 2022-01-21 13:06:15 +01:00
26a3d1b53b add nyx_mode to make clean target 2022-01-21 10:36:41 +01:00
2a0f082723 code-format 2022-01-21 10:14:20 +01:00
22da04f077 fix 2022-01-21 10:13:37 +01:00
5933e787f9 Merge pull request #1300 from schumilo/dev
add Nyx LTO support (and some other improvements)
2022-01-21 08:51:29 +01:00
6ce736aa91 use MAX_FILE as maximum size in Nyx mode 2022-01-21 08:13:33 +01:00
830dcacc07 update nyx custom_harness example 2022-01-21 08:06:31 +01:00
74d9da7203 update nyx_mode README 2022-01-21 08:05:30 +01:00
9d3e6a869e add LTO support in nyx_mode 2022-01-21 07:33:42 +01:00
1a15e98fff fix typo (QEMU_NXY_VERSION -> QEMU_NYX_VERSION) 2022-01-21 07:33:42 +01:00
a594182314 update nyx_mode build script 2022-01-21 07:33:42 +01:00
9d87f408dd update nyx_mode git submodules 2022-01-21 07:33:13 +01:00
b4c2fc9416 Fix formatting and line length 2022-01-20 21:40:28 +01:00
ecf8db0014 Fix punctuation 2022-01-20 21:26:13 +01:00
ec7b14a3d6 Fix line length 2022-01-20 21:25:06 +01:00
c74686e20d Fix structure 2022-01-20 21:23:28 +01:00
4902bb91d2 Fix links and spelling of Redqueen 2022-01-20 20:59:36 +01:00
237a475d9b Fix structure and formatting 2022-01-20 20:54:38 +01:00
686a595df3 Fix typo 2022-01-20 20:48:09 +01:00
1529bd070e Fix punctuation, formatting, and line length 2022-01-20 20:41:49 +01:00
29f8040f09 Fix formatting and line length 2022-01-20 20:35:19 +01:00
029bfc386f Fix formatting 2022-01-20 20:33:23 +01:00
88905c65af Add missing tags, fix punctuation 2022-01-20 20:27:02 +01:00
492418ebd6 Fix punctuation and line length 2022-01-20 20:22:00 +01:00
a9d549ca07 Raw read syscall in aflpp_driver.c to bypass ASan checks 2022-01-20 17:41:38 +01:00
4721d869ad Poison with ASan the remaining unused input buffer in aflpp_driver.c 2022-01-20 17:33:17 +01:00
7aced239e8 Merge pull request #1294 from AFLplusplus/dev
Push to stable
2022-01-20 16:17:08 +01:00
d1de12d617 updated uc ref 2022-01-20 16:14:58 +01:00
5deae7924f insert android.bp outdated statement 2022-01-20 12:06:15 +01:00
1d9d5936d9 Merge remote-tracking branch 'origin/dev' into dev 2022-01-19 23:03:19 +01:00
7afad147d1 update uc2 ref 2022-01-19 22:59:36 +01:00
550ba4d772 nits and code format 2022-01-19 22:26:52 +01:00
25c8336c0c tidy up unicornafl, changelog 2022-01-19 22:23:25 +01:00
4bcb177f62 Revert "fix classify counts"
This reverts commit 4217a6606c.
2022-01-19 22:17:36 +01:00
409a6517c1 update changelog 2022-01-19 22:12:14 +01:00
d9fefafae7 move to unicorn2 2022-01-19 22:10:29 +01:00
16bd6aad7c Merge pull request #1298 from WorksButNotTested/mapsize
Changes to support variations in the mapsize
2022-01-19 21:55:30 +01:00
5b06078a41 Changes to support variations in the mapsize 2022-01-19 18:22:27 +00:00
a3cf7c1224 change video order 2022-01-19 15:22:03 +01:00
6de9b37b2a Merge pull request #1296 from hardik05/patch-1
Update tutorials.md
2022-01-19 15:20:10 +01:00
1e5699ccaa Update tutorials.md 2022-01-19 19:36:29 +05:30
bdec40ae5d Merge pull request #1295 from devnexen/afl_untracer_disable_aslr_fbsd
afl-untracer, disable ASLR on FreeBSD.
2022-01-18 21:16:25 +01:00
56ce081ac7 afl-untracer, disable ASLR on FreeBSD. 2022-01-18 18:53:18 +00:00
861bd5e04b update macos path info 2022-01-17 20:31:08 +01:00
c5117b42ca fix iselect instrumentation 2022-01-17 20:15:27 +01:00
0e2c832499 fix laf transform for strcmp like functions 2022-01-17 19:35:49 +01:00
34caf7d781 Cleaned unicorn speedtest sample README 2022-01-17 17:38:46 +01:00
c8061e5b35 fix nyx -M 2022-01-17 17:16:58 +01:00
a45cdb240c fixup! Fixed Rust harness name to be consistent with the others 2022-01-17 14:32:06 +01:00
2b82492457 Merge pull request #1260 from 0xsan-z/Welcome2022
more welcome 2022
2022-01-16 16:43:40 +01:00
d51ec57d91 more welcome 2022 2022-01-15 15:19:29 -05:00
751e09f47b Fixed Rust harness name to be consistent with the others 2022-01-15 20:02:57 +01:00
c1415b816a Adjustments to unicorn docs and speedtest sample 2022-01-15 19:28:18 +01:00
4217a6606c fix classify counts 2022-01-15 13:58:17 +01:00
20177151e6 add email 2022-01-14 15:56:51 +01:00
9a4552d6c4 Merge pull request #1258 from llzmb/docs_edit_images_2
Edit images
2022-01-14 15:54:41 +01:00
8c58bdb504 Add margin to images 2022-01-14 15:17:25 +01:00
f42c0047c8 nits 2022-01-14 15:01:14 +01:00
1ca3317425 Add link to image 2022-01-14 11:22:16 +01:00
630ba07054 Merge pull request #1251 from pwnforce/patch-2
Update fuzzing_binary-only_targets.md
2022-01-13 16:40:22 +01:00
27ab84fbf1 fix skipping unfavored fuzzed entries 2022-01-13 16:38:18 +01:00
4c07e37eae Update fuzzing_binary-only_targets.md 2022-01-13 14:48:05 +01:00
8f7e584b82 more faq 2022-01-13 12:29:49 +01:00
f6c08c3a1c Merge pull request #1256 from dmell/lpm_patches
Lpm patches
2022-01-13 10:34:24 +01:00
9e38c43686 update changelog 2022-01-13 10:32:47 +01:00
c8e6a59e7d Removed unused byte in allocation 2022-01-13 10:12:23 +01:00
bedd812e7b Fixed wrong delete operator and added mutator's destructor 2022-01-13 10:11:43 +01:00
110cc27632 fix laf-intel split switches 2022-01-13 10:09:35 +01:00
21ebfec79c better ignore problem handling 2022-01-12 21:59:38 +01:00
8701cdcc2c Merge pull request #1255 from llzmb/docs_edit_images
Edit SVG files
2022-01-12 21:32:35 +01:00
e7ddd15fa5 Incorporate feedback 2022-01-12 20:46:37 +01:00
5e47829462 Add white background to SVG files 2022-01-12 20:27:09 +01:00
e663897a8a fix 2022-01-12 11:27:19 +01:00
b7ddde636b svg test 2022-01-12 10:42:40 +01:00
8764375357 test svg background 2022-01-12 10:36:22 +01:00
657c1e9b9b Merge pull request #1252 from tokatoka/dev
Add missing backticks (`)
2022-01-11 21:46:04 +01:00
0ed1cb4d31 change 2022-01-12 04:42:47 +09:00
741dcabd5d Merge pull request #1248 from intrigus-lgtm/patch-2
Fix two typos.
2022-01-11 19:35:04 +01:00
2342c85db4 Update fuzzing_binary-only_targets.md 2022-01-11 18:08:52 +01:00
091fa09e5e Update fuzzing_binary-only_targets.md
Fixing some parts in the description of Retrowrite.
2022-01-11 17:42:38 +01:00
d8920e31f8 Add a comma to make sentence easier to understand. 2022-01-11 17:13:25 +01:00
6a7f184c4e Fix broken code formatting 2022-01-11 17:00:26 +01:00
30666cb81e Highlight what a basic block is.
Highlight the different parts that characterize what
a basic block is. This makes it slightly easier to
read/understand IMHO.
2022-01-11 16:59:37 +01:00
9242e0db8a Merge pull request #1249 from AFLplusplus/dev
update nyx in stable
2022-01-11 16:36:42 +01:00
add85f34d1 Format some terms as code. 2022-01-11 15:26:30 +01:00
c7dbeb8568 update nyx 2022-01-11 15:21:07 +01:00
179b118bc9 Fix some typos and wrong words. 2022-01-11 15:13:04 +01:00
7884e0f449 Fix two typos. 2022-01-11 15:06:14 +01:00
10dae419d6 Merge pull request #1236 from AFLplusplus/dev
push to stable
2022-01-11 12:20:35 +01:00
d2715336a5 link docs/README.md 2022-01-11 12:03:21 +01:00
41b07983f1 add feature list 2022-01-11 11:59:12 +01:00
ef77d552e9 add new tutorial 2022-01-10 11:12:19 +01:00
85f3ebc714 Merge pull request #1243 from yuawn/dev
more welcome 2022
2022-01-07 10:38:00 +01:00
b7d741b18e more welcome 2022 2022-01-07 09:18:51 +00:00
da5ff0df0a Merge pull request #1242 from yuawn/dev
rename
2022-01-07 10:03:03 +01:00
7ae90a66c4 rename 2022-01-07 08:49:56 +00:00
ee295801a6 Merge pull request #1240 from adrianherrera/bugfix/optimin-showmap
optimin: -A -> -H
2022-01-04 12:21:12 +01:00
03ba344e6d optimin: -A -> -H
Inline with afl-showmap change
2022-01-04 15:18:31 +11:00
cc94e37ae1 doc nits 2022-01-03 23:26:23 +01:00
8c1015ac39 Proofreading 2022-01-03 22:50:08 +01:00
dc7b607080 doc nits 2022-01-03 20:47:52 +01:00
511ffc06d2 typo fixed 2022-01-03 20:42:34 +01:00
3b96c8ae13 doc nits 2022-01-03 17:02:38 +01:00
226450600c Merge pull request #1239 from MegaManSec/dev
Fix typo.
2022-01-03 17:02:08 +01:00
845c32b5fb Fix typo. 2022-01-03 16:47:33 +01:00
ee57053be1 add missing gcc env vars 2022-01-03 11:18:10 +01:00
a010d356de wording 2022-01-03 10:02:27 +01:00
3b3ba08daa did some proofreading 2022-01-03 09:37:33 +01:00
72cebac42e fix wrong replacements 2022-01-03 09:14:43 +01:00
e1082f2548 welcome 2022 2022-01-01 00:49:17 +01:00
128413690e nyx references 2022-01-01 00:38:54 +01:00
b6b81a687d update qemuafl 2021-12-31 17:06:16 +01:00
b8e61da8ab Merge pull request #1238 from AFLplusplus/more_havoc
more havoc
2021-12-31 17:04:01 +01:00
cda84594cc Merge pull request #1237 from MegaManSec/dev
Fix LeakSanitizer Usage.
2021-12-30 10:38:10 +01:00
fd9f61a8c5 fix map size for nyx 2021-12-30 10:37:16 +01:00
8b75680c7a Fix type. 2021-12-30 03:09:04 +01:00
09c4d9ed75 Fix LeakSanitizer Usage.
Previously, __lsan_do_leak_check() was run when using __AFL_LEAK_CHECK,
however this was the incorrect function to use. According to the
documentation: "Subsequent calls to this function will have no effect
and end-of-process leak check will not run".
This meant that if the memory did not leak on the first usage of
__AFL_LEAK_CHECK, subsquent calls to this macro would never do anything.

Likewise, it is not possible to use an LSAN suppression list with
symbolize=0, so instead __lsan_disable and __lsan_enable are used to
'ignore' certain memory allocations where needed.
2021-12-30 02:54:40 +01:00
02082bcd2e afl-cc lto fix 2021-12-29 18:24:47 +01:00
fa6a0aba61 typo 2021-12-29 12:54:24 +01:00
dbc62dbe56 sprinkle nyx links in the docs 2021-12-29 11:55:16 +01:00
1a25ccb618 readme for nyx 2021-12-29 11:43:21 +01:00
0792cab566 add power schedule info 2021-12-29 10:57:37 +01:00
b5cb99f6fe fix nyx lib loading 2021-12-28 20:30:52 +01:00
0a18bf8db5 add readme (needs more though) 2021-12-28 18:01:52 +01:00
48ad95f0e5 nit 2021-12-28 17:42:45 +01:00
fd99ddb1d6 nyx build and install 2021-12-28 17:40:23 +01:00
7e8a491500 exec perm 2021-12-28 17:27:37 +01:00
8b8aaa93bd nyx code format 2021-12-28 17:26:54 +01:00
f511ebd125 nyx nits 2021-12-28 17:25:46 +01:00
83bf876255 Merge pull request #1233 from nyx-fuzz/dev
add Nyx mode
2021-12-28 17:19:34 +01:00
41291d8c72 add Nyx mode 2021-12-28 15:51:43 +01:00
f9d4dcdd85 Merge pull request #1232 from WorksButNotTested/frida
Removed redundant instruction
2021-12-28 12:07:16 +01:00
jon
8a681bc163 Removed redundant instruction 2021-12-28 10:10:42 +00:00
53fa703755 more havoc 2021-12-27 19:06:06 +01:00
51d6f863f5 fix imports to build on Mac (#1231)
Co-authored-by: Jesse Hertz <>
2021-12-27 18:12:02 +01:00
be00dbc2ac Merge pull request #1230 from WorksButNotTested/frida
Further optimization of AARCH64 code
2021-12-27 15:26:10 +01:00
jon
65ffa4b472 Further optimization of AARCH64 code 2021-12-27 13:07:31 +00:00
7bd2899f2e fix cpu selection 2021-12-27 12:52:16 +01:00
43b162c222 Merge pull request #1228 from WorksButNotTested/frida
Frida
2021-12-27 11:23:24 +01:00
5d9134d6ad Added test for libxslt 2021-12-27 03:46:28 +00:00
jon
6c8a47f7dc Changes to not build addr for OSX 2021-12-27 02:38:38 +00:00
jon
89c4fa3051 Fix broken op-codes for AARCH64 2021-12-27 02:28:52 +00:00
jon
81aae9b54c Changes to explicitly place the previous_pc 2021-12-27 02:28:34 +00:00
54eca027a5 doc review 2021-12-26 03:54:29 +01:00
8fe6282164 force frida test in ci for macos 2021-12-26 03:04:48 +01:00
8588becf47 force frida test in ci for macos 2021-12-26 02:34:34 +01:00
a91d445b5f make tests working on macos 2021-12-26 01:55:52 +01:00
2d9e0f56b0 debug ci 2021-12-26 01:54:19 +01:00
146eb32c31 make tests working on macos 2021-12-26 01:49:31 +01:00
550dc989b3 debug ci 2021-12-26 01:35:10 +01:00
251264fde5 debug ci 2021-12-26 01:29:58 +01:00
649076600d debug ci 2021-12-26 01:24:03 +01:00
8521eb8413 debug ci 2021-12-26 01:15:53 +01:00
699c16c7e0 macos ci 2021-12-26 01:08:45 +01:00
6b50a001b0 macos ci 2021-12-26 01:07:29 +01:00
24dd35ef96 macos ci 2021-12-26 01:05:07 +01:00
8217b5ff81 macos ci 2021-12-26 00:00:49 +01:00
7b3b707ae6 macos ci 2021-12-25 23:59:17 +01:00
60b0c38022 macos ci 2021-12-25 23:53:29 +01:00
17d4ae9a16 macos ci 2021-12-25 23:51:12 +01:00
71621bbc52 macos ci 2021-12-25 23:49:47 +01:00
ddc90e1176 macos ci 2021-12-25 23:47:38 +01:00
47488dcd02 nits 2021-12-25 14:21:59 +01:00
185d7f2ede Merge pull request #1227 from WorksButNotTested/frida
Frida
2021-12-24 12:43:42 +01:00
376d1736a8 Optimize AARCH64 inline assembly 2021-12-23 23:55:07 +00:00
edeaf72ea8 Fix compiler warnings 2021-12-23 22:39:43 +00:00
c76dc73c7a better macos install docs 2021-12-22 01:25:32 +01:00
964819d3fc fix qbdi 2021-12-21 15:06:14 +01:00
68436b277b update grammar mutator 2021-12-21 11:05:05 +01:00
6106efa301 Merge pull request #1223 from WorksButNotTested/frida
Improvements to debug output
2021-12-20 21:30:55 +01:00
d59a76261d Improvements to debug output 2021-12-20 18:14:57 +00:00
db19116ce6 Merge pull request #1221 from WorksButNotTested/frida
Frida
2021-12-17 21:14:34 +01:00
a3421f8099 Added addr for finding default base address 2021-12-17 18:23:49 +00:00
fd1d162149 Fix broken test configuration 2021-12-17 18:23:49 +00:00
5a28157ffd Fix instrumentation debugging (inadvertant CS_MODE_THUMB) 2021-12-17 18:23:49 +00:00
e3106e6f52 Changes to build frida-source without devkit 2021-12-17 18:23:49 +00:00
b3a0ecfd48 allow ignore dlopen issues 2021-12-17 09:42:05 +01:00
641a943d95 more -z defs filtering 2021-12-16 21:31:37 +01:00
74a8f145e0 Merge pull request #1219 from AFLplusplus/dev
push to stable
2021-12-16 12:40:35 +01:00
3cb7319ccd fix for older llvm 2021-12-16 10:41:33 +01:00
5f70bc5404 disable cmplog vector FP cmp hooking 2021-12-16 10:08:31 +01:00
ee10461f48 fix llvm 14 changes for ctx and ngram 2021-12-16 01:44:50 +01:00
9f911bf0bd cleanup of TIMES macro 2021-12-15 20:43:18 +01:00
88814be474 Merge pull request #1218 from CityOfLight77/dev
Add AFLtriage in crash processing tool
2021-12-15 17:14:07 +01:00
a2314fc37f Add AFLtriage in crash processing tool 2021-12-15 20:38:52 +07:00
176ede3fc8 afl-cc -v without errors 2021-12-15 09:50:45 +01:00
d89fa8c7ad Merge pull request #1217 from CityOfLight77/dev
Fix typo
2021-12-15 09:32:08 +01:00
63087d9bd9 Fix env var typo
`AFL_MAX_EXRAS` -> `AFL_MAX_EXTRAS`
2021-12-15 09:24:28 +07:00
fad8a3feb8 Fix CodeQL command typo
fix command to create CodeQL database and use all cores to compile CodeQL database
2021-12-15 09:22:17 +07:00
02fba1cc7e Merge pull request #1215 from AFLplusplus/dev
Push to stable
2021-12-14 22:10:19 +01:00
2564eb6f8c Merge pull request #1214 from yuawn/dev
Fix and update afl-whatup
2021-12-14 17:28:21 +01:00
495348261d update output 2021-12-14 14:08:58 +00:00
7a939a6c59 remove "locally unique" 2021-12-14 14:08:36 +00:00
425cbb9025 update variables name 2021-12-14 14:03:58 +00:00
ab699bbeea update comments 2021-12-14 14:00:09 +00:00
bf8e07d168 update output 2021-12-14 13:58:54 +00:00
ae958acc83 rename unique_crashes 2021-12-14 13:38:36 +00:00
088aae7c25 rename path 2021-12-14 13:37:56 +00:00
75ac9c013c better instrumentlist filename detection 2021-12-14 10:15:09 +01:00
22e2362f0f Merge pull request #1213 from AFLplusplus/dev
push to stable
2021-12-13 22:58:19 +01:00
c6bad07d75 Merge pull request #1208 from llzmb/docs_add_overview
Add docs content overview
2021-12-13 22:17:02 +01:00
83487415b1 Fix images 2021-12-13 21:22:33 +01:00
9de3de6cdf Update images 2021-12-13 21:14:20 +01:00
aceb1af908 Merge branch 'dev' into docs_add_overview 2021-12-13 18:23:28 +01:00
3a60f6a251 Add image references, update image 2021-12-13 18:03:02 +01:00
52dd5d479d update qemu 2021-12-13 17:13:31 +01:00
ece717c424 fix 2021-12-13 16:43:16 +01:00
57bc3c0701 fix qemu/unicorn oob 2021-12-13 15:45:52 +01:00
630272bac5 Merge pull request #1211 from llzmb/docs_add_images
Add images
2021-12-13 12:59:33 +01:00
5590d1836a Merge pull request #1210 from llzmb/docs_quality_assurance_2
Docs content - quality assurance - 2nd run
2021-12-13 12:59:26 +01:00
e41ac9564b Merge pull request #1212 from devnexen/libradmsa_fbsd_upd
radamsa mutator adding freebsd specific fcntl flags.
2021-12-13 12:58:57 +01:00
2c144e88fb Delete fuzzing_process_overview.drawio.svg 2021-12-12 22:42:15 +01:00
5c7e84c5c8 Add images 2021-12-12 22:41:19 +01:00
52cae6d132 Fix formatting and spelling 2021-12-12 22:35:11 +01:00
6eb752a65c radamsa mutator adding freebsd specific fcntl flags. 2021-12-12 20:32:18 +00:00
ed3eb61610 Add image with fuzzing process overview 2021-12-12 20:05:26 +01:00
0993bcdc4e Delete image 2021-12-12 20:04:42 +01:00
d28bb47a38 Fix formatting and spelling 2021-12-12 20:01:44 +01:00
9d7dd5a69f Fix formatting and references 2021-12-12 17:59:14 +01:00
77ce31c8ba Add docs content overview 2021-12-11 19:13:22 +01:00
08ca4d54a5 Merge pull request #1101 from AFLplusplus/dev
Dev
2021-12-09 11:55:36 +01:00
328 changed files with 12769 additions and 5577 deletions

View File

@ -6,7 +6,7 @@
# Written and maintaned by Andrea Fioraldi <andreafioraldi@gmail.com>
#
# Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
# Copyright 2019-2022 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.
@ -19,40 +19,22 @@ import subprocess
import sys
import os
import re
import shutil
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use
with open(".clang-format") as f:
fmt = f.read()
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
if CLANG_FORMAT_BIN is None:
o = 0
try:
p = subprocess.Popen(["clang-format-11", "--version"], stdout=subprocess.PIPE)
o, _ = p.communicate()
o = str(o, "utf-8")
o = re.sub(r".*ersion ", "", o)
# o = o[len("clang-format version "):].strip()
o = o[: o.find(".")]
o = int(o)
except:
print("clang-format-11 is needed. Aborted.")
exit(1)
# if o < 7:
# if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
# CLANG_FORMAT_BIN = 'clang-format-7'
# elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0:
# CLANG_FORMAT_BIN = 'clang-format-8'
# elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0:
# CLANG_FORMAT_BIN = 'clang-format-9'
# elif subprocess.call(['which', 'clang-format-11'], stdout=subprocess.PIPE) == 0:
# CLANG_FORMAT_BIN = 'clang-format-11'
# else:
# print ("clang-format 7 or above is needed. Aborted.")
# exit(1)
else:
CLANG_FORMAT_BIN = "clang-format-11"
CURRENT_LLVM = os.getenv('LLVM_VERSION', 14)
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
if shutil.which(CLANG_FORMAT_BIN) is None:
CLANG_FORMAT_BIN = f"clang-format-{CURRENT_LLVM}"
if shutil.which(CLANG_FORMAT_BIN) is None:
print(f"[!] clang-format-{CURRENT_LLVM} is needed. Aborted.")
exit(1)
COLUMN_LIMIT = 80
for line in fmt.split("\n"):

View File

@ -1,65 +1,75 @@
!/coresight_mode
*.dSYM
*.o
*.pyc
*.so
.sync_tmp
.test
.test2
.sync_tmp
*.o
*.so
*.pyc
*.dSYM
as
ld
in
out
core*
.git
.dockerignore
.github
CITATION.cff
CONTRIBUTING.md
Changelog.md
Dockerfile
LICENSE
TODO.md
afl-analyze
afl-as
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-qemu-trace
afl-showmap
afl-tmin
afl-analyze.8
afl-as
afl-as.8
afl-clang-fast\+\+.8
afl-clang
afl-clang-fast
afl-clang-fast.8
afl-clang-fast\+\+
afl-clang-fast\+\+.8
afl-clang-lto
afl-clang-lto.8
afl-clang-lto\+\+
afl-clang-lto\+\+.8
afl-clang\+\+
afl-cmin.8
afl-cmin.bash.8
afl-fuzz
afl-fuzz.8
afl-gcc.8
afl-gcc-fast.8
afl-g\+\+
afl-g\+\+-fast
afl-g\+\+-fast.8
afl-gcc
afl-gcc-fast
afl-gcc-fast.8
afl-gcc.8
afl-gotcpu
afl-gotcpu.8
afl-ld
afl-ld-lto
afl-plot.8
afl-qemu-trace
afl-showmap
afl-showmap.8
afl-system-config.8
afl-tmin
afl-tmin.8
afl-whatsup.8
as
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
in
ld
out
qemu_mode/libcompcov/compcovtest
qemu_mode/qemu-*
test/unittests/unit_hash
test/unittests/unit_list
test/unittests/unit_maybe_alloc
test/unittests/unit_preallocable
test/unittests/unit_rand
unicorn_mode/samples/*/\.test-*
unicorn_mode/samples/*/output
unicorn_mode/unicornafl
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

View File

@ -1,25 +0,0 @@
name: Publish Docker Images
on:
push:
branches: [ stable ]
# paths:
# - Dockerfile
jobs:
push_to_registry:
name: Push Docker images to Dockerhub
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Login to Dockerhub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Publish aflpp to Registry
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: aflplusplus/aflplusplus:latest

View File

@ -2,29 +2,55 @@ name: CI
on:
push:
branches: [ stable, dev ]
branches:
- stable
- dev
pull_request:
branches: [ stable, dev ]
branches:
- dev # No need for stable-pull-request, as that equals dev-push
jobs:
build:
runs-on: '${{ matrix.os }}'
linux:
runs-on: "${{ matrix.os }}"
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-18.04]
os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04]
env:
AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: debug
run: apt-cache search plugin-dev | grep gcc- ; echo ; apt-cache search clang-format- | grep clang-format-
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
- name: update
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
- name: compiler installed
run: gcc -v ; echo ; clang -v
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
- name: run tests
run: sudo -E ./afl-system-config ; export AFL_SKIP_CPUFREQ=1 ; make 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

33
.github/workflows/code-format.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: Formatting
on:
push:
branches:
- stable
- dev
pull_request:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
jobs:
code-format-check:
name: Check code format
if: ${{ 'false' == 'true' }} # Disable the job
runs-on: ubuntu-22.04
container: docker.io/aflplusplus/aflplusplus:dev
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Format
run: |
git config --global --add safe.directory /__w/AFLplusplus/AFLplusplus
apt-get update
apt-get install -y clang-format-${LLVM_VERSION}
make code-format
- name: Check if code needed formatting
run: |
git --no-pager -c color.ui=always diff HEAD
if ! git diff HEAD --quiet; then
echo "[!] Please run 'make code-format' and push its changes."
exit 1
fi

View File

@ -2,31 +2,32 @@ name: "CodeQL"
on:
push:
branches: [ stable, dev ]
branches:
- stable
- dev
pull_request:
branches: [ stable, dev ]
branches:
- dev # No need for stable-pull-request, as that equals dev-push
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
container: # We use a previous image as it's expected to have all the dependencies
image: docker.io/aflplusplus/aflplusplus:dev
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
- name: Fix for using external repo in container build # https://github.com/actions/checkout/issues/760
run: git config --global --add safe.directory /__w/AFLplusplus/AFLplusplus
- name: Checkout
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: cpp, python
- name: Build AFLplusplus # Rebuild because CodeQL needs to monitor the build process
env:
CC: gcc # These are symlinked to the version used in the container build
CXX: g++
run: make -i all # Best effort using -i
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

75
.github/workflows/container.yml vendored Normal file
View File

@ -0,0 +1,75 @@
name: Container
on:
push:
branches:
- stable
- dev
tags:
- "*"
pull_request:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
jobs:
build-and-test-amd64:
name: Test amd64 image
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build amd64
uses: docker/build-push-action@v3
with:
context: .
tags: aflplusplus:test-amd64
load: true
cache-to: type=gha,mode=max
build-args: |
TEST_BUILD=1
- name: Test amd64
run: >
docker run --rm aflplusplus:test-amd64 bash -c "
apt-get update &&
apt-get install -y libcmocka-dev &&
make -i tests
"
push:
name: Push amd64 and arm64 images
runs-on: ubuntu-latest
needs:
- build-and-test-amd64
if: ${{ github.event_name == 'push' && github.repository == 'AFLplusplus/AFLplusplus' }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to docker.io
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Set tags to push
id: push-tags
run: |
PUSH_TAGS=docker.io/aflplusplus/aflplusplus:${GITHUB_REF_NAME}
if [ "${GITHUB_REF_NAME}" = "stable" ]; then
PUSH_TAGS=${PUSH_TAGS},docker.io/aflplusplus/aflplusplus:latest
fi
export PUSH_TAGS
echo "::set-output name=PUSH_TAGS::${PUSH_TAGS}"
- name: Push to docker.io registry
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.push-tags.outputs.PUSH_TAGS }}
cache-from: type=gha

View File

@ -2,9 +2,12 @@ name: Rust Custom Mutators
on:
push:
branches: [ stable, dev ]
branches:
- stable
- dev
pull_request:
branches: [ stable, dev ]
branches:
- dev # No need for stable-pull-request, as that equals dev-push
jobs:
test:
@ -15,9 +18,9 @@ jobs:
working-directory: custom_mutators/rust
strategy:
matrix:
os: [ubuntu-20.04]
os: [ubuntu-22.04, ubuntu-20.04]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install Rust Toolchain
uses: actions-rs/toolchain@v1
with:
@ -27,4 +30,4 @@ jobs:
- name: Run General Tests
run: cargo test
- name: Run Tests for afl_internals feature flag
run: cd custom_mutator && cargo test --features=afl_internals
run: cd custom_mutator && cargo test --features=afl_internals

1
.gitignore vendored
View File

@ -97,3 +97,4 @@ utils/persistent_mode/persistent_demo_new
utils/persistent_mode/test-instr
!coresight_mode
!coresight_mode/coresight-trace
vuln_prog

12
.gitmodules vendored
View File

@ -10,12 +10,18 @@
[submodule "custom_mutators/gramatron/json-c"]
path = custom_mutators/gramatron/json-c
url = https://github.com/json-c/json-c
[submodule "utils/optimin/EvalMaxSAT"]
path = utils/optimin/EvalMaxSAT
url = https://github.com/FlorentAvellaneda/EvalMaxSAT
[submodule "coresight_mode/patchelf"]
path = coresight_mode/patchelf
url = https://github.com/NixOS/patchelf.git
[submodule "coresight_mode/coresight-trace"]
path = coresight_mode/coresight-trace
url = https://github.com/RICSecLab/coresight-trace.git
[submodule "nyx_mode/libnyx"]
path = nyx_mode/libnyx
url = https://github.com/nyx-fuzz/libnyx.git
[submodule "nyx_mode/QEMU-Nyx"]
path = nyx_mode/QEMU-Nyx
url = https://github.com/nyx-fuzz/qemu-nyx.git
[submodule "nyx_mode/packer"]
path = nyx_mode/packer
url = https://github.com/nyx-fuzz/packer.git

View File

@ -1,3 +1,11 @@
//
// NOTE: This file is outdated. None of the AFL++ team uses Android hence
// we need users to keep this updated.
// In the current state it will likely fail, please send fixes!
// Also, this should build frida_mode.
//
cc_defaults {
name: "afl-defaults",
@ -68,6 +76,7 @@ cc_binary {
srcs: [
"src/afl-fuzz*.c",
"src/afl-common.c",
"src/afl-forkserver.c",
"src/afl-sharedmem.c",
"src/afl-forkserver.c",
"src/afl-performance.c",
@ -175,7 +184,7 @@ cc_binary_host {
}
cc_library_static {
name: "afl-llvm-rt",
name: "afl-compiler-rt",
compile_multilib: "64",
vendor_available: true,
host_supported: true,
@ -225,6 +234,7 @@ cc_library_headers {
],
}
/*
cc_prebuilt_library_static {
name: "libfrida-gum",
compile_multilib: "64",
@ -272,7 +282,7 @@ cc_binary {
],
static_libs: [
"afl-llvm-rt",
"afl-compiler-rt",
"libfrida-gum",
],
@ -290,6 +300,7 @@ cc_binary {
"utils/afl_frida/android",
],
}
*/
cc_binary {
name: "afl-fuzz-32",
@ -346,7 +357,7 @@ cc_binary_host {
}
cc_library_static {
name: "afl-llvm-rt-32",
name: "afl-compiler-rt-32",
compile_multilib: "32",
vendor_available: true,
host_supported: true,
@ -385,6 +396,7 @@ cc_library_static {
],
}
/*
cc_prebuilt_library_static {
name: "libfrida-gum-32",
compile_multilib: "32",
@ -400,6 +412,7 @@ cc_prebuilt_library_static {
"utils/afl_frida/android/arm",
],
}
*/
subdirs = [
"custom_mutators",

31
CITATION.cff Normal file
View File

@ -0,0 +1,31 @@
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- given-names: Marc
family-names: Heuse
email: mh@mh-sec.de
- given-names: Heiko
family-names: Eißfeldt
email: heiko.eissfeldt@hexco.de
- given-names: Andrea
family-names: Fioraldi
email: andreafioraldi@gmail.com
- given-names: Dominik
family-names: Maier
email: mail@dmnk.co
title: "AFL++"
version: 4.00c
type: software
date-released: 2022-01-26
url: "https://github.com/AFLplusplus/AFLplusplus"
keywords:
- fuzzing
- fuzzer
- fuzz-testing
- instrumentation
- afl-fuzz
- qemu
- llvm
- unicorn-emulator
- securiy
license: AGPL-3.0-or-later

View File

@ -1,75 +1,88 @@
#
# This Dockerfile for AFLplusplus uses Ubuntu 20.04 focal and
# installs LLVM 11 from llvm.org for afl-clang-lto support :-)
# It also installs gcc/g++ 10 from the Ubuntu development platform
# since focal has gcc-10 but not g++-10 ...
# This Dockerfile for AFLplusplus uses Ubuntu 22.04 jammy and
# installs LLVM 14 for afl-clang-lto support.
#
# GCC 11 is used instead of 12 because genhtml for afl-cov doesn't like it.
#
FROM ubuntu:20.04 AS aflplusplus
FROM ubuntu:22.04 AS aflplusplus
LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
LABEL "about"="AFLplusplus docker image"
LABEL "about"="AFLplusplus container image"
ARG DEBIAN_FRONTEND=noninteractive
env NO_ARCH_OPT 1
RUN apt-get update && \
apt-get -y install --no-install-suggests --no-install-recommends \
automake \
cmake \
meson \
ninja-build \
bison flex \
build-essential \
git \
python3 python3-dev python3-setuptools python-is-python3 \
libtool libtool-bin \
libglib2.0-dev \
wget vim jupp nano bash-completion less \
apt-utils apt-transport-https ca-certificates gnupg dialog \
libpixman-1-dev \
gnuplot-nox \
&& rm -rf /var/lib/apt/lists/*
RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main" >> /etc/apt/sources.list && \
wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main" >> /etc/apt/sources.list && \
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1E9377A2BA9EF27F
ENV NO_ARCH_OPT=1
ENV IS_DOCKER=1
RUN apt-get update && apt-get full-upgrade -y && \
apt-get -y install --no-install-suggests --no-install-recommends \
gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gcc-multilib gdb lcov \
clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools \
&& rm -rf /var/lib/apt/lists/*
apt-get install -y --no-install-recommends wget ca-certificates && \
rm -rf /var/lib/apt/lists/*
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 0
RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
ENV LLVM_VERSION=14
ENV GCC_VERSION=11
ENV LLVM_CONFIG=llvm-config-12
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
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 \
libtool libtool-bin libglib2.0-dev \
apt-utils apt-transport-https gnupg dialog \
gnuplot-nox libpixman-1-dev \
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-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} \
lld-${LLVM_VERSION} lldb-${LLVM_VERSION} llvm-${LLVM_VERSION} \
llvm-${LLVM_VERSION}-dev llvm-${LLVM_VERSION}-runtime llvm-${LLVM_VERSION}-tools \
$([ "$(dpkg --print-architecture)" = "amd64" ] && echo gcc-${GCC_VERSION}-multilib gcc-multilib) \
$([ "$(dpkg --print-architecture)" = "arm64" ] && echo libcapstone-dev) && \
rm -rf /var/lib/apt/lists/*
# gcc-multilib is only used for -m32 support on x86
# libcapstone-dev is used for coresight_mode on arm64
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0 && \
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} 0 && \
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 0 && \
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_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
ENV LLVM_CONFIG=llvm-config-${LLVM_VERSION}
ENV AFL_SKIP_CPUFREQ=1
ENV AFL_TRY_AFFINITY=1
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov
RUN cd /afl-cov && make install && cd ..
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
COPY . /AFLplusplus
WORKDIR /AFLplusplus
COPY . .
RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \
make distrib && make install && make clean
ARG CC=gcc-$GCC_VERSION
ARG CXX=g++-$GCC_VERSION
RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc'
RUN echo '. /etc/bash_completion' >> ~/.bashrc
RUN echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc
RUN echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc
ENV IS_DOCKER="1"
# Used in CI to prevent a 'make clean' which would remove the binaries to be tested
ARG TEST_BUILD
# Disabled until we have the container ready
#COPY --from=aflplusplus/afl-dyninst /usr/local/lib/libdyninstAPI_RT.so /usr/local/lib/libdyninstAPI_RT.so
#COPY --from=aflplusplus/afl-dyninst /afl-dyninst/libAflDyninst.so /usr/local/lib/libAflDyninst.so
RUN sed -i.bak 's/^ -/ /g' GNUmakefile && \
make clean && make distrib && \
([ "${TEST_BUILD}" ] || (make install && make clean)) && \
mv GNUmakefile.bak 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

View File

@ -76,9 +76,9 @@ else
endif
endif
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
endif
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
# SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
#endif
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
# ifndef SOURCE_DATE_EPOCH
@ -92,9 +92,13 @@ ifneq "$(SYS)" "Darwin"
# 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=2
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
ifeq "$(SYS)" "SunOS"
@ -138,12 +142,13 @@ ifdef DEBUG
$(info Compiling DEBUG version of binaries)
override CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror $(CFLAGS_OPT)
else
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
CFLAGS ?= -O2 $(CFLAGS_OPT) # -funroll-loops is slower on modern compilers
endif
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \
-I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wno-pointer-arith \
-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
# -fstack-protector
ifeq "$(SYS)" "FreeBSD"
override CFLAGS += -I /usr/local/include/
@ -167,9 +172,9 @@ endif
ifeq "$(SYS)" "Haiku"
SHMAT_OK=0
override CFLAGS += -DUSEMMAP=1 -Wno-error=format -fPIC
override CFLAGS += -DUSEMMAP=1 -Wno-error=format
override LDFLAGS += -Wno-deprecated-declarations -lgnu -lnetwork
SPECIAL_PERFORMANCE += -DUSEMMAP=1
#SPECIAL_PERFORMANCE += -DUSEMMAP=1
endif
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
@ -241,9 +246,6 @@ else
endif
ifneq "$(filter Linux GNU%,$(SYS))" ""
ifndef DEBUG
override CFLAGS += -D_FORTIFY_SOURCE=2
endif
override LDFLAGS += -ldl -lrt -lm
endif
@ -310,7 +312,7 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
.PHONY: llvm
llvm:
-$(MAKE) -j4 -f GNUmakefile.llvm
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
.PHONY: gcc_plugin
@ -345,9 +347,9 @@ performance-test: source-only
help:
@echo "HELP --- the following make targets exist:"
@echo "=========================================="
@echo "all: just the main afl++ binaries"
@echo "binary-only: everything for binary-only fuzzing: qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator, libtokencap"
@echo "source-only: everything for source code fuzzing: gcc_plugin, libdislocator, libtokencap"
@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)"
@echo "man: creates simple man pages from the help option of the programs"
@echo "install: installs everything you have compiled with the build option above"
@ -365,14 +367,18 @@ help:
@echo Known build environment options:
@echo "=========================================="
@echo STATIC - compile AFL++ static
@echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
@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 PROFILING - compile afl-fuzz with profiling information
@echo INTROSPECTION - compile afl-fuzz with mutation introspection
@echo NO_PYTHON - disable python support
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
@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 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 "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
@ -384,7 +390,7 @@ test_x86:
@echo "[*] Testing the PATH environment variable..."
@test "$${PATH}" != "$${PATH#.:}" && { echo "Please remove current directory '.' from PATH to avoid recursion of 'as', thanks!"; echo; exit 1; } || :
@echo "[*] Checking for the ability to compile x86 code..."
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
@echo 'int main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) $(LDFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
@rm -f .test1
else
test_x86:
@ -420,7 +426,7 @@ afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
@ln -sf afl-as as
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
$(CC) $(CFLAGS) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
$(CC) $(CFLAGS) $(CFLAGS_OPT) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
@ -528,7 +534,7 @@ code-format:
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 -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; 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
@rm -f test-instr
@ -564,24 +570,26 @@ all_done: test_build
.PHONY: clean
clean:
rm -rf $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-cs-proxy afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM
rm -rf $(PROGS) afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-cs-proxy afl-qemu-trace afl-gcc-fast afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM lib*.a
-$(MAKE) -f GNUmakefile.llvm clean
-$(MAKE) -f GNUmakefile.gcc_plugin clean
$(MAKE) -C utils/libdislocator clean
$(MAKE) -C utils/libtokencap clean
$(MAKE) -C utils/aflpp_driver clean
$(MAKE) -C utils/afl_network_proxy clean
$(MAKE) -C utils/socket_fuzzing clean
$(MAKE) -C utils/argv_fuzzing clean
-$(MAKE) -C utils/libdislocator clean
-$(MAKE) -C utils/libtokencap clean
-$(MAKE) -C utils/aflpp_driver clean
-$(MAKE) -C utils/afl_network_proxy clean
-$(MAKE) -C utils/socket_fuzzing clean
-$(MAKE) -C utils/argv_fuzzing clean
-$(MAKE) -C utils/plot_ui clean
$(MAKE) -C qemu_mode/unsigaction clean
$(MAKE) -C qemu_mode/libcompcov clean
$(MAKE) -C qemu_mode/libqasan clean
-$(MAKE) -C qemu_mode/unsigaction clean
-$(MAKE) -C qemu_mode/libcompcov clean
-$(MAKE) -C qemu_mode/libqasan clean
-$(MAKE) -C frida_mode clean
rm -rf nyx_mode/packer/linux_initramfs/init.cpio.gz nyx_mode/libnyx/libnyx/target/release/* nyx_mode/QEMU-Nyx/x86_64-softmmu/qemu-system-x86_64
ifeq "$(IN_REPO)" "1"
-test -e coresight_mode/coresight-trace/Makefile && $(MAKE) -C coresight_mode/coresight-trace clean || true
-test -e qemu_mode/qemuafl/Makefile && $(MAKE) -C qemu_mode/qemuafl clean || true
test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
-test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
-test -e nyx_mode/QEMU-Nyx/Makefile && $(MAKE) -C nyx_mode/QEMU-Nyx clean || true
else
rm -rf coresight_mode/coresight_trace
rm -rf qemu_mode/qemuafl
@ -593,60 +601,94 @@ deepclean: clean
rm -rf coresight_mode/coresight-trace
rm -rf unicorn_mode/unicornafl
rm -rf qemu_mode/qemuafl
rm -rf nyx_mode/libnyx nyx_mode/packer nyx_mode/QEMU-Nyx
ifeq "$(IN_REPO)" "1"
# NEVER EVER ACTIVATE THAT!!!!! git reset --hard >/dev/null 2>&1 || true
git checkout coresight_mode/coresight-trace
git checkout unicorn_mode/unicornafl
git checkout qemu_mode/qemuafl
git checkout nyx_mode/libnyx
git checkout nyx_mode/packer
git checkout nyx_mode/QEMU-Nyx
endif
.PHONY: distrib
distrib: all
-$(MAKE) -j4 -f GNUmakefile.llvm
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
endif
$(MAKE) -C utils/libdislocator
$(MAKE) -C utils/libtokencap
$(MAKE) -C utils/afl_network_proxy
$(MAKE) -C utils/socket_fuzzing
$(MAKE) -C utils/argv_fuzzing
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
-$(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
-$(MAKE) -C coresight_mode
endif
endif
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
-cd nyx_mode && ./build_nyx_support.sh
endif
endif
-cd qemu_mode && sh ./build_qemu_support.sh
ifeq "$(ARCH)" "aarch64"
ifndef NO_UNICORN_ARM64
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
endif
else
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
endif
endif
.PHONY: binary-only
binary-only: test_shm test_python ready $(PROGS)
$(MAKE) -C utils/libdislocator
$(MAKE) -C utils/libtokencap
$(MAKE) -C utils/afl_network_proxy
$(MAKE) -C utils/socket_fuzzing
$(MAKE) -C utils/argv_fuzzing
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
-$(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
-$(MAKE) -C coresight_mode
endif
endif
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
-cd nyx_mode && ./build_nyx_support.sh
endif
endif
-cd qemu_mode && sh ./build_qemu_support.sh
ifeq "$(ARCH)" "aarch64"
ifndef NO_UNICORN_ARM64
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
endif
else
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
endif
endif
.PHONY: source-only
source-only: all
-$(MAKE) -j4 -f GNUmakefile.llvm
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
endif
$(MAKE) -C utils/libdislocator
$(MAKE) -C utils/libtokencap
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
# -$(MAKE) -C utils/plot_ui
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
-cd nyx_mode && ./build_nyx_support.sh
endif
endif
%.8: %
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
@ -673,6 +715,7 @@ install: all $(MANPAGES)
@rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
@rm -f $${DESTDIR}$(BIN_PATH)/afl-as
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
@for i in afl-llvm-dict2file.so afl-llvm-lto-instrumentlist.so afl-llvm-pass.so cmplog-instructions-pass.so cmplog-routines-pass.so cmplog-switches-pass.so compare-transform-pass.so libcompcov.so libdislocator.so libnyx.so libqasan.so libtokencap.so SanitizerCoverageLTO.so SanitizerCoveragePCGUARD.so split-compares-pass.so split-switches-pass.so; do echo rm -fv $${DESTDIR}$(HELPER_PATH)/$${i}; done
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
@if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
@if [ -f utils/plot_ui/afl-plot-ui ]; then install -m 755 utils/plot_ui/afl-plot-ui $${DESTDIR}$(BIN_PATH); fi
@ -684,6 +727,7 @@ install: all $(MANPAGES)
@if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi
@if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi
@if [ -f afl-frida-trace.so ]; then install -m 755 afl-frida-trace.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f libnyx.so ]; then install -m 755 libnyx.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi
@if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
@if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
@ -706,7 +750,7 @@ endif
.PHONY: uninstall
uninstall:
-cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-cs-proxy afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-server afl-g* afl-plot.sh afl-as afl-ld-lto afl-c* afl-lto*
-cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a as afl-as SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt
-cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so libnyx.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a as afl-as SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt
-rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries
-sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f"
-cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES)

View File

@ -11,7 +11,7 @@
# from Laszlo Szekeres.
#
# Copyright 2015 Google Inc. All rights reserved.
# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
# Copyright 2019-2022 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.
@ -100,7 +100,9 @@ ifeq "$(SYS)" "SunOS"
endif
PROGS = ./afl-gcc-pass.so ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
PASSES = ./afl-gcc-pass.so ./afl-gcc-cmplog-pass.so ./afl-gcc-cmptrs-pass.so
PROGS = $(PASSES) ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
.PHONY: all
all: test_shm test_deps $(PROGS) test_build all_done
@ -135,11 +137,13 @@ afl-common.o: ./src/afl-common.c
./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-32.o afl-llvm-rt-32.o; else echo "failed (that's fine)"; fi
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-64.o afl-llvm-rt-64.o; else echo "failed (that's fine)"; fi
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
$(PASSES): instrumentation/afl-gcc-common.h
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
@ -148,6 +152,12 @@ afl-common.o: ./src/afl-common.c
ln -sf afl-cc.8 afl-gcc-fast.8
ln -sf afl-cc.8 afl-g++-fast.8
./afl-gcc-cmplog-pass.so: instrumentation/afl-gcc-cmplog-pass.so.cc | test_deps
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
./afl-gcc-cmptrs-pass.so: instrumentation/afl-gcc-cmptrs-pass.so.cc | test_deps
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
.PHONY: test_build
test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..."
@ -190,6 +200,8 @@ install: all
ln -sf afl-c++ $${DESTDIR}$(BIN_PATH)/afl-g++-fast
ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
install -m 755 ./afl-gcc-pass.so $${DESTDIR}$(HELPER_PATH)
install -m 755 ./afl-gcc-cmplog-pass.so $${DESTDIR}$(HELPER_PATH)
install -m 755 ./afl-gcc-cmptrs-pass.so $${DESTDIR}$(HELPER_PATH)
install -m 644 -T instrumentation/README.gcc_plugin.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
.PHONY: clean

View File

@ -46,7 +46,7 @@ LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 )
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[4-9]' && 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 )
@ -86,6 +86,12 @@ ifeq "$(LLVM_TOO_OLD)" "1"
$(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
endif
ifeq "$(LLVM_HAVE_LTO)" "1"
$(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
LLVM_LTO = 1
@ -93,7 +99,7 @@ ifeq "$(LLVM_HAVE_LTO)" "1"
endif
ifeq "$(LLVM_LTO)" "0"
$(info [+] llvm_mode detected llvm < 11, afl-lto LTO will not be build.)
$(info [+] llvm_mode detected llvm < 11 or llvm 15, afl-lto LTO will not be build.)
endif
ifeq "$(LLVM_APPLE_XCODE)" "1"
@ -394,7 +400,7 @@ endif
./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
ifeq "$(LLVM_10_OK)" "1"
-$(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
-$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
endif
./afl-llvm-lto-instrumentlist.so: instrumentation/afl-llvm-lto-instrumentlist.so.cc instrumentation/afl-llvm-common.o
@ -407,7 +413,7 @@ ifeq "$(LLVM_LTO)" "1"
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
endif
./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc
./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc instrumentation/afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o
@ -447,11 +453,11 @@ document:
./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-32.o afl-llvm-rt-32.o; else echo "failed (that's fine)"; fi
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-64.o afl-llvm-rt-64.o; else echo "failed (that's fine)"; fi
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
.PHONY: test_build
test_build: $(PROGS)
@ -474,11 +480,11 @@ install: all
@install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
@if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt*.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt*.o
@if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o ;fi
@if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
@if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o ;fi
@if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o ; fi
@if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi
@if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi
@ -520,4 +526,4 @@ endif
.PHONY: clean
clean:
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo
rm -f $(PROGS) afl-common.o ./afl-c++ ./afl-lto ./afl-lto++ ./afl-clang-lto* ./afl-clang-fast* ./afl-clang*.8 ./ld ./afl-ld ./afl-llvm-rt*.o instrumentation/*.o
rm -f $(PROGS) afl-common.o ./afl-c++ ./afl-lto ./afl-lto++ ./afl-clang-lto* ./afl-clang-fast* ./afl-clang*.8 ./ld ./afl-ld ./afl-compiler-rt*.o ./afl-llvm-rt*.o instrumentation/*.o

View File

@ -1,20 +1,21 @@
# American Fuzzy Lop plus plus (AFL++)
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ logo">
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/master/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250">
Release version: [3.14c](https://github.com/AFLplusplus/AFLplusplus/releases)
Release version: [4.02c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 3.15a
GitHub version: 4.02c
Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
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> and
* Dominik Maier <mail@dmnk.co>.
* 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>
* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
Originally developed by Michał "lcamtuf" Zalewski.
@ -28,9 +29,14 @@ terms of the Apache-2.0 License. See the [LICENSE](LICENSE) for details.
Here is some information to get you started:
* For an overview of the AFL++ documentation and a very helpful graphical guide,
please visit [docs/README.md](docs/README.md).
* To get you started with tutorials, go to
[docs/tutorials.md](docs/tutorials.md).
* For releases, see the
[Releases tab](https://github.com/AFLplusplus/AFLplusplus/releases) and
[branches](#branches). Also take a look at the list of
[branches](#branches). The best branches to use are, however, `stable` or
`dev` - depending on your risk appetite. Also take a look at the list of
[important changes in AFL++](docs/important_changes.md) and the list of
[features](docs/features.md).
* If you want to use AFL++ for your academic work, check the
@ -40,24 +46,26 @@ Here is some information to get you started:
`afl-clang-fast` with `AFL_LLVM_CMPLOG=1`. You can find the `aflplusplus`
default configuration on Google's
[fuzzbench](https://github.com/google/fuzzbench/tree/master/fuzzers/aflplusplus).
* To get you started with tutorials, go to
[docs/tutorials.md](docs/tutorials.md).
## Building and installing AFL++
To have AFL++ easily available with everything compiled, pull the image directly
from the Docker Hub:
from the Docker Hub (available for both x86_64 and arm64):
```shell
docker pull aflplusplus/aflplusplus
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
```
This image is automatically generated when a push to the stable repo happens
(see [branches](#branches)). You will find your target source code in `/src` in
the container.
This image is automatically published when a push to the stable branch happens
(see [branches](#branches)). If you use the command above, you will find your
target source code in `/src` in the container.
To build AFL++ yourself, continue at [docs/INSTALL.md](docs/INSTALL.md).
Note: you can also pull `aflplusplus/aflplusplus:dev` which is the most current
development state of AFL++.
To build AFL++ yourself - *which we recommend* - continue at
[docs/INSTALL.md](docs/INSTALL.md).
## Quick start: Fuzzing with AFL++
@ -107,7 +115,7 @@ Step-by-step quick start:
5. You will find found crashes and hangs in the subdirectories `crashes/` and
`hangs/` in the `-o output_dir` directory. You can replay the crashes by
feeding them to the target, e.g.:
feeding them to the target, e.g. if your target is using stdin:
```
cat output_dir/crashes/id:000000,* | /path/to/tested/program [...program's cmdline...]
@ -115,20 +123,24 @@ Step-by-step quick start:
You can generate cores or use gdb directly to follow up the crashes.
6. We cannot stress this enough - if you want to fuzz effectively, read the
[docs/fuzzing_in_depth.md](docs/fuzzing_in_depth.md) document!
## Contact
Questions? Concerns? Bug reports?
* The contributors can be reached via
* The contributors can be reached via (e.g., by creating an issue):
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus).
* Take a look at our [FAQ](docs/FAQ.md). If you find an interesting or important
question missing, submit it via
[https://github.com/AFLplusplus/AFLplusplus/discussions](https://github.com/AFLplusplus/AFLplusplus/discussions).
* There is a mailing list for the AFL/AFL++ project
* Best: join the [Awesome Fuzzing](https://discord.gg/gCraWct) Discord server.
* There is a (not really used) mailing list for the AFL/AFL++ project
([browse archive](https://groups.google.com/group/afl-users)). To compare
notes with other users or to get notified about major new features, send an
email to <afl-users+subscribe@googlegroups.com>.
* Or join the [Awesome Fuzzing](https://discord.gg/gCraWct) Discord server.
email to <afl-users+subscribe@googlegroups.com>, but note that this is not
managed by us.
## Branches
@ -141,7 +153,7 @@ The following branches exist:
stability
* [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev): development state
of AFL++ - bleeding edge and you might catch a checkout which does not compile
or has a bug. *We only accept PRs in dev!!*
or has a bug. **We only accept PRs (pull requests) for the 'dev' branch!**
* (any other): experimental branches to work on specific features or testing new
functionality or changes.
@ -155,7 +167,7 @@ This can be your way to support and contribute to AFL++ - extend it to do
something cool.
For everyone who wants to contribute (and send pull requests), please read our
[contributing guidelines](CONTRIBUTING.md) before your submit.
[contributing guidelines](CONTRIBUTING.md) before you submit.
## Special thanks
@ -215,7 +227,7 @@ Thank you! (For people sending pull requests - please add yourself to this list
Josephine Calliotte Konrad Welc
Thomas Rooijakkers David Carlier
Ruben ten Hove Joey Jiao
fuzzah
fuzzah @intrigus-lgtm
```
</details>
@ -243,4 +255,4 @@ presented at WOOT'20:
}
```
</details>
</details>

View File

@ -2,6 +2,8 @@
## Should
- makefiles should show provide a build summary success/failure
- better documentation for custom mutators
- better autodetection of shifting runtime timeout values
- Update afl->pending_not_fuzzed for MOpt
- afl-plot to support multiple plot_data
@ -10,6 +12,8 @@
## 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
@ -29,4 +33,4 @@ QEMU mode/FRIDA mode:
using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow up
edge numbers that both following cmp paths have been found and then disable
working on this edge id -> cmplog_intelligence branch
- use cmplog colorization taint result for havoc locations?
- use cmplog colorization taint result for havoc locations?

View File

@ -135,6 +135,12 @@ function exists_and_is_executable(binarypath) {
}
BEGIN {
if (0 != system( "test -t 1")) {
redirected = 1
} else {
redirected = 0
}
print "corpus minimization tool for afl++ (awk version)\n"
# defaults
@ -217,7 +223,7 @@ BEGIN {
for (; Optind < ARGC; Optind++) {
prog_args[i++] = ARGV[Optind]
if (i > 1)
prog_args_string = prog_args_string" "ARGV[Optind]
prog_args_string = prog_args_string" '"ARGV[Optind]"'"
}
# sanity checks
@ -463,7 +469,8 @@ BEGIN {
while (cur < in_count) {
fn = infilesSmallToBig[cur]
++cur
printf "\r Processing file "cur"/"in_count
if (redirected == 0) { printf "\r Processing file "cur"/"in_count }
else { print " Processing file "cur"/"in_count }
# create path for the trace file from afl-showmap
tracefile_path = trace_dir"/"fn
# gather all keys, and count them
@ -502,7 +509,9 @@ BEGIN {
key = field[nrFields]
++tcnt;
printf "\r Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..."
if (redirected == 0) { printf "\r Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..." }
else { print " Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..." }
if (key in keyAlreadyKnown) {
continue
}
@ -525,7 +534,6 @@ BEGIN {
}
}
close(sortedKeys)
print ""
print "[+] Found "tuple_count" unique tuples across "in_count" files."
if (out_count == 1) {

View File

@ -76,6 +76,9 @@ EOF
DONE=1
fi
if [ "$PLATFORM" = "OpenBSD" ] ; then
doas sysctl vm.malloc_conf=
echo 'Freecheck on allocation in particular can be detrimental to performance.'
echo 'Also we might not want necessarily to abort at any allocation failure.'
echo 'System security features cannot be disabled on OpenBSD.'
echo
DONE=1
@ -115,7 +118,7 @@ if [ "$PLATFORM" = "Darwin" ] ; then
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist >/dev/null 2>&1
echo
fi
echo It is recommended to disable System Integration Protection for increased performance.
echo It is recommended to disable System Integrity Protection for increased performance.
echo
DONE=1
fi

View File

@ -6,7 +6,7 @@
# Originally written by Michal Zalewski
#
# Copyright 2015 Google Inc. All rights reserved.
# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
# Copyright 2019-2022 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.
@ -91,9 +91,9 @@ TOTAL_CRASHES=0
TOTAL_PFAV=0
TOTAL_PENDING=0
# Time since last path / crash / hang, formatted as string
# Time since last find / crash / hang, formatted as string
FMT_TIME="0 days 0 hours"
FMT_PATH="${RED}none seen yet${NC}"
FMT_FIND="${RED}none seen yet${NC}"
FMT_CRASH="none seen yet"
FMT_HANG="none seen yet"
@ -135,7 +135,7 @@ fmt_duration()
FIRST=true
TOTAL_WCOP=
TOTAL_LAST_PATH=0
TOTAL_LAST_FIND=0
for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
@ -169,7 +169,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
fi
DEAD_CNT=$((DEAD_CNT + 1))
last_path=0
last_find=0
if [ "$PROCESS_DEAD" = "" ]; then
@ -183,17 +183,17 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
EXEC_SEC=0
test -z "$RUN_UNIX" -o "$RUN_UNIX" = 0 || EXEC_SEC=$((execs_done / RUN_UNIX))
PATH_PERC=$((cur_path * 100 / paths_total))
PATH_PERC=$((cur_item * 100 / corpus_count))
TOTAL_TIME=$((TOTAL_TIME + RUN_UNIX))
TOTAL_EPS=$((TOTAL_EPS + EXEC_SEC))
TOTAL_EXECS=$((TOTAL_EXECS + execs_done))
TOTAL_CRASHES=$((TOTAL_CRASHES + unique_crashes))
TOTAL_CRASHES=$((TOTAL_CRASHES + saved_crashes))
TOTAL_PENDING=$((TOTAL_PENDING + pending_total))
TOTAL_PFAV=$((TOTAL_PFAV + pending_favs))
if [ "$last_path" -gt "$TOTAL_LAST_PATH" ]; then
TOTAL_LAST_PATH=$last_path
if [ "$last_find" -gt "$TOTAL_LAST_FIND" ]; then
TOTAL_LAST_FIND=$last_find
fi
if [ "$SUMMARY_ONLY" = "" ]; then
@ -210,7 +210,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
echo " ${RED}slow execution, $EXEC_SEC execs/sec${NC}"
fi
fmt_duration $last_path && FMT_PATH=$DUR_STRING
fmt_duration $last_find && FMT_FIND=$DUR_STRING
fmt_duration $last_crash && FMT_CRASH=$DUR_STRING
fmt_duration $last_hang && FMT_HANG=$DUR_STRING
FMT_CWOP="not available"
@ -220,7 +220,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
test "$cycles_wo_finds" -gt 50 && FMT_CWOP="${RED}$cycles_wo_finds${NC}"
}
echo " last_path : $FMT_PATH"
echo " last_find : $FMT_FIND"
echo " last_crash : $FMT_CRASH"
echo " last_hang : $FMT_HANG"
echo " cycles_wo_finds : $FMT_CWOP"
@ -229,12 +229,12 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
MEM_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $4}')
echo " cpu usage $CPU_USAGE%, memory usage $MEM_USAGE%"
echo " cycle $((cycles_done + 1)), lifetime speed $EXEC_SEC execs/sec, path $cur_path/$paths_total (${PATH_PERC}%)"
echo " cycles $((cycles_done + 1)), lifetime speed $EXEC_SEC execs/sec, items $cur_item/$corpus_count (${PATH_PERC}%)"
if [ "$unique_crashes" = "0" ]; then
if [ "$saved_crashes" = "0" ]; then
echo " pending $pending_favs/$pending_total, coverage $bitmap_cvg, no crashes yet"
else
echo " pending $pending_favs/$pending_total, coverage $bitmap_cvg, crash count $unique_crashes (!)"
echo " pending $pending_favs/$pending_total, coverage $bitmap_cvg, crashes saved $saved_crashes (!)"
fi
echo
@ -243,7 +243,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
done
# Formatting for total time, time since last path, crash, and hang
# Formatting for total time, time since last find, crash, and hang
fmt_duration $((CUR_TIME - TOTAL_TIME)) && FMT_TIME=$DUR_STRING
# Formatting for total execution
FMT_EXECS="0 millions"
@ -263,7 +263,7 @@ TOTAL_DAYS=$((TOTAL_TIME / 60 / 60 / 24))
TOTAL_HRS=$(((TOTAL_TIME / 60 / 60) % 24))
test -z "$TOTAL_WCOP" && TOTAL_WCOP="not available"
fmt_duration $TOTAL_LAST_PATH && TOTAL_LAST_PATH=$DUR_STRING
fmt_duration $TOTAL_LAST_FIND && TOTAL_LAST_FIND=$DUR_STRING
test "$TOTAL_TIME" = "0" && TOTAL_TIME=1
@ -293,15 +293,15 @@ echo " Cumulative speed : $TOTAL_EPS execs/sec"
if [ "$ALIVE_CNT" -gt "0" ]; then
echo " Average speed : $((TOTAL_EPS / ALIVE_CNT)) execs/sec"
fi
echo " Pending paths : $TOTAL_PFAV faves, $TOTAL_PENDING total"
echo " Pending items : $TOTAL_PFAV faves, $TOTAL_PENDING total"
if [ "$ALIVE_CNT" -gt "1" ]; then
echo " Pending per fuzzer : $((TOTAL_PFAV/ALIVE_CNT)) faves, $((TOTAL_PENDING/ALIVE_CNT)) total (on average)"
fi
echo " Crashes found : $TOTAL_CRASHES locally unique"
echo " Crashes saved : $TOTAL_CRASHES"
echo "Cycles without finds : $TOTAL_WCOP"
echo " Time without finds : $TOTAL_LAST_PATH"
echo " Time without finds : $TOTAL_LAST_FIND"
echo
exit 0

View File

@ -54,7 +54,7 @@ $(GLIBC_LDSO): | $(GLIBC_NAME).tar.xz
$(MAKE) install
$(GLIBC_NAME).tar.xz:
wget -O $@ $(GLIBC_URL_BASE)/$@
wget -qO $@ $(GLIBC_URL_BASE)/$@
clean:
$(MAKE) -C $(CS_TRACE) clean

View File

@ -352,7 +352,7 @@ uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
* @return if the file contents was modified return 1 (True), 0 (False)
* otherwise
*/
uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
uint8_t afl_custom_queue_new_entry(my_mutator_t *data,
const uint8_t *filename_new_queue,
const uint8_t *filename_orig_queue) {

View File

@ -72,6 +72,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alloc-inl.h"
/* Header that must be present at the beginning of every test case: */
@ -127,9 +128,11 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
}
/* Allocate memory for new buffer, reusing previous allocation if
possible. */
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 = realloc(data->buf, len);
*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
@ -142,9 +145,9 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
}
/* Copy the original data to the new location. */
memcpy(*out_buf, in_buf, len);
if (len > strlen(HEADER))
memcpy(*out_buf + strlen(HEADER), in_buf + strlen(HEADER),
len - strlen(HEADER));
/* Insert the new header. */

View File

@ -29,8 +29,8 @@
#include <stdint.h>
#include <string.h>
#include <zlib.h>
#include <arpa/inet.h>
#include "alloc-inl.h"
/* A macro to round an integer up to 4 kB. */
@ -70,9 +70,6 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
unsigned int len,
const unsigned char **out_buf) {
unsigned char *new_buf = (unsigned char *)in_buf;
unsigned int pos = 8;
/* Don't do anything if there's not enough room for the PNG header
(8 bytes). */
@ -83,6 +80,22 @@ 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);
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
don't have that, we can bail out. */
@ -111,33 +124,6 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
if (real_cksum != file_cksum) {
/* First modification? Make a copy of the input buffer. Round size
up to 4 kB to minimize the number of reallocs needed. */
if (new_buf == in_buf) {
if (len <= data->size) {
new_buf = data->buf;
} else {
new_buf = realloc(data->buf, UP4K(len));
if (!new_buf) {
*out_buf = in_buf;
return len;
}
data->buf = new_buf;
data->size = UP4K(len);
memcpy(new_buf, in_buf, len);
}
}
*(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
}

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-2020 AFLplusplus Project. All rights reserved.
# Copyright 2019-2022 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.
@ -115,9 +115,9 @@ if [ $? -eq 0 ]; then
git submodule update ./json-c 2>/dev/null # ignore errors
else
echo "[*] cloning json-c"
test -d json-c || {
test -d json-c/.git || {
CNT=1
while [ '!' -d json-c -a "$CNT" -lt 4 ]; do
while [ '!' -d json-c/.git -a "$CNT" -lt 4 ]; do
echo "Trying to clone json-c (attempt $CNT/3)"
git clone "$JSONC_REPO"
CNT=`expr "$CNT" + 1`
@ -125,7 +125,7 @@ else
}
fi
test -d json-c || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
test -d 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

@ -1 +1 @@
eedf07d
ff4e5a2

View File

@ -14,7 +14,7 @@
# <andreafioraldi@gmail.com>
#
# Copyright 2017 Battelle Memorial Institute. All rights reserved.
# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
# Copyright 2019-2022 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.
@ -109,9 +109,9 @@ if [ $? -eq 0 ]; then
git submodule update ./grammar_mutator 2>/dev/null # ignore errors
else
echo "[*] cloning grammar mutator"
test -d grammar_mutator || {
test -d grammar_mutator/.git || {
CNT=1
while [ '!' -d grammar_mutator -a "$CNT" -lt 4 ]; do
while [ '!' -d grammar_mutator/.git -a "$CNT" -lt 4 ]; do
echo "Trying to clone grammar_mutator (attempt $CNT/3)"
git clone "$GRAMMAR_REPO"
CNT=`expr "$CNT" + 1`
@ -119,15 +119,16 @@ else
}
fi
test -d grammar_mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
test -f 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
echo "[*] Checking out $GRAMMAR_VERSION"
git pull >/dev/null 2>&1
sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
git checkout "$GRAMMAR_VERSION" || exit 1
echo "[*] Downloading antlr..."
wget -c https://www.antlr.org/download/antlr-4.8-complete.jar
wget -q https://www.antlr.org/download/antlr-4.8-complete.jar
cd ..
echo

10
custom_mutators/libafl_base/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Generated by Cargo
# will have compiled files and executables
/target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk

View File

@ -0,0 +1,14 @@
[package]
name = "libafl_base"
version = "0.1.0"
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" }
custom_mutator = { path = "../rust/custom_mutator", features = ["afl_internals"] }
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
[lib]
crate-type = ["cdylib"]

View File

@ -0,0 +1,9 @@
all: target/release/liblibafl_base.so
cp target/release/liblibafl_base.so libafl_base.so
target/release/liblibafl_base.so: src/lib.rs
cargo build --release
clean:
cargo clean
rm -f libafl_base.so

View File

@ -0,0 +1,11 @@
# libafl basic havoc + token mutator
This uses the [libafl](https://github.com/AFLplusplus/libafl) StdScheduledMutator with `havoc_mutations` and `token_mutations`.
Make sure to have [cargo installed](https://rustup.rs/) and just type `make` to build.
Run with:
```
AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/libafl_base/libafl_base.so AFL_CUSTOM_MUTATOR_ONLY=1 afl-fuzz ...
```

View File

@ -0,0 +1,238 @@
#![cfg(unix)]
#![allow(unused_variables)]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
cell::{RefCell, UnsafeCell},
collections::HashMap,
ffi::CStr,
};
use custom_mutator::{afl_state, export_mutator, CustomMutator};
use libafl::{
bolts::{rands::StdRand, serdeany::SerdeAnyMap, tuples::Merge},
corpus::{Corpus, Testcase},
inputs::{BytesInput, HasBytesVec},
mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
Mutator,
},
state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State},
Error,
};
const MAX_FILE: usize = 1 * 1024 * 1024;
static mut AFL: Option<&'static afl_state> = None;
static mut CURRENT_ENTRY: Option<usize> = None;
fn afl() -> &'static afl_state {
unsafe { AFL.unwrap() }
}
#[derive(Default, Debug)]
pub struct AFLCorpus {
entries: UnsafeCell<HashMap<usize, RefCell<Testcase<BytesInput>>>>,
}
impl Clone for AFLCorpus {
fn clone(&self) -> Self {
unsafe {
Self {
entries: UnsafeCell::new(self.entries.get().as_ref().unwrap().clone()),
}
}
}
}
impl Serialize for AFLCorpus {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
unimplemented!();
}
}
impl<'de> Deserialize<'de> for AFLCorpus {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!();
}
}
impl Corpus<BytesInput> for AFLCorpus {
#[inline]
fn count(&self) -> usize {
afl().queued_items as usize
}
#[inline]
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
unimplemented!();
}
#[inline]
fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> {
unimplemented!();
}
#[inline]
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
unimplemented!();
}
#[inline]
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<BytesInput>>, Error> {
unsafe {
let entries = self.entries.get().as_mut().unwrap();
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())
.to_str()
.unwrap()
.to_owned();
let mut testcase = Testcase::with_filename(BytesInput::new(vec![]), fname);
*testcase.input_mut() = None;
RefCell::new(testcase)
});
Ok(&self.entries.get().as_ref().unwrap()[&idx])
}
}
#[inline]
fn current(&self) -> &Option<usize> {
unsafe {
CURRENT_ENTRY = Some(afl().current_entry as usize);
&CURRENT_ENTRY
}
}
#[inline]
fn current_mut(&mut self) -> &mut Option<usize> {
unimplemented!();
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AFLState {
rand: StdRand,
corpus: AFLCorpus,
metadata: SerdeAnyMap,
max_size: usize,
}
impl AFLState {
pub fn new(seed: u32) -> Self {
Self {
rand: StdRand::with_seed(seed as u64),
corpus: AFLCorpus::default(),
metadata: SerdeAnyMap::new(),
max_size: MAX_FILE,
}
}
}
impl State for AFLState {}
impl HasRand for AFLState {
type Rand = StdRand;
#[inline]
fn rand(&self) -> &Self::Rand {
&self.rand
}
#[inline]
fn rand_mut(&mut self) -> &mut Self::Rand {
&mut self.rand
}
}
impl HasCorpus<BytesInput> for AFLState {
type Corpus = AFLCorpus;
#[inline]
fn corpus(&self) -> &Self::Corpus {
&self.corpus
}
#[inline]
fn corpus_mut(&mut self) -> &mut Self::Corpus {
&mut self.corpus
}
}
impl HasMetadata for AFLState {
#[inline]
fn metadata(&self) -> &SerdeAnyMap {
&self.metadata
}
#[inline]
fn metadata_mut(&mut self) -> &mut SerdeAnyMap {
&mut self.metadata
}
}
impl HasMaxSize for AFLState {
fn max_size(&self) -> usize {
self.max_size
}
fn set_max_size(&mut self, max_size: usize) {
self.max_size = max_size;
}
}
struct LibAFLBaseCustomMutator {
state: AFLState,
input: BytesInput,
}
impl CustomMutator for LibAFLBaseCustomMutator {
type Error = libafl::Error;
fn init(afl: &'static afl_state, seed: u32) -> Result<Self, Self::Error> {
unsafe {
AFL = Some(afl);
let mut state = AFLState::new(seed);
let extras = std::slice::from_raw_parts(afl.extras, afl.extras_cnt as usize);
let mut tokens = vec![];
for extra in extras {
let data = std::slice::from_raw_parts(extra.data, extra.len as usize);
tokens.push(data.to_vec());
}
if !tokens.is_empty() {
state.add_metadata(Tokens::new(tokens));
}
Ok(Self {
state,
input: BytesInput::new(vec![]),
})
}
}
fn fuzz<'b, 's: 'b>(
&'s mut self,
buffer: &'b mut [u8],
add_buff: Option<&[u8]>,
max_size: usize,
) -> Result<Option<&'b [u8]>, Self::Error> {
self.state.set_max_size(max_size);
// TODO avoid copy
self.input.bytes_mut().clear();
self.input.bytes_mut().extend_from_slice(buffer);
let mut mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
mutator.mutate(&mut self.state, &mut self.input, 0)?;
Ok(Some(self.input.bytes()))
}
}
export_mutator!(LibAFLBaseCustomMutator);

View File

@ -100,8 +100,8 @@ extern "C" size_t afl_custom_fuzz(MyMutator *mutator, // return value from afl_c
// Copy to a new buffer ( mutated_out )
size_t mutated_size = s.size() <= max_size ? s.size() : max_size; // check if raw data's size is larger than max_size
delete mutator->mutated_out;
mutator->mutated_out = new uint8_t[mutated_size+1];
delete[] mutator->mutated_out;
mutator->mutated_out = new uint8_t[mutated_size];
memcpy(mutator->mutated_out, s.c_str(), mutated_size); // copy the mutated data
// Assign the mutated data and return mutated_size
*out_buf = mutator->mutated_out;

View File

@ -4,4 +4,7 @@
class MyMutator : public protobuf_mutator::Mutator {
public:
uint8_t *mutated_out = nullptr;
~MyMutator() {
delete[] mutated_out;
}
};

View File

@ -4473,6 +4473,10 @@ static word prim_sys(word op, word a, word b, word c) {
FD_CLOEXEC,
F_DUPFD,
F_DUPFD_CLOEXEC,
#if defined(F_DUP2FD)
F_DUP2FD,
F_DUP2FD_CLOEXEC,
#endif
F_GETFD,
F_SETFD,
F_GETFL,

View File

@ -358,6 +358,36 @@ pub mod wrappers {
}
}
/// An exported macro to defined afl_custom_init meant for insternal usage
#[cfg(feature = "afl_internals")]
#[macro_export]
macro_rules! _define_afl_custom_init {
($mutator_type:ty) => {
#[no_mangle]
pub extern "C" fn afl_custom_init(
afl: ::std::option::Option<&'static $crate::afl_state>,
seed: ::std::os::raw::c_uint,
) -> *const ::std::os::raw::c_void {
$crate::wrappers::afl_custom_init_::<$mutator_type>(afl, seed as u32)
}
};
}
/// An exported macro to defined afl_custom_init meant for insternal usage
#[cfg(not(feature = "afl_internals"))]
#[macro_export]
macro_rules! _define_afl_custom_init {
($mutator_type:ty) => {
#[no_mangle]
pub extern "C" fn afl_custom_init(
_afl: *const ::std::os::raw::c_void,
seed: ::std::os::raw::c_uint,
) -> *const ::std::os::raw::c_void {
$crate::wrappers::afl_custom_init_::<$mutator_type>(seed as u32)
}
};
}
/// exports the given Mutator as a custom mutator as the C interface that AFL++ expects.
/// It is not possible to call this macro multiple times, because it would define the custom mutator symbols multiple times.
/// # Example
@ -381,23 +411,7 @@ pub mod wrappers {
#[macro_export]
macro_rules! export_mutator {
($mutator_type:ty) => {
#[cfg(feature = "afl_internals")]
#[no_mangle]
pub extern "C" fn afl_custom_init(
afl: ::std::option::Option<&'static $crate::afl_state>,
seed: ::std::os::raw::c_uint,
) -> *const ::std::os::raw::c_void {
$crate::wrappers::afl_custom_init_::<$mutator_type>(afl, seed as u32)
}
#[cfg(not(feature = "afl_internals"))]
#[no_mangle]
pub extern "C" fn afl_custom_init(
_afl: *const ::std::os::raw::c_void,
seed: ::std::os::raw::c_uint,
) -> *const ::std::os::raw::c_void {
$crate::wrappers::afl_custom_init_::<$mutator_type>(seed as u32)
}
$crate::_define_afl_custom_init!($mutator_type);
#[no_mangle]
pub unsafe extern "C" fn afl_custom_fuzz_count(

View File

@ -1,6 +1,9 @@
# custum mutator: symcc
This uses the excellent symcc to find new paths into the target.
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.
To use this custom mutator follow the steps in the symcc repository
[https://github.com/eurecom-s3/symcc/](https://github.com/eurecom-s3/symcc/)

View File

@ -1,6 +1,6 @@
# AFL++ dictionaries
(See [../README.md](../README.md) for the general instruction manual.)
For the general instruction manual, see [docs/README.md](../docs/README.md).
This subdirectory contains a set of dictionaries that can be used in conjunction
with the -x option to allow the fuzzer to effortlessly explore the grammar of

View File

@ -1,24 +1,87 @@
# Changelog
This is the list of all noteworthy changes made in every public release of
the tool. See README.md for the general instruction manual.
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
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 ++3.15a (dev)
- documentation restructuring, made possible by Google Season of Docs
### Version ++4.02c (release)
- afl-cc:
- important fix for the default pcguard mode when LLVM IR vector
selects are produced, thanks to @juppytt for reporting!
- gcc_plugin:
- Adacore submitted CMPLOG support to the gcc_plugin! :-)
- llvm_mode:
- laf cmp splitting fixed for more comparison types
- frida_mode:
- now works on Android!
- afl-fuzz:
- 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 :)
- afl-fuzz:
- when you just want to compile once and set CMPLOG, then just
set -c 0 to tell afl-fuzz that the fuzzing binary is also for
CMPLOG.
- new commandline options -g/G to set min/max length of generated
fuzz inputs
- you can set the time for syncing to other fuzzer now with
AFL_SYNC_TIME
- reintroduced AFL_PERSISTENT and AFL_DEFER_FORKSRV to allow
persistent mode and manual forkserver support if these are not
in the target binary (e.g. are in a shared library)
- add AFL_EARLY_FORKSERVER to install the forkserver as earliest as
possible in the target (for afl-gcc-fast/afl-clang-fast/
afl-clang-lto)
- "saved timeouts" was wrong information, timeouts are still thrown
away by default even if they have new coverage (hangs are always
kept), unless AFL_KEEP_TIMEOUTS are set
- AFL never implemented auto token inserts (but user token inserts,
user token overwrite and auto token overwrite), added now!
- fixed a mutation type in havoc mode
- Mopt fix to always select the correct algorithm
- fix effector map calculation (deterministic mode)
- fix custom mutator post_process functionality
- document and auto-activate pizza mode on condition
- afl-cc:
- due a bug in lld of llvm 15 LTO instrumentation wont work atm :-(
- converted all passed to use the new llvm pass manager for llvm 11+
- AFL++ PCGUARD mode is not available for 10.0.1 anymore (11+ only)
- trying to stay on top on all these #$&§!! changes in llvm 15 ...
- frida_mode:
- update to new frida release, handles now c++ throw/catch
- unicorn_mode:
- update unicorn engine, fix C example
- utils:
- removed optimin because it looses coverage due to a bug and is
unmaintained :-(
### Version ++4.00c (release)
- complete documentation restructuring, made possible by Google Season
of Docs :) thank you Jana!
- we renamed several UI and fuzzer_stat entries to be more precise,
e.g. "unique crashes" -> "saved crashes", "total paths" ->
"corpus count", "current path" -> "current item".
This might need changing custom scripting!
- Nyx mode (full system emulation with snapshot capability) has been
added - thanks to @schumilo and @eqv!
- unicorn_mode:
- Moved to unicorn2! by Ziqiao Kong (@lazymio)
- Faster, more accurate emulation (newer QEMU base), risc-v support
- removed indirections in rust callbacks
- new binary-only fuzzing mode: coresight_mode for aarch64 CPUs :)
thanks to RICSecLab submitting!
- if instrumented libaries are dlopen()'ed after the forkserver you
will now see crashes. before you would have colliding coverage.
we changed this to force fixing a broken setup rather then allowing
will now see a crash. Before you would have colliding coverage.
We changed this to force fixing a broken setup rather then allowing
ineffective fuzzing.
See docs/best_practices.md how to fix such setups.
- afl-fuzz:
@ -26,14 +89,17 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
(it is better!)
- fix a regression introduced in 3.10 that resulted in less
coverage being detected. thanks to Collin May for reporting!
- ensure all spawned targets are killed on exit
- added AFL_IGNORE_PROBLEMS, plus checks to identify and abort on
incorrect LTO usage setups and enhanced the READMEs for better
information on how to deal with instrumenting libraries
- fix -n dumb mode (nobody should use this)
- fix -n dumb mode (nobody should use this mode though)
- fix stability issue with LTO and cmplog
- better banner
- more effective cmplog mode
- more often update the UI when in input2stage mode
- qemu_mode/unicorn_mode: fixed OOB write when using libcompcov,
thanks to kotee4ko for reporting!
- frida_mode:
- better performance, bug fixes
- David Carlier added Android support :)
@ -43,16 +109,22 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- fix bug where targets are not killed on timeouts
- moved hidden afl-showmap -A option to -H to be used for
coresight_mode
- Prevent accidently killing non-afl/fuzz services when aborting
- Prevent accidentally killing non-afl/fuzz services when aborting
afl-showmap and other tools.
- afl-cc:
- detect overflow reads on initial input buffer for asan
- 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
on filename matching (requires llvm 11 or newer)
- fixed a potential crash in targets for LAF string handling
- fixed a bad assert in LAF split switches
- added AFL_USE_TSAN thread sanitizer support
- llvm and LTO mode modified to work with new llvm 14-dev (again. again.)
- llvm and LTO mode modified to work with new llvm 14-dev (again.)
- fix for AFL_REAL_LD
- more -z defs filtering
- make -v without options work
- added the very good grammar mutator "GramaTron" to the
custom_mutators
- added optimin, a faster and better corpus minimizer by
@ -60,11 +132,10 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- added afl-persistent-config script to set perform permanent system
configuration settings for fuzzing, for Linux and Macos.
thanks to jhertz!
- added xml, curl and exotic string functions to llvm dictionary features
- added xml, curl & exotic string functions to llvm dictionary feature
- fix AFL_PRELOAD issues on MacOS
- removed utils/afl_frida because frida_mode/ is now so much better
- added uninstall target to makefile (todo: update new readme!)
- removed indirections in rust callbacks for unicornafl
### Version ++3.14c (release)
- afl-fuzz:
@ -84,7 +155,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- Fix to instrument global namespace functions in c++
- Fix for llvm 13
- support partial linking
- do honor AFL_LLVM_{ALLOW/DENY}LIST for LTO autodictionary and DICT2FILE
- do honor AFL_LLVM_{ALLOW/DENY}LIST for LTO autodictionary andDICT2FILE
- We do support llvm versions from 3.8 to 5.0 again
- frida_mode:
- several fixes for cmplog

View File

@ -58,10 +58,10 @@ If you find an interesting or important question missing, submit it via
A program contains `functions`, `functions` contain the compiled machine code.
The compiled machine code in a `function` can be in a single or many `basic
blocks`. A `basic block` is the largest possible number of subsequent machine
code instructions that has exactly one entry point (which can be be entered by
multiple other basic blocks) and runs linearly without branching or jumping to
other addresses (except at the end).
blocks`. A `basic block` is the **largest possible number of subsequent machine
code instructions** that has **exactly one entry point** (which can be be entered by
multiple other basic blocks) and runs linearly **without branching or jumping to
other addresses** (except at the end).
```
function() {
@ -180,8 +180,58 @@ If you find an interesting or important question missing, submit it via
[best_practices.md#improving-stability](best_practices.md#improving-stability).
</p></details>
<details>
<summary id="what-are-power-schedules">What are power schedules?</summary><p>
Not every item in our queue/corpus is the same, some are more interesting,
others provide little value.
A power schedule measures how "interesting" a value is, and depending on
the calculated value spends more or less time mutating it.
AFL++ comes with several power schedules, initially ported from
[AFLFast](https://github.com/mboehme/aflfast), however, modified to be more
effective and several more modes added.
The most effective modes are `-p fast` (default) and `-p explore`.
If you fuzz with several parallel afl-fuzz instances, then it is beneficial
to assign a different schedule to each instance, however the majority should
be `fast` and `explore`.
It does not make sense to explain the details of the calculation and
reasoning behind all of the schedules. If you are interested, read the source
code and the AFLFast paper.
</p></details>
## Troubleshooting
<details>
<summary id="fatal-forkserver-is-already-up-but-an-instrumented-dlopen-library-loaded-afterwards">FATAL: forkserver is already up but an instrumented dlopen library loaded afterwards</summary><p>
It can happen that you see this error on startup when fuzzing a target:
```
[-] FATAL: forkserver is already up, but an instrumented dlopen() library
loaded afterwards. You must AFL_PRELOAD such libraries to be able
to fuzz them or LD_PRELOAD to run outside of afl-fuzz.
To ignore this set AFL_IGNORE_PROBLEMS=1.
```
As the error describes, a dlopen() call is happening in the target that is
loading an instrumented library after the forkserver is already in place. This
is a problem for afl-fuzz because when the forkserver is started, we must know
the map size already and it can't be changed later.
The best solution is to simply set `AFL_PRELOAD=foo.so` to the libraries that
are dlopen'ed (e.g., use `strace` to see which), or to set a manual forkserver
after the final dlopen().
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.
</p></details>
<details>
<summary id="i-got-a-weird-compile-error-from-clang">I got a weird compile error from clang.</summary><p>
@ -204,4 +254,4 @@ If you find an interesting or important question missing, submit it via
package and because of that the AFL++ llvm plugins do not match anymore.
Solution: `git pull ; make clean install` of AFL++.
</p></details>
</p></details>

View File

@ -3,26 +3,33 @@
## 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-11 -
hence afl-clang-lto is available!) or just pull directly from the Docker Hub:
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):
```shell
docker pull aflplusplus/aflplusplus
docker pull aflplusplus/aflplusplus:
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
```
This image is automatically generated when a push to the stable repo happens.
You will find your target source code in /src in the container.
This image is automatically generated when a push to the stable branch happens.
You will find your target source code in `/src` in the container.
Note: you can also pull `aflplusplus/aflplusplus:dev` which is the most current
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!
```shell
sudo apt-get update
sudo apt-get install -y build-essential python3-dev automake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools
# try to install llvm 11 and install the distro default if that fails
sudo apt-get install -y lld-11 llvm-11 llvm-11-dev clang-11 || 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 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
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
cd AFLplusplus
@ -33,10 +40,10 @@ sudo make install
It is recommended to install the newest available gcc, clang and llvm-dev
possible in your distribution!
Note that "make distrib" also builds instrumentation, QEMU mode, unicorn_mode
and more. If you just want plain AFL++, then do "make all". However, compiling
and using at least instrumentation is highly recommended for much better results
- hence in this case choose:
Note that `make distrib` also builds FRIDA mode, QEMU mode, unicorn_mode, and
more. If you just want plain AFL++, then do `make all`. If you want some
assisting tooling compiled but are not interested in binary-only targets, then
instead choose:
```shell
make source-only
@ -44,11 +51,12 @@ make source-only
These build targets exist:
* all: just the main AFL++ binaries
* binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode,
libdislocator, libtokencap
* source-only: everything for source code fuzzing: instrumentation,
libdislocator, libtokencap
* 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
* source-only: everything for source code fuzzing: nyx_mode, libdislocator,
libtokencap
* distrib: everything (for both binary-only and source code fuzzing)
* man: creates simple man pages from the help option of the programs
* install: installs everything you have compiled with the build options above
@ -71,47 +79,59 @@ make STATIC=1
These build options exist:
* STATIC - compile AFL++ static
* ASAN_BUILD - compiles with memory sanitizer for debug purposes
* ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for
debug purposes
* DEBUG - no optimization, -ggdb3, all warnings and -Werror
* PROFILING - compile with profiling information (gprof)
* 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_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)
e.g.: `make ASAN_BUILD=1`
e.g.: `make LLVM_CONFIG=llvm-config-14`
## MacOS X on x86 and arm64 (M1)
MacOS X should work, but there are some gotchas due to the idiosyncrasies of the
platform. On top of this, we have limited release testing capabilities and
depend mostly on user feedback.
MacOS has some gotchas due to the idiosyncrasies of the platform.
To build AFL, install llvm (and perhaps gcc) from brew and follow the general
instructions for Linux. If possible, avoid Xcode at all cost.
`brew install wget git make cmake llvm gdb`
```shell
brew install wget git make cmake llvm gdb coreutils
```
Be sure to setup `PATH` to point to the correct clang binaries and use the
freshly installed clang, clang++ and gmake, e.g.:
freshly installed clang, clang++, llvm-config, gmake and coreutils, e.g.:
```
export PATH="/usr/local/Cellar/llvm/12.0.1/bin/:$PATH"
```shell
# Depending on your MacOS system + brew version it is either
export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
# or
export PATH="/usr/local/opt/llvm/bin:$PATH"
# you can check with "brew info llvm"
export PATH="/usr/local/opt/coreutils/libexec/gnubin:/usr/local/bin:$PATH"
export CC=clang
export CXX=clang++
gmake
cd frida_mode
gmake
cd ..
gmake install
sudo gmake install
```
`afl-gcc` will fail unless you have GCC installed, but that is using outdated
instrumentation anyway. You don't want that. Note that `afl-clang-lto`,
`afl-gcc-fast` and `qemu_mode` are not working on MacOS.
instrumentation anyway. `afl-clang` might fail too depending on your PATH setup.
But you don't want neither, you want `afl-clang-fast` anyway :) Note that
`afl-clang-lto`, `afl-gcc-fast` and `qemu_mode` are not working on MacOS.
The crash reporting daemon that comes by default with MacOS X will cause
problems with fuzzing. You need to turn it off:
@ -132,8 +152,8 @@ and definitely don't look POSIX-compliant. This means two things:
environment before starting afl-fuzz.
User emulation mode of QEMU does not appear to be supported on MacOS X, so
black-box instrumentation mode (`-Q`) will not work. However, Frida mode (`-O`)
should work on x86 and arm64 MacOS boxes.
black-box instrumentation mode (`-Q`) will not work. However, FRIDA mode (`-O`)
works on both x86 and arm64 MacOS boxes.
MacOS X supports SYSV shared memory used by AFL's instrumentation, but the
default settings aren't usable with AFL++. The default settings on 10.14 seem to
@ -169,4 +189,4 @@ sysctl kern.sysv.shmall=98304
See
[http://www.spy-hill.com/help/apple/SharedMemory.html](http://www.spy-hill.com/help/apple/SharedMemory.html)
for documentation for these settings and how to make them permanent.
for documentation for these settings and how to make them permanent.

65
docs/README.md Normal file
View File

@ -0,0 +1,65 @@
# AFL++ documentation
This is the overview of the AFL++ docs content.
For general information on AFL++, see the
[README.md of the repository](../README.md).
Also take a look at our [FAQ.md](FAQ.md) and
[best_practices.md](best_practices.md).
## Fuzzing targets with the source code available
You can find a quickstart for fuzzing targets with the source code available in
the [README.md of the repository](../README.md#quick-start-fuzzing-with-afl).
For in-depth information on the steps of the fuzzing process, see
[fuzzing_in_depth.md](fuzzing_in_depth.md) or click on the following
image and select a step.
![Fuzzing process overview](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/0_fuzzing_process_overview.drawio.svg "Fuzzing process overview")
For further information on instrumentation, see the
[READMEs in the instrumentation/ folder](../instrumentation/).
### Instrumenting the target
For more information, click on the following image and select a step.
![Instrumenting the target](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/1_instrument_target.drawio.svg "Instrumenting the target")
### Preparing the fuzzing campaign
For more information, click on the following image and select a step.
![Preparing the fuzzing campaign](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/2_prepare_campaign.drawio.svg "Preparing the fuzzing campaign")
### Fuzzing the target
For more information, click on the following image and select a step.
![Fuzzing the target](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/3_fuzz_target.drawio.svg "Fuzzing the target")
### Managing the fuzzing campaign
For more information, click on the following image and select a step.
![Managing the fuzzing campaign](https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/dev/docs/resources/4_manage_campaign.drawio.svg "Managing the fuzzing campaign")
## Fuzzing other targets
To learn about fuzzing other targets, see:
* Binary-only: [fuzzing_binary-only_targets.md](fuzzing_binary-only_targets.md)
* GUI programs:
[best_practices.md#fuzzing-a-gui-program](best_practices.md#fuzzing-a-gui-program)
* Libraries: [frida_mode/README.md](../frida_mode/README.md)
* Network services:
[best_practices.md#fuzzing-a-network-service](best_practices.md#fuzzing-a-network-service)
* Non-linux: [unicorn_mode/README.md](../unicorn_mode/README.md)
## Additional information
* Tools that help fuzzing with AFL++:
[third_party_tools.md](third_party_tools.md)
* Tutorials: [tutorials.md](tutorials.md)

View File

@ -40,7 +40,7 @@ superior to blind fuzzing or coverage-only tools.
This section provides an overview of the status screen - plus tips for
troubleshooting any warnings and red text shown in the UI.
For the general instruction manual, see [README.md](../README.md).
For the general instruction manual, see [README.md](README.md).
### A note about colors

View File

@ -116,7 +116,7 @@ allows you to define network state with different type of data packets.
### Improving stability
For fuzzing a 100% stable target that covers all edges is the best case. A 90%
For fuzzing, a 100% stable target that covers all edges is the best case. A 90%
stable target that covers all edges is, however, better than a 100% stable
target that ignores 10% of the edges.
@ -189,4 +189,4 @@ coding and/or disassembly and is effectively possible only with `afl-clang-fast`
Recompile, fuzz it, be happy :)
This link explains this process for
[Fuzzbench](https://github.com/google/fuzzbench/issues/677).
[Fuzzbench](https://github.com/google/fuzzbench/issues/677).

View File

@ -38,6 +38,11 @@ performed with the custom mutator.
## 2) APIs
**IMPORTANT NOTE**: If you use our C/C++ API and you want to increase the size
of an **out_buf buffer, you have to use `afl_realloc()` for this, so include
`include/alloc-inl.h` - otherwise afl-fuzz will crash when trying to free
your buffers.
C/C++:
```c
@ -159,6 +164,10 @@ def deinit(): # optional for Python
This can return any python object that implements the buffer protocol and
supports PyBUF_SIMPLE. These include bytes, bytearray, etc.
You can decide in the post_process mutator to not send the mutated data
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).
- `queue_new_entry` (optional):
This methods is called after adding a new test case to the queue. If the

View File

@ -1,122 +0,0 @@
# Restructure AFL++'s documentation
## About us
We are dedicated to everything around fuzzing, our main and most well known
contribution is the fuzzer `AFL++` which is part of all major Unix
distributions (e.g. Debian, Arch, FreeBSD, etc.) and is deployed on Google's
oss-fuzz and clusterfuzz. It is rated the top fuzzer on Google's fuzzbench.
We are four individuals from Europe supported by a large community.
All our tools are open source.
## About the AFL++ fuzzer project
AFL++ inherited it's documentation from the original Google AFL project.
Since then it has been massively improved - feature and performance wise -
and although the documenation has likewise been continued it has grown out
of proportion.
The documentation is done by non-natives to the English language, plus
none of us has a writer background.
We see questions on AFL++ usage on mailing lists (e.g. afl-users), discord
channels, web forums and as issues in our repository.
This only increases as AFL++ has been on the top of Google's fuzzbench
statistics (which measures the performance of fuzzers) and is now being
integrated in Google's oss-fuzz and clusterfuzz - and is in many Unix
packaging repositories, e.g. Debian, FreeBSD, etc.
AFL++ now has 44 (!) documentation files with 13k total lines of content.
This is way too much.
Hence AFL++ needs a complete overhaul of it's documentation, both on a
organisation/structural level as well as the content.
Overall the following actions have to be performed:
* Create a better structure of documentation so it is easier to find the
information that is being looked for, combining and/or splitting up the
existing documents as needed.
* Rewrite some documentation to remove duplication. Several information is
present several times in the documentation. These should be removed to
where needed so that we have as little bloat as possible.
* The documents have been written and modified by a lot of different people,
most of them non-native English speaker. Hence an overall review where
parts should be rewritten has to be performed and then the rewrite done.
* Create a cheat-sheet for a very short best-setup build and run of AFL++
* Pictures explain more than 1000 words. We need at least 4 images that
explain the workflow with AFL++:
- the build workflow
- the fuzzing workflow
- the fuzzing campaign management workflow
- the overall workflow that is an overview of the above
- maybe more? where the technical writes seems it necessary for
understanding.
Requirements:
* Documentation has to be in Markdown format
* Images have to be either in SVG or PNG format.
* All documentation should be (moved) in(to) docs/
The project does not require writing new documentation or tutorials beside the
cheat sheet. The technical information for the cheat sheet will be provided by
us.
## Metrics
AFL++ is a the highest performant fuzzer publicly available - but is also the
most feature rich and complex. With the publicity of AFL++' success and
deployment in Google projects internally and externally and availability as
a package on most Linux distributions we see more and more issues being
created and help requests on our Discord channel that would not be
necessary if people would have read through all our documentation - which
is unrealistic.
We expect the the new documenation after this project to be cleaner, easier
accessible and lighter to digest by our users, resulting in much less
help requests. On the other hand the amount of users using AFL++ should
increase as well as it will be more accessible which would also increase
questions again - but overall resulting in a reduction of help requests.
In numbers: we currently have per week on average 5 issues on Github,
10 questions on discord and 1 on mailing lists that would not be necessary
with perfect documentation and perfect people.
We would consider this project a success if afterwards we only have
2 issues on Github and 3 questions on discord anymore that would be answered
by reading the documentation. The mailing list is usually used by the most
novice users and we don't expect any less questions there.
## Project Budget
We have zero experience with technical writers, so this is very hard for us
to calculate. We expect it to be a lot of work though because of the amount
of documentation we have that needs to be restructured and partially rewritten
(44 documents with 13k total lines of content).
We assume the daily rate of a very good and experienced technical writer in
times of a pandemic to be ~500$ (according to web research), and calculate
the overall amout of work to be around 20 days for everything incl. the
graphics (but again - this is basically just guessing).
Technical Writer 10000$
Volunteer stipends 0$ (waved)
T-Shirts for the top 10 contributors and helpers to this documentation project:
10 AFL++ logo t-shirts 20$ each 200$
10 shipping cost of t-shirts 10$ each 100$
Total: 10.300$
(in the submission form 10.280$ was entered)
## Additional Information
We have participated in Google Summer of Code in 2020 and hope to be selected
again in 2021.
We have no experience with a technical writer, but we will support that person
with video calls, chats, emails and messaging, provide all necessary information
and write technical contents that is required for the success of this project.
It is clear to us that a technical writer knows how to write, but cannot know
the technical details in a complex tooling like in AFL++. This guidance, input,
etc. has to come from us.

View File

@ -1,124 +0,0 @@
# Restructure AFL++'s documentation - Case Study
## Problem statement
AFL++ inherited it's documentation from the original Google AFL project.
Since then it has been massively improved - feature and performance wise -
and although the documenation has likewise been continued it has grown out
of proportion.
The documentation is done by non-natives to the English language, plus
none of us has a writer background.
We see questions on AFL++ usage on mailing lists (e.g. afl-users), discord
channels, web forums and as issues in our repository.
Most of them could be answered if people would read through all the
documentation.
This only increases as AFL++ has been on the top of Google's fuzzbench
statistics (which measures the performance of fuzzers) and has been
integrated in Google's oss-fuzz and clusterfuzz - and is in many Unix
packaging repositories, e.g. Debian, FreeBSD, etc.
AFL++ had 44 (!) documentation files with 13k total lines of content.
This was way too much.
## Proposal abstract
AFL++'s documentatin needs a complete overhaul, both on a
organisation/structural level as well as the content.
Overall the following actions have to be performed:
* Create a better structure of documentation so it is easier to find the
information that is being looked for, combining and/or splitting up the
existing documents as needed.
* Rewrite some documentation to remove duplication. Several information is
present several times in the documentation. These should be removed to
where needed so that we have as little bloat as possible.
* The documents have been written and modified by a lot of different people,
most of them non-native English speaker. Hence an overall review where
parts should be rewritten has to be performed and then the rewrite done.
* Create a cheat-sheet for a very short best-setup build and run of AFL++
* Pictures explain more than 1000 words. We need at least 4 images that
explain the workflow with AFL++:
- the build workflow
- the fuzzing workflow
- the fuzzing campaign management workflow
- the overall workflow that is an overview of the above
- maybe more? where the technical writes seems it necessary for
understanding.
Requirements:
* Documentation has to be in Markdown format
* Images have to be either in SVG or PNG format.
* All documentation should be (moved) in(to) docs/
## Project description
We created our proposal by discussing in the team what the issues are and
what was needed to fix it.
This resulted in the [project proposal](https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/docs.md).
We did not want to be selected by a writer but select a writer ourselves, so
we combed through the list and reviewed every single one of them.
We were not looking for coders writing technical documentation, but rather
someone who is an experienced writer and has documented experience with
structuring documentation.
Few fit that profile and we sent out messages to 6 people.
We finally decided on Jana because she had a strong background in technical
documentation and structuring information.
She had no technical experience in fuzzing whatsoever, but we saw that as
a plus - of course this made the whole process longer to explain details,
but overall ensured that the documentation can be read by (mostly) everyone.
We communicated via video calls every few weeks and she kept a public kanban
board about her todos, additional we used a Signal channel.
Her changes were imported via PRs where we discussed details.
The project was off to a good start, but then Jana got pregnant with serious
side effects that made working impossible for her for a longer time, hence
the schedule was thrown back.
She offered to rescind the payment and we select a new writer, but we saw
little opportunity in that, as that would mean a new selection of a writer,
someone else with a different vision on how the result should look like so
basically a full restart of the project and a large impact on our own time.
So we agreed on - after discussion with the Google GSoD team - that she
continues the project after the GSoD completion deadline as best as she can.
End of November she took one week off from work and fully dedicated her time
for the documenation which brought the project a big step forward.
Originally the project should have been ended begin of October, but now - at
nearing the end of November, we are at about 85% completion, with the end
being expected around mid of December.
## Metrics
We merged most of the changes in our development branch and are getting
close to a state where the user documentation part is completed and we
can create a new release. Only then the new documentatin is actually visible
to users. Therefore no metrics could be collected so far.
We plan on a user-assisted QA review end of November/begin of December.
The documentation was reviewed by a few test users so far however who gave
it a thumbs up.
## Summary
The GSoD project itself is great. It helps to get the documentation back in
line.
It was and is a larger time investment from our side, but we expected that.
When the project is done, the documentation will be more accessible by users
and also need less maintenance by us.
There is still follow-up work to be done by us afterwards (web site for the
docs, etc.).
Not sure what we would do differently next time. I think we prepared best as
possible and reacted best as possible to the unexpected.
Recommendations for other organizations who would like to participate in GSoD:
- expect the process to take a larger part of your time. the writer needs
your full support.
- have someone dedicated from the dev/org side to support, educate and
supervice the writer
- set clear goals and expectations

View File

@ -105,7 +105,8 @@ fairly broad use of environment variables instead:
within your program at a certain point (such as at the end of an
`__AFL_LOOP()`), you can run the macro `__AFL_LEAK_CHECK();` which will
cause an abort if any memory is leaked (you can combine this with the
`LSAN_OPTIONS=...` suppression option to suppress some known leaks).
`__AFL_LSAN_OFF();` and `__AFL_LSAN_ON();` macros to avoid checking for
memory leaks from memory allocated between these two calls.
- `AFL_USE_MSAN=1` - activates the memory sanitizer (uninitialized memory)
- `AFL_USE_TSAN=1` - activates the thread sanitizer to find thread race
conditions
@ -159,6 +160,8 @@ Available options:
Setting `AFL_LLVM_CMPLOG=1` during compilation will tell afl-clang-fast to
produce a CmpLog binary.
For afl-gcc-fast, set `AFL_GCC_CMPLOG=1` instead.
For more information, see
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
@ -283,12 +286,24 @@ mode.
TMPDIR=$PWD/assembly_here AFL_KEEP_ASSEMBLY=1 make clean all
```
- GCC_PLUGIN mode only: Setting `AFL_GCC_INSTRUMENT_FILE` with a filename will
only instrument those files that match the names listed in this file (one
filename per line). See
- GCC_PLUGIN mode only: Setting `AFL_GCC_INSTRUMENT_FILE` or
`AFL_GCC_ALLOWLIST` with a filename will only instrument those files that
match the names listed in this file (one filename per line).
Setting `AFL_GCC_DENYLIST` or `AFL_GCC_BLOCKLIST` with a file name and/or
function will only skip those files that match the names listed in the
specified file. See
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
for more information.
Setting `AFL_GCC_OUT_OF_LINE=1` will instruct afl-gcc-fast to instrument the
code with calls to an injected subroutine instead of the much more efficient
inline instrumentation.
Setting `AFL_GCC_SKIP_NEVERZERO=1` will not implement the skip zero test. If
the target performs only a few loops, then this will give a small
performance boost.
## 4) Settings for afl-fuzz
The main fuzzer binary accepts several options that disable a couple of sanity
@ -336,6 +351,9 @@ checks or alter some of the more exotic semantics of the tool:
- Setting `AFL_DISABLE_TRIM` tells afl-fuzz not to trim test cases. This is
usually a bad idea!
- Setting `AFL_KEEP_TIMEOUTS` will keep longer running inputs if they reach
new coverage
- `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.
@ -387,6 +405,10 @@ checks or alter some of the more exotic semantics of the tool:
This makes the "own finds" counter in the UI more accurate. Beyond counter
aesthetics, not much else should change.
- Setting `AFL_INPUT_LEN_MIN` and `AFL_INPUT_LEN_MAX` are an alternative to
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
likely don't have to set it. By default, on timeout and on exit, `SIGKILL`
@ -397,7 +419,7 @@ checks or alter some of the more exotic semantics of the tool:
target. This must be equal or larger than the size the target was compiled
with.
- Setting `AFL_MAX_DET_EXRAS` will change the threshold at what number of
- Setting `AFL_MAX_DET_EXTRAS` will change the threshold at what number of
elements in the `-x` dictionary and LTO autodict (combined) the
probabilistic mode will kick off. In probabilistic mode, not all dictionary
entries will be used all of the time for fuzzing mutations to not slow down
@ -440,7 +462,7 @@ checks or alter some of the more exotic semantics of the tool:
some basic stats. This behavior is also automatically triggered when the
output from afl-fuzz is redirected to a file or to a pipe.
- In QEMU mode (-Q) and Frida mode (-O), `AFL_PATH` will be searched for
- In QEMU mode (-Q) and FRIDA mode (-O), `AFL_PATH` will be searched for
afl-qemu-trace and afl-frida-trace.so.
- If you are using persistent mode (you should, see
@ -497,11 +519,20 @@ checks or alter some of the more exotic semantics of the tool:
(empty/non present) will add no tags to the metrics. For more information,
see [rpc_statsd.md](rpc_statsd.md).
- `AFL_SYNC_TIME` allows you to specify a different minimal time (in minutes)
between fuzzing instances synchronization. Default sync time is 30 minutes,
note that time is halved for -M main nodes.
- Setting `AFL_TARGET_ENV` causes AFL++ to set extra environment variables for
the target binary. Example: `AFL_TARGET_ENV="VAR1=1 VAR2='a b c'" afl-fuzz
... `. This exists mostly for things like `LD_LIBRARY_PATH` but it would
theoretically allow fuzzing of AFL++ itself (with 'target' AFL++ using some
AFL_ vars that would disrupt work of 'fuzzer' AFL++).
AFL_ vars that would disrupt work of 'fuzzer' AFL++). Note that when using
QEMU mode, the `AFL_TARGET_ENV` environment variables will apply to QEMU, as
well as the target binary. Therefore, in this case, you might want to use
QEMU's `QEMU_SET_ENV` environment variable (see QEMU's documentation because
the format is different from `AFL_TARGET_ENV`) to apply the environment
variables to the target and not QEMU.
- `AFL_TESTCACHE_SIZE` allows you to override the size of `#define
TESTCASE_CACHE` in config.h. Recommended values are 50-250MB - or more if
@ -515,9 +546,20 @@ checks or alter some of the more exotic semantics of the tool:
- Setting `AFL_TRY_AFFINITY` tries to attempt binding to a specific CPU core
on Linux systems, but will not terminate if that fails.
- Outdated environment variables that are not supported anymore:
- `AFL_DEFER_FORKSRV`
- `AFL_PERSISTENT`
- The following environment variables are only needed if you implemented
your own forkserver or persistent mode, or if __AFL_LOOP or __AFL_INIT
are in a shared library and not the main binary:
- `AFL_DEFER_FORKSRV` enforces a deferred forkserver even if none was
detected in the target binary
- `AFL_PERSISTENT` enforces persistent mode even if none was detected
in the target binary
- If you need an early forkserver in your target because of early
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.
## 5) Settings for afl-qemu-trace
@ -579,6 +621,10 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
emulation" variables (e.g., `QEMU_STACK_SIZE`), but there should be no
reason to touch them.
- Normally a `README.txt` is written to the `crashes/` directory when a first
crash is found. Setting `AFL_NO_CRASH_README` will prevent this. Useful when
counting crashes based on a file count in that directory.
## 7) Settings for afl-frida-trace
The FRIDA wrapper used to instrument binary-only code supports many of the same

View File

@ -1,39 +1,96 @@
# Important features of AFL++
AFL++ supports llvm from 3.8 up to version 12, very fast binary fuzzing with
QEMU 5.1 with laf-intel and redqueen, FRIDA mode, unicorn mode, gcc plugin, full
QEMU 5.1 with laf-intel and Redqueen, FRIDA mode, unicorn mode, gcc plugin, full
*BSD, Mac OS, Solaris and Android support and much, much, much more.
| Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | FRIDA mode(9) | QEMU mode(10) |unicorn_mode(10) |coresight_mode(11)|
| -------------------------|:-------:|:---------:|:----------:|:----------------:|:----------------:|:----------------:|:----------------:|
| Threadsafe counters | | x(3) | | | | | |
| NeverZero | x86[_64]| x(1) | x | x | x | x | |
| Persistent Mode | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | |
| LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | |
| CmpLog | | x | | x86[_64]/arm64 | x86[_64]/arm[64] | | |
| Selective Instrumentation| | x | x | x | x | | |
| Non-Colliding Coverage | | x(4) | | | (x)(5) | | |
| Ngram prev_loc Coverage | | x(6) | | | | | |
| Context Coverage | | x(6) | | | | | |
| Auto Dictionary | | x(7) | | | | | |
| Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | |
| Shared Memory Test cases | | x | x | x86[_64]/arm64 | x | x | |
## Features and instrumentation
1. default for LLVM >= 9.0, environment variable for older version due an
| Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | FRIDA mode(9) | QEMU mode(10) | unicorn_mode(10) | nyx_mode(12) | coresight_mode(11) |
| ------------------------------|:--------:|:---------:|:----------:|:--------------:|:----------------:|:----------------:|:------------:|:------------------:|
| Threadsafe counters [A] | | x(3) | | | | | x | |
| NeverZero [B] | x86[_64] | x(1) | x | x | x | x | | |
| Persistent Mode [C] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | |
| LAF-Intel / CompCov [D] | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | |
| CmpLog [E] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
| Selective Instrumentation [F] | | x | x | x | x | | | |
| Non-Colliding Coverage [G] | | x(4) | | | (x)(5) | | | |
| Ngram prev_loc Coverage [H] | | x(6) | | | | | | |
| Context Coverage [I] | | x(6) | | | | | | |
| Auto Dictionary [J] | | x(7) | | | | | | |
| Snapshot Support [K] | | (x)(8) | (x)(8) | | (x)(5) | | x | |
| Shared Memory Test cases [L] | | x | x | x86[_64]/arm64 | x | x | x | |
## More information about features
A. Default is not thread-safe coverage counter updates for better performance,
see [instrumentation/README.llvm.md](../instrumentation/README.llvm.md)
B. On wrapping coverage counters (255 + 1), skip the 0 value and jump to 1
instead. This has shown to give better coverage data and is the default; see
[instrumentation/README.llvm.md](../instrumentation/README.llvm.md).
C. Instead of forking, reiterate the fuzz target function in a loop (like
`LLVMFuzzerTestOneInput`. Great speed increase but only works with target
functions that do not keep state, leak memory, or exit; see
[instrumentation/README.persistent_mode.md](../instrumentation/README.persistent_mode.md)
D. Split any non-8-bit comparison to 8-bit comparison; see
[instrumentation/README.laf-intel.md](../instrumentation/README.laf-intel.md)
E. CmpLog is our enhanced
[Redqueen](https://www.ndss-symposium.org/ndss-paper/redqueen-fuzzing-with-input-to-state-correspondence/)
implementation, see
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md)
F. Similar and compatible to clang 13+ sancov sanitize-coverage-allow/deny but
for all llvm versions and all our compile modes, only instrument what should
be instrumented, for more speed, directed fuzzing and less instability; see
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
G. Vanilla AFL uses coverage where edges could collide to the same coverage
bytes the larger the target is. Our default instrumentation in LTO and
afl-clang-fast (PCGUARD) uses non-colliding coverage that also makes it
faster. Vanilla AFL style is available with `AFL_LLVM_INSTRUMENT=AFL`; see
[instrumentation/README.llvm.md](../instrumentation/README.llvm.md).
H.+I. Alternative coverage based on previous edges (NGRAM) or depending on the
caller (CTX), based on
[https://www.usenix.org/system/files/raid2019-wang-jinghan.pdf](https://www.usenix.org/system/files/raid2019-wang-jinghan.pdf);
see [instrumentation/README.llvm.md](../instrumentation/README.llvm.md).
J. An LTO feature that creates a fuzzing dictionary based on comparisons found
during compilation/instrumentation. Automatic feature :) See
[instrumentation/README.lto.md](../instrumentation/README.lto.md)
K. The snapshot feature requires a kernel module that was a lot of work to get
right and maintained so it is no longer supported. We have
[nyx_mode](../nyx_mode/README.md) instead.
L. Faster fuzzing and less kernel syscall overhead by in-memory fuzz testcase
delivery, see
[instrumentation/README.persistent_mode.md](../instrumentation/README.persistent_mode.md)
## More information about instrumentation
1. Default for LLVM >= 9.0, environment variable for older version due an
efficiency bug in previous llvm versions
2. GCC creates non-performant code, hence it is disabled in gcc_plugin
3. with `AFL_LLVM_THREADSAFE_INST`, disables NeverZero
4. with pcguard mode and LTO mode for LLVM 11 and newer
5. upcoming, development in the branch
6. not compatible with LTO instrumentation and needs at least LLVM v4.1
7. automatic in LTO mode with LLVM 11 and newer, an extra pass for all LLVM
3. With `AFL_LLVM_THREADSAFE_INST`, disables NeverZero
4. With pcguard mode and LTO mode for LLVM 11 and newer
5. Upcoming, development in the branch
6. Not compatible with LTO instrumentation and needs at least LLVM v4.1
7. Automatic in LTO mode with LLVM 11 and newer, an extra pass for all LLVM
versions that write to a file to use with afl-fuzz' `-x`
8. the snapshot LKM is currently unmaintained due to too many kernel changes
8. The snapshot LKM is currently unmaintained due to too many kernel changes
coming too fast :-(
9. FRIDA mode is supported on Linux and MacOS for Intel and ARM
10. QEMU/Unicorn is only supported on Linux
11. Coresight mode is only available on AARCH64 Linux with a CPU with Coresight
extension
12. Nyx mode is only supported on Linux and currently restricted to x86_x64
## Integrated features and patches
Among others, the following features and patches have been integrated:
@ -43,7 +100,7 @@ Among others, the following features and patches have been integrated:
* Unicorn mode which allows fuzzing of binaries from completely different
platforms (integration provided by domenukk)
* The new CmpLog instrumentation for LLVM and QEMU inspired by
[Redqueen](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf)
[Redqueen](https://github.com/RUB-SysSec/redqueen)
* Win32 PE binary-only fuzzing with QEMU and Wine
* AFLfast's power schedules by Marcel Böhme:
[https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)

View File

@ -12,11 +12,11 @@ fuzzed with AFL++.
## TL;DR:
QEMU mode in persistent mode is the fastest - if the stability is high enough.
Otherwise, try RetroWrite, Dyninst, and if these fail, too, then try standard
QEMU mode with `AFL_ENTRYPOINT` to where you need it.
FRIDA mode and QEMU mode in persistent mode are the fastest - if persistent mode
is possible and the stability is high enough.
If your target is a library, then use FRIDA mode.
Otherwise, try Zafl, RetroWrite, Dyninst, and if these fail, too, then try
standard FRIDA/QEMU mode with `AFL_ENTRYPOINT` to where you need it.
If your target is non-linux, then use unicorn_mode.
@ -48,11 +48,12 @@ The following setup to use QEMU mode is recommended:
Then run as many instances as you have cores left with either -Q mode or - even
better - use a binary rewriter like Dyninst, RetroWrite, ZAFL, etc.
The binary rewriters all have their own advantages and caveats.
ZAFL is the best but cannot be used in a business/commercial context.
If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for your
binary, then you can use afl-fuzz normally and it will have twice the speed
compared to QEMU mode (but slower than QEMU persistent mode). Note that several
other binary rewriters exist, all with their advantages and caveats.
If a binary rewriter works for your target then you can use afl-fuzz normally
and it will have twice the speed compared to QEMU mode (but slower than QEMU
persistent mode).
The speed decrease of QEMU mode is at about 50%. However, various options exist
to increase the speed:
@ -92,7 +93,7 @@ For more information, see
### FRIDA mode
In FRIDA mode, you can fuzz binary-only targets as easily as with QEMU mode.
FRIDA mode is sometimes faster and sometimes slower than QEMU mode. It is also
FRIDA mode is most of the times slightly faster than QEMU mode. It is also
newer, lacks COMPCOV, and has the advantage that it works on MacOS (both intel
and M1).
@ -100,7 +101,7 @@ To build FRIDA mode:
```shell
cd frida_mode
make
gmake
```
For additional instructions and caveats, see
@ -126,6 +127,16 @@ to check out our sister project libafl which supports Frida, too:
[https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL).
Working examples already exist :-)
### Nyx mode
Nyx is a full system emulation fuzzing environment with snapshot support that is
built upon KVM and QEMU. It is only available on Linux and currently restricted
to x86_x64.
For binary-only fuzzing a special 5.10 kernel is required.
See [nyx_mode/README.md](../nyx_mode/README.md).
### Unicorn
Unicorn is a fork of QEMU. The instrumentation is, therefore, very similar. In
@ -189,12 +200,15 @@ afl-clang-fast's.
### RetroWrite
If you have an x86/x86_64 binary that still has its symbols, is compiled with
position independent code (PIC/PIE), and does not use most of the C++ features,
then the RetroWrite solution might be for you. It decompiles to ASM files which
can then be instrumented with afl-gcc.
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.
It is at about 80-85% performance.
Binaries that are statically instrumented for fuzzing using RetroWrite are close
in performance to compiler-instrumented binaries and outperform the QEMU-based
instrumentation.
[https://github.com/HexHive/retrowrite](https://github.com/HexHive/retrowrite)
@ -293,4 +307,4 @@ some are very hard to set-up...
## Closing words
That's it! News, corrections, updates? Send an email to vh@thc.org.
That's it! News, corrections, updates? Send an email to vh@thc.org.

View File

@ -55,7 +55,7 @@ tasks, fuzzing may put a strain on your hardware and on the OS. In particular:
### a) Selecting the best AFL++ compiler for instrumenting the target
AFL++ comes with a central compiler `afl-cc` that incorporates various different
kinds of compiler targets and and instrumentation options. The following
kinds of compiler targets and instrumentation options. The following
evaluation flow will help you to select the best possible.
It is highly recommended to have the newest llvm version possible installed,
@ -95,38 +95,43 @@ Clickable README links for the chosen compiler:
* GCC/CLANG modes (afl-gcc/afl-clang) have no README as they have no own
features
You can select the mode for the afl-cc compiler by:
1. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++,
afl-gcc-fast, afl-g++-fast (recommended!)
2. using the environment variable AFL_CC_COMPILER with MODE
3. passing --afl-MODE command line options to the compiler via
CFLAGS/CXXFLAGS/CPPFLAGS
You can select the mode for the afl-cc compiler by one of the following methods:
MODE can be one of: LTO (afl-clang-lto*), LLVM (afl-clang-fast*), GCC_PLUGIN
(afl-g*-fast) or GCC (afl-gcc/afl-g++) or CLANG(afl-clang/afl-clang++).
* Using a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++,
afl-gcc-fast, afl-g++-fast (recommended!).
* Using the environment variable `AFL_CC_COMPILER` with `MODE`.
* Passing --afl-`MODE` command line options to the compiler via
`CFLAGS`/`CXXFLAGS`/`CPPFLAGS`.
`MODE` can be one of the following:
* LTO (afl-clang-lto*)
* LLVM (afl-clang-fast*)
* GCC_PLUGIN (afl-g*-fast) or GCC (afl-gcc/afl-g++)
* CLANG(afl-clang/afl-clang++)
Because no AFL++ specific command-line options are accepted (beside the
--afl-MODE command), the compile-time tools make fairly broad use of environment
variables, which can be listed with `afl-cc -hh` or by reading
variables, which can be listed with `afl-cc -hh` or looked up in
[env_variables.md](env_variables.md).
### b) Selecting instrumentation options
The following options are available when you instrument with LTO mode
(afl-clang-fast/afl-clang-lto):
If you instrument with LTO mode (afl-clang-fast/afl-clang-lto), the following
options are available:
* Splitting integer, string, float and switch comparisons so AFL++ can easier
* Splitting integer, string, float, and switch comparisons so AFL++ can easier
solve these. This is an important option if you do not have a very good and
large input corpus. This technique is called laf-intel or COMPCOV. To use this
set the following environment variable before compiling the target: `export
AFL_LLVM_LAF_ALL=1` You can read more about this in
large input corpus. This technique is called laf-intel or COMPCOV. To use
this, set the following environment variable before compiling the target:
`export AFL_LLVM_LAF_ALL=1`. You can read more about this in
[instrumentation/README.laf-intel.md](../instrumentation/README.laf-intel.md).
* A different technique (and usually a better one than laf-intel) is to
instrument the target so that any compare values in the target are sent to
AFL++ which then tries to put these values into the fuzzing data at different
locations. This technique is very fast and good - if the target does not
transform input data before comparison. Therefore this technique is called
transform input data before comparison. Therefore, this technique is called
`input to state` or `redqueen`. If you want to use this technique, then you
have to compile the target twice, once specifically with/for this mode by
setting `AFL_LLVM_CMPLOG=1`, and pass this binary to afl-fuzz via the `-c`
@ -135,24 +140,49 @@ The following options are available when you instrument with LTO mode
about this in
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
If you use LTO, LLVM or GCC_PLUGIN mode
(afl-clang-fast/afl-clang-lto/afl-gcc-fast) you have the option to selectively
only instrument parts of the target that you are interested in:
If you use LTO, LLVM, or GCC_PLUGIN mode
(afl-clang-fast/afl-clang-lto/afl-gcc-fast), you have the option to selectively
instrument _parts_ of the target that you are interested in. For afl-clang-fast,
you have to use an llvm version newer than 10.0.0 or a mode other than
DEFAULT/PCGUARD.
* To instrument only those parts of the target that you are interested in create
a file with all the filenames of the source code that should be instrumented.
For afl-clang-lto and afl-gcc-fast - or afl-clang-fast if a mode other than
DEFAULT/PCGUARD is used or you have llvm > 10.0.0 - just put one filename or
function per line (no directory information necessary for filenames9, and
either set `export AFL_LLVM_ALLOWLIST=allowlist.txt` **or** `export
AFL_LLVM_DENYLIST=denylist.txt` - depending on if you want per default to
instrument unless noted (DENYLIST) or not perform instrumentation unless
requested (ALLOWLIST). **NOTE:** During optimization functions might be
inlined and then would not match! See
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
This step can be done either by explicitly including parts to be instrumented or
by explicitly excluding parts from instrumentation.
* To instrument _only specified parts_, create a file (e.g., `allowlist.txt`)
with all the filenames and/or functions of the source code that should be
instrumented and then:
1. Just put one filename or function (prefixing with `fun: `) per line (no
directory information necessary for filenames) in the file `allowlist.txt`.
Example:
```
foo.cpp # will match foo/foo.cpp, bar/foo.cpp, barfoo.cpp etc.
fun: foo_func # will match the function foo_func
```
2. Set `export AFL_LLVM_ALLOWLIST=allowlist.txt` to enable selective positive
instrumentation.
* Similarly to _exclude_ specified parts from instrumentation, create a file
(e.g., `denylist.txt`) with all the filenames of the source code that should
be skipped during instrumentation and then:
1. Same as above. Just put one filename or function per line in the file
`denylist.txt`.
2. Set `export AFL_LLVM_DENYLIST=denylist.txt` to enable selective negative
instrumentation.
**NOTE:** During optimization functions might be
inlined and then would not match the list! See
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md).
There are many more options and modes available, however, these are most of the
time less effective. See:
* [instrumentation/README.llvm.md#6) AFL++ Context Sensitive Branch Coverage](../instrumentation/README.llvm.md#6-afl-context-sensitive-branch-coverage)
* [instrumentation/README.llvm.md#7) AFL++ N-Gram Branch Coverage](../instrumentation/README.llvm.md#7-afl-n-gram-branch-coverage)
@ -166,26 +196,27 @@ It is possible to use sanitizers when instrumenting targets for fuzzing, which
allows you to find bugs that would not necessarily result in a crash.
Note that sanitizers have a huge impact on CPU (= less executions per second)
and RAM usage. Also you should only run one afl-fuzz instance per sanitizer
type. This is enough because a use-after-free bug will be picked up, e.g., by
ASAN (address sanitizer) anyway when syncing to other fuzzing instances, so not
all fuzzing instances need to be instrumented with ASAN.
and RAM usage. Also, you should only run one afl-fuzz instance per sanitizer
type. This is enough because e.g. a use-after-free bug will be picked up by ASAN
(address sanitizer) anyway after syncing test cases from other fuzzing
instances, so running more than one address sanitized target would be a waste.
The following sanitizers have built-in support in AFL++:
* ASAN = Address SANitizer, finds memory corruption vulnerabilities like
use-after-free, NULL pointer dereference, buffer overruns, etc. Enabled with
`export AFL_USE_ASAN=1` before compiling.
* MSAN = Memory SANitizer, finds read access to uninitialized memory, e.g., a
* MSAN = Memory SANitizer, finds read accesses to uninitialized memory, e.g., a
local variable that is defined and read before it is even set. Enabled with
`export AFL_USE_MSAN=1` before compiling.
* UBSAN = Undefined Behavior SANitizer, finds instances where - by the C and C++
standards - undefined behavior happens, e.g., adding two signed integers
together where the result is larger than a signed integer can hold. Enabled
with `export AFL_USE_UBSAN=1` before compiling.
standards - undefined behavior happens, e.g., adding two signed integers where
the result is larger than what a signed integer can hold. Enabled with `export
AFL_USE_UBSAN=1` before compiling.
* CFISAN = Control Flow Integrity SANitizer, finds instances where the control
flow is found to be illegal. Originally this was rather to prevent return
oriented programming exploit chains from functioning, in fuzzing this is
mostly reduced to detecting type confusion vulnerabilities - which is,
oriented programming (ROP) exploit chains from functioning. In fuzzing, this
is mostly reduced to detecting type confusion vulnerabilities - which is,
however, one of the most important and dangerous C++ memory corruption
classes! Enabled with `export AFL_USE_CFISAN=1` before compiling.
* TSAN = Thread SANitizer, finds thread race conditions. Enabled with `export
@ -194,7 +225,10 @@ The following sanitizers have built-in support in AFL++:
security issue, but for developers this can be very valuable. Note that unlike
the other sanitizers above this needs `__AFL_LEAK_CHECK();` added to all areas
of the target source code where you find a leak check necessary! Enabled with
`export AFL_USE_LSAN=1` before compiling.
`export AFL_USE_LSAN=1` before compiling. To ignore the memory-leaking check
for certain allocations, `__AFL_LSAN_OFF();` can be used before memory is
allocated, and `__AFL_LSAN_ON();` afterwards. Memory allocated between these
two macros will not be checked for memory leaks.
It is possible to further modify the behavior of the sanitizers at run-time by
setting `ASAN_OPTIONS=...`, `LSAN_OPTIONS` etc. - the available parameters can
@ -227,20 +261,20 @@ All AFL++ compilers will set this preprocessor definition automatically.
### e) Instrumenting the target
In this step the target source code is compiled so that it can be fuzzed.
In this step, the target source code is compiled so that it can be fuzzed.
Basically you have to tell the target build system that the selected AFL++
Basically, you have to tell the target build system that the selected AFL++
compiler is used. Also - if possible - you should always configure the build
system such that the target is compiled statically and not dynamically. How to
do this is described below.
system in such way that the target is compiled statically and not dynamically.
How to do this is described below.
The #1 rule when instrumenting a target is: avoid instrumenting shared libraries
at all cost. You would need to set LD_LIBRARY_PATH to point to these, you could
accidentally type "make install" and install them system wide - so don't. Really
don't. **Always compile libraries you want to have instrumented as static and
link these to the target program!**
at all cost. You would need to set `LD_LIBRARY_PATH` to point to these, you
could accidentally type "make install" and install them system wide - so don't.
Really don't. **Always compile libraries you want to have instrumented as static
and link these to the target program!**
Then build the target. (Usually with `make`)
Then build the target. (Usually with `make`.)
**NOTES**
@ -254,45 +288,75 @@ Then build the target. (Usually with `make`)
3. In case the configure/build system complains about AFL++'s compiler and
aborts, then set `export AFL_NOOPT=1` which will then just behave like the
real compiler. This option has to be unset again before building the target!
real compiler and run the configure step separately. For building the target
afterwards this option has to be unset again!
#### configure
For `configure` build systems this is usually done by:
For `configure` build systems, this is usually done by:
`CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --disable-shared`
```
CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --disable-shared
```
Note that if you are using the (better) afl-clang-lto compiler, you also have to
set `AR` to llvm-ar[-VERSION] and `RANLIB` to llvm-ranlib[-VERSION] - as is
described in [instrumentation/README.lto.md](../instrumentation/README.lto.md).
#### CMake
For CMake build systems, this is usually done by:
```
mkdir build; cd build; cmake -DCMAKE_C_COMPILER=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..
```
Note that if you are using the (better) afl-clang-lto compiler you also have to
set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is
described in [instrumentation/README.lto.md](../instrumentation/README.lto.md).
#### cmake
#### Meson Build System
For `cmake` build systems this is usually done by:
For the Meson Build System, you have to set the AFL++ compiler with the very
first command!
`mkdir build; cd build; cmake -DCMAKE_C_COMPILER=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..`
```
CC=afl-cc CXX=afl-c++ meson
```
Note that if you are using the (better) afl-clang-lto compiler you also have to
set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is
described in [instrumentation/README.lto.md](../instrumentation/README.lto.md).
#### Other build systems or if configure/cmake didn't work
#### meson
Sometimes `cmake` and `configure` do not pick up the AFL++ compiler or the
`RANLIB`/`AR` that is needed - because this was just not foreseen by the
developer of the target. Or they have non-standard options. Figure out if there
is a non-standard way to set this, otherwise set up the build normally and edit
the generated build environment afterwards manually to point it to the right
compiler (and/or `RANLIB` and `AR`).
For meson you have to set the AFL++ compiler with the very first command!
`CC=afl-cc CXX=afl-c++ meson`
In complex, weird, alien build systems you can try this neat project:
[https://github.com/fuzzah/exeptor](https://github.com/fuzzah/exeptor)
#### other build systems or if configure/cmake didn't work
#### Linker scripts
Sometimes cmake and configure do not pick up the AFL++ compiler, or the
ranlib/ar that is needed - because this was just not foreseen by the developer
of the target. Or they have non-standard options. Figure out if there is a
non-standard way to set this, otherwise set up the build normally and edit the
generated build environment afterwards manually to point it to the right
compiler (and/or ranlib and ar).
If the project uses linker scripts to hide the symbols exported by the
binary, then you may see errors such as:
```
undefined symbol: __afl_area_ptr
```
The solution is to modify the linker script to add:
```
{
global:
__afl_*;
}
```
### f) Better instrumentation
If you just fuzz a target program as-is you are wasting a great opportunity for
If you just fuzz a target program as-is, you are wasting a great opportunity for
much more fuzzing speed.
This variant requires the usage of afl-clang-lto, afl-clang-fast or
@ -304,7 +368,7 @@ that you want to fuzz, plus a few specific AFL++ functions around it. See
[instrumentation/README.persistent_mode.md](../instrumentation/README.persistent_mode.md)
for details.
Basically if you do not fuzz a target in persistent mode, then you are just
Basically, if you do not fuzz a target in persistent mode, then you are just
doing it for a hobby and not professionally :-).
### g) libfuzzer fuzzer harnesses with LLVMFuzzerTestOneInput()
@ -319,7 +383,7 @@ afl-clang-fast++ -fsanitize=fuzzer -o harness harness.cpp targetlib.a
```
You can even use advanced libfuzzer features like `FuzzedDataProvider`,
`LLVMFuzzerMutate()` etc. and they will work!
`LLVMFuzzerInitialize()` etc. and they will work!
The generated binary is fuzzed with afl-fuzz like any other fuzz target.
@ -354,22 +418,28 @@ You can find many good examples of starting files in the
### b) Making the input corpus unique
Use the AFL++ tool `afl-cmin` to remove inputs from the corpus that do not
produce a new path/coverage in the target.
produce a new path/coverage in the target:
Put all files from step a) into one directory, e.g., INPUTS.
1. Put all files from [step a](#a-collecting-inputs) into one directory, e.g.,
`INPUTS`.
2. Run afl-cmin:
* If the target program is to be called by fuzzing as `bin/target INPUTFILE`,
replace the INPUTFILE argument that the target program would read from with
`@@`:
If the target program is to be called by fuzzing as `bin/target -d INPUTFILE`
the run afl-cmin like this:
```
afl-cmin -i INPUTS -o INPUTS_UNIQUE -- bin/target -someopt @@
```
`afl-cmin -i INPUTS -o INPUTS_UNIQUE -- bin/target -d @@`
* If the target reads from stdin (standard input) instead, just omit the `@@`
as this is the default:
Note that the INPUTFILE argument that the target program would read from has to
be set as `@@`.
```
afl-cmin -i INPUTS -o INPUTS_UNIQUE -- bin/target -someopt
```
If the target reads from stdin instead, just omit the `@@` as this is the
default.
This step is highly recommended!
This step is highly recommended, because afterwards the testcase corpus is not
bloated with duplicates anymore, which would slow down the fuzzing progress!
### c) Minimizing all corpus files
@ -381,18 +451,20 @@ however, it is a long process as this has to be done for every file:
mkdir input
cd INPUTS_UNIQUE
for i in *; do
afl-tmin -i "$i" -o "../input/$i" -- bin/target -d @@
afl-tmin -i "$i" -o "../input/$i" -- bin/target -someopt @@
done
```
This step can also be parallelized, e.g., with `parallel`. Note that this step
is rather optional though.
This step can also be parallelized, e.g., with `parallel`.
Note that this step is rather optional though.
### Done!
The INPUTS_UNIQUE/ directory from step b) - or even better the directory input/
if you minimized the corpus in step c) - is the resulting input corpus directory
to be used in fuzzing! :-)
The INPUTS_UNIQUE/ directory from [step b](#b-making-the-input-corpus-unique) -
or even better the directory input/ if you minimized the corpus in
[step c](#c-minimizing-all-corpus-files) - is the resulting input corpus
directory to be used in fuzzing! :-)
## 3. Fuzzing the target
@ -400,77 +472,90 @@ In this final step, fuzz the target. There are not that many important options
to run the target - unless you want to use many CPU cores/threads for the
fuzzing, which will make the fuzzing much more useful.
If you just use one CPU for fuzzing, then you are fuzzing just for fun and not
seriously :-)
If you just use one instance for fuzzing, then you are fuzzing just for fun and
not seriously :-)
### a) Running afl-fuzz
Before you do even a test run of afl-fuzz execute `sudo afl-system-config` (on
the host if you execute afl-fuzz in a docker container). This reconfigures the
Before you do even a test run of afl-fuzz, execute `sudo afl-system-config` (on
the host if you execute afl-fuzz in a Docker container). This reconfigures the
system for optimal speed - which afl-fuzz checks and bails otherwise. Set
`export AFL_SKIP_CPUFREQ=1` for afl-fuzz to skip this check if you cannot run
afl-system-config with root privileges on the host for whatever reason.
Note there is also `sudo afl-persistent-config` which sets additional permanent
boot options for a much better fuzzing performance.
Note:
Note that both scripts improve your fuzzing performance but also decrease your
system protection against attacks! So set strong firewall rules and only expose
SSH as a network service if you use these (which is highly recommended).
* There is also `sudo afl-persistent-config` which sets additional permanent
boot options for a much better fuzzing performance.
* Both scripts improve your fuzzing performance but also decrease your system
protection against attacks! So set strong firewall rules and only expose SSH
as a network service if you use these (which is highly recommended).
If you have an input corpus from step 2, then specify this directory with the
`-i` option. Otherwise, create a new directory and create a file with any
content as test data in there.
If you have an input corpus from [step 2](#2-preparing-the-fuzzing-campaign),
then specify this directory with the `-i` option. Otherwise, create a new
directory and create a file with any content as test data in there.
If you do not want anything special, the defaults are already usually best,
hence all you need is to specify the seed input directory with the result of
step [2a) Collect inputs](#a-collect-inputs):
step [2a) Collecting inputs](#a-collecting-inputs):
`afl-fuzz -i input -o output -- bin/target -d @@`
```
afl-fuzz -i input -o output -- bin/target -someopt @@
```
Note that the directory specified with `-o` will be created if it does not
exist.
It can be valuable to run afl-fuzz in a screen or tmux shell so you can log off,
or afl-fuzz is not aborted if you are running it in a remote ssh session where
the connection fails in between. Only do that though once you have verified that
your fuzzing setup works! Run it like `screen -dmS afl-main -- afl-fuzz -M
main-$HOSTNAME -i ...` and it will start away in a screen session. To enter this
session, type `screen -r afl-main`. You see - it makes sense to name the screen
session same as the afl-fuzz -M/-S naming :-) For more information on screen or
tmux, check their documentation.
It can be valuable to run afl-fuzz in a `screen` or `tmux` shell so you can log
off, or afl-fuzz is not aborted if you are running it in a remote ssh session
where the connection fails in between. Only do that though once you have
verified that your fuzzing setup works! Run it like `screen -dmS afl-main --
afl-fuzz -M main-$HOSTNAME -i ...` and it will start away in a screen session.
To enter this session, type `screen -r afl-main`. You see - it makes sense to
name the screen session same as the afl-fuzz `-M`/`-S` naming :-) For more
information on screen or tmux, check their documentation.
If you need to stop and re-start the fuzzing, use the same command line options
(or even change them by selecting a different power schedule or another mutation
mode!) and switch the input directory with a dash (`-`):
`afl-fuzz -i - -o output -- bin/target -d @@`
```
afl-fuzz -i - -o output -- bin/target -someopt @@
```
Adding a dictionary is helpful. See the directory
[dictionaries/](../dictionaries/) if something is already included for your data
format, and tell afl-fuzz to load that dictionary by adding `-x
dictionaries/FORMAT.dict`. With afl-clang-lto, you have an autodictionary
generation for which you need to do nothing except to use afl-clang-lto as the
compiler. You also have the option to generate a dictionary yourself, see
[utils/libtokencap/README.md](../utils/libtokencap/README.md).
Adding a dictionary is helpful. You have to following options:
* See the directory
[dictionaries/](../dictionaries/), if something is already included for your
data format, and tell afl-fuzz to load that dictionary by adding `-x
dictionaries/FORMAT.dict`.
* With `afl-clang-lto`, you have an autodictionary generation for which you need
to do nothing except to use afl-clang-lto as the compiler.
* With `afl-clang-fast`, you can set
`AFL_LLVM_DICT2FILE=/full/path/to/new/file.dic` to automatically generate a
dictionary during target compilation.
* 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).
* Finally, you can also write a dictionary file manually, of course.
afl-fuzz has a variety of options that help to workaround target quirks like
specific locations for the input file (`-f`), performing deterministic fuzzing
(`-D`) and many more. Check out `afl-fuzz -h`.
very specific locations for the input file (`-f`), performing deterministic
fuzzing (`-D`) and many more. Check out `afl-fuzz -h`.
We highly recommend that you set a memory limit for running the target with `-m`
which defines the maximum memory in MB. This prevents a potential out-of-memory
problem for your system plus helps you detect missing `malloc()` failure
handling in the target. Play around with various -m values until you find one
handling in the target. Play around with various `-m` values until you find one
that safely works for all your input seeds (if you have good ones and then
double or quadruple that.
double or quadruple that).
By default, afl-fuzz never stops fuzzing. To terminate AFL++, press Control-C or
send a signal SIGINT. You can limit the number of executions or approximate
runtime in seconds with options also.
When you start afl-fuzz you will see a user interface that shows what the status
is:
When you start afl-fuzz, you will see a user interface that shows what the
status is:
![resources/screenshot.png](resources/screenshot.png)
@ -514,8 +599,8 @@ can set the cache size (in MB) by setting the environment variable
There should be one main fuzzer (`-M main-$HOSTNAME` option) and as many
secondary fuzzers (e.g., `-S variant1`) as you have cores that you use. Every
-M/-S entry needs a unique name (that can be whatever), however, the same -o
output directory location has to be used for all instances.
`-M`/`-S` entry needs a unique name (that can be whatever), however, the same
`-o` output directory location has to be used for all instances.
For every secondary fuzzer there should be a variation, e.g.:
* one should fuzz the target that was compiled differently: with sanitizers
@ -530,9 +615,10 @@ For every secondary fuzzer there should be a variation, e.g.:
All other secondaries should be used like this:
* a quarter to a third with the MOpt mutator enabled: `-L 0`
* run with a different power schedule, recommended are:
`fast (default), explore, coe, lin, quad, exploit and rare` which you can set
with, e.g., `-p explore`
* run with a different power schedule, recommended are: `fast` (default),
`explore`, `coe`, `lin`, `quad`, `exploit`, and `rare` which you can set with
the `-p` option, e.g., `-p explore`. See the
[FAQ](FAQ.md#what-are-power-schedules) for details.
* a few instances should use the old queue cycling with `-Z`
Also, it is recommended to set `export AFL_IMPORT_FIRST=1` to load test cases
@ -556,7 +642,7 @@ A long list can be found at
[https://github.com/Microsvuln/Awesome-AFL](https://github.com/Microsvuln/Awesome-AFL).
However, you can also sync AFL++ with honggfuzz, libfuzzer with `-entropic=1`,
etc. Just show the main fuzzer (-M) with the `-F` option where the queue/work
etc. Just show the main fuzzer (`-M`) with the `-F` option where the queue/work
directory of a different fuzzer is, e.g., `-F /src/target/honggfuzz`. Using
honggfuzz (with `-n 1` or `-n 2`) and libfuzzer in parallel is highly
recommended!
@ -575,7 +661,7 @@ Now there are three strategies on how you can sync between the servers:
* regularly (~4h): this ensures that all fuzzing campaigns on the servers "see"
the same thing. It is like fuzzing on a huge server.
* in intervals of 1/10th of the overall expected runtime of the fuzzing you
sync. This tries a bit to combine both. have some individuality of the paths
sync. This tries a bit to combine both. Have some individuality of the paths
each campaign on a server explores, on the other hand if one gets stuck where
another found progress this is handed over making it unstuck.
@ -596,7 +682,8 @@ done
```
You can run this manually, per cron job - as you need it. There is a more
complex and configurable script in `utils/distributed_fuzzing`.
complex and configurable script in
[utils/distributed_fuzzing](../utils/distributed_fuzzing).
### e) The status of the fuzz campaign
@ -612,7 +699,7 @@ If you have multiple servers, then use the command after a sync or you have to
execute this script per server.
Another tool to inspect the current state and history of a specific instance is
afl-plot, which generates an index.html file and a graphs that show how the
afl-plot, which generates an index.html file and graphs that show how the
fuzzing instance is performing. The syntax is `afl-plot instance_dir web_dir`,
e.g., `afl-plot out/default /srv/www/htdocs/plot`.
@ -623,7 +710,7 @@ To stop an afl-fuzz run, press Control-C.
To restart an afl-fuzz run, just reuse the same command line but replace the `-i
directory` with `-i -` or set `AFL_AUTORESUME=1`.
If you want to add new seeds to a fuzzing campaign you can run a temporary
If you want to add new seeds to a fuzzing campaign, you can run a temporary
fuzzing instance, e.g., when your main fuzzer is using `-o out` and the new
seeds are in `newseeds/` directory:
@ -686,21 +773,21 @@ or honggfuzz.
### i) Improve the speed!
* Use [persistent mode](../instrumentation/README.persistent_mode.md) (x2-x20
speed increase)
speed increase).
* If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input
file on a tempfs location, see [env_variables.md](env_variables.md)
file on a tempfs location, see [env_variables.md](env_variables.md).
* Linux: Improve kernel performance: modify `/etc/default/grub`, set
`GRUB_CMDLINE_LINUX_DEFAULT="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"`; then
`update-grub` and `reboot` (warning: makes the system more insecure) - you can
also just run `sudo afl-persistent-config`
also just run `sudo afl-persistent-config`.
* Linux: Running on an `ext2` filesystem with `noatime` mount option will be a
bit faster than on any other journaling filesystem
* Use your cores! [3c) Using multiple cores](#c-using-multiple-cores)
bit faster than on any other journaling filesystem.
* Use your cores! See [3c) Using multiple cores](#c-using-multiple-cores).
* Run `sudo afl-system-config` before starting the first afl-fuzz instance after
a reboot
a reboot.
### j) Going beyond crashes
@ -751,9 +838,10 @@ Here are some of the most important caveats for AFL++:
- There is no direct support for fuzzing network services, background daemons,
or interactive apps that require UI interaction to work. You may need to make
simple code changes to make them behave in a more traditional way. Preeny may
offer a relatively simple option, too - see:
[https://github.com/zardus/preeny](https://github.com/zardus/preeny)
simple code changes to make them behave in a more traditional way. Preeny or
libdesock may offer a relatively simple option, too - see:
[https://github.com/zardus/preeny](https://github.com/zardus/preeny) or
[https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
Some useful tips for modifying network-based services can be also found at:
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
@ -774,7 +862,7 @@ making it easier to diagnose faults.
Having said that, it's important to acknowledge that some fuzzing crashes can be
difficult to quickly evaluate for exploitability without a lot of debugging and
code analysis work. To assist with this task, afl-fuzz supports a very unique
"crash exploration" mode enabled with the -C flag.
"crash exploration" mode enabled with the `-C` flag.
In this mode, the fuzzer takes one or more crashing test cases as the input and
uses its feedback-driven fuzzing strategies to very quickly enumerate all code
@ -800,43 +888,44 @@ mode, it will happily accept instrumented and non-instrumented binaries. In the
non-crashing mode, the minimizer relies on standard AFL++ instrumentation to
make the file simpler without altering the execution path.
The minimizer accepts the -m, -t, -f and @@ syntax in a manner compatible with
afl-fuzz.
The minimizer accepts the `-m`, `-t`, `-f`, and `@@` syntax in a manner
compatible with afl-fuzz.
Another tool in AFL++ is the afl-analyze tool. It takes an input file, attempts
to sequentially flip bytes, and observes the behavior of the tested program. It
then color-codes the input based on which sections appear to be critical, and
to sequentially flip bytes and observes the behavior of the tested program. It
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.
## 5. CI fuzzing
Some notes on CI fuzzing - this fuzzing is different to normal fuzzing campaigns
as these are much shorter runnings.
Some notes on continuous integration (CI) fuzzing - this fuzzing is different to
normal fuzzing campaigns as these are much shorter runnings.
1. Always:
* LTO has a much longer compile time which is diametrical to short fuzzing -
hence use afl-clang-fast instead.
* If you compile with CMPLOG, then you can save fuzzing time and reuse that
compiled target for both the `-c` option and the main fuzz target. This
will impact the speed by ~15% though.
* `AFL_FAST_CAL` - Enable fast calibration, this halves the time the
* If you compile with CMPLOG, then you can save compilation time and reuse
that compiled target with the `-c` option and as the main fuzz target.
This will impact the speed by ~15% though.
* `AFL_FAST_CAL` - enables fast calibration, this halves the time the
saturated corpus needs to be loaded.
* `AFL_CMPLOG_ONLY_NEW` - only perform cmplog on new finds, not the
initial corpus as this very likely has been done for them already.
* `AFL_CMPLOG_ONLY_NEW` - only perform cmplog on new finds, not the initial
corpus as this very likely has been done for them already.
* Keep the generated corpus, use afl-cmin and reuse it every time!
2. Additionally randomize the AFL++ compilation options, e.g.:
* 40% for `AFL_LLVM_CMPLOG`
* 10% for `AFL_LLVM_LAF_ALL`
* 30% for `AFL_LLVM_CMPLOG`
* 5% for `AFL_LLVM_LAF_ALL`
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`
* 40% use MOpt (`-L 0`)
* 40% for `AFL_EXPAND_HAVOC_NOW`
* 20% for old queue processing (`-Z`)
* for CMPLOG targets, 60% for `-l 2`, 40% for `-l 3`
* for CMPLOG targets, 70% for `-l 2`, 10% for `-l 3`, 20% for `-l 2AT`
4. Do *not* run any `-M` modes, just running `-S` modes is better for CI
fuzzing. `-M` enables old queue handling etc. which is good for a fuzzing
@ -849,8 +938,8 @@ and
## The End
Check out the [FAQ](FAQ.md) if it maybe answers your question (that you might
not even have known you had ;-) ).
Check out the [FAQ](FAQ.md). Maybe it answers your question (that you might not
even have known you had ;-) ).
This is basically all you need to know to professionally run fuzzing campaigns.
If you want to know more, the tons of texts in [docs/](./) will have you
@ -858,4 +947,4 @@ covered.
Note that there are also a lot of tools out there that help fuzzing with AFL++
(some might be deprecated or unsupported), see
[third_party_tools.md](third_party_tools.md).
[third_party_tools.md](third_party_tools.md).

View File

@ -19,18 +19,18 @@ Mentor: vanhauser-thc
## WASM Instrumentation
Currently, AFL++ can be used for source code fuzzing and traditional binaries.
With the rise of WASM as 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 VMs of choice, similar to the current Unicorn
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 (easily?) supported
for fuzzing, e.g., mono, swift, go, kotlin native, fortran, ...
Other programming languages also use llvm hence they could be (easily?)
supported for fuzzing, e.g., mono, swift, go, kotlin native, fortran, ...
GCC also supports: Objective-C, Fortran, Ada, Go, and D (according to
[Gcc homepage](https://gcc.gnu.org/))
@ -54,4 +54,4 @@ Mentor: domenukk
## Your idea!
Finally, we are open to proposals! Create an issue at
https://github.com/AFLplusplus/AFLplusplus/issues and let's discuss :-)
https://github.com/AFLplusplus/AFLplusplus/issues and let's discuss :-)

View File

@ -5,24 +5,25 @@ changes.
## From version 3.00 onwards
With AFL++ 3.13-3.20, we introduce FRIDA mode (`-O`) to have an alternative for
binary-only fuzzing. It is slower than QEMU mode but works on MacOS, Android,
iOS etc.
With AFL++ 4.00, we introduced the following changes from previous behaviors:
* the complete documentation was overhauled and restructured thanks to @llzmb!
* a new CMPLOG target format requires recompiling CMPLOG targets for use with
AFL++ 4.0 onwards
* better naming for several fields in the UI
With AFL++ 3.15, we introduced the following changes from previous behaviors:
* Also -M main mode does not do deterministic fuzzing by default anymore
* afl-cmin and afl-showmap -Ci now descent into subdirectories like afl-fuzz
-i does (but note that afl-cmin.bash does not)
* afl-cmin and afl-showmap `-Ci` now descend into subdirectories like afl-fuzz
`-i` does (but note that afl-cmin.bash does not)
With AFL++ 3.14, we introduced the following changes from previous behaviors:
* afl-fuzz: deterministic fuzzing it not a default for -M main anymore
* afl-fuzz: deterministic fuzzing is not a default for `-M main` anymore
* afl-cmin/afl-showmap -i now descends into subdirectories (afl-cmin.bash,
however, does not)
With AFL++ 3.10, we introduced the following changes from previous behaviors:
* The '+' feature of the '-t' option now means to auto-calculate the timeout
* The '+' feature of the `-t` option now means to auto-calculate the timeout
with the value given being the maximum timeout. The original meaning of
"skipping timeouts instead of abort" is now inherent to the -t option.
"skipping timeouts instead of abort" is now inherent to the `-t` option.
With AFL++ 3.00, we introduced changes that break some previous AFL and AFL++
behaviors and defaults:
@ -40,19 +41,20 @@ behaviors and defaults:
if any were given. This allows to fuzz targets build regularly like those
for debug or release versions.
* afl-fuzz:
* if neither -M or -S is specified, `-S default` is assumed, so more fuzzers
can easily be added later
* if neither `-M` or `-S` is specified, `-S default` is assumed, so more
fuzzers can easily be added later
* `-i` input directory option now descends into subdirectories. It also does
not fatal on crashes and too large files, instead it skips them and uses
not fail on crashes and too large files, instead it skips them and uses
them for splicing mutations
* -m none is now default, set memory limits (in MB) with, e.g., -m 250
* deterministic fuzzing is now disabled by default (unless using -M) and can
be enabled with -D
* `-m` none is now the default, set memory limits (in MB) with, e.g., `-m
250`
* deterministic fuzzing is now disabled by default (unless using `-M`) and
can be enabled with `-D`
* a caching of test cases can now be performed and can be modified by
editing config.h for TESTCASE_CACHE or by specifying the environment
editing config.h for `TESTCASE_CACHE` or by specifying the environment
variable `AFL_TESTCACHE_SIZE` (in MB). Good values are between 50-500
(default: 50).
* -M mains do not perform trimming
* examples/ got renamed to utils/
* libtokencap/ libdislocator/ and qdbi_mode/ were moved to utils/
* afl-cmin/afl-cmin.bash now search first in PATH and last in AFL_PATH
* `-M` mains do not perform trimming
* `examples/` got renamed to `utils/`
* `libtokencap/`, `libdislocator/`, and `qdbi_mode/` were moved to `utils/`
* afl-cmin/afl-cmin.bash now search first in `PATH` and last in `AFL_PATH`

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -424,7 +424,7 @@
"steppedLine": false,
"targets": [
{
"expr": "fuzzing{type=\"unique_crashes\"}",
"expr": "fuzzing{type=\"saved_crashes\"}",
"interval": "",
"legendFormat": "",
"refId": "A"
@ -519,7 +519,7 @@
"steppedLine": false,
"targets": [
{
"expr": "fuzzing{type=\"unique_hangs\"}",
"expr": "fuzzing{type=\"saved_hangs\"}",
"interval": "",
"legendFormat": "",
"refId": "A"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 141 KiB

View File

@ -1,11 +1,13 @@
# Tools that help fuzzing with AFL++
Speeding up fuzzing:
## Speeding up fuzzing
* [libfiowrapper](https://github.com/marekzmyslowski/libfiowrapper) - if the
function you want to fuzz requires loading a file, this allows using the
shared memory test case feature :-) - recommended.
Minimization of test cases:
## Minimization of test cases
* [afl-pytmin](https://github.com/ilsani/afl-pytmin) - a wrapper for afl-tmin
that tries to speed up the process of minimization of a single test case by
using many CPU cores.
@ -14,7 +16,8 @@ Minimization of test cases:
* [halfempty](https://github.com/googleprojectzero/halfempty) - is a fast
utility for minimizing test cases by Tavis Ormandy based on parallelization.
Distributed execution:
## Distributed execution
* [disfuzz-afl](https://github.com/MartijnB/disfuzz-afl) - distributed fuzzing
for AFL.
* [AFLDFF](https://github.com/quantumvm/AFLDFF) - AFL distributed fuzzing
@ -26,7 +29,8 @@ Distributed execution:
* [afl-in-the-cloud](https://github.com/abhisek/afl-in-the-cloud) - another
script for running AFL in AWS.
Deployment, management, monitoring, reporting
## Deployment, management, monitoring, reporting
* [afl-utils](https://gitlab.com/rc0r/afl-utils) - a set of utilities for
automatic processing/analysis of crashes and reducing the number of test
cases.
@ -44,7 +48,10 @@ Deployment, management, monitoring, reporting
* [afl-extras](https://github.com/fekir/afl-extras) - shell scripts to
parallelize afl-tmin, startup, and data collection.
Crash processing
## Crash processing
* [AFLTriage](https://github.com/quic/AFLTriage) -
triage crashing input files using gdb.
* [afl-crash-analyzer](https://github.com/floyd-fuh/afl-crash-analyzer) -
another crash analyzer for AFL.
* [fuzzer-utils](https://github.com/ThePatrickStar/fuzzer-utils) - a set of
@ -54,4 +61,4 @@ Crash processing
* [AFLize](https://github.com/d33tah/aflize) - a tool that automatically
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.
working with input data.

View File

@ -1,5 +1,9 @@
# Tutorials
If you are a total newbie, try this guide:
* [https://github.com/alex-maleno/Fuzzing-Module](https://github.com/alex-maleno/Fuzzing-Module)
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/)
@ -9,6 +13,7 @@ Here are some good write-ups to show how to effectively use AFL++:
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
* [https://securitylab.github.com/research/fuzzing-sockets-FreeRDP](https://securitylab.github.com/research/fuzzing-sockets-FreeRDP)
* [https://securitylab.github.com/research/fuzzing-apache-1](https://securitylab.github.com/research/fuzzing-apache-1)
* [https://mmmds.pl/fuzzing-map-parser-part-1-teeworlds/](https://mmmds.pl/fuzzing-map-parser-part-1-teeworlds/)
If you do not want to follow a tutorial but rather try an exercise type of
training, then we can highly recommend the following:
@ -16,15 +21,25 @@ training, then we can highly recommend the following:
* [https://github.com/antonio-morales/Fuzzing101](https://github.com/antonio-morales/Fuzzing101)
If you are interested in fuzzing structured data (where you define what the
structure is), these links have you covered:
structure is), these links have you covered (some are outdated though):
* Superion for AFL++:
[https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
* libprotobuf for AFL++:
[https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator)
* libprotobuf 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)
* libprotobuf for old AFL++ API:
[https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
* Superion for AFL++:
[https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
If you find other good ones, please send them to us :-)
## Video Tutorials
* [Install AFL++ Ubuntu](https://www.youtube.com/watch?v=5dCvhkbi3RA)
* [[Fuzzing with AFLplusplus] Installing AFLPlusplus and fuzzing a simple C program](https://www.youtube.com/watch?v=9wRVo0kYSlc)
* [[Fuzzing with AFLplusplus] How to fuzz a binary with no source code on Linux in persistent mode](https://www.youtube.com/watch?v=LGPJdEO02p4)
* [Blackbox Fuzzing #1: Start Binary-Only Fuzzing using AFL++ QEMU mode](https://www.youtube.com/watch?v=sjLFf9q2NRc)
* [HOPE 2020 (2020): Hunting Bugs in Your Sleep - How to Fuzz (Almost) Anything With AFL/AFL++](https://www.youtube.com/watch?v=A8ex1hqaQ7E)
* [How Fuzzing with AFL works!](https://www.youtube.com/watch?v=COHUWuLTbdk)
* [WOOT '20 - AFL++ : Combining Incremental Steps of Fuzzing Research](https://www.youtube.com/watch?v=cZidm6I7KWU)
If you find other good ones, please send them to us :-)

View File

@ -13,6 +13,16 @@ JS_SRC:=$(BUILD_DIR)api.c
JS_OBJ:=$(BUILD_DIR)api.o
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
TARGET_CC?=$(CC)
TARGET_CXX?=$(CXX)
HOST_CC?=$(CC)
HOST_CXX?=$(CXX)
IS_ANDROID:=$(findstring android, $(shell $(TARGET_CC) --version 2>/dev/null))
IS_x86:=$(findstring i686, $(shell $(TARGET_CC) --version 2>/dev/null))
IS_x86_64:=$(findstring x86_64, $(shell $(TARGET_CC) --version 2>/dev/null))
IS_ARM:=$(findstring arm, $(shell $(TARGET_CC) --version 2>/dev/null))
IS_ARM64:=$(findstring aarch64, $(shell $(TARGET_CC) --version 2>/dev/null))
CFLAGS+=-fPIC \
-D_GNU_SOURCE \
-D_FORTIFY_SOURCE=2 \
@ -21,6 +31,10 @@ CFLAGS+=-fPIC \
-funroll-loops \
-ffunction-sections \
ifdef IS_ANDROID
CFLAGS+=-DANDROID
endif
AFL_CFLAGS:=-Wno-unused-parameter \
-Wno-sign-compare \
-Wno-unused-function \
@ -28,9 +42,16 @@ AFL_CFLAGS:=-Wno-unused-parameter \
-Wno-int-to-pointer-cast \
-Wno-pointer-sign
ifdef IS_ANDROID
LDFLAGS+= -static-libstdc++ \
-DANDROID \
-llog \
-shared
else
LDFLAGS+=-shared \
-lpthread \
-lresolv
endif
ifdef DEBUG
CFLAGS+=-Werror \
@ -43,10 +64,12 @@ endif
FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/
FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so
FRIDA_TRACE_LIB:=$(BUILD_DIR)libafl-frida-trace.a
FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded
TARGET_CC?=$(CC)
TARGET_CXX?=$(CXX)
TARGET_AR?=$(AR)
HOST_CC?=$(CC)
HOST_CXX?=$(CXX)
@ -66,18 +89,21 @@ ifeq "$(ARCH)" "i686"
endif
endif
GUM_ARCH="-$(ARCH)"
ifeq "$(shell uname)" "Darwin"
OS:=macos
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-deprecated-declarations
GUM_ARCH:=""
else
ifdef DEBUG
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-prio-ctor-dtor
endif
LDFLAGS+= -z noexecstack \
-Wl,--gc-sections \
-Wl,--exclude-libs,ALL \
-ldl \
-lrt
-ldl
LDSCRIPT:=-Wl,--version-script=$(PWD)frida.map
endif
@ -88,46 +114,48 @@ ifeq "$(shell uname)" "Linux"
endif
endif
ifneq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
ifdef IS_ANDROID
OS:=android
ifneq "$(findstring aarch64, $(shell $(CC) --version 2>/dev/null))" ""
ARCH:=arm64
ifdef IS_x86
ARCH:=x86
endif
ifneq "$(findstring arm, $(shell $(CC) --version 2>/dev/null))" ""
ifdef IS_x86
ARCH:=x86_64
endif
ifdef IS_ARM
ARCH:=arm
endif
ifneq "$(findstring x86_64, $(shell $(CC) --version 2>/dev/null))" ""
ARCH:=x86_64
endif
ifneq "$(findstring i686, $(shell $(CC) --version 2>/dev/null))" ""
ARCH:=x86
ifdef IS_ARM64
ARCH:=arm64
endif
endif
ifeq "$(ARCH)" "armhf"
TARGET_CC:=arm-linux-gnueabihf-gcc
TARGET_CXX:=arm-linux-gnueabihf-g++
TARGET_AR:=arm-linux-gnueabihf-ar
endif
ifndef OS
$(error "Operating system unsupported")
endif
GUM_DEVKIT_VERSION=15.1.13
GUM_DEVKIT_VERSION=15.2.1
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
ifdef FRIDA_SOURCE
GUM_DEVIT_LIBRARY=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gumjs-1.0.a
else
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
endif
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
FRIDA_DIR:=$(PWD)build/frida-source/
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
FRIDA_GUM:=$(FRIDA_DIR)build/frida-linux-x86_64/lib/libfrida-gumjs-1.0.a
FRIDA_GUM_DEVKIT_DIR:=$(FRIDA_DIR)build/gum-devkit/
FRIDA_GUM_DEVKIT_HEADER:=$(FRIDA_GUM_DEVKIT_DIR)frida-gumjs.h
FRIDA_GUM_DEVKIT_TARBALL:=$(FRIDA_DIR)build/frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar
FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL:=$(FRIDA_DIR)build/$(GUM_DEVKIT_FILENAME)
AFL_COMPILER_RT_SRC:=$(ROOT)instrumentation/afl-compiler-rt.o.c
AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o
@ -142,14 +170,20 @@ AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(BUILD_DIR)frida_hook.so
AFLPP_QEMU_DRIVER_HOOK_SRC:=$(HOOK_DIR)qemu_hook.c
AFLPP_QEMU_DRIVER_HOOK_OBJ:=$(BUILD_DIR)qemu_hook.so
ifneq "$(shell uname)" "Darwin"
ADDR_DIR:=$(PWD)addr/
ADDR_SRC:=$(ADDR_DIR)addr.c
ADDR_BIN:=$(BUILD_DIR)addr
endif
BIN2C:=$(BUILD_DIR)bin2c
BIN2C_SRC:=$(PWD)util/bin2c.c
.PHONY: all 32 clean format hook $(FRIDA_GUM)
.PHONY: all 32 clean format hook addr $(FRIDA_GUM)
############################## ALL #############################################
all: $(FRIDA_TRACE) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ)
all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN)
32:
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
@ -160,44 +194,135 @@ $(BUILD_DIR):
$(OBJ_DIR): | $(BUILD_DIR)
mkdir -p $@
############################# FRIDA ############################################
$(FRIDA_MAKEFILE): | $(BUILD_DIR)
git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR)
$(FRIDA_GUM): $(FRIDA_MAKEFILE)
cd $(FRIDA_DIR) && make gum-linux-$(ARCH)
$(FRIDA_GUM_DEVKIT_HEADER): $(FRIDA_GUM)
$(FRIDA_DIR)releng/devkit.py frida-gumjs linux-$(ARCH) $(FRIDA_DIR)build/gum-devkit/
$(FRIDA_GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_HEADER)
cd $(FRIDA_GUM_DEVKIT_DIR) && tar cvf $(FRIDA_GUM_DEVKIT_TARBALL) .
$(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL): $(FRIDA_GUM_DEVKIT_TARBALL)
xz -k -f -0 $(FRIDA_GUM_DEVKIT_TARBALL)
############################# DEVKIT ###########################################
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
mkdir -p $@
ifdef FRIDA_SOURCE
$(GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL)| $(FRIDA_BUILD_DIR)
cp -v $< $@
$(FRIDA_MAKEFILE): | $(BUILD_DIR)
git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR)
.PHONY: $(GUM_DEVIT_LIBRARY)
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE)
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH)
$(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
echo "#include <stdio.h>" > $@
echo "#include <unistd.h>" >> $@
echo "#include <gum/gumreturnaddress.h>" >> $@
echo "#include <gum/gumbacktracer.h>" >> $@
echo "#include <gum/gumsymbolutil.h>" >> $@
echo "#include <gum/gumstalker.h>" >> $@
echo "#include <gum/gumlibc.h>" >> $@
echo "#include <gumjs/gumscriptbackend.h>" >> $@
ifeq "$(OS)" "macos"
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libiconv.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libv8-8.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgmodule-2.0.a \
else ifeq "$(ARCH)" "arm64"
CFLAGS+=-I $(FRIDA_DIR)build/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/ \
ifeq "$(OS)" "android"
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/ \
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 \
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
ifeq "$(OS)" "android"
CFLAGS += -static-libstdc++
endif
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
else
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
wget -O $@ $(GUM_DEVKIT_URL) || curl -L -o $@ $(GUM_DEVKIT_URL)
endif
wget -qO $@ $(GUM_DEVKIT_URL) || curl -L -o $@ $(GUM_DEVKIT_URL)
$(GUM_DEVIT_LIBRARY): $(GUM_DEVKIT_TARBALL)
tar Jxvfm $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
$(GUM_DEVIT_HEADER): $(GUM_DEVKIT_TARBALL)
tar Jxvfm $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
endif
############################## AFL #############################################
$(AFL_COMPILER_RT_OBJ): $(AFL_COMPILER_RT_SRC)
$(AFL_COMPILER_RT_OBJ): $(AFL_COMPILER_RT_SRC) $(ROOT)include/config.h
$(TARGET_CC) \
$(CFLAGS) \
$(AFL_CFLAGS) \
@ -235,7 +360,7 @@ $(JS_OBJ): $(JS_SRC) GNUmakefile
############################# SOURCE ###########################################
define BUILD_SOURCE
$(2): $(1) $(INCLUDES) GNUmakefile | $(OBJ_DIR)
$(2): $(1) $(INCLUDES) $(GUM_DEVIT_HEADER) | $(OBJ_DIR)
$(TARGET_CC) \
$(CFLAGS) \
-I $(ROOT)include \
@ -256,12 +381,22 @@ $(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL
$(GUM_DEVIT_LIBRARY) \
$(AFL_COMPILER_RT_OBJ) \
$(AFL_PERFORMANCE_OBJ) \
$(TRACE_LDFLAGS) \
$(LDFLAGS) \
$(LDSCRIPT) \
-o $@ \
cp -v $(FRIDA_TRACE) $(ROOT)
$(FRIDA_TRACE_LIB): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL_COMPILER_RT_OBJ) $(AFL_PERFORMANCE_OBJ) GNUmakefile | $(BUILD_DIR)
$(TARGET_AR) \
-rcs \
$@ \
$(OBJS) \
$(JS_OBJ) \
$(AFL_COMPILER_RT_OBJ) \
$(AFL_PERFORMANCE_OBJ) \
############################# HOOK #############################################
$(AFLPP_FRIDA_DRIVER_HOOK_OBJ): $(AFLPP_FRIDA_DRIVER_HOOK_SRC) $(GUM_DEVIT_HEADER) | $(BUILD_DIR)
@ -272,13 +407,44 @@ $(AFLPP_QEMU_DRIVER_HOOK_OBJ): $(AFLPP_QEMU_DRIVER_HOOK_SRC) | $(BUILD_DIR)
hook: $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ)
############################# ADDR #############################################
ifneq "$(OS)" "android"
$(ADDR_BIN): $(ADDR_SRC) | $(BUILD_DIR)
-$(TARGET_CC) \
$(CFLAGS) \
-Werror \
-Wall \
-Wextra \
-Wpointer-arith \
-z noexecstack \
-Wl,--gc-sections \
-Wl,--exclude-libs,ALL \
-ldl \
-lrt \
$< -o $@
else
$(ADDR_BIN): $(ADDR_SRC) | $(BUILD_DIR)
-$(TARGET_CC) \
$(CFLAGS) \
-Werror \
-Wall \
-Wextra \
-Wpointer-arith \
-z noexecstack \
-Wl,--gc-sections \
-Wl,--exclude-libs,ALL \
-ldl \
$< -o $@
endif
addr: $(ADDR_BIN)
############################# CLEAN ############################################
clean:
rm -rf $(BUILD_DIR)
############################# FORMAT ###########################################
format:
cd $(ROOT) && echo $(SOURCES) $(AFLPP_FRIDA_DRIVER_HOOK_SRC) $(BIN2C_SRC) | xargs -L1 ./.custom-format.py -i
cd $(ROOT) && echo $(SOURCES) $(AFLPP_FRIDA_DRIVER_HOOK_SRC) $(BIN2C_SRC) $(ADDR_BIN ) | xargs -L1 ./.custom-format.py -i
cd $(ROOT) && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i
############################# RUN #############################################

View File

@ -146,39 +146,45 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
QEMU driver to provide a `main` loop for a user provided
`LLVMFuzzerTestOneInput`, this option configures the driver to read input from
`stdin` rather than using in-memory test cases.
* `AFL_FRIDA_INST_COVERAGE_ABSOLUTE` - Generate coverage files using absolute
virtual addresses rather than relative virtual addresses.
* `AFL_FRIDA_INST_COVERAGE_FILE` - File to write DynamoRIO format coverage
information (e.g., to be loaded within IDA lighthouse).
* `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks
and their instrumented counterparts during block compilation.
```
***
```
Creating block for 0x7ffff7953313:
0x7ffff7953313 mov qword ptr [rax], 0
0x7ffff795331a add rsp, 8
0x7ffff795331e ret
Creating block for 0x7ffff7953313:
0x7ffff7953313 mov qword ptr [rax], 0
0x7ffff795331a add rsp, 8
0x7ffff795331e ret
Generated block 0x7ffff75e98e2
0x7ffff75e98e2 mov qword ptr [rax], 0
0x7ffff75e98e9 add rsp, 8
0x7ffff75e98ed lea rsp, [rsp - 0x80]
0x7ffff75e98f5 push rcx
0x7ffff75e98f6 movabs rcx, 0x7ffff795331e
0x7ffff75e9900 jmp 0x7ffff75e9384
Generated block 0x7ffff75e98e2
0x7ffff75e98e2 mov qword ptr [rax], 0
0x7ffff75e98e9 add rsp, 8
0x7ffff75e98ed lea rsp, [rsp - 0x80]
0x7ffff75e98f5 push rcx
0x7ffff75e98f6 movabs rcx, 0x7ffff795331e
0x7ffff75e9900 jmp 0x7ffff75e9384
***
```
```
* `AFL_FRIDA_INST_CACHE_SIZE` - Set the size of the instrumentation cache used
as a look-up table to cache real to instrumented address block translations.
Default is 256Mb.
* `AFL_FRIDA_INST_INSN` - Generate instrumentation for conditional
instructions (e.g. `CMOV` instructions on x64).
* `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_OPTIMIZE` - Don't use optimized inline assembly coverage
instrumentation (the default where available). Required to use
* `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_BACKPATCH` - Disable backpatching. At the end of executing
each block, control will return to FRIDA to identify the next block to
execute.
* `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
report instrumented blocks back to the parent so that it can also instrument
them and they be inherited by the next child on fork, implies
@ -227,6 +233,9 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
* `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
call back into FRIDA to find the next block. Default is 32.
* `AFL_FRIDA_STALKER_NO_BACKPATCH` - Disable backpatching. At the end of executing
each block, control will return to FRIDA to identify the next block to
execute.
* `AFL_FRIDA_STATS_FILE` - Write statistics information about the code being
instrumented to the given file name. The statistics are written only for the
child process when new block is instrumented (when the
@ -307,6 +316,7 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
core dump of the instrumented target. Note that in order to capture the core
dump you must set a sufficient timeout (using `-t`) to avoid `afl-fuzz`
killing the process whilst it is being dumped.
* `AFL_FRIDA_VERBOSE` - Enable verbose output from FRIDA mode.
## FASAN - FRIDA Address Sanitizer mode
@ -376,4 +386,4 @@ Should you encounter problems with FRIDA mode, refer to
The next features to be added are Aarch32 support as well as looking at
potential performance improvements. The intention is to achieve feature parity
with QEMU mode in due course. Contributions are welcome, but please get in touch
to ensure that efforts are deconflicted.
to ensure that efforts are deconflicted.

View File

@ -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-2020 AFLplusplus Project. All rights reserved.
Copyright 2019-2022 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:
@ -782,7 +782,7 @@ class Afl {
Afl.jsApiWrite(STDOUT_FILENO, buf, log.length);
}
/**
* See `AFL_FRIDA_INST_NO_BACKPATCH`.
* See `AFL_FRIDA_STALKER_NO_BACKPATCH`.
*/
static setBackpatchDisable() {
Afl.jsApiSetBackpatchDisable();
@ -850,6 +850,14 @@ class Afl {
static setInstrumentNoOptimize() {
Afl.jsApiSetInstrumentNoOptimize();
}
/**
* See `AFL_FRIDA_INST_REGS_FILE`. This function takes a single `string` as
* an argument.
*/
public static setInstrumentRegsFile(file: string): void {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetInstrumentRegsFile(buf);
}
/*
* See `AFL_FRIDA_INST_SEED`
*/
@ -995,4 +1003,4 @@ class Afl {
return Afl.module.getExportByName(name);
}
}
```
```

39
frida_mode/addr/addr.c Normal file
View File

@ -0,0 +1,39 @@
#include <errno.h>
#include <link.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/personality.h>
#define UNUSED_PARAMETER(x) (void)(x)
int phdr_callback(struct dl_phdr_info *info, size_t size, void *data)
{
UNUSED_PARAMETER (size);
ElfW(Addr) * base = data;
if (info->dlpi_name[0] == 0) { *base = info->dlpi_addr; }
return 0;
}
int main (int argc, char** argv, char** envp) {
UNUSED_PARAMETER (argc);
ElfW(Addr) base = 0;
int persona = personality(ADDR_NO_RANDOMIZE);
if (persona == -1) {
printf("Failed to set ADDR_NO_RANDOMIZE: %d", errno);
return 1;
}
if ((persona & ADDR_NO_RANDOMIZE) == 0) { execvpe(argv[0], argv, envp); }
dl_iterate_phdr(phdr_callback, &base);
printf("%p\n", (void *)base);
if (base == 0) { return 1; }
return 0;
}

View File

@ -9,13 +9,18 @@
js_api_done;
js_api_error;
js_api_set_backpatch_disable;
js_api_set_cache_disable;
js_api_set_debug_maps;
js_api_set_entrypoint;
js_api_set_instrument_cache_size;
js_api_set_instrument_coverage_absolute;
js_api_set_instrument_coverage_file;
js_api_set_instrument_debug_file;
js_api_set_instrument_jit;
js_api_set_instrument_libraries;
js_api_set_instrument_instructions;
js_api_set_instrument_no_optimize;
js_api_set_instrument_regs_file;
js_api_set_instrument_seed;
js_api_set_instrument_trace;
js_api_set_instrument_trace_unique;
@ -37,6 +42,7 @@
js_api_set_stderr;
js_api_set_stdout;
js_api_set_traceable;
js_api_set_verbose;
local:
*;

View File

@ -31,7 +31,7 @@ __attribute__((visibility("default"))) void afl_persistent_hook(
// do a length check matching the target!
void **esp = (void **)regs->esp;
void * arg1 = esp[0];
void *arg1 = esp[0];
void **arg2 = &esp[1];
memcpy(arg1, input_buf, input_buf_len);
*arg2 = (void *)input_buf_len;
@ -50,6 +50,16 @@ __attribute__((visibility("default"))) void afl_persistent_hook(
}
#elif defined(__arm__)
__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
#pragma error "Unsupported architecture"
#endif

View File

@ -5,14 +5,16 @@
#include "config.h"
extern char * instrument_debug_filename;
extern char * instrument_coverage_filename;
extern gboolean instrument_tracing;
extern gboolean instrument_optimize;
extern gboolean instrument_unique;
extern __thread guint64 instrument_previous_pc;
extern guint64 instrument_hash_zero;
extern char * instrument_coverage_unstable_filename;
extern char *instrument_debug_filename;
extern char *instrument_coverage_filename;
extern bool instrument_coverage_absolute;
extern gboolean instrument_tracing;
extern gboolean instrument_optimize;
extern gboolean instrument_unique;
extern guint64 instrument_hash_zero;
extern char *instrument_coverage_unstable_filename;
extern gboolean instrument_coverage_insn;
extern char *instrument_regs_filename;
extern gboolean instrument_use_fixed_seed;
extern guint64 instrument_fixed_seed;
@ -20,6 +22,11 @@ extern guint64 instrument_fixed_seed;
extern uint8_t *__afl_area_ptr;
extern uint32_t __afl_map_size;
extern __thread guint64 *instrument_previous_pc_addr;
extern gboolean instrument_cache_enabled;
extern gsize instrument_cache_size;
void instrument_config(void);
void instrument_init(void);
@ -30,8 +37,10 @@ GumStalkerTransformer *instrument_get_transformer(void);
gboolean instrument_is_coverage_optimize_supported(void);
void instrument_coverage_optimize_init(void);
void instrument_coverage_optimize(const cs_insn * instr,
void instrument_coverage_optimize(const cs_insn *instr,
GumStalkerOutput *output);
void instrument_coverage_optimize_insn(const cs_insn *instr,
GumStalkerOutput *output);
void instrument_debug_config(void);
void instrument_debug_init(void);
@ -51,9 +60,16 @@ void instrument_coverage_unstable(guint64 edge, guint64 previous_rip,
guint64 previous_end, guint64 current_rip,
guint64 current_end);
void instrument_on_fork();
void instrument_on_fork(void);
guint64 instrument_get_offset_hash(GumAddress current_rip);
void instrument_cache_config(void);
void instrument_cache_init(void);
void instrument_cache_insert(gpointer real_address, gpointer code_address);
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output);
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data);
void instrument_regs_format(int fd, char *format, ...);
#endif

View File

@ -0,0 +1,11 @@
#ifndef _MODULE_H
#define _MODULE_H
#include "frida-gumjs.h"
void module_config(void);
void module_init(void);
#endif

View File

@ -13,7 +13,7 @@ typedef void (*afl_persistent_hook_fn)(api_regs *regs, uint64_t guest_base,
extern int __afl_persistent_loop(unsigned int max_cnt);
extern unsigned int * __afl_fuzz_len;
extern unsigned int *__afl_fuzz_len;
extern unsigned char *__afl_fuzz_ptr;
extern guint64 persistent_start;

View File

@ -1,7 +1,7 @@
#ifndef _SECCOMP_H
#define _SECCOMP_H
#ifndef __APPLE__
#if !defined(__APPLE__) && !defined(__ANDROID__)
#include <stdint.h>
#include <linux/filter.h>
@ -401,9 +401,9 @@ enum {
typedef void (*seccomp_child_func_t)(int event_fd, void *ctx);
typedef void (*seccomp_filter_callback_t)(struct seccomp_notif * req,
typedef void (*seccomp_filter_callback_t)(struct seccomp_notif *req,
struct seccomp_notif_resp *resp,
GumReturnAddressArray * frames);
GumReturnAddressArray *frames);
void seccomp_atomic_set(volatile bool *ptr, bool val);
bool seccomp_atomic_try_set(volatile bool *ptr, bool val);

9
frida_mode/include/shm.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _SHM_H
#define _SHM_H
#include <stddef.h>
void *shm_create(size_t size);
#endif

View File

@ -43,7 +43,7 @@ typedef struct {
G_DECLARE_FINAL_TYPE(GumAflStalkerStats, gum_afl_stalker_stats, GUM,
AFL_STALKER_STATS, GObject)
extern char * stats_filename;
extern char *stats_filename;
extern guint64 stats_interval;
void stats_config(void);

View File

@ -5,12 +5,23 @@
#include "debug.h"
#ifndef MAP_FIXED_NOREPLACE
#ifdef MAP_EXCL
#define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
#else
#define MAP_FIXED_NOREPLACE MAP_FIXED
#endif
#endif
#define UNUSED_PARAMETER(x) (void)(x)
#define IGNORED_RETURN(x) (void)!(x)
extern gboolean util_verbose;
guint64 util_read_address(char *key, guint64 default_value);
guint64 util_read_num(char *key, guint64 default_value);
gboolean util_output_enabled(void);
gboolean util_verbose_enabled(void);
gsize util_rotate(gsize val, gsize shift, gsize size);
gsize util_log2(gsize val);
@ -19,7 +30,8 @@ gsize util_log2(gsize val);
\
if (!util_output_enabled()) { break; } \
\
OKF(x); \
SAYF(cLGN "[F] " cRST x); \
SAYF(cRST "\n"); \
\
} while (0)
@ -37,5 +49,15 @@ gsize util_log2(gsize val);
\
} while (0)
#define FVERBOSE(x...) \
do { \
\
if (!util_verbose_enabled()) { break; } \
\
SAYF(cGRA "[F] " x); \
SAYF(cRST "\n"); \
\
} while (0)
#endif

View File

@ -9,21 +9,15 @@ gboolean asan_initialized = FALSE;
void asan_config(void) {
if (getenv("AFL_USE_FASAN") != NULL) {
FOKF("Frida ASAN mode enabled");
asan_enabled = TRUE;
} else {
FOKF("Frida ASAN mode disabled");
}
if (getenv("AFL_USE_FASAN") != NULL) { asan_enabled = TRUE; }
}
void asan_init(void) {
FOKF(cBLU "Instrumentation" cRST " - " cGRN "asan:" cYEL " [%c]",
asan_enabled ? 'X' : ' ');
if (asan_enabled) {
asan_arch_init();
@ -36,12 +30,21 @@ void asan_init(void) {
static gboolean asan_exclude_module(const GumModuleDetails *details,
gpointer user_data) {
gchar * symbol_name = (gchar *)user_data;
gchar *symbol_name = (gchar *)user_data;
GumAddress address;
address = gum_module_find_export_by_name(details->name, symbol_name);
if (address == 0) { return TRUE; }
/* If the reported address of the symbol is outside of the range of the module
* then ignore it */
if (address < details->range->base_address) { return TRUE; }
if (address > (details->range->base_address + details->range->size)) {
return TRUE;
}
ranges_add_exclude((GumMemoryRange *)details->range);
return FALSE;

View File

@ -22,8 +22,8 @@ asan_storeN_t asan_storeN = NULL;
static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
asan_ctx_t * asan_ctx = (asan_ctx_t *)user_data;
cs_arm64_op * operand = &asan_ctx->operand;
asan_ctx_t *asan_ctx = (asan_ctx_t *)user_data;
cs_arm64_op *operand = &asan_ctx->operand;
arm64_op_mem *mem = &operand->mem;
gsize base = 0;
gsize index = 0;
@ -59,7 +59,7 @@ void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
cs_arm64 arm64 = instr->detail->arm64;
cs_arm64_op *operand;
asan_ctx_t * ctx;
asan_ctx_t *ctx;
if (!asan_initialized) return;

View File

@ -17,7 +17,7 @@ static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
UNUSED_PARAMETER(user_data);
cs_x86_op * operand = (cs_x86_op *)user_data;
cs_x86_op *operand = (cs_x86_op *)user_data;
x86_op_mem *mem = &operand->mem;
gsize base = 0;
gsize index = 0;
@ -48,9 +48,9 @@ void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
UNUSED_PARAMETER(iterator);
cs_x86 x86 = instr->detail->x86;
cs_x86_op * operand;
cs_x86_op *operand;
x86_op_mem *mem;
cs_x86_op * ctx;
cs_x86_op *ctx;
if (!asan_initialized) return;

View File

@ -17,7 +17,7 @@ static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
UNUSED_PARAMETER(user_data);
cs_x86_op * operand = (cs_x86_op *)user_data;
cs_x86_op *operand = (cs_x86_op *)user_data;
x86_op_mem *mem = &operand->mem;
gsize base = 0;
gsize index = 0;
@ -48,9 +48,9 @@ void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
UNUSED_PARAMETER(iterator);
cs_x86 x86 = instr->detail->x86;
cs_x86_op * operand;
cs_x86_op *operand;
x86_op_mem *mem;
cs_x86_op * ctx;
cs_x86_op *ctx;
if (!asan_initialized) return;

View File

@ -13,9 +13,9 @@
#define MAX_MEMFD_SIZE (64UL << 10)
extern struct cmp_map *__afl_cmp_map;
static GArray * cmplog_ranges = NULL;
static GHashTable * hash_yes = NULL;
static GHashTable * hash_no = NULL;
static GArray *cmplog_ranges = NULL;
static GHashTable *hash_yes = NULL;
static GHashTable *hash_no = NULL;
static long page_size = 0;
static long page_offset_mask = 0;
@ -24,7 +24,7 @@ static long page_mask = 0;
static gboolean cmplog_range(const GumRangeDetails *details,
gpointer user_data) {
GArray * cmplog_ranges = (GArray *)user_data;
GArray *cmplog_ranges = (GArray *)user_data;
GumMemoryRange range = *details->range;
g_array_append_val(cmplog_ranges, range);
return TRUE;
@ -54,7 +54,7 @@ static gint cmplog_sort(gconstpointer a, gconstpointer b) {
static void cmplog_get_ranges(void) {
FOKF("CMPLOG - Collecting ranges");
FVERBOSE("CMPLOG - Collecting ranges");
cmplog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100);
gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, cmplog_ranges);
@ -68,18 +68,21 @@ void cmplog_config(void) {
void cmplog_init(void) {
FOKF("CMPLOG - Enabled [%c]", __afl_cmp_map == NULL ? ' ' : 'X');
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cmplog:" cYEL " [%c]",
__afl_cmp_map == NULL ? ' ' : 'X');
if (__afl_cmp_map == NULL) { return; }
cmplog_get_ranges();
FVERBOSE("Cmplog Ranges");
for (guint i = 0; i < cmplog_ranges->len; i++) {
GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i);
FOKF("CMPLOG Range - %3u: 0x%016" G_GINT64_MODIFIER
"X - 0x%016" G_GINT64_MODIFIER "X",
i, range->base_address, range->base_address + range->size);
FVERBOSE("\t%3u: 0x%016" G_GINT64_MODIFIER "X - 0x%016" G_GINT64_MODIFIER
"X",
i, range->base_address, range->base_address + range->size);
}
@ -115,7 +118,7 @@ gboolean cmplog_test_addr(guint64 addr, size_t size) {
if (g_hash_table_contains(hash_yes, GSIZE_TO_POINTER(addr))) { return true; }
if (g_hash_table_contains(hash_no, GSIZE_TO_POINTER(addr))) { return false; }
void * page_addr = GSIZE_TO_POINTER(addr & page_mask);
void *page_addr = GSIZE_TO_POINTER(addr & page_mask);
size_t page_offset = addr & page_offset_mask;
/* If it spans a page, then bail */

View File

@ -148,7 +148,7 @@ static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
}
static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
cs_arm64_op * operand) {
cs_arm64_op *operand) {
ctx->type = operand->type;
switch (operand->type) {
@ -169,7 +169,7 @@ static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
}
static void cmplog_instrument_call(const cs_insn * instr,
static void cmplog_instrument_call(const cs_insn *instr,
GumStalkerIterator *iterator) {
cs_arm64 arm64 = instr->detail->arm64;
@ -247,8 +247,8 @@ static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
}
static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
cs_arm64_op * operand1,
cs_arm64_op * operand2,
cs_arm64_op *operand1,
cs_arm64_op *operand2,
size_t size) {
cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
@ -263,7 +263,7 @@ static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
}
static void cmplog_instrument_cmp_sub(const cs_insn * instr,
static void cmplog_instrument_cmp_sub(const cs_insn *instr,
GumStalkerIterator *iterator) {
cs_arm64 arm64 = instr->detail->arm64;

View File

@ -141,7 +141,7 @@ static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
}
static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
cs_x86_op * operand) {
cs_x86_op *operand) {
ctx->type = operand->type;
ctx->size = operand->size;
@ -163,7 +163,7 @@ static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
}
static void cmplog_instrument_call(const cs_insn * instr,
static void cmplog_instrument_call(const cs_insn *instr,
GumStalkerIterator *iterator) {
cs_x86 x86 = instr->detail->x86;
@ -230,7 +230,7 @@ static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
}
static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
cs_x86_op * operand1,
cs_x86_op *operand1,
cs_x86_op *operand2) {
cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
@ -244,7 +244,7 @@ static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
}
static void cmplog_instrument_cmp_sub(const cs_insn * instr,
static void cmplog_instrument_cmp_sub(const cs_insn *instr,
GumStalkerIterator *iterator) {
cs_x86 x86 = instr->detail->x86;

View File

@ -146,7 +146,7 @@ static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
}
static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
cs_x86_op * operand) {
cs_x86_op *operand) {
ctx->type = operand->type;
ctx->size = operand->size;
@ -168,7 +168,7 @@ static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
}
static void cmplog_instrument_call(const cs_insn * instr,
static void cmplog_instrument_call(const cs_insn *instr,
GumStalkerIterator *iterator) {
cs_x86 x86 = instr->detail->x86;
@ -238,7 +238,7 @@ static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
}
static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
cs_x86_op * operand1,
cs_x86_op *operand1,
cs_x86_op *operand2) {
cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
@ -252,7 +252,7 @@ static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
}
static void cmplog_instrument_cmp_sub(const cs_insn * instr,
static void cmplog_instrument_cmp_sub(const cs_insn *instr,
GumStalkerIterator *iterator) {
cs_x86 x86 = instr->detail->x86;

View File

@ -24,7 +24,7 @@ gboolean entry_run = FALSE;
static void entry_launch(void) {
FOKF("Entry point reached");
FVERBOSE("Entry point reached");
__afl_manual_init();
/* Child here */
@ -69,8 +69,8 @@ void entry_config(void) {
void entry_init(void) {
FOKF("entry_point: 0x%016" G_GINT64_MODIFIER "X", entry_point);
FOKF("dumpable: [%c]", traceable ? 'X' : ' ');
FVERBOSE("Entry Point: 0x%016" G_GINT64_MODIFIER "X", entry_point);
FVERBOSE("Dumpable: [%c]", traceable ? 'X' : ' ');
if (dlopen(NULL, RTLD_NOW) == NULL) { FFATAL("Failed to dlopen: %d", errno); }
@ -78,6 +78,13 @@ void entry_init(void) {
void entry_start(void) {
if (persistent_start == 0) {
ranges_exclude();
stalker_trust();
}
if (entry_point == 0) { entry_launch(); }
}
@ -94,7 +101,7 @@ static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) {
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) {
UNUSED_PARAMETER(output);
FOKF("AFL_ENTRYPOINT reached");
FVERBOSE("AFL_ENTRYPOINT reached");
if (persistent_start == 0) {

View File

@ -1,6 +1,5 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include "frida-gumjs.h"
@ -16,10 +15,13 @@
#include "persistent.h"
#include "prefetch.h"
#include "ranges.h"
#include "shm.h"
#include "stalker.h"
#include "stats.h"
#include "util.h"
#define FRIDA_DEFAULT_MAP_SIZE (64UL << 10)
gboolean instrument_tracing = false;
gboolean instrument_optimize = false;
gboolean instrument_unique = false;
@ -28,15 +30,20 @@ guint64 instrument_hash_seed = 0;
gboolean instrument_use_fixed_seed = FALSE;
guint64 instrument_fixed_seed = 0;
char * instrument_coverage_unstable_filename = NULL;
char *instrument_coverage_unstable_filename = NULL;
gboolean instrument_coverage_insn = FALSE;
char *instrument_regs_filename = NULL;
static GumStalkerTransformer *transformer = NULL;
__thread guint64 instrument_previous_pc = 0;
static GumAddress previous_rip = 0;
static GumAddress previous_end = 0;
static u8 * edges_notified = NULL;
static u8 *edges_notified = NULL;
static int regs_fd = -1;
__thread guint64 instrument_previous_pc;
__thread guint64 *instrument_previous_pc_addr = NULL;
typedef struct {
@ -105,8 +112,14 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context,
guint16 current_end = ctx->end;
guint64 current_pc = instrument_get_offset_hash(current_rip);
guint64 edge;
if (instrument_previous_pc_addr == NULL) {
edge = current_pc ^ instrument_previous_pc;
instrument_previous_pc_addr = &instrument_previous_pc;
*instrument_previous_pc_addr = instrument_hash_zero;
}
edge = current_pc ^ *instrument_previous_pc_addr;
instrument_increment_map(edge);
@ -136,12 +149,12 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context,
previous_end = current_end;
gsize map_size_pow2 = util_log2(__afl_map_size);
instrument_previous_pc = util_rotate(current_pc, 1, map_size_pow2);
*instrument_previous_pc_addr = util_rotate(current_pc, 1, map_size_pow2);
}
static void instrument_basic_block(GumStalkerIterator *iterator,
GumStalkerOutput * output,
GumStalkerOutput *output,
gpointer user_data) {
UNUSED_PARAMETER(user_data);
@ -149,7 +162,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
const cs_insn *instr;
gboolean begin = TRUE;
gboolean excluded;
block_ctx_t * ctx = NULL;
block_ctx_t *ctx = NULL;
while (gum_stalker_iterator_next(iterator, &instr)) {
@ -222,11 +235,22 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
}
if (unlikely(instrument_regs_filename != NULL)) {
gum_stalker_iterator_put_callout(iterator, instrument_write_regs,
(void *)(size_t)regs_fd, NULL);
}
}
}
instrument_debug_instruction(instr->address, instr->size, output);
if (instrument_coverage_insn) {
instrument_coverage_optimize_insn(instr, output);
}
if (likely(!excluded)) {
@ -235,6 +259,8 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
}
instrument_cache(instr, output);
if (js_stalker_callback(instr, begin, excluded, output)) {
gum_stalker_iterator_keep(iterator);
@ -262,26 +288,38 @@ void instrument_config(void) {
instrument_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED", 0);
instrument_coverage_unstable_filename =
(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_debug_config();
instrument_coverage_config();
asan_config();
cmplog_config();
instrument_cache_config();
}
void instrument_init(void) {
if (__afl_map_size == MAP_SIZE) __afl_map_size = FRIDA_DEFAULT_MAP_SIZE;
if (!instrument_is_coverage_optimize_supported()) instrument_optimize = false;
FOKF("Instrumentation - optimize [%c]", instrument_optimize ? 'X' : ' ');
FOKF("Instrumentation - tracing [%c]", instrument_tracing ? 'X' : ' ');
FOKF("Instrumentation - unique [%c]", instrument_unique ? 'X' : ' ');
FOKF("Instrumentation - fixed seed [%c] [0x%016" G_GINT64_MODIFIER "x]",
FOKF(cBLU "Instrumentation" cRST " - " cGRN "optimize:" cYEL " [%c]",
instrument_optimize ? 'X' : ' ');
FOKF(cBLU "Instrumentation" cRST " - " cGRN "tracing:" cYEL " [%c]",
instrument_tracing ? 'X' : ' ');
FOKF(cBLU "Instrumentation" cRST " - " cGRN "unique:" cYEL " [%c]",
instrument_unique ? 'X' : ' ');
FOKF(cBLU "Instrumentation" cRST " - " cGRN "fixed seed:" cYEL
" [%c] [0x%016" G_GINT64_MODIFIER "x]",
instrument_use_fixed_seed ? 'X' : ' ', instrument_fixed_seed);
FOKF("Instrumentation - unstable coverage [%c] [%s]",
instrument_coverage_unstable_filename == NULL ? ' ' : 'X',
instrument_coverage_unstable_filename);
FOKF(cBLU "Instrumentation" cRST " - " cGRN "unstable coverage:" cYEL " [%s]",
instrument_coverage_unstable_filename == NULL
? " "
: instrument_coverage_unstable_filename);
FOKF(cBLU "Instrumentation" cRST " - " cGRN "instructions:" cYEL " [%c]",
instrument_coverage_insn ? 'X' : ' ');
if (instrument_tracing && instrument_optimize) {
@ -306,38 +344,10 @@ void instrument_init(void) {
if (instrument_unique) { instrument_tracing = TRUE; }
if (__afl_map_size != 0x10000) {
FATAL("Bad map size: 0x%08x", __afl_map_size);
}
transformer = gum_stalker_transformer_make_from_callback(
instrument_basic_block, NULL, NULL);
if (instrument_unique) {
int shm_id =
shmget(IPC_PRIVATE, __afl_map_size, IPC_CREAT | IPC_EXCL | 0600);
if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); }
edges_notified = shmat(shm_id, NULL, 0);
g_assert(edges_notified != MAP_FAILED);
/*
* Configure the shared memory region to be removed once the process
* dies.
*/
if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
}
/* Clear it, not sure it's necessary, just seems like good practice */
memset(edges_notified, '\0', __afl_map_size);
}
if (instrument_unique) { edges_notified = shm_create(__afl_map_size); }
if (instrument_use_fixed_seed) {
@ -366,15 +376,36 @@ void instrument_init(void) {
}
FOKF("Instrumentation - seed [0x%016" G_GINT64_MODIFIER "x]",
FOKF(cBLU "Instrumentation" cRST " - " cGRN "seed:" cYEL
" [0x%016" G_GINT64_MODIFIER "x]",
instrument_hash_seed);
instrument_hash_zero = instrument_get_offset_hash(0);
instrument_coverage_optimize_init();
instrument_debug_init();
instrument_coverage_init();
FOKF(cBLU "Instrumentation" cRST " - " cGRN "regs:" cYEL " [%s]",
instrument_regs_filename == NULL ? " " : instrument_regs_filename);
if (instrument_regs_filename != NULL) {
char *path =
g_canonicalize_filename(instrument_regs_filename, g_get_current_dir());
FOKF(cBLU "Instrumentation" cRST " - " cGRN "path:" cYEL " [%s]", path);
regs_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (regs_fd < 0) { FFATAL("Failed to open regs file '%s'", path); }
g_free(path);
}
asan_init();
cmplog_init();
instrument_coverage_init();
instrument_coverage_optimize_init();
instrument_debug_init();
instrument_cache_init();
}
@ -387,7 +418,30 @@ GumStalkerTransformer *instrument_get_transformer(void) {
void instrument_on_fork() {
instrument_previous_pc = instrument_hash_zero;
if (instrument_previous_pc_addr != NULL) {
*instrument_previous_pc_addr = instrument_hash_zero;
}
}
void instrument_regs_format(int fd, char *format, ...) {
va_list ap;
char buffer[4096] = {0};
int ret;
int len;
va_start(ap, format);
ret = vsnprintf(buffer, sizeof(buffer) - 1, format, ap);
va_end(ap);
if (ret < 0) { return; }
len = strnlen(buffer, sizeof(buffer));
IGNORED_RETURN(write(fd, buffer, len));
}

View File

@ -5,24 +5,193 @@
#if defined(__arm__)
gboolean instrument_is_coverage_optimize_supported(void) {
#define PAGE_MASK (~(GUM_ADDRESS(0xfff)))
#define PAGE_ALIGNED(x) ((GUM_ADDRESS(x) & PAGE_MASK) == GUM_ADDRESS(x))
return false;
gboolean instrument_cache_enabled = FALSE;
gsize instrument_cache_size = 0;
extern __thread guint64 instrument_previous_pc;
__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_SIZE];
#pragma pack(push, 1)
typedef struct {
// cur_location = (block_address >> 4) ^ (block_address << 8);
// shared_mem[cur_location ^ prev_location]++;
// prev_location = cur_location >> 1;
/* We can remove this branch when we add support for branch suppression */
uint32_t b_code; /* b imm */
uint8_t *shared_mem;
uint64_t *prev_location;
/* code */
/* save regs */
uint32_t str_r0_sp_rz; /* str r0, [sp - RED_ZONE] */
uint32_t str_r1_sp_rz_4; /* str r1, [sp - (RED_ZONE + 4)] */
/* load prev */
uint32_t ldr_r0_pprev; /* ldr r0, [pc-x] */
uint32_t ldrh_r1_r0; /* ldrh r1, [r0] */
/* load curr */
uint32_t mov_r0_block_id; /* mov r0, #imm16 */
/* calculate new */
uint32_t eor_r0_r0_r1; /* eor r0, r0, r1 */
/* load map */
uint32_t ldr_r1_pmap; /* ldr r1, [pc-x] */
/* calculate offset */
uint32_t add_r1_r1_r0; /* add r1, r1, r0 */
/* Load the value */
uint32_t ldrb_r0_r1; /* ldrb r0, [r1] */
/* Increment the value */
uint32_t add_r0_r0_1; /* add r0, r0, #1 */
uint32_t add_r0_r0_r0_lsr_8; /* add r0, r0, r0, lsr #8 */
/* Save the value */
uint32_t strb_r0_r1; /* strb r0, [r1] */
/* load curr shifted */
uint32_t mov_r0_block_id_shr_1; /* mov r0, #imm16 >> 1*/
/* Update prev */
uint32_t ldr_r1_pprev; /* ldr r1, [pc-x] */
uint32_t strh_r0_r1; /* strh r0, [r1] */
/* restore regs */
uint32_t ldr_r1_sp_rz_4; /* ldr r1, [sp - (RED_ZONE + 4)] */
uint32_t ldr_r0_sp_rz; /* ldr r0, [sp - RED_ZONE] */
} afl_log_code_asm_t;
typedef union {
afl_log_code_asm_t code;
uint8_t bytes[0];
} afl_log_code;
#pragma pack(pop)
static const afl_log_code_asm_t template =
{
.b_code = GUINT32_TO_LE(0xea000001),
.shared_mem = (uint8_t *)GUINT32_TO_LE(0xcefaadde),
.prev_location = (uint64_t *)GUINT32_TO_LE(0xadba0df0),
.str_r0_sp_rz = GUINT32_TO_LE(0xe50d0080),
.str_r1_sp_rz_4 = GUINT32_TO_LE(0xe50d1084),
.ldr_r0_pprev = GUINT32_TO_LE(0xe51f0014),
.ldrh_r1_r0 = GUINT32_TO_LE(0xe1d010b0),
.mov_r0_block_id = GUINT32_TO_LE(0xe3000000),
.eor_r0_r0_r1 = GUINT32_TO_LE(0xe0200001),
.ldr_r1_pmap = GUINT32_TO_LE(0xe51f1028),
.add_r1_r1_r0 = GUINT32_TO_LE(0xe0811000),
.ldrb_r0_r1 = GUINT32_TO_LE(0xe5d10000),
.add_r0_r0_1 = GUINT32_TO_LE(0xe2800001),
.add_r0_r0_r0_lsr_8 = GUINT32_TO_LE(0xe0800420),
.strb_r0_r1 = GUINT32_TO_LE(0xe5c10000),
.mov_r0_block_id_shr_1 = GUINT32_TO_LE(0xe3000000),
.ldr_r1_pprev = GUINT32_TO_LE(0xe51f1040),
.strh_r0_r1 = GUINT32_TO_LE(0xe1c100b0),
.ldr_r1_sp_rz_4 = GUINT32_TO_LE(0xe51d1084),
.ldr_r0_sp_rz = GUINT32_TO_LE(0xe51d0080),
}
void instrument_coverage_optimize(const cs_insn * instr,
;
gboolean instrument_is_coverage_optimize_supported(void) {
return true;
}
static void patch_t3_insn(uint32_t *insn, uint16_t val) {
uint32_t orig = GUINT32_FROM_LE(*insn);
uint32_t imm12 = (val & 0xfff);
uint32_t imm4 = (val >> 12);
orig |= imm12;
orig |= (imm4 << 16);
*insn = GUINT32_TO_LE(orig);
}
void instrument_coverage_optimize(const cs_insn *instr,
GumStalkerOutput *output) {
afl_log_code code = {0};
GumArmWriter *cw = output->writer.arm;
gpointer block_start;
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;
block_start = GSIZE_TO_POINTER(GUM_ADDRESS(cw->code));
code.code = template;
g_assert(PAGE_ALIGNED(__afl_area_ptr));
map_size_pow2 = util_log2(__afl_map_size);
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
code.code.shared_mem = __afl_area_ptr;
code.code.prev_location = instrument_previous_pc_addr;
patch_t3_insn(&code.code.mov_r0_block_id, (uint16_t)area_offset);
patch_t3_insn(&code.code.mov_r0_block_id_shr_1, (uint16_t)area_offset_ror);
// gum_arm_writer_put_breakpoint(cw);
gum_arm_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
}
void instrument_coverage_optimize_insn(const cs_insn *instr,
GumStalkerOutput *output) {
UNUSED_PARAMETER(instr);
UNUSED_PARAMETER(output);
FFATAL("Optimized coverage not supported on this architecture");
}
void instrument_coverage_optimize_init(void) {
FWARNF("Optimized coverage not supported on this architecture");
char *shm_env = getenv(SHM_ENV_VAR);
FVERBOSE("SHM_ENV_VAR: %s", shm_env);
if (shm_env == NULL) {
FWARNF("SHM_ENV_VAR not set, using dummy for debugging purposes");
__afl_area_ptr = area_ptr_dummy;
memset(area_ptr_dummy, '\0', sizeof(area_ptr_dummy));
}
FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr);
if (instrument_previous_pc_addr == NULL) {
instrument_previous_pc_addr = &instrument_previous_pc;
*instrument_previous_pc_addr = instrument_hash_zero;
FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
}
}
@ -46,5 +215,48 @@ gpointer instrument_cur(GumStalkerOutput *output) {
}
void instrument_cache_config(void) {
}
void instrument_cache_init(void) {
}
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
UNUSED_PARAMETER(real_address);
UNUSED_PARAMETER(code_address);
}
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
UNUSED_PARAMETER(instr);
UNUSED_PARAMETER(output);
}
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
int fd = (int)user_data;
instrument_regs_format(fd,
"r0 : 0x%08x, r1 : 0x%08x, r2 : 0x%08x, r3 : 0x%08x\n",
cpu_context->r[0], cpu_context->r[2],
cpu_context->r[1], cpu_context->r[3]);
instrument_regs_format(fd,
"r4 : 0x%08x, r5 : 0x%08x, r6 : 0x%08x, r7 : 0x%08x\n",
cpu_context->r[4], cpu_context->r[5],
cpu_context->r[6], cpu_context->r[7]);
instrument_regs_format(
fd, "r8 : 0x%08x, r9 : 0x%08x, r10: 0x%08x, r11: 0x%08x\n",
cpu_context->r8, cpu_context->r9, cpu_context->r10, cpu_context->r11);
instrument_regs_format(
fd, "r12: 0x%08x, sp : 0x%08x, lr : 0x%08x, pc : 0x%08x\n",
cpu_context->r12, cpu_context->sp, cpu_context->lr, cpu_context->pc);
instrument_regs_format(fd, "cpsr: 0x%08x\n\n", cpu_context->cpsr);
}
#endif

View File

@ -1,50 +1,123 @@
#include <stddef.h>
#include "frida-gumjs.h"
#include "config.h"
#include "instrument.h"
#include "ranges.h"
#include "stalker.h"
#include "util.h"
#define G_MININT33 ((gssize)0xffffffff00000000)
#define G_MAXINT33 ((gssize)0x00000000ffffffff)
#define PAGE_MASK (~(GUM_ADDRESS(0xfff)))
#define PAGE_ALIGNED(x) ((GUM_ADDRESS(x) & PAGE_MASK) == GUM_ADDRESS(x))
#define GUM_RESTORATION_PROLOG_SIZE 4
#if defined(__aarch64__)
static GumAddress current_log_impl = GUM_ADDRESS(0);
gboolean instrument_cache_enabled = FALSE;
gsize instrument_cache_size = 0;
static GHashTable *coverage_blocks = NULL;
static const guint8 afl_log_code[] = {
__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_SIZE];
// __afl_area_ptr[current_pc ^ previous_pc]++;
// previous_pc = current_pc ROR 1;
0xE1, 0x0B, 0xBF, 0xA9, // stp x1, x2, [sp, -0x10]!
0xE3, 0x13, 0xBF, 0xA9, // stp x3, x4, [sp, -0x10]!
#pragma pack(push, 1)
typedef struct {
// x0 = current_pc
0x21, 0x02, 0x00, 0x58, // ldr x1, #0x44, =&__afl_area_ptr
0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr)
// cur_location = (block_address >> 4) ^ (block_address << 8);
// shared_mem[cur_location ^ prev_location]++;
// prev_location = cur_location >> 1;
0x22, 0x02, 0x00, 0x58, // ldr x2, #0x44, =&previous_pc
0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2] (=previous_pc)
// stp x0, x1, [sp, #-160]
// adrp x0, 0x7fb7738000
// ldr x1, [x0]
// mov x0, #0x18b8
// eor x0, x1, x0
// adrp x1, 0x7fb7d73000
// add x0, x1, x0
// ldrb w1, [x0]
// add w1, w1, #0x1
// add x1, x1, x1, lsr #8
// strb w1, [x0]
// adrp x0, 0x7fb7738000
// mov x1, #0xc5c
// str x1, [x0]
// ldp x0, x1, [sp, #-160]
// b 0x7fb6f0dee4
// ldp x16, x17, [sp], #144
// __afl_area_ptr[current_pc ^ previous_pc]++;
0x42, 0x00, 0x00, 0xca, // eor x2, x2, x0
0x23, 0x68, 0x62, 0xf8, // ldr x3, [x1, x2]
0x63, 0x04, 0x00, 0x91, // add x3, x3, #1
0x63, 0x00, 0x1f, 0x9a, // adc x3, x3, xzr
0x23, 0x68, 0x22, 0xf8, // str x3, [x1, x2]
uint32_t b_imm8; /* br #68 */
uint32_t restoration_prolog; /* ldp x16, x17, [sp], #0x90 */
// previous_pc = current_pc ROR 1;
0xe4, 0x07, 0x40, 0x8b, // add x4, xzr, x0, LSR #1
0xe0, 0xff, 0x00, 0x8b, // add x0, xzr, x0, LSL #63
0x80, 0xc0, 0x40, 0x8b, // add x0, x4, x0, LSR #48
uint32_t stp_x0_x1; /* stp x0, x1, [sp, #-0xa0] */
0xe2, 0x00, 0x00, 0x58, // ldr x2, #0x1c, =&previous_pc
0x40, 0x00, 0x00, 0xf9, // str x0, [x2]
uint32_t adrp_x0_prev_loc1; /* adrp x0, #0xXXXX */
uint32_t ldr_x1_ptr_x0; /* ldr x1, [x0] */
0xE3, 0x13, 0xc1, 0xA8, // ldp x3, x4, [sp], #0x10
0xE1, 0x0B, 0xc1, 0xA8, // ldp x1, x2, [sp], #0x10
0xC0, 0x03, 0x5F, 0xD6, // ret
uint32_t mov_x0_curr_loc; /* movz x0, #0xXXXX */
uint32_t eor_x0_x1_x0; /* eor x0, x1, x0 */
uint32_t adrp_x1_area_ptr; /* adrp x1, #0xXXXX */
uint32_t add_x0_x1_x0; /* add x0, x1, x0 */
// &afl_area_ptr_ptr
// &afl_prev_loc_ptr
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 adrp_x0_prev_loc2; /* adrp x0, #0xXXXX */
uint32_t mov_x1_curr_loc_shr_1; /* movz x1, #0xXXXX */
uint32_t str_x1_ptr_x0; /* str x1, [x0] */
uint32_t ldp_x0_x1; /* ldp x0, x1, [sp, #-0xa0] */
} afl_log_code_asm_t;
#pragma pack(pop)
typedef union {
afl_log_code_asm_t code;
uint8_t bytes[0];
} afl_log_code;
static const afl_log_code_asm_t template =
{
.b_imm8 = 0x14000011,
.restoration_prolog = 0xa8c947f0,
.stp_x0_x1 = 0xa93607e0,
.adrp_x0_prev_loc1 = 0x90000000,
.ldr_x1_ptr_x0 = 0xf9400001,
.mov_x0_curr_loc = 0xd2800000,
.eor_x0_x1_x0 = 0xca000020,
.adrp_x1_area_ptr = 0x90000001,
.add_x0_x1_x0 = 0x8b000020,
.ldrb_w1_x0 = 0x39400001,
.add_w1_w1_1 = 0x11000421,
.add_w1_w1_w1_lsr_8 = 0x8b412021,
.strb_w1_ptr_x0 = 0x39000001,
.adrp_x0_prev_loc2 = 0x90000000,
.mov_x1_curr_loc_shr_1 = 0xd2800001,
.str_x1_ptr_x0 = 0xf9000001,
.ldp_x0_x1 = 0xa97607e0,
}
;
gboolean instrument_is_coverage_optimize_supported(void) {
@ -52,50 +125,251 @@ gboolean instrument_is_coverage_optimize_supported(void) {
}
void instrument_coverage_optimize(const cs_insn * instr,
GumStalkerOutput *output) {
static gboolean instrument_is_deterministic(const cs_insn *from_insn) {
guint64 current_pc = instr->address;
guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
GumArm64Writer *cw = output->writer.arm64;
cs_arm64 *arm64;
arm64_cc cc;
if (current_log_impl == 0 ||
!gum_arm64_writer_can_branch_directly_between(cw, cw->pc,
current_log_impl) ||
!gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128,
current_log_impl)) {
if (from_insn == NULL) { return FALSE; }
gconstpointer after_log_impl = cw->code + 1;
arm64 = &from_insn->detail->arm64;
cc = arm64->cc;
gum_arm64_writer_put_b_label(cw, after_log_impl);
switch (from_insn->id) {
current_log_impl = cw->pc;
gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code));
case ARM64_INS_B:
case ARM64_INS_BL:
if (cc == ARM64_CC_INVALID) { return TRUE; }
break;
uint8_t **afl_area_ptr_ptr = &__afl_area_ptr;
uint64_t *afl_prev_loc_ptr = &instrument_previous_pc;
gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr,
sizeof(afl_area_ptr_ptr));
gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr,
sizeof(afl_prev_loc_ptr));
gum_arm64_writer_put_label(cw, after_log_impl);
case ARM64_INS_RET:
case ARM64_INS_RETAA:
case ARM64_INS_RETAB:
if (arm64->op_count == 0) { return TRUE; }
break;
default:
return FALSE;
}
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE),
GUM_INDEX_PRE_ADJUST);
gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset);
gum_arm64_writer_put_bl_imm(cw, current_log_impl);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE,
GUM_INDEX_POST_ADJUST);
return FALSE;
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn *from_insn,
gpointer *target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(from_address);
UNUSED_PARAMETER(start_address);
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))) {
return;
}
if (instrument_is_deterministic(from_insn)) { return; }
/*
* Since each block is prefixed with a restoration prologue, we need to be
* able to begin execution at an offset into the block and execute both this
* restoration prologue and the instrumented block without the coverage code.
* We therefore layout our block as follows:
*
* +-----+------------------+-----+--------------------------+-------------+
* | LDP | BR <TARGET CODE> | LDP | COVERAGE INSTRUMENTATION | TARGET CODE |
* +-----+------------------+-----+--------------------------+-------------+
*
* ^ ^ ^ ^
* | | | |
* A B C D
*
* Without instrumentation suppression, the block is either executed at point
* (C) if it is reached by an indirect branch (and registers need to be
* restored) or point (D) if it is reached by an direct branch (and hence the
* registers don't need restoration). Similarly, we can start execution of the
* block at points (A) or (B) to achieve the same functionality, but without
* executing the coverage instrumentation.
*
* In either case, Stalker will call us back with the address of the target
* block to be executed as the destination. We can then check if the branch is
* a deterministic one and if so branch to point (C) or (D) rather than (A)
* or (B). We lay the code out in this fashion so that in the event we can't
* suppress coverage (the most likely), we can vector directly to the coverage
* instrumentation code and execute entirely without any branches. If we
* suppress the coverage, we simply branch beyond it instead.
*/
fixup_offset = GUM_RESTORATION_PROLOG_SIZE +
G_STRUCT_OFFSET(afl_log_code_asm_t, restoration_prolog);
*target += fixup_offset;
}
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 gboolean instrument_coverage_in_range(gssize offset) {
return (offset >= G_MININT33 && offset <= G_MAXINT33);
}
static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
GumAddress target) {
if (!PAGE_ALIGNED(target)) { FATAL("Target not page aligned"); }
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);
}
guint32 imm_low = ((distance >> 12) & 0x3) << 29;
guint32 imm_high = ((distance >> 14) & 0x7FFFF) << 5;
*patch |= imm_low;
*patch |= imm_high;
}
void instrument_coverage_optimize(const cs_insn *instr,
GumStalkerOutput *output) {
afl_log_code code = {0};
GumArm64Writer *cw = output->writer.arm64;
gpointer block_start;
guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
gsize map_size_pow2;
gsize area_offset_ror;
GumAddress code_addr = 0;
if (instrument_previous_pc_addr == NULL) {
GumAddressSpec spec = {.near_address = cw->code,
.max_distance = 1ULL << 30};
guint page_size = gum_query_page_size();
instrument_previous_pc_addr = gum_memory_allocate_near(
&spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE);
*instrument_previous_pc_addr = instrument_hash_zero;
FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
FVERBOSE("code_addr: %p", cw->code);
}
// gum_arm64_writer_put_brk_imm(cw, 0x0);
instrument_coverage_suppress_init();
code_addr = cw->pc;
/*
* On AARCH64, immediate branches can only be encoded with a 28-bit offset. To
* make a longer branch, it is necessary to load a register with the target
* address, this register must be saved beyond the red-zone before the branch
* is taken. To restore this register each block is prefixed by Stalker with
* an instruction to load x16,x17 from beyond the red-zone on the stack. A
* pair of registers are saved/restored because on AARCH64, the stack pointer
* must be 16 byte aligned. This instruction is emitted into the block before
* the tranformer (from which we are called) is executed. If is is possible
* for Stalker to make a direct branch (the target block is close enough), it
* can forego pushing the registers and instead branch at an offset into the
* block to skip this restoration prolog.
*/
block_start =
GSIZE_TO_POINTER(GUM_ADDRESS(cw->code) - GUM_RESTORATION_PROLOG_SIZE);
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.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
}
void instrument_coverage_optimize_insn(const cs_insn *instr,
GumStalkerOutput *output) {
UNUSED_PARAMETER(instr);
UNUSED_PARAMETER(output);
}
void instrument_coverage_optimize_init(void) {
char *shm_env = getenv(SHM_ENV_VAR);
FVERBOSE("SHM_ENV_VAR: %s", shm_env);
if (shm_env == NULL) {
FWARNF("SHM_ENV_VAR not set, using dummy for debugging purposes");
__afl_area_ptr = area_ptr_dummy;
memset(area_ptr_dummy, '\0', sizeof(area_ptr_dummy));
}
FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr);
}
void instrument_flush(GumStalkerOutput *output) {
@ -110,5 +384,65 @@ gpointer instrument_cur(GumStalkerOutput *output) {
}
void instrument_cache_config(void) {
}
void instrument_cache_init(void) {
}
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
UNUSED_PARAMETER(real_address);
UNUSED_PARAMETER(code_address);
}
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
UNUSED_PARAMETER(instr);
UNUSED_PARAMETER(output);
}
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
int fd = (int)(size_t)user_data;
instrument_regs_format(
fd, "x0 : 0x%016x, x1 : 0x%016x, x2 : 0x%016x, x3 : 0x%016x\n",
cpu_context->x[0], cpu_context->x[1], cpu_context->x[2],
cpu_context->x[3]);
instrument_regs_format(
fd, "x4 : 0x%016x, x5 : 0x%016x, x6 : 0x%016x, x7 : 0x%016x\n",
cpu_context->x[4], cpu_context->x[5], cpu_context->x[6],
cpu_context->x[7]);
instrument_regs_format(
fd, "x8 : 0x%016x, x9 : 0x%016x, x10: 0x%016x, x11: 0x%016x\n",
cpu_context->x[8], cpu_context->x[9], cpu_context->x[10],
cpu_context->x[11]);
instrument_regs_format(
fd, "x12: 0x%016x, x13: 0x%016x, x14: 0x%016x, x15: 0x%016x\n",
cpu_context->x[12], cpu_context->x[13], cpu_context->x[14],
cpu_context->x[15]);
instrument_regs_format(
fd, "x16: 0x%016x, x17: 0x%016x, x18: 0x%016x, x19: 0x%016x\n",
cpu_context->x[16], cpu_context->x[17], cpu_context->x[18],
cpu_context->x[19]);
instrument_regs_format(
fd, "x20: 0x%016x, x21: 0x%016x, x22: 0x%016x, x23: 0x%016x\n",
cpu_context->x[20], cpu_context->x[21], cpu_context->x[22],
cpu_context->x[23]);
instrument_regs_format(
fd, "x24: 0x%016x, x25: 0x%016x, x26: 0x%016x, x27: 0x%016x\n",
cpu_context->x[24], cpu_context->x[25], cpu_context->x[26],
cpu_context->x[27]);
instrument_regs_format(
fd, "x28: 0x%016x, fp : 0x%016x, lr : 0x%016x, sp : 0x%016x\n",
cpu_context->x[28], cpu_context->fp, cpu_context->lr, cpu_context->sp);
instrument_regs_format(fd, "pc : 0x%016x\n\n", cpu_context->pc);
}
#endif

View File

@ -9,6 +9,7 @@
#include "util.h"
char *instrument_coverage_filename = NULL;
bool instrument_coverage_absolute = false;
static int normal_coverage_fd = -1;
static int normal_coverage_pipes[2] = {-1, -1};
@ -17,7 +18,7 @@ static int unstable_coverage_fd = -1;
static int unstable_coverage_pipes[2] = {-1, -1};
static uint64_t normal_coverage_last_start = 0;
static gchar * unstable_coverage_fuzzer_stats = NULL;
static gchar *unstable_coverage_fuzzer_stats = NULL;
typedef struct {
@ -68,7 +69,7 @@ typedef struct {
static gboolean coverage_range(const GumRangeDetails *details,
gpointer user_data) {
GArray * coverage_ranges = (GArray *)user_data;
GArray *coverage_ranges = (GArray *)user_data;
coverage_range_t coverage = {0};
if (details->file == NULL) { return TRUE; }
@ -210,8 +211,8 @@ static GArray *coverage_get_modules(void) {
static void instrument_coverage_mark(void *key, void *value, void *user_data) {
UNUSED_PARAMETER(key);
coverage_mark_ctx_t * ctx = (coverage_mark_ctx_t *)user_data;
GArray * coverage_modules = ctx->modules;
coverage_mark_ctx_t *ctx = (coverage_mark_ctx_t *)user_data;
GArray *coverage_modules = ctx->modules;
normal_coverage_data_t *val = (normal_coverage_data_t *)value;
guint i;
@ -237,6 +238,18 @@ static void instrument_coverage_mark(void *key, void *value, void *user_data) {
}
static void instrument_coverage_mark_first(void *key, void *value,
void *user_data) {
UNUSED_PARAMETER(key);
coverage_range_t *module = (coverage_range_t *)user_data;
normal_coverage_data_t *val = (normal_coverage_data_t *)value;
val->module = module;
module->count++;
}
static void coverage_write(int fd, void *data, size_t size) {
ssize_t written;
@ -289,9 +302,9 @@ static void coverage_write_modules(int fd, GArray *coverage_modules) {
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", module->base_address);
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", module->limit);
/* entry */
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0);
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0UL);
/* checksum */
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0);
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0UL);
/* timestamp */
coverage_format(fd, "%08" G_GINT32_MODIFIER "X, ", 0);
coverage_format(fd, "%s\n", module->path);
@ -317,6 +330,12 @@ static void coverage_write_events(void *key, void *value, void *user_data) {
};
#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
evt.offset = __builtin_bswap32(evt.offset);
evt.length = __builtin_bswap16(evt.length);
evt.module = __builtin_bswap16(evt.module);
#endif
coverage_write(fd, &evt, sizeof(coverage_event_t));
}
@ -398,35 +417,76 @@ static void instrument_coverage_normal_run() {
instrument_coverage_print("Coverage - Preparing\n");
GArray *coverage_modules = coverage_get_modules();
if (instrument_coverage_absolute) {
guint size = g_hash_table_size(coverage_hash);
instrument_coverage_print("Coverage - Total Entries: %u\n", size);
guint size = g_hash_table_size(coverage_hash);
instrument_coverage_print("Coverage - Total Entries: %u\n", size);
coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
coverage_range_t module = {
g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx);
instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
.base_address = GUM_ADDRESS(0),
.limit = GUM_ADDRESS(-1),
.size = GUM_ADDRESS(-1),
.path = "absolute",
.offset = 0,
.is_executable = true,
.count = size,
.id = 0,
guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
instrument_coverage_print("Coverage - Marked Modules: %u\n",
coverage_marked_modules);
};
coverage_write_header(normal_coverage_fd, coverage_marked_modules);
coverage_write_modules(normal_coverage_fd, coverage_modules);
coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", ctx.count);
g_hash_table_foreach(coverage_hash, coverage_write_events,
&normal_coverage_fd);
instrument_coverage_print("Coverage Module - 0x%016" G_GINT64_MODIFIER
"X - 0x%016" G_GINT64_MODIFIER "X (%s)\n",
module.base_address, module.limit, module.path);
GArray *coverage_modules =
g_array_sized_new(false, false, sizeof(coverage_range_t), 1);
g_array_append_val(coverage_modules, module);
g_hash_table_foreach(coverage_hash, instrument_coverage_mark_first,
&module);
coverage_write_header(normal_coverage_fd, 1);
coverage_write_modules(normal_coverage_fd, coverage_modules);
coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", size);
g_hash_table_foreach(coverage_hash, coverage_write_events,
&normal_coverage_fd);
} else {
GArray *coverage_modules = coverage_get_modules();
guint size = g_hash_table_size(coverage_hash);
instrument_coverage_print("Coverage - Total Entries: %u\n", size);
coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
/* For each coverage event in the hashtable associate it with a module and
* count the number of entries per module */
g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx);
instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
/* For each module with coverage events assign it an incrementing number */
guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
instrument_coverage_print("Coverage - Marked Modules: %u\n",
coverage_marked_modules);
coverage_write_header(normal_coverage_fd, coverage_marked_modules);
coverage_write_modules(normal_coverage_fd, coverage_modules);
coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", ctx.count);
g_hash_table_foreach(coverage_hash, coverage_write_events,
&normal_coverage_fd);
}
g_hash_table_unref(coverage_hash);
instrument_coverage_print("Coverage - Completed\n");
}
static GArray *instrument_coverage_unstable_read_unstable_ids(void) {
gchar * contents = NULL;
gchar *contents = NULL;
gsize length = 0;
GArray *unstable_edge_ids =
g_array_sized_new(false, false, sizeof(gpointer), 100);
@ -533,7 +593,7 @@ static GHashTable *instrument_collect_unstable_blocks(
while (g_hash_table_iter_next(&iter, NULL, &value)) {
unstable_coverage_data_t *unstable = (unstable_coverage_data_t *)value;
normal_coverage_data_t * from =
normal_coverage_data_t *from =
gum_malloc0(sizeof(normal_coverage_data_t));
normal_coverage_data_t *to = gum_malloc0(sizeof(normal_coverage_data_t));
from->start = unstable->from;
@ -616,8 +676,6 @@ static void instrument_coverage_unstable_run(void) {
instrument_coverage_print("Coverage - Preparing\n");
GArray *coverage_modules = coverage_get_modules();
instrument_coverage_print("Found edges: %u\n", edges);
GArray *unstable_edge_ids = instrument_coverage_unstable_read_unstable_ids();
@ -628,20 +686,60 @@ static void instrument_coverage_unstable_run(void) {
guint size = g_hash_table_size(unstable_blocks);
instrument_coverage_print("Unstable blocks: %u\n", size);
coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
if (instrument_coverage_absolute) {
g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx);
instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
instrument_coverage_print("Coverage - Total Entries: %u\n", size);
guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
instrument_coverage_print("Coverage - Marked Modules: %u\n",
coverage_marked_modules);
coverage_range_t module = {
coverage_write_header(unstable_coverage_fd, coverage_marked_modules);
coverage_write_modules(unstable_coverage_fd, coverage_modules);
coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", ctx.count);
g_hash_table_foreach(unstable_blocks, coverage_write_events,
&unstable_coverage_fd);
.base_address = GUM_ADDRESS(0),
.limit = GUM_ADDRESS(-1),
.size = GUM_ADDRESS(-1),
.path = "absolute",
.offset = 0,
.is_executable = true,
.count = size,
.id = 0,
};
instrument_coverage_print("Coverage Module - 0x%016" G_GINT64_MODIFIER
"X - 0x%016" G_GINT64_MODIFIER "X (%s)\n",
module.base_address, module.limit, module.path);
GArray *coverage_modules =
g_array_sized_new(false, false, sizeof(coverage_range_t), 1);
g_array_append_val(coverage_modules, module);
g_hash_table_foreach(unstable_blocks, instrument_coverage_mark_first,
&module);
coverage_write_header(unstable_coverage_fd, 1);
coverage_write_modules(unstable_coverage_fd, coverage_modules);
coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", size);
g_hash_table_foreach(unstable_blocks, coverage_write_events,
&unstable_coverage_fd);
} else {
GArray *coverage_modules = coverage_get_modules();
coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx);
instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
instrument_coverage_print("Coverage - Marked Modules: %u\n",
coverage_marked_modules);
coverage_write_header(unstable_coverage_fd, coverage_marked_modules);
coverage_write_modules(unstable_coverage_fd, coverage_modules);
coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", ctx.count);
g_hash_table_foreach(unstable_blocks, coverage_write_events,
&unstable_coverage_fd);
}
g_hash_table_unref(unstable_blocks);
g_array_free(unstable_edge_ids, TRUE);
@ -654,22 +752,24 @@ static void instrument_coverage_unstable_run(void) {
void instrument_coverage_config(void) {
instrument_coverage_filename = getenv("AFL_FRIDA_INST_COVERAGE_FILE");
instrument_coverage_absolute =
(getenv("AFL_FRIDA_INST_COVERAGE_ABSOLUTE") != NULL);
}
void instrument_coverage_normal_init(void) {
FOKF("Coverage - enabled [%c]",
instrument_coverage_filename == NULL ? ' ' : 'X');
FOKF(cBLU "Instrumentation" cRST " - " cGRN "coverage:" cYEL " [%s]",
instrument_coverage_filename == NULL ? " "
: instrument_coverage_filename);
if (instrument_coverage_filename == NULL) { return; }
FOKF("Coverage - file [%s]", instrument_coverage_filename);
char *path = g_canonicalize_filename(instrument_coverage_filename,
g_get_current_dir());
FOKF("Coverage - path [%s]", path);
FOKF(cBLU "Instrumentation" cRST " - " cGRN "coverage path:" cYEL " [%s]",
path);
normal_coverage_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
@ -718,7 +818,7 @@ void instrument_coverage_unstable_find_output(void) {
GDir *dir = g_dir_open(fds_name, 0, NULL);
FOKF("Coverage Unstable - fds: %s", fds_name);
FVERBOSE("Coverage Unstable - fds: %s", fds_name);
for (const gchar *filename = g_dir_read_name(dir); filename != NULL;
filename = g_dir_read_name(dir)) {
@ -782,18 +882,24 @@ void instrument_coverage_unstable_find_output(void) {
}
FOKF("Fuzzer stats: %s", unstable_coverage_fuzzer_stats);
FVERBOSE("Fuzzer stats: %s", unstable_coverage_fuzzer_stats);
}
void instrument_coverage_unstable_init(void) {
FOKF(cBLU "Instrumentation" cRST " - " cGRN "unstable coverage:" cYEL " [%s]",
instrument_coverage_unstable_filename == NULL
? " "
: instrument_coverage_unstable_filename);
if (instrument_coverage_unstable_filename == NULL) { return; }
char *path = g_canonicalize_filename(instrument_coverage_unstable_filename,
g_get_current_dir());
FOKF("Coverage - unstable path [%s]", instrument_coverage_unstable_filename);
FOKF(cBLU "Instrumentation" cRST " - " cGRN "unstable coverage path:" cYEL
" [%s]",
path == NULL ? " " : path);
unstable_coverage_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);

View File

@ -35,6 +35,10 @@ static void instrument_debug(char *format, ...) {
static void instrument_disasm(guint8 *start, guint8 *end,
GumStalkerOutput *output) {
#if !defined(__arm__)
UNUSED_PARAMETER(output);
#endif
csh capstone;
cs_err err;
cs_mode mode;
@ -50,9 +54,7 @@ static void instrument_disasm(guint8 *start, guint8 *end,
if (output->encoding == GUM_INSTRUCTION_SPECIAL) { mode |= CS_MODE_THUMB; }
#endif
err = cs_open(GUM_DEFAULT_CS_ARCH,
CS_MODE_THUMB | GUM_DEFAULT_CS_MODE | GUM_DEFAULT_CS_ENDIAN,
&capstone);
err = cs_open(GUM_DEFAULT_CS_ARCH, mode, &capstone);
g_assert(err == CS_ERR_OK);
size = GPOINTER_TO_SIZE(end) - GPOINTER_TO_SIZE(start);
@ -64,7 +66,7 @@ static void instrument_disasm(guint8 *start, guint8 *end,
instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t* 0x%016" G_GSIZE_MODIFIER
"x\n",
curr, *(size_t *)curr);
(uint64_t)(size_t)curr, *(size_t *)curr);
len += sizeof(size_t);
continue;
@ -96,19 +98,15 @@ void instrument_debug_config(void) {
void instrument_debug_init(void) {
FOKF("Instrumentation debugging - enabled [%c]",
instrument_debug_filename == NULL ? ' ' : 'X');
if (instrument_debug_filename == NULL) { return; }
FOKF("Instrumentation debugging - file [%s]", instrument_debug_filename);
FOKF(cBLU "Instrumentation" cRST " - " cGRN "debugging:" cYEL " [%s]",
instrument_debug_filename == NULL ? " " : instrument_debug_filename);
if (instrument_debug_filename == NULL) { return; }
char *path =
g_canonicalize_filename(instrument_debug_filename, g_get_current_dir());
FOKF("Instrumentation debugging - path [%s]", path);
FOKF(cBLU "Instrumentation" cRST " - " cGRN "path:" cYEL " [%s]", path);
debugging_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);

View File

@ -23,13 +23,39 @@
#if defined(__x86_64__)
#ifndef MAP_FIXED_NOREPLACE
#ifdef MAP_EXCL
#define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
#else
#define MAP_FIXED_NOREPLACE MAP_FIXED
#endif
#endif
enum jcc_opcodes {
OPC_JO = 0x70,
OPC_JNO = 0x71,
OPC_JB = 0x72,
OPC_JAE = 0x73,
OPC_JE = 0x74,
OPC_JNE = 0x75,
OPC_JBE = 0x76,
OPC_JA = 0x77,
OPC_JS = 0x78,
OPC_JNS = 0x79,
OPC_JP = 0x7a,
OPC_JNP = 0x7b,
OPC_JL = 0x7c,
OPC_JGE = 0x7d,
OPC_JLE = 0x7e,
OPC_JG = 0x7f,
};
typedef union {
struct {
uint8_t opcode;
uint8_t distance;
};
uint8_t bytes[0];
} jcc_insn;
static GHashTable *coverage_blocks = NULL;
@ -45,8 +71,7 @@ static gboolean instrument_coverage_in_range(gssize offset) {
}
#ifdef __APPLE__
#pragma pack(push, 1)
#pragma pack(push, 1)
typedef struct {
@ -54,21 +79,28 @@ typedef struct {
// shared_mem[cur_location ^ prev_location]++;
// prev_location = cur_location >> 1;
// mov QWORD PTR [rsp-0x80],rax
// lahf
// mov QWORD PTR [rsp-0x88],rax
// mov QWORD PTR [rsp-0x90],rbx
// mov eax,DWORD PTR [rip+0x333d5a] # 0x7ffff6ff2740
// mov DWORD PTR [rip+0x333d3c],0x9fbb # 0x7ffff6ff2740
// lea rax,[rip + 0x103f77]
// mov bl,BYTE PTR [rax]
// add bl,0x1
// adc bl,0x0
// mov BYTE PTR [rax],bl
// mov rbx,QWORD PTR [rsp-0x90]
// mov rax,QWORD PTR [rsp-0x88]
// sahf
// mov rax,QWORD PTR [rsp-0x80]
// mov QWORD PTR [rsp-0x88],rax
// lahf
// mov QWORD PTR [rsp-0x90],rax
// mov QWORD PTR [rsp-0x98],rbx
// mov eax,DWORD PTR [rip+0x1312334]
// xor eax,0x3f77
// lea rbx,[rip+0x132338]
// add rax,rbx
// mov bl,BYTE PTR [rax]
// add bl,0x1
// adc bl,0x0
// mov BYTE PTR [rax],bl
// mov rbx,QWORD PTR [rsp-0x98]
// mov rax,QWORD PTR [rsp-0x90]
// sahf
// mov rax,QWORD PTR [rsp-0x88]
// mov DWORD PTR [rip+0x13122f8],0x9fbb
uint8_t mov_rax_rsp_88[8];
uint8_t lahf;
@ -76,84 +108,11 @@ typedef struct {
uint8_t mov_rbx_rsp_98[8];
uint8_t mov_eax_prev_loc[6];
uint8_t mov_prev_loc_curr_loc_shr1[10];
uint8_t leax_eax_curr_loc[7];
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_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_t;
#pragma pack(pop)
static const afl_log_code_asm_t template =
{
.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_eax_prev_loc = {0x8b, 0x05},
.mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05},
.leax_eax_curr_loc = {0x48, 0x8d, 0x05},
.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_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},
}
;
#else
#pragma pack(push, 1)
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-0x80],rax
// lahf
// mov QWORD PTR [rsp-0x88],rax
// mov QWORD PTR [rsp-0x90],rbx
// mov eax,DWORD PTR [rip+0x333d5a] # 0x7ffff6ff2740
// mov DWORD PTR [rip+0x333d3c],0x9fbb # 0x7ffff6ff2740
// xor eax,0x103f77
// mov bl,BYTE PTR [rax]
// add bl,0x1
// adc bl,0x0
// mov BYTE PTR [rax],bl
// mov rbx,QWORD PTR [rsp-0x90]
// mov rax,QWORD PTR [rsp-0x88]
// sahf
// mov rax,QWORD PTR [rsp-0x80]
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_eax_prev_loc[6];
uint8_t mov_prev_loc_curr_loc_shr1[10];
uint8_t xor_eax_curr_loc[5];
uint8_t lea_rbx_area_ptr[7];
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];
@ -164,9 +123,11 @@ typedef struct {
uint8_t sahf;
uint8_t mov_rsp_88_rax[8];
uint8_t mov_prev_loc_curr_loc_shr1[10];
} afl_log_code_asm_t;
#pragma pack(pop)
#pragma pack(pop)
static const afl_log_code_asm_t template =
{
@ -177,9 +138,10 @@ static const afl_log_code_asm_t template =
.mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
.mov_eax_prev_loc = {0x8b, 0x05},
.mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05},
.xor_eax_curr_loc = {0x35},
.lea_rbx_area_ptr = {0x48, 0x8d, 0x1d},
.add_rax_rbx = {0x48, 0x01, 0xd8},
.mov_rbx_ptr_rax = {0x8a, 0x18},
.add_bl_1 = {0x80, 0xc3, 0x01},
.adc_bl_0 = {0x80, 0xd3, 0x00},
@ -190,10 +152,11 @@ static const afl_log_code_asm_t template =
.sahf = 0x9e,
.mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
.mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05},
}
;
#endif
typedef union {
@ -202,179 +165,22 @@ typedef union {
} afl_log_code;
#ifdef __APPLE__
void instrument_coverage_optimize_init(void) {
}
#else
static gboolean instrument_coverage_find_low(const GumRangeDetails *details,
gpointer user_data) {
static GumAddress last_limit = (64ULL << 10);
gpointer * address = (gpointer *)user_data;
if ((details->range->base_address - last_limit) > __afl_map_size) {
*address = GSIZE_TO_POINTER(last_limit);
return FALSE;
}
if (details->range->base_address > ((2ULL << 30) - __afl_map_size)) {
return FALSE;
}
/*
* Align our buffer on a 64k boundary so that the low 16-bits of the address
* are zero, then we can just XOR the base address in, when we XOR with the
* current block ID.
*/
last_limit = GUM_ALIGN_SIZE(
details->range->base_address + details->range->size, (64ULL << 10));
return TRUE;
FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr);
}
static void instrument_coverage_optimize_map_mmap_anon(gpointer address) {
__afl_area_ptr =
mmap(address, __afl_map_size, PROT_READ | PROT_WRITE,
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (__afl_area_ptr != address) {
FATAL("Failed to map mmap __afl_area_ptr: %d", errno);
}
}
static void instrument_coverage_optimize_map_mmap(char * shm_file_path,
gpointer address) {
int shm_fd = -1;
if (munmap(__afl_area_ptr, __afl_map_size) != 0) {
FATAL("Failed to unmap previous __afl_area_ptr");
}
__afl_area_ptr = NULL;
#if !defined(__ANDROID__)
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
if (shm_fd == -1) { FATAL("shm_open() failed\n"); }
#else
shm_fd = open("/dev/ashmem", O_RDWR);
if (shm_fd == -1) { FATAL("open() failed\n"); }
if (ioctl(shm_fd, ASHMEM_SET_NAME, shm_file_path) == -1) {
FATAL("ioctl(ASHMEM_SET_NAME) failed");
}
if (ioctl(shm_fd, ASHMEM_SET_SIZE, __afl_map_size) == -1) {
FATAL("ioctl(ASHMEM_SET_SIZE) failed");
}
#endif
__afl_area_ptr = mmap(address, __afl_map_size, PROT_READ | PROT_WRITE,
MAP_FIXED_NOREPLACE | MAP_SHARED, shm_fd, 0);
if (__afl_area_ptr != address) {
FATAL("Failed to map mmap __afl_area_ptr: %d", errno);
}
if (close(shm_fd) != 0) { FATAL("Failed to close shm_fd"); }
}
static void instrument_coverage_optimize_map_shm(guint64 shm_env_val,
gpointer address) {
if (shmdt(__afl_area_ptr) != 0) {
FATAL("Failed to detach previous __afl_area_ptr");
}
__afl_area_ptr = shmat(shm_env_val, address, 0);
if (__afl_area_ptr != address) {
FATAL("Failed to map shm __afl_area_ptr: %d", errno);
}
}
void instrument_coverage_optimize_init(void) {
gpointer low_address = NULL;
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, instrument_coverage_find_low,
&low_address);
FOKF("Low address: %p", low_address);
if (low_address == 0 ||
GPOINTER_TO_SIZE(low_address) > ((2UL << 20) - __afl_map_size)) {
FATAL("Invalid low_address: %p", low_address);
}
ranges_print_debug_maps();
char *shm_env = getenv(SHM_ENV_VAR);
FOKF("SHM_ENV_VAR: %s", shm_env);
if (shm_env == NULL) {
FWARNF("SHM_ENV_VAR not set, using anonymous map for debugging purposes");
instrument_coverage_optimize_map_mmap_anon(low_address);
} else {
guint64 shm_env_val = g_ascii_strtoull(shm_env, NULL, 10);
if (shm_env_val == 0) {
instrument_coverage_optimize_map_mmap(shm_env, low_address);
} else {
instrument_coverage_optimize_map_shm(shm_env_val, low_address);
}
}
FOKF("__afl_area_ptr: %p", __afl_area_ptr);
FOKF("instrument_previous_pc: %p", &instrument_previous_pc);
}
#endif
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn * from_insn,
gpointer * target) {
const cs_insn *from_insn,
gpointer *target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(start_address);
UNUSED_PARAMETER(from_address);
cs_x86 * x86;
cs_x86 *x86;
cs_x86_op *op;
if (from_insn == NULL) { return; }
@ -397,10 +203,17 @@ static void instrument_coverage_switch(GumStalkerObserver *self,
}
if (op[0].type != X86_OP_IMM) { return; }
if (op[0].type != X86_OP_IMM) {
instrument_cache_insert(start_address, *target);
return;
}
break;
case X86_INS_RET:
instrument_cache_insert(start_address,
(guint8 *)*target + sizeof(afl_log_code));
break;
default:
return;
@ -417,7 +230,7 @@ static void instrument_coverage_suppress_init(void) {
if (initialized) { return; }
initialized = true;
GumStalkerObserver * observer = stalker_get_observer();
GumStalkerObserver *observer = stalker_get_observer();
GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer);
iface->switch_callback = instrument_coverage_switch;
@ -430,39 +243,22 @@ static void instrument_coverage_suppress_init(void) {
}
void instrument_coverage_optimize(const cs_insn * instr,
GumStalkerOutput *output) {
static void instrument_coverage_write(GumAddress address,
GumStalkerOutput *output) {
afl_log_code code = {0};
GumX86Writer *cw = output->writer.x86;
guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
gsize map_size_pow2;
gsize area_offset_ror;
GumAddress code_addr = 0;
instrument_coverage_suppress_init();
// gum_x86_writer_put_breakpoint(cw);
code_addr = cw->pc;
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
FATAL("Failed - g_hash_table_add");
}
guint64 area_offset = instrument_get_offset_hash(address);
gsize map_size_pow2;
gsize area_offset_ror;
GumAddress code_addr = cw->pc;
code.code = template;
gssize curr_loc_shr_1_offset =
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);
/* mov_prev_loc_curr_loc_shr1 */
gssize prev_loc_value =
GPOINTER_TO_SIZE(&instrument_previous_pc) -
GPOINTER_TO_SIZE(instrument_previous_pc_addr) -
(code_addr + offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
sizeof(code.code.mov_prev_loc_curr_loc_shr1));
gssize prev_loc_value_offset =
@ -477,8 +273,10 @@ void instrument_coverage_optimize(const cs_insn * instr,
*((gint *)&code.bytes[prev_loc_value_offset]) = (gint)prev_loc_value;
/* mov_eax_prev_loc */
gssize prev_loc_value2 =
GPOINTER_TO_SIZE(&instrument_previous_pc) -
GPOINTER_TO_SIZE(instrument_previous_pc_addr) -
(code_addr + offsetof(afl_log_code, code.mov_eax_prev_loc) +
sizeof(code.code.mov_eax_prev_loc));
gssize prev_loc_value_offset2 =
@ -492,40 +290,172 @@ void instrument_coverage_optimize(const cs_insn * instr,
*((gint *)&code.bytes[prev_loc_value_offset2]) = (gint)prev_loc_value2;
#ifdef __APPLE__
gssize xor_curr_loc_offset = offsetof(afl_log_code, code.leax_eax_curr_loc) +
sizeof(code.code.leax_eax_curr_loc) -
sizeof(guint32);
gssize xor_curr_loc_value =
((GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset) -
(code_addr + offsetof(afl_log_code, code.mov_eax_prev_loc) +
sizeof(code.code.mov_eax_prev_loc)));
if (!instrument_coverage_in_range(xor_curr_loc_value)) {
FATAL("Patch out of range (xor_curr_loc_value): 0x%016lX",
xor_curr_loc_value);
}
*((guint32 *)&code.bytes[xor_curr_loc_offset]) = xor_curr_loc_value;
#else
/* xor_eax_curr_loc */
gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) +
sizeof(code.code.xor_eax_curr_loc) -
sizeof(guint32);
*((guint32 *)&code.bytes[xor_curr_loc_offset]) =
(guint32)(GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset);
#endif
*((guint32 *)&code.bytes[xor_curr_loc_offset]) = area_offset;
/* lea_rbx_area_ptr */
gssize lea_rbx_area_ptr_offset =
offsetof(afl_log_code, code.lea_rbx_area_ptr) +
sizeof(code.code.lea_rbx_area_ptr) - sizeof(guint32);
gssize lea_rbx_area_ptr_value =
(GPOINTER_TO_SIZE(__afl_area_ptr) -
(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);
}
*((guint32 *)&code.bytes[lea_rbx_area_ptr_offset]) = lea_rbx_area_ptr_value;
/* mov_prev_loc_curr_loc_shr1 */
gssize curr_loc_shr_1_offset =
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);
gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
}
void instrument_coverage_optimize(const cs_insn *instr,
GumStalkerOutput *output) {
GumX86Writer *cw = output->writer.x86;
if (instrument_previous_pc_addr == NULL) {
GumAddressSpec spec = {.near_address = cw->code,
.max_distance = 1ULL << 30};
guint page_size = gum_query_page_size();
instrument_previous_pc_addr = gum_memory_allocate_near(
&spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE);
*instrument_previous_pc_addr = instrument_hash_zero;
FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
FVERBOSE("code_addr: %p", cw->code);
}
instrument_coverage_suppress_init();
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
FATAL("Failed - g_hash_table_add");
}
instrument_coverage_write(GUM_ADDRESS(instr->address), output);
}
void instrument_coverage_optimize_insn(const cs_insn *instr,
GumStalkerOutput *output) {
GumX86Writer *cw = output->writer.x86;
jcc_insn taken, not_taken;
switch (instr->id) {
case X86_INS_CMOVA:
taken.opcode = OPC_JA;
not_taken.opcode = OPC_JBE;
break;
case X86_INS_CMOVAE:
taken.opcode = OPC_JAE;
not_taken.opcode = OPC_JB;
break;
case X86_INS_CMOVB:
taken.opcode = OPC_JB;
not_taken.opcode = OPC_JAE;
break;
case X86_INS_CMOVBE:
taken.opcode = OPC_JBE;
not_taken.opcode = OPC_JA;
break;
case X86_INS_CMOVE:
taken.opcode = OPC_JE;
not_taken.opcode = OPC_JNE;
break;
case X86_INS_CMOVG:
taken.opcode = OPC_JG;
not_taken.opcode = OPC_JLE;
break;
case X86_INS_CMOVGE:
taken.opcode = OPC_JGE;
not_taken.opcode = OPC_JL;
break;
case X86_INS_CMOVL:
taken.opcode = OPC_JL;
not_taken.opcode = OPC_JGE;
break;
case X86_INS_CMOVLE:
taken.opcode = OPC_JLE;
not_taken.opcode = OPC_JG;
break;
case X86_INS_CMOVNE:
taken.opcode = OPC_JNE;
not_taken.opcode = OPC_JE;
break;
case X86_INS_CMOVNO:
taken.opcode = OPC_JNO;
not_taken.opcode = OPC_JO;
break;
case X86_INS_CMOVNP:
taken.opcode = OPC_JNP;
not_taken.opcode = OPC_JP;
break;
case X86_INS_CMOVNS:
taken.opcode = OPC_JNS;
not_taken.opcode = OPC_JS;
break;
case X86_INS_CMOVO:
taken.opcode = OPC_JO;
not_taken.opcode = OPC_JNO;
break;
case X86_INS_CMOVP:
taken.opcode = OPC_JP;
not_taken.opcode = OPC_JNP;
break;
case X86_INS_CMOVS:
taken.opcode = OPC_JS;
not_taken.opcode = OPC_JNS;
break;
default:
return;
}
taken.distance = sizeof(afl_log_code);
not_taken.distance = sizeof(afl_log_code);
// gum_x86_writer_put_breakpoint(cw);
gum_x86_writer_put_bytes(cw, taken.bytes, sizeof(jcc_insn));
instrument_coverage_write(GUM_ADDRESS(instr->address), output);
gum_x86_writer_put_bytes(cw, not_taken.bytes, sizeof(jcc_insn));
instrument_coverage_write(GUM_ADDRESS(instr->address + instr->size), output);
FVERBOSE("Instrument - 0x%016lx: %s %s", instr->address, instr->mnemonic,
instr->op_str);
}
void instrument_flush(GumStalkerOutput *output) {
gum_x86_writer_flush(output->writer.x86);
@ -538,5 +468,24 @@ gpointer instrument_cur(GumStalkerOutput *output) {
}
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
int fd = (int)(size_t)user_data;
instrument_regs_format(
fd, "rax: 0x%016x, rbx: 0x%016x, rcx: 0x%016x, rdx: 0x%016x\n",
cpu_context->rax, cpu_context->rbx, cpu_context->rcx, cpu_context->rdx);
instrument_regs_format(
fd, "rdi: 0x%016x, rsi: 0x%016x, rbp: 0x%016x, rsp: 0x%016x\n",
cpu_context->rdi, cpu_context->rsi, cpu_context->rbp, cpu_context->rsp);
instrument_regs_format(
fd, "r8 : 0x%016x, r9 : 0x%016x, r10: 0x%016x, r11: 0x%016x\n",
cpu_context->r8, cpu_context->r9, cpu_context->r10, cpu_context->r11);
instrument_regs_format(
fd, "r12: 0x%016x, r13: 0x%016x, r14: 0x%016x, r15: 0x%016x\n",
cpu_context->r12, cpu_context->r13, cpu_context->r14, cpu_context->r15);
instrument_regs_format(fd, "rip: 0x%016x\n\n", cpu_context->rip);
}
#endif

View File

@ -0,0 +1,435 @@
#include <sys/mman.h>
#include <sys/resource.h>
#include "instrument.h"
#include "util.h"
#if defined(__x86_64__)
#define INVALID 1
#define DEFAULT_CACHE_SIZE (256ULL << 20)
gboolean instrument_cache_enabled = TRUE;
gsize instrument_cache_size = DEFAULT_CACHE_SIZE;
static gpointer *map_base = MAP_FAILED;
void instrument_cache_config(void) {
instrument_cache_enabled = (getenv("AFL_FRIDA_INST_NO_CACHE") == NULL);
if (getenv("AFL_FRIDA_INST_CACHE_SIZE") != NULL) {
if (!instrument_cache_enabled) {
FFATAL(
"AFL_FRIDA_INST_CACHE_SIZE incomatible with "
"AFL_FRIDA_INST_NO_CACHE");
}
instrument_cache_size =
util_read_address("AFL_FRIDA_INST_CACHE_SIZE", DEFAULT_CACHE_SIZE);
util_log2(instrument_cache_size);
}
}
void instrument_cache_init(void) {
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache:" cYEL " [%c]",
instrument_cache_enabled ? 'X' : ' ');
if (!instrument_cache_enabled) { return; }
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache size:" cYEL " [0x%016lX]",
instrument_cache_size);
const struct rlimit data_limit = {.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY};
if (setrlimit(RLIMIT_AS, &data_limit) != 0) {
FFATAL("Failed to setrlimit: %d", errno);
}
map_base =
gum_memory_allocate(NULL, instrument_cache_size, instrument_cache_size,
GUM_PAGE_READ | GUM_PAGE_WRITE);
if (map_base == MAP_FAILED) { FFATAL("Failed to map segment: %d", errno); }
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache addr:" cYEL " [0x%016lX]",
GUM_ADDRESS(map_base));
}
static gpointer *instrument_cache_get_addr(gpointer addr) {
gsize mask = (instrument_cache_size / sizeof(gpointer)) - 1;
return &map_base[GPOINTER_TO_SIZE(addr) & mask];
}
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
if (!instrument_cache_enabled) { return; }
gpointer *target = instrument_cache_get_addr(real_address);
if (*target == code_address) {
return;
} else if (*target == NULL) {
*target = code_address;
} else {
*target = GSIZE_TO_POINTER(INVALID);
}
}
static gboolean instrument_cache_relocate(GumAddress old_pc, GumAddress new_pc,
gint32 old_offset,
gint32 *new_offset) {
guint64 old_target = old_pc + old_offset;
gint64 relocated = old_target - new_pc;
if (relocated > G_MAXINT32 || relocated < G_MININT32) { return FALSE; }
*new_offset = relocated;
return TRUE;
}
static void instrument_cache_rewrite_branch_insn(const cs_insn *instr,
GumStalkerOutput *output) {
GumX86Writer *cw = output->writer.x86;
cs_x86 *x86 = &instr->detail->x86;
guint8 modified[sizeof(instr->bytes)] = {0};
guint8 offset = 0;
guint8 skip = 0;
g_assert(sizeof(x86->prefix) == 4);
g_assert(sizeof(x86->opcode) == 4);
/*
* If the target is simply RAX, we can skip writing the code to load the
* RIP
*/
if (x86->operands[0].type == X86_OP_REG ||
x86->operands[0].reg == X86_REG_RAX) {
return;
}
/* Write the prefix */
for (gsize i = 0; i < sizeof(x86->prefix); i++) {
if (x86->prefix[i] != 0) {
if (x86->prefix[i] == 0xf2) {
skip++;
} else {
modified[offset++] = x86->prefix[i];
skip++;
}
}
}
/* Write the REX */
if (x86->rex == 0) {
/*
* CALL (near) and JMP (near) default to 64-bit operands, MOV does not,
* write REX.W
*/
modified[offset++] = 0x48;
} else {
if ((x86->rex & 0xF8) != 0x40) {
FATAL("Unexpected REX byte: 0x%02x", x86->rex);
}
modified[offset++] = x86->rex | 0x08;
skip++;
}
/*
* CALL is FF /2, JMP is FF /4. The remaining op-code fields should thus be
* unused
*/
if (x86->opcode[0] != 0xFF || x86->opcode[1] != 0x00 ||
x86->opcode[2] != 0x00 || x86->opcode[3] != 0x00) {
FFATAL("Unexpected Op-code: 0x%02x 0x%02x 0x%02x 0x%02x", x86->opcode[0],
x86->opcode[1], x86->opcode[2], x86->opcode[3]);
}
/* The reg field of the ModRM should be set to 2 for CALL and 4 for JMP */
guint8 reg = (x86->modrm >> 3) & 7;
if (reg != 0x4 && reg != 0x2) {
FFATAL("Unexpected Reg: 0x%02x, ModRM: 0x%02x", reg, x86->modrm);
}
/* MOV */
modified[offset++] = 0x8b;
skip++;
/* Clear the reg field (RAX) */
modified[offset++] = x86->modrm & 0xc7;
skip++;
/* Operands */
guint8 op_len = instr->size - skip;
/* If our branch was RIP relative, we'll need to fix-up the offset */
if (x86->operands[0].type == X86_OP_MEM &&
x86->operands[0].mem.base == X86_REG_RIP) {
/* RIP relative offsets should be 32-bits */
if (op_len != sizeof(gint32)) {
FFATAL("Unexpected operand length: %d\n", op_len);
}
gint32 old_offset = *(gint32 *)&instr->bytes[skip];
gint32 new_offset = 0;
if (instrument_cache_relocate(instr->address, cw->pc, old_offset,
&new_offset)) {
gint32 *output = (gint32 *)&modified[offset];
*output = new_offset;
offset += sizeof(gint32);
} else {
GumAddress target = instr->address + old_offset;
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, target);
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_X86_RAX, GUM_X86_RAX);
return;
}
} else {
for (int i = 0; i < op_len; i++) {
guint8 val = instr->bytes[i + skip];
modified[offset++] = val;
}
}
gum_x86_writer_put_bytes(cw, modified, offset);
}
static void instrument_cache_write_push_frame(GumX86Writer *cw) {
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))),
GUM_X86_XAX);
gum_x86_writer_put_lahf(cw);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (2 * sizeof(gpointer))),
GUM_X86_XAX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (3 * sizeof(gpointer))),
GUM_X86_XBX);
}
static void instrument_cache_write_pop_frame(GumX86Writer *cw) {
gum_x86_writer_put_mov_reg_reg_offset_ptr(
cw, GUM_X86_XBX, GUM_X86_XSP,
-(GUM_RED_ZONE_SIZE + (3 * sizeof(gpointer))));
gum_x86_writer_put_mov_reg_reg_offset_ptr(
cw, GUM_X86_XAX, GUM_X86_XSP,
-(GUM_RED_ZONE_SIZE + (2 * sizeof(gpointer))));
gum_x86_writer_put_sahf(cw);
gum_x86_writer_put_mov_reg_reg_offset_ptr(
cw, GUM_X86_XAX, GUM_X86_XSP,
-(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))));
}
static void instrument_cache_write_lookup(GumX86Writer *cw) {
/* &map_base[GPOINTER_TO_SIZE(addr) & MAP_MASK]; */
gsize mask = (instrument_cache_size / sizeof(gpointer)) - 1;
gum_x86_writer_put_mov_reg_u64(cw, GUM_X86_XBX, mask);
gum_x86_writer_put_and_reg_reg(cw, GUM_X86_XAX, GUM_X86_XBX);
gum_x86_writer_put_shl_reg_u8(cw, GUM_X86_XAX, util_log2(sizeof(gpointer)));
gum_x86_writer_put_mov_reg_u64(cw, GUM_X86_XBX, GPOINTER_TO_SIZE(map_base));
gum_x86_writer_put_add_reg_reg(cw, GUM_X86_XAX, GUM_X86_XBX);
/* Read the return address lookup */
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_X86_XAX, GUM_X86_XAX);
}
void instrument_cache_jmp_call(const cs_insn *instr, GumStalkerOutput *output) {
GumX86Writer *cw = output->writer.x86;
cs_x86 *x86 = &instr->detail->x86;
if (x86->op_count != 1) { FFATAL("Unexpected operand count"); }
if (x86->operands[0].type == X86_OP_IMM) { return; }
gconstpointer null = cw->code;
instrument_cache_write_push_frame(cw);
/*
* We are about to re-write the CALL or JMP instruction, but replace the
* op-code with that for a MOV into RAX. Since we are keeping the operand from
* the JMP exactly the same, it is imperative that the target register state
* be exactly the same as how the target left it. Since `LAHF` spoils `RAX` we
* must restore it from the stack. We also must avoid adjusting `RSP`, so we
* use `MOV` instructions to store our context into the stack beyond the
* red-zone.
*/
gum_x86_writer_put_mov_reg_reg_offset_ptr(
cw, GUM_X86_XAX, GUM_X86_XSP,
-(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))));
instrument_cache_rewrite_branch_insn(instr, output);
instrument_cache_write_lookup(cw);
/* Test if its set*/
gum_x86_writer_put_cmp_reg_i32(cw, GUM_X86_XAX, INVALID);
gum_x86_writer_put_jcc_short_label(cw, X86_INS_JLE, null, GUM_UNLIKELY);
/* If it's set, then stash the address beyond the red-zone */
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (4 * sizeof(gpointer))),
GUM_X86_XAX);
if (instr->id == X86_INS_JMP) {
instrument_cache_write_pop_frame(cw);
gum_x86_writer_put_jmp_reg_offset_ptr(
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (4 * sizeof(gpointer))));
} else {
gum_x86_writer_put_mov_reg_address(
cw, GUM_X86_XAX, GUM_ADDRESS(instr->address + instr->size));
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_X86_XSP,
-sizeof(gpointer), GUM_X86_XAX);
instrument_cache_write_pop_frame(cw);
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_XSP, GUM_X86_XSP,
-sizeof(gpointer));
gum_x86_writer_put_jmp_reg_offset_ptr(
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + ((4 - 1) * sizeof(gpointer))));
}
/* Tidy up our mess and let FRIDA handle it */
gum_x86_writer_put_label(cw, null);
instrument_cache_write_pop_frame(cw);
}
void instrument_cache_ret(const cs_insn *instr, GumStalkerOutput *output) {
GumX86Writer *cw = output->writer.x86;
cs_x86 *x86 = &instr->detail->x86;
guint16 n = 0;
if (x86->op_count != 0) {
if (x86->operands[0].type != X86_OP_IMM) {
FFATAL("Unexpected operand type");
}
n = x86->operands[0].imm;
}
gconstpointer null = cw->code;
instrument_cache_write_push_frame(cw);
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_X86_XAX, GUM_X86_XSP);
instrument_cache_write_lookup(cw);
/* Test if its set*/
gum_x86_writer_put_cmp_reg_i32(cw, GUM_X86_XAX, INVALID);
gum_x86_writer_put_jcc_short_label(cw, X86_INS_JLE, null, GUM_UNLIKELY);
/* If it's set, then overwrite our return address and return */
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_X86_XSP, GUM_X86_XAX);
instrument_cache_write_pop_frame(cw);
if (n == 0) {
gum_x86_writer_put_ret(cw);
} else {
gum_x86_writer_put_ret_imm(cw, n);
}
/* Tidy up our mess and let FRIDA handle it */
gum_x86_writer_put_label(cw, null);
instrument_cache_write_pop_frame(cw);
}
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
if (!instrument_cache_enabled) { return; }
switch (instr->id) {
case X86_INS_RET:
instrument_cache_ret(instr, output);
break;
case X86_INS_CALL:
case X86_INS_JMP:
instrument_cache_jmp_call(instr, output);
break;
default:
return;
}
}
#endif

View File

@ -6,6 +6,9 @@
#if defined(__i386__)
gboolean instrument_cache_enabled = FALSE;
gsize instrument_cache_size = 0;
static GHashTable *coverage_blocks = NULL;
#pragma pack(push, 1)
@ -81,14 +84,16 @@ 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) {
const cs_insn *from_insn,
gpointer *target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(from_address);
UNUSED_PARAMETER(start_address);
cs_x86 * x86;
cs_x86 *x86;
cs_x86_op *op;
if (from_insn == NULL) { return; }
@ -131,7 +136,7 @@ static void instrument_coverage_suppress_init(void) {
if (initialized) { return; }
initialized = true;
GumStalkerObserver * observer = stalker_get_observer();
GumStalkerObserver *observer = stalker_get_observer();
GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer);
iface->switch_callback = instrument_coverage_switch;
@ -144,7 +149,7 @@ static void instrument_coverage_suppress_init(void) {
}
void instrument_coverage_optimize(const cs_insn * instr,
void instrument_coverage_optimize(const cs_insn *instr,
GumStalkerOutput *output) {
afl_log_code code = {0};
@ -153,6 +158,20 @@ void instrument_coverage_optimize(const cs_insn * instr,
gsize map_size_pow2;
gsize area_offset_ror;
if (instrument_previous_pc_addr == NULL) {
GumAddressSpec spec = {.near_address = cw->code,
.max_distance = 1ULL << 30};
guint page_size = gum_query_page_size();
instrument_previous_pc_addr = gum_memory_allocate_near(
&spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE);
*instrument_previous_pc_addr = instrument_hash_zero;
FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
FVERBOSE("code_addr: %p", cw->code);
}
code.code = template;
instrument_coverage_suppress_init();
@ -170,7 +189,7 @@ void instrument_coverage_optimize(const cs_insn * instr,
sizeof(code.code.mov_eax_prev_loc) - sizeof(gint);
*((gint *)&code.bytes[prev_loc_value_offset2]) =
(gint)GPOINTER_TO_SIZE(&instrument_previous_pc);
(gint)GPOINTER_TO_SIZE(instrument_previous_pc_addr);
gssize curr_loc_shr_1_offset =
offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
@ -187,7 +206,7 @@ void instrument_coverage_optimize(const cs_insn * instr,
sizeof(guint32);
*((gint *)&code.bytes[prev_loc_value_offset]) =
(gint)GPOINTER_TO_SIZE(&instrument_previous_pc);
(gint)GPOINTER_TO_SIZE(instrument_previous_pc_addr);
gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) +
sizeof(code.code.xor_eax_curr_loc) -
@ -205,6 +224,14 @@ void instrument_coverage_optimize(const cs_insn * instr,
}
void instrument_coverage_optimize_insn(const cs_insn *instr,
GumStalkerOutput *output) {
UNUSED_PARAMETER(instr);
UNUSED_PARAMETER(output);
}
void instrument_coverage_optimize_init(void) {
}
@ -221,5 +248,40 @@ gpointer instrument_cur(GumStalkerOutput *output) {
}
void instrument_cache_config(void) {
}
void instrument_cache_init(void) {
}
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
UNUSED_PARAMETER(real_address);
UNUSED_PARAMETER(code_address);
}
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
UNUSED_PARAMETER(instr);
UNUSED_PARAMETER(output);
}
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
int fd = (int)(size_t)user_data;
instrument_regs_format(
fd, "eax: 0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x\n",
cpu_context->eax, cpu_context->ebx, cpu_context->ecx, cpu_context->edx);
instrument_regs_format(
fd, "esi: 0x%08x, edi: 0x%08x, ebp: 0x%08x, esp: 0x%08x\n",
cpu_context->esi, cpu_context->edi, cpu_context->ebp, cpu_context->esp);
instrument_regs_format(fd, "eip: 0x%08x\n\n", cpu_context->eip);
}
#endif

View File

@ -7,8 +7,8 @@ void intercept_hook(void *address, gpointer replacement, gpointer user_data) {
GumInterceptor *interceptor = gum_interceptor_obtain();
gum_interceptor_begin_transaction(interceptor);
GumReplaceReturn ret =
gum_interceptor_replace(interceptor, address, replacement, user_data);
GumReplaceReturn ret = gum_interceptor_replace(interceptor, address,
replacement, user_data, NULL);
if (ret != GUM_REPLACE_OK) { FFATAL("gum_interceptor_attach: %d", ret); }
gum_interceptor_end_transaction(interceptor);

View File

@ -63,11 +63,17 @@ class Afl {
Afl.jsApiWrite(STDOUT_FILENO, buf, log.length);
}
/**
* See `AFL_FRIDA_INST_NO_BACKPATCH`.
* See `AFL_FRIDA_STALKER_NO_BACKPATCH`.
*/
static setBackpatchDisable() {
Afl.jsApiSetBackpatchDisable();
}
/**
* See `AFL_FRIDA_INST_NO_CACHE`.
*/
static setCacheDisable() {
Afl.jsApiSetCacheDisable();
}
/**
* See `AFL_FRIDA_DEBUG_MAPS`.
*/
@ -91,6 +97,19 @@ class Afl {
static setInMemoryFuzzing() {
Afl.jsApiAflSharedMemFuzzing.writeInt(1);
}
/**
* See `AFL_FRIDA_INST_CACHE_SIZE`. This function takes a single `number`
* as an argument.
*/
static setInstrumentCacheSize(size) {
Afl.jsApiSetInstrumentCacheSize(size);
}
/**
* See `AFL_FRIDA_INST_COVERAGE_ABSOLUTE`.
*/
static setInstrumentCoverageAbsolute() {
Afl.jsApiSetInstrumentCoverageAbsolute();
}
/**
* See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
* as an argument.
@ -113,6 +132,12 @@ class Afl {
static setInstrumentEnableTracing() {
Afl.jsApiSetInstrumentTrace();
}
/**
* See `AFL_FRIDA_INST_INSN`
*/
static setInstrumentInstructions() {
Afl.jsApiSetInstrumentInstructions();
}
/**
* See `AFL_FRIDA_INST_JIT`.
*/
@ -131,6 +156,14 @@ class Afl {
static setInstrumentNoOptimize() {
Afl.jsApiSetInstrumentNoOptimize();
}
/**
* See `AFL_FRIDA_INST_REGS_FILE`. This function takes a single `string` as
* an argument.
*/
static setInstrumentRegsFile(file) {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetInstrumentRegsFile(buf);
}
/*
* See `AFL_FRIDA_INST_SEED`
*/
@ -268,6 +301,12 @@ class Afl {
static setTraceable() {
Afl.jsApiSetTraceable();
}
/**
* See `AFL_FRIDA_VERBOSE`
*/
static setVerbose() {
Afl.jsApiSetVerbose();
}
static jsApiGetFunction(name, retType, argTypes) {
const addr = Afl.module.getExportByName(name);
return new NativeFunction(addr, retType, argTypes);
@ -287,13 +326,18 @@ Afl.jsApiAflSharedMemFuzzing = Afl.jsApiGetSymbol("__afl_sharedmem_fuzzing");
Afl.jsApiDone = Afl.jsApiGetFunction("js_api_done", "void", []);
Afl.jsApiError = Afl.jsApiGetFunction("js_api_error", "void", ["pointer"]);
Afl.jsApiSetBackpatchDisable = Afl.jsApiGetFunction("js_api_set_backpatch_disable", "void", []);
Afl.jsApiSetCacheDisable = Afl.jsApiGetFunction("js_api_set_cache_disable", "void", []);
Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []);
Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
Afl.jsApiSetInstrumentCacheSize = Afl.jsApiGetFunction("js_api_set_instrument_cache_size", "void", ["size_t"]);
Afl.jsApiSetInstrumentCoverageAbsolute = Afl.jsApiGetFunction("js_api_set_instrument_coverage_absolute", "void", []);
Afl.jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_coverage_file", "void", ["pointer"]);
Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]);
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.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.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []);
Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []);
@ -315,6 +359,7 @@ Afl.jsApiSetStatsInterval = Afl.jsApiGetFunction("js_api_set_stats_interval", "v
Afl.jsApiSetStdErr = Afl.jsApiGetFunction("js_api_set_stderr", "void", ["pointer"]);
Afl.jsApiSetStdOut = Afl.jsApiGetFunction("js_api_set_stdout", "void", ["pointer"]);
Afl.jsApiSetTraceable = Afl.jsApiGetFunction("js_api_set_traceable", "void", []);
Afl.jsApiSetVerbose = Afl.jsApiGetFunction("js_api_set_verbose", "void", []);
Afl.jsApiWrite = new NativeFunction(
/* tslint:disable-next-line:no-null-keyword */
Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]);

View File

@ -7,16 +7,16 @@ gboolean js_done = FALSE;
js_api_stalker_callback_t js_user_callback = NULL;
js_main_hook_t js_main_hook = NULL;
static char * js_script = NULL;
static gchar * filename = "afl.js";
static gchar * contents;
static GumScriptBackend * backend;
static GCancellable * cancellable = NULL;
static GError * error = NULL;
static GumScript * script;
static char *js_script = NULL;
static gchar *filename = "afl.js";
static gchar *contents;
static GumScriptBackend *backend;
static GCancellable *cancellable = NULL;
static GError *error = NULL;
static GumScript *script;
static GumScriptScheduler *scheduler;
static GMainContext * context;
static GMainLoop * main_loop;
static GMainContext *context;
static GMainLoop *main_loop;
static void js_msg(GumScript *script, const gchar *message, GBytes *data,
gpointer user_data) {
@ -55,7 +55,10 @@ static gchar *js_get_script() {
} else {
FOKF("Loaded AFL script: %s, %" G_GSIZE_MODIFIER "d bytes", filename,
FOKF(cBLU "Javascript" cRST " - " cGRN "script:" cYEL " [%s]",
filename == NULL ? " " : filename);
FOKF(cBLU "Javascript" cRST " - " cGRN "size: " cYEL "%" G_GSIZE_MODIFIER
"d bytes",
length);
gchar *source = g_malloc0(api_js_len + length + 1);
@ -74,7 +77,7 @@ static void js_print_script(gchar *source) {
for (size_t i = 0; split[i] != NULL; i++) {
FOKF("%3" G_GSIZE_MODIFIER "d. %s", i + 1, split[i]);
FVERBOSE("%3" G_GSIZE_MODIFIER "d. %s", i + 1, split[i]);
}

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