mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
480 Commits
Author | SHA1 | Date | |
---|---|---|---|
02294d368a | |||
d20d031141 | |||
67293b298d | |||
95f47ac3a4 | |||
3844e79492 | |||
da2d4d8258 | |||
8b7a7b29c6 | |||
d0225c2c4d | |||
ade1d2819e | |||
4e402ba9fc | |||
48cef3c747 | |||
3b5fa3632b | |||
86a8ef168d | |||
b41ea92a67 | |||
2bd7206ec5 | |||
70bf4b4ab0 | |||
b6643a8ad1 | |||
495cbd42b7 | |||
6e75832082 | |||
c30999562e | |||
3c68208dd3 | |||
b03424073e | |||
11be1fa86e | |||
400ab10cfd | |||
5dad048674 | |||
98989f1088 | |||
2019b42ced | |||
523aaaebef | |||
846a46e060 | |||
89d4565092 | |||
624c1dce46 | |||
72a4bc7039 | |||
950648c513 | |||
e41d1183cc | |||
c8e96e5253 | |||
4f93220c4b | |||
45b5e3622e | |||
43e16cf13d | |||
d0390f3b76 | |||
9d3a2b693a | |||
f2a83c4a50 | |||
b815c32f0e | |||
71f3d82d43 | |||
cd40fa1745 | |||
61a918f820 | |||
ab0f13ed06 | |||
4a0e0270ad | |||
fd8dc14552 | |||
f0d300b32a | |||
eb3aa2a227 | |||
6069cac313 | |||
92a3081337 | |||
5e72568a45 | |||
ae9087b390 | |||
36c7c49738 | |||
1fabfd5a32 | |||
be880f2476 | |||
50bb931ea6 | |||
0c06371cda | |||
86bf55ff8b | |||
ef33193d77 | |||
c19d1f0c75 | |||
019b26de58 | |||
43ca2d3113 | |||
9c517199b2 | |||
bfe7e3fd55 | |||
46e35e9401 | |||
28878c69e0 | |||
9d1be3162a | |||
7181112233 | |||
2e6e1e566b | |||
19690b606d | |||
5ab14f22a5 | |||
201d82ae0d | |||
43b1a0d46b | |||
a02d84a11c | |||
f2efd94035 | |||
96b743094d | |||
3c846859ee | |||
845c584b9c | |||
f7179e44f6 | |||
c23183f1dc | |||
99819cf5d1 | |||
53facd8882 | |||
fee7470083 | |||
afc4da47f7 | |||
d35a90101f | |||
a7141b6a6e | |||
2b4e93faba | |||
c4ad4681cf | |||
05c13588d7 | |||
050f331c54 | |||
d5fc03b718 | |||
70e9757044 | |||
6c88b6b362 | |||
8d894eec90 | |||
7a3dfbce71 | |||
7f6d256014 | |||
4291c3db5d | |||
8f9d1fd7b0 | |||
b7d12c8532 | |||
b418c31479 | |||
6514e33ab6 | |||
920e9402a4 | |||
bc99b5ba03 | |||
c4f418c3b2 | |||
67989e9f2a | |||
7a383342de | |||
01658fb2e8 | |||
cabde32140 | |||
6088a0d4c2 | |||
a26ed3b758 | |||
565f61a6ab | |||
3ff4ca348c | |||
e20f0bf0ea | |||
c9a96b268b | |||
1004fb9a41 | |||
e190ba1a2f | |||
221616a1b7 | |||
049ace8a40 | |||
89eb285a23 | |||
0709d00b10 | |||
84a99f49b8 | |||
7ca51fab19 | |||
1edc3ece61 | |||
eda1ee0807 | |||
5ee2dd6bbd | |||
eac254ae57 | |||
fa349b4f4c | |||
a50d95b831 | |||
3439d641c0 | |||
1006abffad | |||
1f3d5c271a | |||
96533f627e | |||
2c5844f665 | |||
22c696ff1c | |||
c169cb3911 | |||
00a53a870d | |||
1725e6be31 | |||
0029c1a83e | |||
c892642057 | |||
236a67621b | |||
2d662ace87 | |||
447d232caf | |||
90e7543038 | |||
3b860c1dd6 | |||
ab394836a9 | |||
d319b4a381 | |||
e1384b5086 | |||
55224e5150 | |||
836aeef595 | |||
c2b58cff6f | |||
6e2a0ef233 | |||
958436be4b | |||
7dc4847869 | |||
2dac4e785f | |||
ee5078f43c | |||
2b3642aa39 | |||
d68bd656fe | |||
8bd5d7676e | |||
70c1de5d64 | |||
2fef89950f | |||
a908a98225 | |||
82554677a8 | |||
dfe6f7f8c9 | |||
5fcd634f05 | |||
28f1e94ab9 | |||
e1d37a802b | |||
0f9dceff3d | |||
8868648f76 | |||
72a70423c2 | |||
84534ae2e8 | |||
687dd9cb67 | |||
ede03a96ed | |||
33dd2ce021 | |||
bc0ff559f5 | |||
090128b3f8 | |||
d7e121e2c9 | |||
749b03d812 | |||
fc73a18e9a | |||
7e67a735e6 | |||
14e1b0ffba | |||
e98cd00822 | |||
2102264acf | |||
e73c7c59c1 | |||
99525dee38 | |||
848ea17154 | |||
1cdf0a898c | |||
00913bce81 | |||
5be7d9c1cc | |||
44347beff0 | |||
166c8f93b5 | |||
9393452d1c | |||
66fa76a061 | |||
d2e7c4ec05 | |||
10fb46301c | |||
c397becd81 | |||
62508c3b44 | |||
94312796f9 | |||
adeeed9e43 | |||
513bd70384 | |||
cdd30c766b | |||
5e2a5f1110 | |||
a7797f0cb9 | |||
d17abce59b | |||
b715050de9 | |||
da5a32792d | |||
f36341b3b4 | |||
dda4757b35 | |||
c6f1c56c15 | |||
413807db01 | |||
f59ef29c26 | |||
65b90001f6 | |||
6840e8fd2a | |||
7c2436c711 | |||
c2df65a0af | |||
175a275a3d | |||
bd64315395 | |||
65e3770bad | |||
f5420e737a | |||
4e567d3f5d | |||
1227776251 | |||
862cb3217f | |||
8e11546536 | |||
73641be796 | |||
ff9f3fbe96 | |||
1dcc3549b6 | |||
23f7bee81c | |||
ac795ae1e1 | |||
aa6a50c2b4 | |||
62f067ec71 | |||
01ad7610be | |||
d4fb7f8b40 | |||
61c8304f24 | |||
27c0480866 | |||
b289e7ad07 | |||
70403f7e1b | |||
1ab125de63 | |||
96574854b3 | |||
281cd47c15 | |||
01ad0f3c6a | |||
db342c9c81 | |||
f1d8a01047 | |||
3753f56c25 | |||
d32b1d6b0c | |||
e5bdba4b9f | |||
c725cb71de | |||
8ff5063545 | |||
e549102563 | |||
b7d90a9e31 | |||
adeb0d18b1 | |||
16e3e2a7f7 | |||
0484d9b024 | |||
d60bbff0d9 | |||
966eba50a6 | |||
ffd8fae22a | |||
cb0fe044dd | |||
4f3b5f8adc | |||
3bb12b456f | |||
a10a627622 | |||
2777784f4f | |||
4bd0d4cbaf | |||
2d92bb483e | |||
071edb1a2d | |||
7f36290703 | |||
6cc59a38be | |||
87eb44abe4 | |||
a0c3011673 | |||
69f3095045 | |||
d678d59372 | |||
b2feada293 | |||
bff02dae0d | |||
851231c846 | |||
f21a5c42c1 | |||
d471fc9509 | |||
9f22a151f3 | |||
0c2478cae6 | |||
b865fc6080 | |||
d44b650cd4 | |||
aa12e46013 | |||
2c18fbbb2e | |||
4131965d48 | |||
5fab0fa51f | |||
9c9232b4e8 | |||
0d6e571237 | |||
40ba8814b3 | |||
a0a917ad87 | |||
8628839c55 | |||
5001779984 | |||
93d91dd7a1 | |||
791c5c171d | |||
a723156740 | |||
0868ea8348 | |||
5a6ad71f3f | |||
47f2650a32 | |||
74a6044b3f | |||
e82ce95251 | |||
e226d1bbb3 | |||
54c1087340 | |||
eb1e8619eb | |||
c96fca6833 | |||
d3f69ab4c6 | |||
517db1b8dc | |||
7f062524c9 | |||
99b4c3f362 | |||
4a0d4c50fc | |||
976cb3e36c | |||
81442ba3f9 | |||
9b3d8c327d | |||
7b907e45ad | |||
e8d580f54d | |||
2dd5a02061 | |||
9844e1a856 | |||
44be521ab8 | |||
c9819e3b94 | |||
16d6f35aa6 | |||
c9854ec8cb | |||
c429021de1 | |||
41ad23041b | |||
3e5ac0af52 | |||
f848562732 | |||
3342aa751d | |||
a2f40aa285 | |||
f34a860d5f | |||
af9aeb89d4 | |||
be5274d4a9 | |||
b6dc529bc3 | |||
0aa93afeb8 | |||
79d75d8e42 | |||
96c526cb78 | |||
02f3319256 | |||
8f538e77ed | |||
1e76079e93 | |||
0e736276e6 | |||
08ef8d6b78 | |||
3977d50b55 | |||
3bcfbf5038 | |||
f0c7967fbf | |||
8bdb40b763 | |||
f0bc2e0e8b | |||
108e588e88 | |||
333509bb0a | |||
c269c3977c | |||
c3a8052a16 | |||
d0a61279b8 | |||
7259075b71 | |||
14fd477147 | |||
05e2f577f6 | |||
a29b360d55 | |||
75d6a8b701 | |||
ad7a7fcf07 | |||
82c05630ba | |||
bd0a23de73 | |||
4619a1395b | |||
0c38850f95 | |||
07884e0054 | |||
bdadbb7207 | |||
e389eb9842 | |||
5cf0655071 | |||
f81ef4abf4 | |||
6036cf8437 | |||
1cad645400 | |||
36846836ed | |||
79f1a44a01 | |||
c2127e3ff7 | |||
2ad495ad0a | |||
8e051fd075 | |||
af628b16d1 | |||
c219502f0f | |||
a5da9ce42c | |||
79e02c2a9b | |||
3a461944ec | |||
78d96c4dc8 | |||
ee0ca07f3c | |||
7ae7b0f373 | |||
e2b4bc9310 | |||
6c9777de13 | |||
2f7e57f6aa | |||
5c239451cf | |||
35ca51c5a8 | |||
047f3436e9 | |||
5d181950eb | |||
48a1a29baa | |||
c05d392cd9 | |||
cc7c651dc9 | |||
e6ef2ee338 | |||
a090b2013f | |||
564f491566 | |||
2daeeab844 | |||
4ab90e739f | |||
745bc083d1 | |||
7674dac1a1 | |||
fb2a6b6941 | |||
70fe872940 | |||
a252943236 | |||
8c133b607c | |||
2785c8b197 | |||
a81b5aa921 | |||
8ad78f5b65 | |||
ac9cfd89da | |||
c67c4ce757 | |||
974aab6cf6 | |||
b957218a3a | |||
f629f4e341 | |||
871c3c91ec | |||
100aac4dd3 | |||
d941da33ae | |||
62767a42dc | |||
89cf94f0e6 | |||
17211253b2 | |||
6998489b26 | |||
4290cb5877 | |||
801f2449ec | |||
aaf5fcd98a | |||
5edfb7ba85 | |||
a5cb522f01 | |||
3195119dad | |||
d6fe6b9537 | |||
c0f9fba6d6 | |||
1a713ff420 | |||
89af2ef7a9 | |||
907c5d4276 | |||
5dd35f5281 | |||
857229654e | |||
4c47b242eb | |||
938512a6b9 | |||
7444cfa450 | |||
f091b8d692 | |||
7d97ffb1e8 | |||
80bdbf7be0 | |||
686719cdca | |||
6caec2169c | |||
5212481352 | |||
d999725de2 | |||
145c673a80 | |||
c5017945f7 | |||
5c4c49d9ca | |||
cebde1f9e6 | |||
0298ae82b0 | |||
512f53984c | |||
e3a5c31307 | |||
dd2fd80274 | |||
ffc1fc655f | |||
fe477e96ae | |||
98559ea8b0 | |||
f31d8b8401 | |||
389e348826 | |||
98fd50f78f | |||
95561ec5a7 | |||
fe9da70705 | |||
95c77c8486 | |||
e45333bcf9 | |||
c906c042be | |||
9bd1e19d7f | |||
6ce9230ed6 | |||
1d60c39191 | |||
70651d60bd | |||
385312c658 | |||
87a607c7d0 | |||
1ba5d1008e | |||
129a5adaf1 | |||
d827bc4580 | |||
64e46dcefc | |||
c0b3127b9d | |||
7cfa690d1c | |||
22a3c7f7d0 | |||
16ffbb37f5 | |||
ea05f3f4cd | |||
91f2f057e4 | |||
d44cf1344d | |||
756206e4d7 | |||
2ff6e5023f | |||
223bd70f1f | |||
dd3f4bb41c | |||
f3e783d343 | |||
2cd4624779 | |||
e11665564b | |||
93cebd6c7f | |||
a124540e50 | |||
84f0b4f187 |
@ -33,13 +33,13 @@ if CLANG_FORMAT_BIN is None:
|
||||
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 = o[len("clang-format version "):].strip()
|
||||
o = o[: o.find(".")]
|
||||
o = int(o)
|
||||
except:
|
||||
print ("clang-format-11 is needed. Aborted.")
|
||||
print("clang-format-11 is needed. Aborted.")
|
||||
exit(1)
|
||||
#if o < 7:
|
||||
# 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:
|
||||
@ -52,8 +52,8 @@ if CLANG_FORMAT_BIN is None:
|
||||
# print ("clang-format 7 or above is needed. Aborted.")
|
||||
# exit(1)
|
||||
else:
|
||||
CLANG_FORMAT_BIN = 'clang-format-11'
|
||||
|
||||
CLANG_FORMAT_BIN = "clang-format-11"
|
||||
|
||||
COLUMN_LIMIT = 80
|
||||
for line in fmt.split("\n"):
|
||||
line = line.split(":")
|
||||
@ -69,26 +69,47 @@ def custom_format(filename):
|
||||
in_define = False
|
||||
last_line = None
|
||||
out = ""
|
||||
|
||||
|
||||
for line in src.split("\n"):
|
||||
if line.lstrip().startswith("#"):
|
||||
if line[line.find("#")+1:].lstrip().startswith("define"):
|
||||
if line[line.find("#") + 1 :].lstrip().startswith("define"):
|
||||
in_define = True
|
||||
|
||||
if "/*" in line and not line.strip().startswith("/*") and line.endswith("*/") and len(line) < (COLUMN_LIMIT-2):
|
||||
|
||||
if (
|
||||
"/*" in line
|
||||
and not line.strip().startswith("/*")
|
||||
and line.endswith("*/")
|
||||
and len(line) < (COLUMN_LIMIT - 2)
|
||||
):
|
||||
cmt_start = line.rfind("/*")
|
||||
line = line[:cmt_start] + " " * (COLUMN_LIMIT-2 - len(line)) + line[cmt_start:]
|
||||
line = (
|
||||
line[:cmt_start]
|
||||
+ " " * (COLUMN_LIMIT - 2 - len(line))
|
||||
+ line[cmt_start:]
|
||||
)
|
||||
|
||||
define_padding = 0
|
||||
if last_line is not None and in_define and last_line.endswith("\\"):
|
||||
last_line = last_line[:-1]
|
||||
define_padding = max(0, len(last_line[last_line.rfind("\n")+1:]))
|
||||
define_padding = max(0, len(last_line[last_line.rfind("\n") + 1 :]))
|
||||
|
||||
if last_line is not None and last_line.strip().endswith("{") and line.strip() != "":
|
||||
if (
|
||||
last_line is not None
|
||||
and last_line.strip().endswith("{")
|
||||
and line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
elif last_line is not None and last_line.strip().startswith("}") and line.strip() != "":
|
||||
elif (
|
||||
last_line is not None
|
||||
and last_line.strip().startswith("}")
|
||||
and line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
elif line.strip().startswith("}") and last_line is not None and last_line.strip() != "":
|
||||
elif (
|
||||
line.strip().startswith("}")
|
||||
and last_line is not None
|
||||
and last_line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
|
||||
if not line.endswith("\\"):
|
||||
@ -97,14 +118,15 @@ def custom_format(filename):
|
||||
out += line + "\n"
|
||||
last_line = line
|
||||
|
||||
return (out)
|
||||
return out
|
||||
|
||||
|
||||
args = sys.argv[1:]
|
||||
if len(args) == 0:
|
||||
print ("Usage: ./format.py [-i] <filename>")
|
||||
print ()
|
||||
print (" The -i option, if specified, let the script to modify in-place")
|
||||
print (" the source files. By default the results are written to stdout.")
|
||||
print("Usage: ./format.py [-i] <filename>")
|
||||
print()
|
||||
print(" The -i option, if specified, let the script to modify in-place")
|
||||
print(" the source files. By default the results are written to stdout.")
|
||||
print()
|
||||
exit(1)
|
||||
|
||||
@ -120,4 +142,3 @@ for filename in args:
|
||||
f.write(code)
|
||||
else:
|
||||
print(code)
|
||||
|
||||
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: AFLplusplusEU
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
25
.github/workflows/build_aflplusplus_docker.yaml
vendored
Normal file
25
.github/workflows/build_aflplusplus_docker.yaml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
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
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -16,8 +16,10 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: debug
|
||||
run: apt-cache search plugin-dev | grep gcc- ; echo ; apt-cache search clang-format- | grep clang-format-
|
||||
- name: update
|
||||
run: sudo apt-get update && sudo apt-get upgrade -y
|
||||
- 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
|
||||
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
|
||||
- name: install gcc plugin
|
||||
|
30
.github/workflows/rust_custom_mutator.yml
vendored
Normal file
30
.github/workflows/rust_custom_mutator.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Rust Custom Mutators
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ stable, dev ]
|
||||
pull_request:
|
||||
branches: [ stable, dev ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test Rust Custom Mutator Support
|
||||
runs-on: '${{ matrix.os }}'
|
||||
defaults:
|
||||
run:
|
||||
working-directory: custom_mutators/rust
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Rust Toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Check Code Compiles
|
||||
run: cargo check
|
||||
- name: Run General Tests
|
||||
run: cargo test
|
||||
- name: Run Tests for afl_internals feature flag
|
||||
run: cd custom_mutator && cargo test --features=afl_internals
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -65,7 +65,6 @@ qemu_mode/qemu-*
|
||||
qemu_mode/qemuafl
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
unicorn_mode/samples/*/output/
|
||||
unicorn_mode/unicornafl
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_list
|
||||
@ -83,3 +82,7 @@ libAFLDriver.a
|
||||
libAFLQemuDriver.a
|
||||
test/.afl_performance
|
||||
gmon.out
|
||||
afl-frida-trace.so
|
||||
utils/afl_network_proxy/afl-network-client
|
||||
utils/afl_network_proxy/afl-network-server
|
||||
*.o.tmp
|
||||
|
143
Android.bp
143
Android.bp
@ -1,8 +1,5 @@
|
||||
cc_defaults {
|
||||
name: "afl-defaults",
|
||||
sanitize: {
|
||||
never: true,
|
||||
},
|
||||
|
||||
local_include_dirs: [
|
||||
"include",
|
||||
@ -23,18 +20,44 @@ cc_defaults {
|
||||
"-DBIN_PATH=\"out/host/linux-x86/bin\"",
|
||||
"-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"",
|
||||
"-D__USE_GNU",
|
||||
"-D__aarch64__",
|
||||
"-DDEBUG_BUILD",
|
||||
"-U_FORTIFY_SOURCE",
|
||||
"-ggdb3",
|
||||
"-g",
|
||||
"-O0",
|
||||
"-fno-omit-frame-pointer",
|
||||
"-fPIC",
|
||||
],
|
||||
|
||||
target: {
|
||||
android_arm64: {
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
],
|
||||
},
|
||||
android_arm: {
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
],
|
||||
},
|
||||
android_x86_64: {
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
],
|
||||
},
|
||||
android_x86: {
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-fuzz",
|
||||
sanitize: {
|
||||
never: true,
|
||||
},
|
||||
host_supported: true,
|
||||
compile_multilib: "64",
|
||||
|
||||
@ -128,7 +151,6 @@ cc_binary_host {
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
|
||||
"-DAFL_CLANG_FLTO=\"-flto=full\"",
|
||||
"-DUSE_BINDIR=1",
|
||||
@ -199,6 +221,7 @@ cc_library_headers {
|
||||
|
||||
export_include_dirs: [
|
||||
"include",
|
||||
"instrumentation",
|
||||
],
|
||||
}
|
||||
|
||||
@ -268,6 +291,116 @@ cc_binary {
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-fuzz-32",
|
||||
sanitize: {
|
||||
never: true,
|
||||
},
|
||||
host_supported: true,
|
||||
compile_multilib: "32",
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-fuzz*.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary_host {
|
||||
name: "afl-cc-32",
|
||||
compile_multilib: "32",
|
||||
static_executable: true,
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
|
||||
"-DAFL_CLANG_FLTO=\"-flto=full\"",
|
||||
"-DUSE_BINDIR=1",
|
||||
"-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"",
|
||||
"-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"",
|
||||
"-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"",
|
||||
"-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"",
|
||||
"-DLLVM_LTO=1",
|
||||
"-DLLVM_MAJOR=11",
|
||||
"-DLLVM_MINOR=2",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-cc.c",
|
||||
"src/afl-common.c",
|
||||
],
|
||||
|
||||
symlinks: [
|
||||
"afl-clang-fast-32",
|
||||
"afl-clang-fast++-32",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "afl-llvm-rt-32",
|
||||
compile_multilib: "32",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
recovery_available: true,
|
||||
sdk_version: "9",
|
||||
|
||||
apex_available: [
|
||||
"com.android.adbd",
|
||||
"com.android.appsearch",
|
||||
"com.android.art",
|
||||
"com.android.bluetooth.updatable",
|
||||
"com.android.cellbroadcast",
|
||||
"com.android.conscrypt",
|
||||
"com.android.extservices",
|
||||
"com.android.cronet",
|
||||
"com.android.neuralnetworks",
|
||||
"com.android.media",
|
||||
"com.android.media.swcodec",
|
||||
"com.android.mediaprovider",
|
||||
"com.android.permission",
|
||||
"com.android.runtime",
|
||||
"com.android.resolv",
|
||||
"com.android.tethering",
|
||||
"com.android.wifi",
|
||||
"com.android.sdkext",
|
||||
"com.android.os.statsd",
|
||||
"//any",
|
||||
],
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"instrumentation/afl-compiler-rt.o.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_prebuilt_library_static {
|
||||
name: "libfrida-gum-32",
|
||||
compile_multilib: "32",
|
||||
strip: {
|
||||
none: true,
|
||||
},
|
||||
|
||||
srcs: [
|
||||
"utils/afl_frida/android/arm/libfrida-gum.a",
|
||||
],
|
||||
|
||||
export_include_dirs: [
|
||||
"utils/afl_frida/android/arm",
|
||||
],
|
||||
}
|
||||
|
||||
subdirs = [
|
||||
"custom_mutators",
|
||||
]
|
||||
|
19
Dockerfile
19
Dockerfile
@ -11,6 +11,8 @@ LABEL "about"="AFLplusplus docker 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 \
|
||||
@ -35,7 +37,7 @@ RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main
|
||||
|
||||
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 gdb lcov \
|
||||
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 \
|
||||
@ -48,19 +50,22 @@ RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
|
||||
|
||||
ENV LLVM_CONFIG=llvm-config-12
|
||||
ENV AFL_SKIP_CPUFREQ=1
|
||||
ENV AFL_TRY_AFFINITY=1
|
||||
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
|
||||
RUN git clone https://github.com/vanhauser-thc/afl-cov /afl-cov
|
||||
RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov
|
||||
RUN cd /afl-cov && make install && cd ..
|
||||
|
||||
COPY . /AFLplusplus
|
||||
WORKDIR /AFLplusplus
|
||||
|
||||
RUN export REAL_CXX=g++-10 && export CC=gcc-10 && \
|
||||
export CXX=g++-10 && make clean && \
|
||||
make distrib CFLAGS="-O3 -funroll-loops -D_FORTIFY_SOURCE=2" && make install && make clean
|
||||
RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \
|
||||
make distrib && make install && make clean
|
||||
|
||||
RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc
|
||||
RUN echo 'export PS1="[afl++]$PS1"' >> ~/.bashrc
|
||||
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"
|
||||
|
||||
# Disabled until we have the container ready
|
||||
|
83
GNUmakefile
83
GNUmakefile
@ -24,7 +24,7 @@ BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/man/man8
|
||||
MAN_PATH = $(PREFIX)/share/man/man8
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
@ -36,6 +36,11 @@ SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
|
||||
ASAN_OPTIONS=detect_leaks=0
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
ARCH = $(shell uname -m)
|
||||
|
||||
$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH))
|
||||
|
||||
ifdef NO_SPLICING
|
||||
override CFLAGS += -DNO_SPLICING
|
||||
endif
|
||||
@ -57,8 +62,6 @@ ifdef MSAN_BUILD
|
||||
override LDFLAGS += -fsanitize=memory
|
||||
endif
|
||||
|
||||
|
||||
|
||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
@ -77,24 +80,24 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -
|
||||
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
|
||||
HAVE_MARCHNATIVE = 1
|
||||
CFLAGS_OPT += -march=native
|
||||
endif
|
||||
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
|
||||
# HAVE_MARCHNATIVE = 1
|
||||
# CFLAGS_OPT += -march=native
|
||||
# endif
|
||||
#endif
|
||||
|
||||
ifneq "$(shell uname)" "Darwin"
|
||||
ifeq "$(HAVE_MARCHNATIVE)" "1"
|
||||
SPECIAL_PERFORMANCE += -march=native
|
||||
endif
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
#ifeq "$(HAVE_MARCHNATIVE)" "1"
|
||||
# SPECIAL_PERFORMANCE += -march=native
|
||||
#endif
|
||||
# OS X does not like _FORTIFY_SOURCE=2
|
||||
ifndef DEBUG
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "SunOS"
|
||||
ifeq "$(SYS)" "SunOS"
|
||||
CFLAGS_OPT += -Wno-format-truncation
|
||||
LDFLAGS = -lkstat -lrt
|
||||
endif
|
||||
@ -121,11 +124,10 @@ ifdef INTROSPECTION
|
||||
CFLAGS_OPT += -DINTROSPECTION=1
|
||||
endif
|
||||
|
||||
|
||||
ifneq "$(shell uname -m)" "x86_64"
|
||||
ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386"
|
||||
ifneq "$(shell uname -m)" "amd64"
|
||||
ifneq "$(shell uname -m)" "i86pc"
|
||||
ifneq "$(ARCH)" "x86_64"
|
||||
ifneq "$(patsubst i%86,i386,$(ARCH))" "i386"
|
||||
ifneq "$(ARCH)" "amd64"
|
||||
ifneq "$(ARCH)" "i86pc"
|
||||
AFL_NO_X86=1
|
||||
endif
|
||||
endif
|
||||
@ -143,30 +145,30 @@ override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpoi
|
||||
-I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
||||
|
||||
ifeq "$(shell uname -s)" "FreeBSD"
|
||||
ifeq "$(SYS)" "FreeBSD"
|
||||
override CFLAGS += -I /usr/local/include/
|
||||
LDFLAGS += -L /usr/local/lib/
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname -s)" "DragonFly"
|
||||
ifeq "$(SYS)" "DragonFly"
|
||||
override CFLAGS += -I /usr/local/include/
|
||||
LDFLAGS += -L /usr/local/lib/
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname -s)" "OpenBSD"
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
override CFLAGS += -I /usr/local/include/ -mno-retpoline
|
||||
LDFLAGS += -Wl,-z,notext -L /usr/local/lib/
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname -s)" "NetBSD"
|
||||
ifeq "$(SYS)" "NetBSD"
|
||||
override CFLAGS += -I /usr/pkg/include/
|
||||
LDFLAGS += -L /usr/pkg/lib/
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname -s)" "Haiku"
|
||||
ifeq "$(SYS)" "Haiku"
|
||||
SHMAT_OK=0
|
||||
override CFLAGS += -DUSEMMAP=1 -Wno-error=format -fPIC
|
||||
LDFLAGS += -Wno-deprecated-declarations -lgnu
|
||||
LDFLAGS += -Wno-deprecated-declarations -lgnu -lnetwork
|
||||
SPECIAL_PERFORMANCE += -DUSEMMAP=1
|
||||
endif
|
||||
|
||||
@ -238,24 +240,24 @@ else
|
||||
BUILD_DATE ?= $(shell date "+%Y-%m-%d")
|
||||
endif
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
ifneq "$(filter Linux GNU%,$(SYS))" ""
|
||||
ifndef DEBUG
|
||||
override CFLAGS += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
LDFLAGS += -ldl -lrt -lm
|
||||
endif
|
||||
|
||||
ifneq "$(findstring FreeBSD, $(shell uname))" ""
|
||||
ifneq "$(findstring FreeBSD, $(SYS))" ""
|
||||
override CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifneq "$(findstring NetBSD, $(shell uname))" ""
|
||||
ifneq "$(findstring NetBSD, $(SYS))" ""
|
||||
override CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifneq "$(findstring OpenBSD, $(shell uname))" ""
|
||||
ifneq "$(findstring OpenBSD, $(SYS))" ""
|
||||
override CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
@ -487,7 +489,7 @@ unit_clean:
|
||||
@rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o
|
||||
|
||||
.PHONY: unit
|
||||
ifneq "$(shell uname)" "Darwin"
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash
|
||||
else
|
||||
unit:
|
||||
@ -501,25 +503,28 @@ code-format:
|
||||
./.custom-format.py -i instrumentation/*.h
|
||||
./.custom-format.py -i instrumentation/*.cc
|
||||
./.custom-format.py -i instrumentation/*.c
|
||||
./.custom-format.py -i *.h
|
||||
./.custom-format.py -i *.c
|
||||
@#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-(
|
||||
@#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-(
|
||||
./.custom-format.py -i utils/*/*.c*
|
||||
./.custom-format.py -i utils/*/*.h
|
||||
./.custom-format.py -i test/*.c
|
||||
./.custom-format.py -i frida_mode/src/*.c
|
||||
./.custom-format.py -i frida_mode/include/*.h
|
||||
-./.custom-format.py -i frida_mode/src/*/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.h
|
||||
./.custom-format.py -i qemu_mode/libqasan/*.c
|
||||
./.custom-format.py -i qemu_mode/libqasan/*.h
|
||||
./.custom-format.py -i *.h
|
||||
./.custom-format.py -i *.c
|
||||
|
||||
|
||||
.PHONY: test_build
|
||||
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_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 -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
|
||||
@ -527,7 +532,7 @@ test_build: afl-cc afl-gcc afl-as afl-showmap
|
||||
@echo
|
||||
@echo "[+] All right, the instrumentation of afl-cc seems to be working!"
|
||||
# @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..."
|
||||
# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 )
|
||||
# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc 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
|
||||
@ -548,7 +553,7 @@ all_done: test_build
|
||||
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it"
|
||||
@test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it"
|
||||
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
|
||||
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
|
||||
@if [ "$(SYS)" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi
|
||||
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
|
||||
|
||||
.NOTPARALLEL: clean all
|
||||
@ -560,6 +565,7 @@ 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
|
||||
@ -578,7 +584,11 @@ endif
|
||||
deepclean: clean
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
rm -rf qemu_mode/qemuafl
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
# NEVER EVER ACTIVATE THAT!!!!! git reset --hard >/dev/null 2>&1 || true
|
||||
git checkout unicorn_mode/unicornafl
|
||||
git checkout qemu_mode/qemuafl
|
||||
endif
|
||||
|
||||
.PHONY: distrib
|
||||
distrib: all
|
||||
@ -590,6 +600,7 @@ distrib: all
|
||||
$(MAKE) -C utils/afl_network_proxy
|
||||
$(MAKE) -C utils/socket_fuzzing
|
||||
$(MAKE) -C utils/argv_fuzzing
|
||||
-$(MAKE) -C frida_mode
|
||||
-cd qemu_mode && sh ./build_qemu_support.sh
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
|
||||
@ -600,6 +611,7 @@ binary-only: test_shm test_python ready $(PROGS)
|
||||
$(MAKE) -C utils/afl_network_proxy
|
||||
$(MAKE) -C utils/socket_fuzzing
|
||||
$(MAKE) -C utils/argv_fuzzing
|
||||
-$(MAKE) -C frida_mode
|
||||
-cd qemu_mode && sh ./build_qemu_support.sh
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
|
||||
@ -645,6 +657,7 @@ install: all $(MANPAGES)
|
||||
@if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
|
||||
@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 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
|
||||
|
@ -41,6 +41,8 @@ CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
|
||||
ifeq "clang" "$(CC)"
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
@ -75,25 +77,25 @@ ifeq "$(TEST_MMAP)" "1"
|
||||
override CFLAGS_SAFE += -DUSEMMAP=1
|
||||
endif
|
||||
|
||||
ifneq "$(shell uname -s)" "Haiku"
|
||||
ifneq "$(shell uname -s)" "OpenBSD"
|
||||
ifneq "$(SYS)" "Haiku"
|
||||
ifneq "$(SYS)" "OpenBSD"
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
else
|
||||
CFLAGS_SAFE += -DUSEMMAP=1
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname -s)" "OpenBSD"
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
CC = egcc
|
||||
CXX = eg++
|
||||
PLUGIN_FLAGS += -I/usr/local/include
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname -s)" "DragonFly"
|
||||
ifeq "$(SYS)" "DragonFly"
|
||||
PLUGIN_FLAGS += -I/usr/local/include
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname -s)" "SunOS"
|
||||
ifeq "$(SYS)" "SunOS"
|
||||
PLUGIN_FLAGS += -I/usr/include/gmp
|
||||
endif
|
||||
|
||||
|
@ -30,11 +30,13 @@ BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/nul
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
|
||||
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
SYS = $(shell uname -s)
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
|
||||
ifeq "$(HAS_OPT)" "1"
|
||||
$(warning llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||
$(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 12) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||
endif
|
||||
else
|
||||
LLVM_CONFIG ?= llvm-config
|
||||
@ -43,7 +45,8 @@ endif
|
||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' )
|
||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
|
||||
LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^1[3-9]' && echo 1 || echo 0 )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-5]\.' && echo 1 || echo 0 )
|
||||
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[3-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 )
|
||||
@ -58,7 +61,11 @@ ifeq "$(LLVMVER)" ""
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(warning llvm_mode only supports llvm versions 3.4 up to 12)
|
||||
$(error llvm_mode only supports llvm from version 6.0 onwards)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_TOO_NEW)" "1"
|
||||
$(warning you are using an in-development llvm version - this might break llvm_mode!)
|
||||
endif
|
||||
|
||||
LLVM_TOO_OLD=1
|
||||
@ -270,13 +277,13 @@ CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
|
||||
|
||||
|
||||
# User teor2345 reports that this is required to make things work on MacOS X.
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
ifeq "$(SYS)" "Darwin"
|
||||
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
|
||||
else
|
||||
CLANG_CPPFL += -Wl,-znodelete
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
|
||||
CLANG_CPPFL += -mno-retpoline
|
||||
CFLAGS += -mno-retpoline
|
||||
@ -299,7 +306,7 @@ ifeq "$(TEST_MMAP)" "1"
|
||||
endif
|
||||
|
||||
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./libLLVMInsTrim.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so
|
||||
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so
|
||||
|
||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||
ifeq "$(LLVMVER)" ""
|
||||
@ -339,7 +346,7 @@ no_build:
|
||||
test_deps:
|
||||
@echo "[*] Checking for working 'llvm-config'..."
|
||||
ifneq "$(LLVM_APPLE_XCODE)" "1"
|
||||
@type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 )
|
||||
@type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-11 or something like that.)"; exit 1 )
|
||||
endif
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
@ -377,9 +384,6 @@ endif
|
||||
instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
|
||||
|
||||
./libLLVMInsTrim.so: instrumentation/LLVMInsTrim.so.cc instrumentation/MarkNodes.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
-$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< instrumentation/MarkNodes.cc -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
|
||||
./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
ifeq "$(LLVM_MIN_4_0_1)" "0"
|
||||
$(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER))
|
||||
@ -502,6 +506,8 @@ install: all
|
||||
@echo .SH LICENSE >> ./$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ./$@
|
||||
@ln -sf afl-cc.8 ./afl-c++.8
|
||||
@ln -sf afl-cc.8 ./afl-clang-fast.8
|
||||
@ln -sf afl-cc.8 ./afl-clang-fast++.8
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
@ln -sf afl-cc.8 ./afl-clang-lto.8
|
||||
|
180
README.md
180
README.md
@ -2,11 +2,9 @@
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
|
||||
|
||||

|
||||
Release Version: [3.13c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
Release Version: [3.00c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
Github Version: 3.01a
|
||||
Github Version: 3.14a
|
||||
|
||||
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
@ -23,11 +21,22 @@
|
||||
mutations, more and better instrumentation, custom module support, etc.
|
||||
|
||||
If you want to use afl++ for your academic work, check the [papers page](https://aflplus.plus/papers/)
|
||||
on the website.
|
||||
on the website. To cite our work, look at the [Cite](#cite) section.
|
||||
For comparisons use the fuzzbench `aflplusplus` setup, or use `afl-clang-fast`
|
||||
with `AFL_LLVM_CMPLOG=1`.
|
||||
|
||||
## Major changes in afl++ 3.0
|
||||
## Major changes in afl++ 3.00 onwards:
|
||||
|
||||
With afl++ 3.0 we introduced changes that break some previous afl and afl++
|
||||
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++ 3.10 we introduced the following changes from previous behaviours:
|
||||
* 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.
|
||||
|
||||
With afl++ 3.00 we introduced changes that break some previous afl and afl++
|
||||
behaviours and defaults:
|
||||
|
||||
* There are no llvm_mode and gcc_plugin subdirectories anymore and there is
|
||||
@ -75,30 +84,32 @@ behaviours and defaults:
|
||||
|
||||
## Important features of afl++
|
||||
|
||||
afl++ supports llvm up to version 12, very fast binary fuzzing with QEMU 5.1
|
||||
with laf-intel and redqueen, unicorn mode, gcc plugin, full *BSD, Solaris and
|
||||
Android support and much, much, much more.
|
||||
afl++ supports llvm from 6.0 up to version 12, very fast binary fuzzing with 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 | qemu_mode | unicorn_mode |
|
||||
| -------------------------|:-------:|:---------:|:----------:|:----------------:|:------------:|
|
||||
| NeverZero | x86[_64]| x(1) | x | x | x |
|
||||
| Persistent Mode | | x | x | x86[_64]/arm[64] | x |
|
||||
| LAF-Intel / CompCov | | x | | x86[_64]/arm[64] | x86[_64]/arm |
|
||||
| CmpLog | | x | | x86[_64]/arm[64] | |
|
||||
| Selective Instrumentation| | 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) | |
|
||||
| Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode |
|
||||
| -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:|
|
||||
| Threadsafe counters | | x(3) | | | | |
|
||||
| NeverZero | x86[_64]| x(1) | x | x | x | x |
|
||||
| Persistent Mode | | x | x | x86[_64] | x86[_64]/arm[64] | x |
|
||||
| LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm |
|
||||
| CmpLog | | x | | x86[_64] | 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 Testcases | | x | x | x | x | x |
|
||||
|
||||
1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
|
||||
1. default for LLVM >= 9.0, env var 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. (currently unassigned)
|
||||
4. with pcguard mode and LTO mode for LLVM >= 11
|
||||
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 >= 4.1
|
||||
7. automatic in LTO mode with LLVM >= 11, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x`
|
||||
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 version that writes to a file to use with afl-fuzz' `-x`
|
||||
8. the snapshot LKM is currently unmaintained due to too many kernel changes coming too fast :-(
|
||||
|
||||
Among others, the following features and patches have been integrated:
|
||||
@ -135,6 +146,7 @@ behaviours and defaults:
|
||||
time when we are satisfied with its 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!!*
|
||||
* [release](https://github.com/AFLplusplus/AFLplusplus/tree/release) : the latest release
|
||||
* (any other) : experimental branches to work on specific features or testing
|
||||
new functionality or changes.
|
||||
|
||||
@ -170,7 +182,13 @@ If you want to build afl++ yourself you have many options.
|
||||
The easiest choice is to build and install everything:
|
||||
|
||||
```shell
|
||||
sudo apt install build-essential python3-dev automake flex bison libglib2.0-dev libpixman-1-dev clang python3-setuptools clang llvm llvm-dev libstdc++-dev
|
||||
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
|
||||
git clone https://github.com/AFLplusplus/AFLplusplus
|
||||
cd AFLplusplus
|
||||
make distrib
|
||||
sudo make install
|
||||
```
|
||||
@ -221,7 +239,7 @@ These build options exist:
|
||||
* 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 ASAN_BUILD=1`
|
||||
|
||||
## Good examples and writeups
|
||||
|
||||
@ -233,10 +251,12 @@ Here are some good writeups to show how to effectively use AFL++:
|
||||
* [https://securitylab.github.com/research/fuzzing-software-2](https://securitylab.github.com/research/fuzzing-software-2)
|
||||
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
|
||||
* [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)
|
||||
|
||||
If you are interested in fuzzing structured data (where you define what the
|
||||
structure is), these links have you covered:
|
||||
* 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)
|
||||
|
||||
@ -276,7 +296,7 @@ anything below 9 is not recommended.
|
||||
|
|
||||
v
|
||||
+---------------------------------+
|
||||
| clang/clang++ 3.3+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++)
|
||||
| clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++)
|
||||
+---------------------------------+ see [instrumentation/README.llvm.md](instrumentation/README.llvm.md)
|
||||
|
|
||||
| if not, or if the target fails with LLVM afl-clang-fast/++
|
||||
@ -298,7 +318,7 @@ Clickable README links for the chosen compiler:
|
||||
* [LTO mode - afl-clang-lto](instrumentation/README.lto.md)
|
||||
* [LLVM mode - afl-clang-fast](instrumentation/README.llvm.md)
|
||||
* [GCC_PLUGIN mode - afl-gcc-fast](instrumentation/README.gcc_plugin.md)
|
||||
* GCC/CLANG mode (afl-gcc/afl-clang) have no README as they have no own features
|
||||
* 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++,
|
||||
@ -358,7 +378,6 @@ There are many more options and modes available however these are most of the
|
||||
time less effective. See:
|
||||
* [instrumentation/README.ctx.md](instrumentation/README.ctx.md)
|
||||
* [instrumentation/README.ngram.md](instrumentation/README.ngram.md)
|
||||
* [instrumentation/README.instrim.md](instrumentation/README.instrim.md)
|
||||
|
||||
afl++ performs "never zero" counting in its bitmap. You can read more about this
|
||||
here:
|
||||
@ -393,10 +412,19 @@ How to do this is described below.
|
||||
|
||||
Then build the target. (Usually with `make`)
|
||||
|
||||
**NOTE**: sometimes configure and build systems are fickle and do not like
|
||||
stderr output (and think this means a test failure) - which is something
|
||||
afl++ like to do to show statistics. It is recommended to disable them via
|
||||
`export AFL_QUIET=1`.
|
||||
**NOTES**
|
||||
|
||||
1. sometimes configure and build systems are fickle and do not like
|
||||
stderr output (and think this means a test failure) - which is something
|
||||
afl++ likes to do to show statistics. It is recommended to disable them via
|
||||
`export AFL_QUIET=1`.
|
||||
|
||||
2. sometimes configure and build systems error on warnings - these should be
|
||||
disabled (e.g. `--disable-werror` for some configure scripts).
|
||||
|
||||
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!
|
||||
|
||||
##### configure
|
||||
|
||||
@ -410,7 +438,7 @@ described in [instrumentation/README.lto.md](instrumentation/README.lto.md).
|
||||
##### cmake
|
||||
|
||||
For `cmake` build systems this is usually done by:
|
||||
`mkdir build; cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..`
|
||||
`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
|
||||
@ -478,8 +506,9 @@ default.
|
||||
#### c) Minimizing all corpus files
|
||||
|
||||
The shorter the input files that still traverse the same path
|
||||
within the target, the better the fuzzing will be. This is done with `afl-tmin`
|
||||
however it is a long process as this has to be done for every file:
|
||||
within the target, the better the fuzzing will be. This minimization
|
||||
is done with `afl-tmin` however it is a long process as this has to
|
||||
be done for every file:
|
||||
|
||||
```
|
||||
mkdir input
|
||||
@ -530,12 +559,10 @@ If you need to stop and re-start the fuzzing, use the same command line options
|
||||
mutation mode!) and switch the input directory with a dash (`-`):
|
||||
`afl-fuzz -i - -o output -- bin/target -d @@`
|
||||
|
||||
Note that afl-fuzz enforces memory limits to prevent the system to run out
|
||||
of memory. By default this is 50MB for a process. If this is too little for
|
||||
the target (which you can usually see by afl-fuzz bailing with the message
|
||||
that it could not connect to the forkserver), then you can increase this
|
||||
with the `-m` option, the value is in MB. To disable any memory limits
|
||||
(beware!) set `-m none` - which is usually required for ASAN compiled targets.
|
||||
Memory limits are not enforced by afl-fuzz by default and the system may run
|
||||
out of memory. You can decrease the memory with the `-m` option, the value is
|
||||
in MB. If this is too small for the target, you can usually see this by
|
||||
afl-fuzz bailing with the message that it could not connect to the forkserver.
|
||||
|
||||
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
|
||||
@ -548,7 +575,9 @@ afl-fuzz has a variety of options that help to workaround target quirks like
|
||||
specific locations for the input file (`-f`), not performing deterministic
|
||||
fuzzing (`-d`) and many more. Check out `afl-fuzz -h`.
|
||||
|
||||
afl-fuzz never stops fuzzing. To terminate afl++ simply press Control-C.
|
||||
By default afl-fuzz never stops fuzzing. To terminate afl++ simply 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:
|
||||
@ -579,8 +608,9 @@ Every -M/-S entry needs a unique name (that can be whatever), however the same
|
||||
For every secondary fuzzer there should be a variation, e.g.:
|
||||
* one should fuzz the target that was compiled differently: with sanitizers
|
||||
activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ;
|
||||
export AFL_USE_CFISAN=1 ; `
|
||||
* one should fuzz the target with CMPLOG/redqueen (see above)
|
||||
export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN=1`)
|
||||
* one or two should fuzz the target with CMPLOG/redqueen (see above), at
|
||||
least one cmplog instance should follow transformations (`-l AT`)
|
||||
* one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV
|
||||
(see above). Important note: If you run more than one laf-intel/COMPCOV
|
||||
fuzzer and you want them to share their intermediate results, the main
|
||||
@ -650,8 +680,8 @@ If you see that an important area or a feature has not been covered so far then
|
||||
try to find an input that is able to reach that and start a new secondary in
|
||||
that fuzzing campaign with that seed as input, let it run for a few minutes,
|
||||
then terminate it. The main node will pick it up and make it available to the
|
||||
other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no
|
||||
free core.
|
||||
other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` or
|
||||
`export AFL_TRY_AFFINITY=1` if you have no free core.
|
||||
|
||||
Note that you in nearly all cases can never reach full coverage. A lot of
|
||||
functionality is usually behind options that were not activated or fuzz e.g.
|
||||
@ -752,22 +782,29 @@ campaigns as these are much shorter runnings.
|
||||
* for CMPLOG targets, 60% for `-l 2`, 40% for `-l 3`
|
||||
|
||||
4. Do *not* run any `-M` modes, just running `-S` modes is better for CI fuzzing.
|
||||
`-M` enables deterministic fuzzing, old queue handling etc. which is good for
|
||||
a fuzzing campaign but not good for short CI runs.
|
||||
|
||||
How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz](https://github.com/google/oss-fuzz/blob/4bb61df7905c6005000f5766e966e6fe30ab4559/infra/base-images/base-builder/compile_afl#L69).
|
||||
|
||||
## Fuzzing binary-only targets
|
||||
|
||||
When source code is *NOT* available, afl++ offers various support for fast,
|
||||
on-the-fly instrumentation of black-box binaries.
|
||||
|
||||
If you do not have to use Unicorn the following setup is recommended:
|
||||
If you do not have to use Unicorn the following setup is recommended to use
|
||||
qemu_mode:
|
||||
* run 1 afl-fuzz -Q instance with CMPLOG (`-c 0` + `AFL_COMPCOV_LEVEL=2`)
|
||||
* run 1 afl-fuzz -Q instance with QASAN (`AFL_USE_QASAN=1`)
|
||||
* run 1 afl-fuzz -Q instance with LAF (``AFL_PRELOAD=libcmpcov.so` + `AFL_COMPCOV_LEVEL=2`)
|
||||
Alternatively you can use frida_mode, just switch `-Q` with `-O` and remove the
|
||||
LAF instance.
|
||||
|
||||
Then run as many instances as you have cores left with either -Q mode or - better -
|
||||
use a binary rewriter like afl-dyninst, retrowrite, zipr, fibre, etc.
|
||||
use a binary rewriter like afl-dyninst, retrowrite, zaflr, etc.
|
||||
|
||||
For Qemu mode, check out the persistent mode and snapshot features, they give
|
||||
a huge speed improvement!
|
||||
For Qemu and Frida mode, check out the persistent mode, it gives a huge speed
|
||||
improvement if it is possible to use.
|
||||
|
||||
### QEMU
|
||||
|
||||
@ -779,18 +816,30 @@ feature by doing:
|
||||
cd qemu_mode
|
||||
./build_qemu_support.sh
|
||||
```
|
||||
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md) -
|
||||
check out the snapshot feature! :-)
|
||||
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
|
||||
If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md).
|
||||
The mode is approximately 2-5x slower than compile-time instrumentation, and is
|
||||
less conducive to parallelization.
|
||||
|
||||
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 persistent mode).
|
||||
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. As rewriting a binary is much faster than Qemu this is a highly
|
||||
recommended approach!
|
||||
caveats.
|
||||
|
||||
### Frida
|
||||
|
||||
Frida mode is sometimes faster and sometimes slower than Qemu mode.
|
||||
It is also newer, lacks COMPCOV, but supports MacOS.
|
||||
|
||||
```shell
|
||||
cd frida_mode
|
||||
make
|
||||
```
|
||||
For additional instructions and caveats, see [frida_mode/README.md](frida_mode/README.md).
|
||||
If possible you should use the persistent mode, see [qemu_frida/README.persistent.md](qemu_frida/README.persistent.md).
|
||||
The mode is approximately 2-5x slower than compile-time instrumentation, and is
|
||||
less conducive to parallelization.
|
||||
|
||||
### Unicorn
|
||||
|
||||
@ -1159,6 +1208,7 @@ without feedback, bug reports, or patches from:
|
||||
Josephine Calliotte Konrad Welc
|
||||
Thomas Rooijakkers David Carlier
|
||||
Ruben ten Hove Joey Jiao
|
||||
fuzzah
|
||||
```
|
||||
|
||||
Thank you!
|
||||
@ -1166,8 +1216,18 @@ Thank you!
|
||||
|
||||
## Cite
|
||||
|
||||
If you use AFLpluplus to compare to your work, please use either `afl-clang-lto`
|
||||
or `afl-clang-fast` with `AFL_LLVM_CMPLOG=1` for building targets and
|
||||
`afl-fuzz` with the command line option `-l 2` for fuzzing.
|
||||
The most effective setup is the `aflplusplus` default configuration on Google's [fuzzbench](https://github.com/google/fuzzbench/tree/master/fuzzers/aflplusplus).
|
||||
|
||||
If you use AFLplusplus in scientific work, consider citing [our paper](https://www.usenix.org/conference/woot20/presentation/fioraldi) presented at WOOT'20:
|
||||
```
|
||||
|
||||
+ Andrea Fioraldi, Dominik Maier, Heiko Eißfeldt, and Marc Heuse. “AFL++: Combining incremental steps of fuzzing research”. In 14th USENIX Workshop on Offensive Technologies (WOOT 20). USENIX Association, Aug. 2020.
|
||||
|
||||
Bibtex:
|
||||
|
||||
```bibtex
|
||||
@inproceedings {AFLplusplus-Woot20,
|
||||
author = {Andrea Fioraldi and Dominik Maier and Heiko Ei{\ss}feldt and Marc Heuse},
|
||||
title = {{AFL++}: Combining Incremental Steps of Fuzzing Research},
|
||||
|
18
TODO.md
18
TODO.md
@ -2,20 +2,22 @@
|
||||
|
||||
## Roadmap 3.00+
|
||||
|
||||
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
|
||||
- CPU affinity for many cores? There seems to be an issue > 96 cores
|
||||
- align map to 64 bytes but keep real IDs
|
||||
- Update afl->pending_not_fuzzed for MOpt
|
||||
- put fuzz target in top line of UI
|
||||
- afl-plot to support multiple plot_data
|
||||
- afl_custom_fuzz_splice_optin()
|
||||
- afl_custom_splice()
|
||||
- intel-pt tracer
|
||||
- better autodetection of shifting runtime timeout values
|
||||
- cmplog: use colorization input for havoc?
|
||||
- parallel builds for source-only targets
|
||||
|
||||
|
||||
## Further down the road
|
||||
|
||||
afl-fuzz:
|
||||
- setting min_len/max_len/start_offset/end_offset limits for mutation output
|
||||
- add __sanitizer_cov_trace_cmp* support via shmem
|
||||
|
||||
llvm_mode:
|
||||
- add __sanitizer_cov_trace_cmp* support
|
||||
|
||||
qemu_mode:
|
||||
- non colliding instrumentation
|
||||
@ -26,9 +28,13 @@ qemu_mode:
|
||||
- add/implement AFL_QEMU_INST_LIBLIST and AFL_QEMU_NOINST_PROGRAM
|
||||
- add/implement AFL_QEMU_INST_REGIONS as a list of _START/_END addresses
|
||||
|
||||
|
||||
## Ideas
|
||||
|
||||
- LTO/sancov: write current edge to prev_loc and use that information when
|
||||
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?
|
||||
- new instrumentation option for a thread-safe variant of feedback to shared mem.
|
||||
The user decides, if this is needed (eg the target is multithreaded).
|
||||
|
45
afl-cmin
45
afl-cmin
@ -106,6 +106,7 @@ function usage() {
|
||||
" -f file - location read by the fuzzed program (stdin)\n" \
|
||||
" -m megs - memory limit for child process ("mem_limit" MB)\n" \
|
||||
" -t msec - run time limit for child process (none)\n" \
|
||||
" -O - use binary-only instrumentation (FRIDA mode)\n" \
|
||||
" -Q - use binary-only instrumentation (QEMU mode)\n" \
|
||||
" -U - use unicorn-based instrumentation (unicorn mode)\n" \
|
||||
"\n" \
|
||||
@ -118,11 +119,13 @@ function usage() {
|
||||
"Environment variables used:\n" \
|
||||
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
|
||||
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
|
||||
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \
|
||||
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \
|
||||
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
|
||||
"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
|
||||
"AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \
|
||||
"AFL_SKIP_BIN_CHECK: skip check for target binary\n"
|
||||
"AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \
|
||||
"AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \
|
||||
"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
|
||||
"printed to stdout\n" \
|
||||
"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@ -140,7 +143,7 @@ BEGIN {
|
||||
# process options
|
||||
Opterr = 1 # default is to diagnose
|
||||
Optind = 1 # skip ARGV[0]
|
||||
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCQU?")) != -1) {
|
||||
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCOQU?")) != -1) {
|
||||
if (_go_c == "i") {
|
||||
if (!Optarg) usage()
|
||||
if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
@ -180,6 +183,12 @@ BEGIN {
|
||||
extra_par = extra_par " -e"
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "O") {
|
||||
if (frida_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
extra_par = extra_par " -O"
|
||||
frida_mode = 1
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "Q") {
|
||||
if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
extra_par = extra_par " -Q"
|
||||
@ -243,7 +252,7 @@ BEGIN {
|
||||
if (!stdin_file) {
|
||||
found_atat = 0
|
||||
for (prog_args_ind in prog_args) {
|
||||
if ("@@" == prog_args[prog_args_ind]) {
|
||||
if (match(prog_args[prog_args_ind], "@@") != 0) {
|
||||
found_atat = 1
|
||||
break
|
||||
}
|
||||
@ -275,7 +284,7 @@ BEGIN {
|
||||
target_bin = tnew
|
||||
}
|
||||
|
||||
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !unicorn_mode) {
|
||||
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) {
|
||||
if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) {
|
||||
print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr"
|
||||
exit 1
|
||||
@ -287,6 +296,10 @@ BEGIN {
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (0 == system( "test -d "in_dir"/default" )) {
|
||||
in_dir = in_dir "/default"
|
||||
}
|
||||
|
||||
if (0 == system( "test -d "in_dir"/queue" )) {
|
||||
in_dir = in_dir "/queue"
|
||||
}
|
||||
@ -342,8 +355,10 @@ BEGIN {
|
||||
} else {
|
||||
stat_format = "-f '%z %N'" # *BSD, MacOS
|
||||
}
|
||||
cmdline = "cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} \\; | sort -k1n -k2r"
|
||||
cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
|
||||
cmdline = "(cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)"
|
||||
#cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
|
||||
#cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r"
|
||||
#cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r"
|
||||
while (cmdline | getline) {
|
||||
sub(/^[0-9]+ (\.\/)?/,"",$0)
|
||||
infilesSmallToBig[i++] = $0
|
||||
@ -354,12 +369,12 @@ BEGIN {
|
||||
|
||||
# Make sure that we're not dealing with a directory.
|
||||
|
||||
if (0 == system("test -d "in_dir"/"first_file)) {
|
||||
if (0 == system("test -d ""\""in_dir"/"first_file"\"")) {
|
||||
print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (0 == system("ln "in_dir"/"first_file" "trace_dir"/.link_test")) {
|
||||
if (0 == system("ln \""in_dir"/"first_file"\" "trace_dir"/.link_test")) {
|
||||
cp_tool = "ln"
|
||||
} else {
|
||||
cp_tool = "cp"
|
||||
@ -374,7 +389,7 @@ BEGIN {
|
||||
if (!stdin_file) {
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
|
||||
} else {
|
||||
system("cp "in_dir"/"first_file" "stdin_file)
|
||||
system("cp \""in_dir"/"first_file"\" "stdin_file)
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
@ -411,8 +426,8 @@ BEGIN {
|
||||
retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
|
||||
} else {
|
||||
print " Processing "in_count" files (forkserver mode)..."
|
||||
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string" </dev/null"
|
||||
retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null"
|
||||
retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
if (retval && !AFL_CMIN_CRASHES_ONLY) {
|
||||
@ -496,7 +511,7 @@ BEGIN {
|
||||
|
||||
# copy file unless already done
|
||||
if (! (fn in file_already_copied)) {
|
||||
system(cp_tool" "in_dir"/"fn" "out_dir"/"fn)
|
||||
system(cp_tool" \""in_dir"/"fn"\" \""out_dir"/"fn"\"")
|
||||
file_already_copied[fn] = ""
|
||||
++out_count
|
||||
#printf "tuple nr %d (%d cnt=%d) -> %s\n",tcnt,key,key_count[key],fn > trace_dir"/.log"
|
||||
|
@ -53,7 +53,7 @@ unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
||||
|
||||
export AFL_QUIET=1
|
||||
|
||||
while getopts "+i:o:f:m:t:eQUCh" opt; do
|
||||
while getopts "+i:o:f:m:t:eOQUCh" opt; do
|
||||
|
||||
case "$opt" in
|
||||
|
||||
@ -83,6 +83,10 @@ while getopts "+i:o:f:m:t:eQUCh" opt; do
|
||||
"C")
|
||||
export AFL_CMIN_CRASHES_ONLY=1
|
||||
;;
|
||||
"O")
|
||||
EXTRA_PAR="$EXTRA_PAR -O"
|
||||
FRIDA_MODE=1
|
||||
;;
|
||||
"Q")
|
||||
EXTRA_PAR="$EXTRA_PAR -Q"
|
||||
QEMU_MODE=1
|
||||
@ -118,6 +122,7 @@ Execution control settings:
|
||||
-f file - location read by the fuzzed program (stdin)
|
||||
-m megs - memory limit for child process ($MEM_LIMIT MB)
|
||||
-t msec - run time limit for child process (none)
|
||||
-O - use binary-only instrumentation (FRIDA mode)
|
||||
-Q - use binary-only instrumentation (QEMU mode)
|
||||
-U - use unicorn-based instrumentation (Unicorn mode)
|
||||
|
||||
@ -209,7 +214,7 @@ if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
|
||||
|
||||
fi
|
||||
|
||||
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
|
||||
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
|
||||
|
||||
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
|
||||
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
|
||||
@ -223,6 +228,7 @@ if [ ! -d "$IN_DIR" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test -d "$IN_DIR/default" && IN_DIR="$IN_DIR/default"
|
||||
test -d "$IN_DIR/queue" && IN_DIR="$IN_DIR/queue"
|
||||
|
||||
find "$OUT_DIR" -name 'id[:_]*' -maxdepth 1 -exec rm -- {} \; 2>/dev/null
|
||||
|
21
afl-plot
21
afl-plot
@ -99,7 +99,7 @@ if [ ! -d "$outputdir" ]; then
|
||||
|
||||
fi
|
||||
|
||||
rm -f "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png"
|
||||
rm -f "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png"
|
||||
mv -f "$outputdir/index.html" "$outputdir/index.html.orig" 2>/dev/null
|
||||
|
||||
echo "[*] Generating plots..."
|
||||
@ -111,9 +111,9 @@ set terminal png truecolor enhanced size 1000,300 butt
|
||||
|
||||
set output '$outputdir/high_freq.png'
|
||||
|
||||
set xdata time
|
||||
set timefmt '%s'
|
||||
set format x "%b %d\n%H:%M"
|
||||
#set xdata time
|
||||
#set timefmt '%s'
|
||||
#set format x "%b %d\n%H:%M"
|
||||
set tics font 'small'
|
||||
unset mxtics
|
||||
unset mytics
|
||||
@ -127,9 +127,8 @@ set key outside
|
||||
set autoscale xfixmin
|
||||
set autoscale xfixmax
|
||||
|
||||
set xlabel "all times in UTC" font "small"
|
||||
#set xlabel "all times in UTC" font "small"
|
||||
|
||||
set ytics auto
|
||||
plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
|
||||
'' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
|
||||
'' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\
|
||||
@ -139,7 +138,6 @@ plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' lin
|
||||
set terminal png truecolor enhanced size 1000,200 butt
|
||||
set output '$outputdir/low_freq.png'
|
||||
|
||||
set ytics 1
|
||||
plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
|
||||
'' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\
|
||||
'' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\
|
||||
@ -148,10 +146,14 @@ plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb
|
||||
set terminal png truecolor enhanced size 1000,200 butt
|
||||
set output '$outputdir/exec_speed.png'
|
||||
|
||||
set ytics auto
|
||||
plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
|
||||
'$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
|
||||
|
||||
set terminal png truecolor enhanced size 1000,300 butt
|
||||
set output '$outputdir/edges.png'
|
||||
|
||||
plot '$inputdir/plot_data' using 1:13 with lines title ' edges' linecolor rgb '#0090ff' linewidth 3
|
||||
|
||||
_EOF_
|
||||
|
||||
) | gnuplot
|
||||
@ -172,6 +174,7 @@ cat >"$outputdir/index.html" <<_EOF_
|
||||
<tr><td><b>Generated on:</b></td><td>`date`</td></tr>
|
||||
</table>
|
||||
<p>
|
||||
<img src="edges.png" width=1000 height=300>
|
||||
<img src="high_freq.png" width=1000 height=300><p>
|
||||
<img src="low_freq.png" width=1000 height=200><p>
|
||||
<img src="exec_speed.png" width=1000 height=200>
|
||||
@ -183,7 +186,7 @@ _EOF_
|
||||
# sensitive, this seems like a reasonable trade-off.
|
||||
|
||||
chmod 755 "$outputdir"
|
||||
chmod 644 "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/index.html"
|
||||
chmod 644 "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png" "$outputdir/index.html"
|
||||
|
||||
echo "[+] All done - enjoy your charts!"
|
||||
|
||||
|
@ -7,7 +7,7 @@ test "$1" = "-h" -o "$1" = "-hh" && {
|
||||
echo afl-system-config has no command line options
|
||||
echo
|
||||
echo afl-system reconfigures the system to a high performance fuzzing state
|
||||
echo WARNING: this reduces the security of the system
|
||||
echo "WARNING: this reduces the security of the system!"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
@ -15,14 +15,20 @@ test "$1" = "-h" -o "$1" = "-hh" && {
|
||||
DONE=
|
||||
PLATFORM=`uname -s`
|
||||
echo This reconfigures the system to have a better fuzzing performance.
|
||||
echo "WARNING: this reduces the security of the system!"
|
||||
echo
|
||||
if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then
|
||||
echo "Warning: you need to be root to run this!"
|
||||
# we do not exit as other mechanisms exist that allows to do this than
|
||||
# being root. let the errors speak for themselves.
|
||||
fi
|
||||
sleep 1
|
||||
if [ "$PLATFORM" = "Linux" ] ; then
|
||||
{
|
||||
sysctl -w kernel.core_pattern=core
|
||||
sysctl -w kernel.core_uses_pid=0
|
||||
# Arch Linux requires core_pattern to be empty :(
|
||||
test -e /etc/arch-release && sysctl -w kernel.core_pattern=
|
||||
test -e /etc/arch-release || sysctl -w kernel.core_pattern=core
|
||||
sysctl -w kernel.randomize_va_space=0
|
||||
sysctl -w kernel.sched_child_runs_first=1
|
||||
sysctl -w kernel.sched_autogroup_enabled=1
|
||||
@ -35,12 +41,17 @@ if [ "$PLATFORM" = "Linux" ] ; then
|
||||
test -e /sys/devices/system/cpu/intel_pstate/no_turbo && echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
|
||||
test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cpu/cpufreq/boost
|
||||
test -e /sys/devices/system/cpu/intel_pstate/max_perf_pct && echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct
|
||||
test -n "$(which auditctl)" && auditctl -a never,task >/dev/null 2>&1
|
||||
} > /dev/null
|
||||
echo Settings applied.
|
||||
echo
|
||||
dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
|
||||
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
|
||||
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=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"'
|
||||
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
|
||||
echo
|
||||
}
|
||||
echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "FreeBSD" ] ; then
|
||||
@ -49,48 +60,70 @@ if [ "$PLATFORM" = "FreeBSD" ] ; then
|
||||
sysctl kern.elf64.aslr.enable=0
|
||||
} > /dev/null
|
||||
echo Settings applied.
|
||||
echo
|
||||
cat <<EOF
|
||||
In order to suppress core file generation during fuzzing it is recommended to set
|
||||
me:\\
|
||||
:coredumpsize=0:
|
||||
in the ~/.login_conf file for the user used for fuzzing.
|
||||
EOF
|
||||
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
|
||||
echo ' sysctl hw.ibrs_disable=1'
|
||||
echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "OpenBSD" ] ; then
|
||||
echo
|
||||
echo 'System security features cannot be disabled on OpenBSD.'
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "DragonFly" ] ; then
|
||||
#/sbin/sysctl kern.corefile=/dev/null
|
||||
#echo Settings applied.
|
||||
cat <<EOF
|
||||
In order to suppress core file generation during fuzzing it is recommended to set
|
||||
me:\\
|
||||
:coredumpsize=0:
|
||||
in the ~/.login_conf file for the user used for fuzzing.
|
||||
EOF
|
||||
echo
|
||||
echo 'System security features cannot be disabled on DragonFly.'
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "NetBSD" ] ; then
|
||||
{
|
||||
#echo It is recommended to enable unprivileged users to set cpu affinity
|
||||
#echo to be able to use afl-gotcpu meaningfully.
|
||||
/sbin/sysctl -w security.models.extensions.user_set_cpu_affinity=1
|
||||
} > /dev/null
|
||||
echo Settings applied.
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "Darwin" ] ; then
|
||||
sysctl kern.sysv.shmmax=8388608
|
||||
sysctl kern.sysv.shmseg=48
|
||||
sysctl kern.sysv.shmall=98304
|
||||
echo Settings applied.
|
||||
echo
|
||||
if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
|
||||
echo We unload the default crash reporter here
|
||||
echo
|
||||
echo Unloading the default crash reporter
|
||||
SL=/System/Library; PL=com.apple.ReportCrash
|
||||
launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
|
||||
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
|
||||
echo Settings applied.
|
||||
else
|
||||
echo Nothing to do.
|
||||
launchctl unload -w ${SL}/LaunchAgents/${PL}.plist >/dev/null 2>&1
|
||||
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
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "Haiku" ] ; then
|
||||
SETTINGS=~/config/settings/system/debug_server/settings
|
||||
DEBUG_SERVER_DIR=~/config/settings/system/debug_server
|
||||
[ ! -d ${DEBUG_SERVER_DIR} ] && mkdir -p ${DEBUG_SERVER_DIR}
|
||||
SETTINGS=${DEBUG_SERVER_DIR}/settings
|
||||
[ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \
|
||||
echo We change the debug_server default_action from user to silenty kill; \
|
||||
echo We change the debug_server default_action from user to silently kill; \
|
||||
[ ! -r ${SETTINGS} ] && echo "default_action kill" >${SETTINGS} || { mv ${SETTINGS} s.tmp; sed -e "s/default_action\s\s*user/default_action kill/" s.tmp > ${SETTINGS}; rm s.tmp; }; \
|
||||
echo Settings applied.; \
|
||||
echo Settings applied.; echo; \
|
||||
}
|
||||
DONE=1
|
||||
fi
|
||||
|
56
afl-whatsup
56
afl-whatsup
@ -21,32 +21,41 @@
|
||||
echo "$0 status check tool for afl-fuzz by Michal Zalewski"
|
||||
echo
|
||||
test "$1" = "-h" -o "$1" = "-hh" && {
|
||||
echo $0 [-s] output_directory
|
||||
echo "Usage: $0 [-s] [-d] afl_output_directory"
|
||||
echo
|
||||
echo Options:
|
||||
echo -s - skip details and output summary results only
|
||||
echo " -s - skip details and output summary results only"
|
||||
echo " -d - include dead fuzzer stats"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "$1" = "-s" ]; then
|
||||
unset SUMMARY_ONLY
|
||||
unset PROCESS_DEAD
|
||||
|
||||
SUMMARY_ONLY=1
|
||||
DIR="$2"
|
||||
while [ "$1" = "-s" -o "$1" = "-d" ]; do
|
||||
|
||||
else
|
||||
if [ "$1" = "-s" ]; then
|
||||
SUMMARY_ONLY=1
|
||||
fi
|
||||
|
||||
unset SUMMARY_ONLY
|
||||
DIR="$1"
|
||||
if [ "$1" = "-d" ]; then
|
||||
PROCESS_DEAD=1
|
||||
fi
|
||||
|
||||
shift
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
DIR="$1"
|
||||
|
||||
if [ "$DIR" = "" ]; then
|
||||
|
||||
echo "Usage: $0 [ -s ] afl_sync_dir" 1>&2
|
||||
echo "Usage: $0 [-s] [-d] afl_output_directory" 1>&2
|
||||
echo 1>&2
|
||||
echo "The -s option causes the tool to skip all the per-fuzzer trivia and show" 1>&2
|
||||
echo "just the summary results. See docs/parallel_fuzzing.md for additional tips." 1>&2
|
||||
echo Options: 1>&2
|
||||
echo " -s - skip details and output summary results only" 1>&2
|
||||
echo " -d - include dead fuzzer stats" 1>&2
|
||||
echo 1>&2
|
||||
exit 1
|
||||
|
||||
@ -133,7 +142,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
|
||||
. "$TMP"
|
||||
|
||||
RUN_UNIX=$((CUR_TIME - start_time))
|
||||
RUN_UNIX=$run_time
|
||||
RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
|
||||
RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
|
||||
|
||||
@ -160,7 +169,13 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
fi
|
||||
|
||||
DEAD_CNT=$((DEAD_CNT + 1))
|
||||
continue
|
||||
last_path=0
|
||||
|
||||
if [ "$PROCESS_DEAD" = "" ]; then
|
||||
|
||||
continue
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
@ -252,13 +267,24 @@ fmt_duration $TOTAL_LAST_PATH && TOTAL_LAST_PATH=$DUR_STRING
|
||||
|
||||
test "$TOTAL_TIME" = "0" && TOTAL_TIME=1
|
||||
|
||||
if [ "$PROCESS_DEAD" = "" ]; then
|
||||
|
||||
TXT="excluded from stats"
|
||||
|
||||
else
|
||||
|
||||
TXT="included in stats"
|
||||
ALIVE_CNT=$(($ALIVE_CNT - $DEAD_CNT))
|
||||
|
||||
fi
|
||||
|
||||
echo "Summary stats"
|
||||
echo "============="
|
||||
echo
|
||||
echo " Fuzzers alive : $ALIVE_CNT"
|
||||
|
||||
if [ ! "$DEAD_CNT" = "0" ]; then
|
||||
echo " Dead or remote : $DEAD_CNT (excluded from stats)"
|
||||
echo " Dead or remote : $DEAD_CNT ($TXT)"
|
||||
fi
|
||||
|
||||
echo " Total run time : $FMT_TIME"
|
||||
|
@ -10,6 +10,8 @@ cc_library_shared {
|
||||
"-fPIC",
|
||||
"-fpermissive",
|
||||
"-std=c++11",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-variable",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
@ -77,6 +79,8 @@ cc_library_shared {
|
||||
"-O0",
|
||||
"-funroll-loops",
|
||||
"-fPIC",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-function",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
@ -99,6 +103,8 @@ cc_library_shared {
|
||||
"-O0",
|
||||
"-funroll-loops",
|
||||
"-fPIC",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-pointer-sign",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
|
@ -3,6 +3,14 @@
|
||||
Custom mutators enhance and alter the mutation strategies of afl++.
|
||||
For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md).
|
||||
|
||||
## Examples
|
||||
|
||||
The `./examples` folder contains examples for custom mutators in python and C.
|
||||
|
||||
## Rust
|
||||
|
||||
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
|
||||
|
||||
## The afl++ Grammar Mutator
|
||||
|
||||
If you use git to clone afl++, then the following will incorporate our
|
||||
@ -46,3 +54,6 @@ https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4
|
||||
has a transform function you need to fill for your protobuf format, however
|
||||
needs to be ported to the updated afl++ custom mutator API (not much work):
|
||||
https://github.com/thebabush/afl-libprotobuf-mutator
|
||||
|
||||
same as above but is for current afl++:
|
||||
https://github.com/P1umer/AFLplusplus-protobuf-mutator
|
||||
|
@ -12,12 +12,13 @@ import random, re, io
|
||||
# The XmlMutatorMin class #
|
||||
###########################
|
||||
|
||||
|
||||
class XmlMutatorMin:
|
||||
|
||||
"""
|
||||
Optionals parameters:
|
||||
seed Seed used by the PRNG (default: "RANDOM")
|
||||
verbose Verbosity (default: False)
|
||||
Optionals parameters:
|
||||
seed Seed used by the PRNG (default: "RANDOM")
|
||||
verbose Verbosity (default: False)
|
||||
"""
|
||||
|
||||
def __init__(self, seed="RANDOM", verbose=False):
|
||||
@ -41,7 +42,12 @@ class XmlMutatorMin:
|
||||
self.tree = None
|
||||
|
||||
# High-level mutators (no database needed)
|
||||
hl_mutators_delete = ["del_node_and_children", "del_node_but_children", "del_attribute", "del_content"] # Delete items
|
||||
hl_mutators_delete = [
|
||||
"del_node_and_children",
|
||||
"del_node_but_children",
|
||||
"del_attribute",
|
||||
"del_content",
|
||||
] # Delete items
|
||||
hl_mutators_fuzz = ["fuzz_attribute"] # Randomly change attribute values
|
||||
|
||||
# Exposed mutators
|
||||
@ -74,7 +80,9 @@ class XmlMutatorMin:
|
||||
|
||||
""" Serialize a XML document. Basic wrapper around lxml.tostring() """
|
||||
|
||||
return ET.tostring(tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding)
|
||||
return ET.tostring(
|
||||
tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding
|
||||
)
|
||||
|
||||
def __ver(self, version):
|
||||
|
||||
@ -161,7 +169,7 @@ class XmlMutatorMin:
|
||||
# Randomly pick one the function calls
|
||||
(func, args) = random.choice(l)
|
||||
# Split by "," and randomly pick one of the arguments
|
||||
value = random.choice(args.split(','))
|
||||
value = random.choice(args.split(","))
|
||||
# Remove superfluous characters
|
||||
unclean_value = value
|
||||
value = value.strip(" ").strip("'")
|
||||
@ -170,49 +178,49 @@ class XmlMutatorMin:
|
||||
value = attrib_value
|
||||
|
||||
# For each type, define some possible replacement values
|
||||
choices_number = ( \
|
||||
"0", \
|
||||
"11111", \
|
||||
"-128", \
|
||||
"2", \
|
||||
"-1", \
|
||||
"1/3", \
|
||||
"42/0", \
|
||||
"1094861636 idiv 1.0", \
|
||||
"-1123329771506872 idiv 3.8", \
|
||||
"17=$numericRTF", \
|
||||
str(3 + random.randrange(0, 100)), \
|
||||
)
|
||||
choices_number = (
|
||||
"0",
|
||||
"11111",
|
||||
"-128",
|
||||
"2",
|
||||
"-1",
|
||||
"1/3",
|
||||
"42/0",
|
||||
"1094861636 idiv 1.0",
|
||||
"-1123329771506872 idiv 3.8",
|
||||
"17=$numericRTF",
|
||||
str(3 + random.randrange(0, 100)),
|
||||
)
|
||||
|
||||
choices_letter = ( \
|
||||
"P" * (25 * random.randrange(1, 100)), \
|
||||
"%s%s%s%s%s%s", \
|
||||
"foobar", \
|
||||
)
|
||||
choices_letter = (
|
||||
"P" * (25 * random.randrange(1, 100)),
|
||||
"%s%s%s%s%s%s",
|
||||
"foobar",
|
||||
)
|
||||
|
||||
choices_alnum = ( \
|
||||
"Abc123", \
|
||||
"020F0302020204030204", \
|
||||
"020F0302020204030204" * (random.randrange(5, 20)), \
|
||||
)
|
||||
choices_alnum = (
|
||||
"Abc123",
|
||||
"020F0302020204030204",
|
||||
"020F0302020204030204" * (random.randrange(5, 20)),
|
||||
)
|
||||
|
||||
# Fuzz the value
|
||||
if random.choice((True,False)) and value == "":
|
||||
if random.choice((True, False)) and value == "":
|
||||
|
||||
# Empty
|
||||
new_value = value
|
||||
|
||||
elif random.choice((True,False)) and value.isdigit():
|
||||
elif random.choice((True, False)) and value.isdigit():
|
||||
|
||||
# Numbers
|
||||
new_value = random.choice(choices_number)
|
||||
|
||||
elif random.choice((True,False)) and value.isalpha():
|
||||
elif random.choice((True, False)) and value.isalpha():
|
||||
|
||||
# Letters
|
||||
new_value = random.choice(choices_letter)
|
||||
|
||||
elif random.choice((True,False)) and value.isalnum():
|
||||
elif random.choice((True, False)) and value.isalnum():
|
||||
|
||||
# Alphanumeric
|
||||
new_value = random.choice(choices_alnum)
|
||||
@ -232,22 +240,25 @@ class XmlMutatorMin:
|
||||
|
||||
# Log something
|
||||
if self.verbose:
|
||||
print("Fuzzing attribute #%i '%s' of tag #%i '%s'" % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag))
|
||||
print(
|
||||
"Fuzzing attribute #%i '%s' of tag #%i '%s'"
|
||||
% (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag)
|
||||
)
|
||||
|
||||
# Modify the attribute
|
||||
rand_elem.set(rand_attrib, new_value.decode("utf-8"))
|
||||
|
||||
def __del_node_and_children(self):
|
||||
|
||||
""" High-level minimizing mutator
|
||||
Delete a random node and its children (i.e. delete a random tree) """
|
||||
"""High-level minimizing mutator
|
||||
Delete a random node and its children (i.e. delete a random tree)"""
|
||||
|
||||
self.__del_node(True)
|
||||
|
||||
def __del_node_but_children(self):
|
||||
|
||||
""" High-level minimizing mutator
|
||||
Delete a random node but its children (i.e. link them to the parent of the deleted node) """
|
||||
"""High-level minimizing mutator
|
||||
Delete a random node but its children (i.e. link them to the parent of the deleted node)"""
|
||||
|
||||
self.__del_node(False)
|
||||
|
||||
@ -270,7 +281,10 @@ class XmlMutatorMin:
|
||||
# Log something
|
||||
if self.verbose:
|
||||
but_or_and = "and" if delete_children else "but"
|
||||
print("Deleting tag #%i '%s' %s its children" % (rand_elem_id, rand_elem.tag, but_or_and))
|
||||
print(
|
||||
"Deleting tag #%i '%s' %s its children"
|
||||
% (rand_elem_id, rand_elem.tag, but_or_and)
|
||||
)
|
||||
|
||||
if delete_children is False:
|
||||
# Link children of the random (soon to be deleted) node to its parent
|
||||
@ -282,8 +296,8 @@ class XmlMutatorMin:
|
||||
|
||||
def __del_content(self):
|
||||
|
||||
""" High-level minimizing mutator
|
||||
Delete the attributes and children of a random node """
|
||||
"""High-level minimizing mutator
|
||||
Delete the attributes and children of a random node"""
|
||||
|
||||
# Select a node to modify
|
||||
(rand_elem_id, rand_elem) = self.__pick_element()
|
||||
@ -297,8 +311,8 @@ class XmlMutatorMin:
|
||||
|
||||
def __del_attribute(self):
|
||||
|
||||
""" High-level minimizing mutator
|
||||
Delete a random attribute from a random node """
|
||||
"""High-level minimizing mutator
|
||||
Delete a random attribute from a random node"""
|
||||
|
||||
# Select a node to modify
|
||||
(rand_elem_id, rand_elem) = self.__pick_element()
|
||||
@ -318,7 +332,10 @@ class XmlMutatorMin:
|
||||
|
||||
# Log something
|
||||
if self.verbose:
|
||||
print("Deleting attribute #%i '%s' of tag #%i '%s'" % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag))
|
||||
print(
|
||||
"Deleting attribute #%i '%s' of tag #%i '%s'"
|
||||
% (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag)
|
||||
)
|
||||
|
||||
# Delete the attribute
|
||||
rand_elem.attrib.pop(rand_attrib)
|
||||
@ -329,4 +346,3 @@ class XmlMutatorMin:
|
||||
|
||||
# High-level mutation
|
||||
self.__exec_among(self, self.hl_mutators_all, min, max)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
'''
|
||||
"""
|
||||
Module containing functions shared between multiple AFL modules
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
@ -12,7 +12,7 @@ License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
@contact: choller@mozilla.com
|
||||
'''
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import random
|
||||
@ -23,18 +23,18 @@ import re
|
||||
def randel(l):
|
||||
if not l:
|
||||
return None
|
||||
return l[random.randint(0, len(l)-1)]
|
||||
return l[random.randint(0, len(l) - 1)]
|
||||
|
||||
|
||||
def randel_pop(l):
|
||||
if not l:
|
||||
return None
|
||||
return l.pop(random.randint(0, len(l)-1))
|
||||
return l.pop(random.randint(0, len(l) - 1))
|
||||
|
||||
|
||||
def write_exc_example(data, exc):
|
||||
exc_name = re.sub(r'[^a-zA-Z0-9]', '_', repr(exc))
|
||||
exc_name = re.sub(r"[^a-zA-Z0-9]", "_", repr(exc))
|
||||
|
||||
if not os.path.exists(exc_name):
|
||||
with open(exc_name, 'w') as f:
|
||||
with open(exc_name, "w") as f:
|
||||
f.write(data)
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
'''
|
||||
"""
|
||||
Example Python Module for AFLFuzz
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
@ -12,7 +12,7 @@ License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
@contact: choller@mozilla.com
|
||||
'''
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
@ -26,12 +26,12 @@ COMMANDS = [
|
||||
|
||||
|
||||
def init(seed):
|
||||
'''
|
||||
"""
|
||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||
|
||||
@type seed: int
|
||||
@param seed: A 32-bit random value
|
||||
'''
|
||||
"""
|
||||
random.seed(seed)
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ def deinit():
|
||||
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
'''
|
||||
"""
|
||||
Called per fuzzing iteration.
|
||||
|
||||
@type buf: bytearray
|
||||
@ -55,13 +55,14 @@ def fuzz(buf, add_buf, max_size):
|
||||
|
||||
@rtype: bytearray
|
||||
@return: A new bytearray containing the mutated data
|
||||
'''
|
||||
"""
|
||||
ret = bytearray(100)
|
||||
|
||||
ret[:3] = random.choice(COMMANDS)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
# Uncomment and implement the following methods if you want to use a custom
|
||||
# trimming algorithm. See also the documentation for a better API description.
|
||||
|
@ -45,6 +45,7 @@
|
||||
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
|
||||
and return the original `len`.
|
||||
|
||||
NOTE: the following is currently NOT true, we abort in this case!
|
||||
2) If you want to skip this test case altogether and have AFL generate a
|
||||
new one, return 0 or set `*out_buf = NULL`.
|
||||
Use this sparingly - it's faster than running the target program
|
||||
@ -53,14 +54,14 @@
|
||||
3) If you want to modify the test case, allocate an appropriately-sized
|
||||
buffer, move the data into that buffer, make the necessary changes, and
|
||||
then return the new pointer as out_buf. Return an appropriate len
|
||||
afterwards.
|
||||
afterwards.
|
||||
|
||||
Note that the buffer will *not* be freed for you. To avoid memory leaks,
|
||||
you need to free it or reuse it on subsequent calls (as shown below).
|
||||
|
||||
*** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
|
||||
|
||||
Aight. The example below shows a simple postprocessor that tries to make
|
||||
Alright. The example below shows a simple postprocessor that tries to make
|
||||
sure that all input files start with "GIF89a".
|
||||
|
||||
PS. If you don't like C, you can try out the unix-based wrapper from
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
'''
|
||||
"""
|
||||
Simple Chunk Cross-Over Replacement Module for AFLFuzz
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
@ -12,24 +12,24 @@ License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
@contact: choller@mozilla.com
|
||||
'''
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
|
||||
def init(seed):
|
||||
'''
|
||||
"""
|
||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||
|
||||
@type seed: int
|
||||
@param seed: A 32-bit random value
|
||||
'''
|
||||
"""
|
||||
# Seed our RNG
|
||||
random.seed(seed)
|
||||
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
'''
|
||||
"""
|
||||
Called per fuzzing iteration.
|
||||
|
||||
@type buf: bytearray
|
||||
@ -44,7 +44,7 @@ def fuzz(buf, add_buf, max_size):
|
||||
|
||||
@rtype: bytearray
|
||||
@return: A new bytearray containing the mutated data
|
||||
'''
|
||||
"""
|
||||
# Make a copy of our input buffer for returning
|
||||
ret = bytearray(buf)
|
||||
|
||||
@ -58,7 +58,9 @@ def fuzz(buf, add_buf, max_size):
|
||||
rand_dst_idx = random.randint(0, len(buf))
|
||||
|
||||
# Make the chunk replacement
|
||||
ret[rand_dst_idx:rand_dst_idx + fragment_len] = add_buf[rand_src_idx:rand_src_idx + fragment_len]
|
||||
ret[rand_dst_idx : rand_dst_idx + fragment_len] = add_buf[
|
||||
rand_src_idx : rand_src_idx + fragment_len
|
||||
]
|
||||
|
||||
# Return data
|
||||
return ret
|
@ -27,7 +27,7 @@ def log(text):
|
||||
|
||||
def init(seed):
|
||||
"""
|
||||
Called once when AFL starts up. Seed is used to identify the AFL instance in log files
|
||||
Called once when AFL starts up. Seed is used to identify the AFL instance in log files
|
||||
"""
|
||||
|
||||
global __mutator__
|
||||
@ -72,7 +72,10 @@ def fuzz(buf, add_buf, max_size):
|
||||
if via_buffer:
|
||||
try:
|
||||
__mutator__.init_from_string(buf_str)
|
||||
log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str))
|
||||
log(
|
||||
"fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)"
|
||||
% len(buf_str)
|
||||
)
|
||||
except Exception:
|
||||
via_buffer = False
|
||||
log("fuzz(): Can't initialize mutator with AFL buffer")
|
||||
@ -104,7 +107,7 @@ def fuzz(buf, add_buf, max_size):
|
||||
|
||||
|
||||
# Main (for debug)
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
|
||||
__log__ = True
|
||||
__log_file__ = "/dev/stdout"
|
||||
@ -112,7 +115,9 @@ if __name__ == '__main__':
|
||||
|
||||
init(__seed__)
|
||||
|
||||
in_1 = bytearray("<foo ddd='eeee'>ffff<a b='c' d='456' eee='ffffff'>zzzzzzzzzzzz</a><b yyy='YYY' zzz='ZZZ'></b></foo>")
|
||||
in_1 = bytearray(
|
||||
"<foo ddd='eeee'>ffff<a b='c' d='456' eee='ffffff'>zzzzzzzzzzzz</a><b yyy='YYY' zzz='ZZZ'></b></foo>"
|
||||
)
|
||||
in_2 = bytearray("<abc abc123='456' abcCBA='ppppppppppppppppppppppppppppp'/>")
|
||||
out = fuzz(in_1, in_2)
|
||||
print(out)
|
@ -1 +1 @@
|
||||
b3c4fcf
|
||||
b79d51a
|
||||
|
@ -106,23 +106,23 @@ git status 1>/dev/null 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "[*] initializing grammar mutator submodule"
|
||||
git submodule init || exit 1
|
||||
git submodule update ./grammar-mutator 2>/dev/null # ignore errors
|
||||
git submodule update ./grammar_mutator 2>/dev/null # ignore errors
|
||||
else
|
||||
echo "[*] cloning grammar mutator"
|
||||
test -d grammar-mutator || {
|
||||
test -d grammar_mutator || {
|
||||
CNT=1
|
||||
while [ '!' -d grammar-mutator -a "$CNT" -lt 4 ]; do
|
||||
echo "Trying to clone grammar-mutator (attempt $CNT/3)"
|
||||
while [ '!' -d grammar_mutator -a "$CNT" -lt 4 ]; do
|
||||
echo "Trying to clone grammar_mutator (attempt $CNT/3)"
|
||||
git clone "$GRAMMAR_REPO"
|
||||
CNT=`expr "$CNT" + 1`
|
||||
done
|
||||
}
|
||||
fi
|
||||
|
||||
test -d grammar-mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||
test -d grammar_mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||
echo "[+] Got grammar mutator."
|
||||
|
||||
cd "grammar-mutator" || exit 1
|
||||
cd "grammar_mutator" || exit 1
|
||||
echo "[*] Checking out $GRAMMAR_VERSION"
|
||||
sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
|
||||
git checkout "$GRAMMAR_VERSION" || exit 1
|
||||
@ -134,7 +134,7 @@ echo
|
||||
echo
|
||||
echo "[+] All successfully prepared!"
|
||||
echo "[!] To build for your grammar just do:"
|
||||
echo " cd grammar-mutator"
|
||||
echo " cd grammar_mutator"
|
||||
echo " make GRAMMAR_FILE=/path/to/your/grammar"
|
||||
echo "[+] You will find a JSON and RUBY grammar in grammar-mutator/grammars to play with."
|
||||
echo "[+] You will find a JSON and RUBY grammar in grammar_mutator/grammars to play with."
|
||||
echo
|
||||
|
Submodule custom_mutators/grammar_mutator/grammar_mutator updated: b3c4fcfa6a...b79d51a8da
@ -39,7 +39,7 @@
|
||||
#include "libhfcommon/util.h"
|
||||
|
||||
#define PROG_NAME "honggfuzz"
|
||||
#define PROG_VERSION "2.3"
|
||||
#define PROG_VERSION "2.4"
|
||||
|
||||
/* Name of the template which will be replaced with the proper name of the file */
|
||||
#define _HF_FILE_PLACEHOLDER "___FILE___"
|
||||
@ -208,6 +208,7 @@ typedef struct {
|
||||
const char* crashDir;
|
||||
const char* covDirNew;
|
||||
bool saveUnique;
|
||||
bool saveSmaller;
|
||||
size_t dynfileqMaxSz;
|
||||
size_t dynfileqCnt;
|
||||
dynfile_t* dynfileqCurrent;
|
||||
@ -279,9 +280,9 @@ typedef struct {
|
||||
cmpfeedback_t* cmpFeedbackMap;
|
||||
int cmpFeedbackFd;
|
||||
bool cmpFeedback;
|
||||
const char* blacklistFile;
|
||||
uint64_t* blacklist;
|
||||
size_t blacklistCnt;
|
||||
const char* blocklistFile;
|
||||
uint64_t* blocklist;
|
||||
size_t blocklistCnt;
|
||||
bool skipFeedbackOnTimeout;
|
||||
uint64_t maxCov[4];
|
||||
dynFileMethod_t dynFileMethod;
|
||||
|
@ -77,11 +77,11 @@ static inline uint64_t util_rndGet(uint64_t min, uint64_t max) {
|
||||
}
|
||||
static inline uint64_t util_rnd64() { return rand_below(afl_struct, 1 << 30); }
|
||||
|
||||
static inline size_t input_getRandomInputAsBuf(run_t *run, const uint8_t **buf) {
|
||||
*buf = queue_input;
|
||||
static inline const uint8_t* input_getRandomInputAsBuf(run_t* run, size_t* len) {
|
||||
*len = queue_input_size;
|
||||
run->dynfile->data = queue_input;
|
||||
run->dynfile->size = queue_input_size;
|
||||
return queue_input_size;
|
||||
return queue_input;
|
||||
}
|
||||
static inline void input_setSize(run_t* run, size_t sz) {
|
||||
run->dynfile->size = sz;
|
||||
|
@ -1 +0,0 @@
|
||||
.
|
3
custom_mutators/honggfuzz/libhfcommon/common.h
Normal file
3
custom_mutators/honggfuzz/libhfcommon/common.h
Normal file
@ -0,0 +1,3 @@
|
||||
#ifndef LOG_E
|
||||
#define LOG_E LOG_F
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,7 @@ cc_library_shared {
|
||||
"-O0",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-Wno-unused-parameter",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
@ -29,4 +30,9 @@ cc_binary {
|
||||
srcs: [
|
||||
"vuln.c",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-Wno-unused-result",
|
||||
"-Wno-unused-parameter",
|
||||
],
|
||||
}
|
||||
|
10
custom_mutators/rust/.gitignore
vendored
Normal file
10
custom_mutators/rust/.gitignore
vendored
Normal 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
|
8
custom_mutators/rust/Cargo.toml
Normal file
8
custom_mutators/rust/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"custom_mutator-sys",
|
||||
"custom_mutator",
|
||||
"example",
|
||||
# Lain needs a nightly toolchain
|
||||
# "example_lain",
|
||||
]
|
11
custom_mutators/rust/README.md
Normal file
11
custom_mutators/rust/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Rust Custom Mutators
|
||||
|
||||
Bindings to create custom mutators in Rust.
|
||||
|
||||
These bindings are documented with rustdoc. To view the documentation run
|
||||
```cargo doc -p custom_mutator --open```.
|
||||
|
||||
A minimal example can be found in `example`. Build it using `cargo build --example example_mutator`.
|
||||
|
||||
An example using [lain](https://github.com/microsoft/lain) for structured fuzzing can be found in `example_lain`.
|
||||
Since lain requires a nightly rust toolchain, you need to set one up before you can play with it.
|
12
custom_mutators/rust/custom_mutator-sys/Cargo.toml
Normal file
12
custom_mutators/rust/custom_mutator-sys/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "custom_mutator-sys"
|
||||
version = "0.1.0"
|
||||
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.56"
|
42
custom_mutators/rust/custom_mutator-sys/build.rs
Normal file
42
custom_mutators/rust/custom_mutator-sys/build.rs
Normal file
@ -0,0 +1,42 @@
|
||||
extern crate bindgen;
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
// this code is largely taken straight from the handbook: https://github.com/fitzgen/bindgen-tutorial-bzip2-sys
|
||||
fn main() {
|
||||
// Tell cargo to invalidate the built crate whenever the wrapper changes
|
||||
println!("cargo:rerun-if-changed=wrapper.h");
|
||||
|
||||
// The bindgen::Builder is the main entry point
|
||||
// to bindgen, and lets you build up options for
|
||||
// the resulting bindings.
|
||||
let bindings = bindgen::Builder::default()
|
||||
// The input header we would like to generate
|
||||
// bindings for.
|
||||
.header("wrapper.h")
|
||||
.whitelist_type("afl_state_t")
|
||||
.blacklist_type(r"u\d+")
|
||||
.opaque_type(r"_.*")
|
||||
.opaque_type("FILE")
|
||||
.opaque_type("in_addr(_t)?")
|
||||
.opaque_type("in_port(_t)?")
|
||||
.opaque_type("sa_family(_t)?")
|
||||
.opaque_type("sockaddr_in(_t)?")
|
||||
.opaque_type("time_t")
|
||||
.rustfmt_bindings(true)
|
||||
.size_t_is_usize(true)
|
||||
// Tell cargo to invalidate the built crate whenever any of the
|
||||
// included header files changed.
|
||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
|
||||
// Finish the builder and generate the bindings.
|
||||
.generate()
|
||||
// Unwrap the Result and panic on failure.
|
||||
.expect("Unable to generate bindings");
|
||||
|
||||
// Write the bindings to the $OUT_DIR/bindings.rs file.
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
bindings
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.expect("Couldn't write bindings!");
|
||||
}
|
5
custom_mutators/rust/custom_mutator-sys/src/lib.rs
Normal file
5
custom_mutators/rust/custom_mutator-sys/src/lib.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
4
custom_mutators/rust/custom_mutator-sys/wrapper.h
Normal file
4
custom_mutators/rust/custom_mutator-sys/wrapper.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include "../../../include/afl-fuzz.h"
|
||||
#include "../../../include/common.h"
|
||||
#include "../../../include/config.h"
|
||||
#include "../../../include/debug.h"
|
13
custom_mutators/rust/custom_mutator/Cargo.toml
Normal file
13
custom_mutators/rust/custom_mutator/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "custom_mutator"
|
||||
version = "0.1.0"
|
||||
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
afl_internals = ["custom_mutator-sys"]
|
||||
|
||||
[dependencies]
|
||||
custom_mutator-sys = { path = "../custom_mutator-sys", optional=true }
|
740
custom_mutators/rust/custom_mutator/src/lib.rs
Normal file
740
custom_mutators/rust/custom_mutator/src/lib.rs
Normal file
@ -0,0 +1,740 @@
|
||||
#![cfg(unix)]
|
||||
//! Somewhat safe and somewhat ergonomic bindings for creating [AFL++](https://github.com/AFLplusplus/AFLplusplus) [custom mutators](https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/custom_mutators.md) in Rust.
|
||||
//!
|
||||
//! # Usage
|
||||
//! AFL++ custom mutators are expected to be dynamic libraries which expose a set of symbols.
|
||||
//! Check out [`CustomMutator`] to see which functions of the API are supported.
|
||||
//! Then use [`export_mutator`] to export the correct symbols for your mutator.
|
||||
//! In order to use the mutator, your crate needs to be a library crate and have a `crate-type` of `cdylib`.
|
||||
//! Putting
|
||||
//! ```yaml
|
||||
//! [lib]
|
||||
//! crate-type = ["cdylib"]
|
||||
//! ```
|
||||
//! into your `Cargo.toml` should do the trick.
|
||||
//! The final executable can be found in `target/(debug|release)/your_crate_name.so`.
|
||||
//! # Example
|
||||
//! See [`export_mutator`] for an example.
|
||||
//!
|
||||
//! # On `panic`s
|
||||
//! This binding is panic-safe in that it will prevent panics from unwinding into AFL++. Any panic will `abort` at the boundary between the custom mutator and AFL++.
|
||||
//!
|
||||
//! # Access to AFL++ internals
|
||||
//! This crate has an optional feature "afl_internals", which gives access to AFL++'s internal state.
|
||||
//! The state is passed to [`CustomMutator::init`], when the feature is activated.
|
||||
//!
|
||||
//! _This is completely unsafe and uses automatically generated types extracted from the AFL++ source._
|
||||
use std::{fmt::Debug, path::Path};
|
||||
|
||||
#[cfg(feature = "afl_internals")]
|
||||
#[doc(hidden)]
|
||||
pub use custom_mutator_sys::afl_state;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[doc(hidden)]
|
||||
pub trait RawCustomMutator {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn init(afl: &'static afl_state, seed: u32) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn init(seed: u32) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Option<&'b [u8]>;
|
||||
|
||||
fn fuzz_count(&mut self, buffer: &[u8]) -> u32 {
|
||||
1
|
||||
}
|
||||
|
||||
fn queue_new_entry(&mut self, filename_new_queue: &Path, _filename_orig_queue: Option<&Path>) {}
|
||||
|
||||
fn queue_get(&mut self, filename: &Path) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn describe(&mut self, max_description: usize) -> Option<&str> {
|
||||
Some(default_mutator_describe::<Self>(max_description))
|
||||
}
|
||||
|
||||
fn introspection(&mut self) -> Option<&str> {
|
||||
None
|
||||
}
|
||||
|
||||
/*fn post_process(&self, buffer: &[u8], unsigned char **out_buf)-> usize;
|
||||
int afl_custom_init_trim(&self, buffer: &[u8]);
|
||||
size_t afl_custom_trim(&self, unsigned char **out_buf);
|
||||
int afl_custom_post_trim(&self, unsigned char success);
|
||||
size_t afl_custom_havoc_mutation(&self, buffer: &[u8], unsigned char **out_buf, size_t max_size);
|
||||
unsigned char afl_custom_havoc_mutation_probability(&self);*/
|
||||
}
|
||||
|
||||
/// Wrappers for the custom mutator which provide the bridging between the C API and CustomMutator.
|
||||
/// These wrappers are not intended to be used directly, rather export_mutator will use them to publish the custom mutator C API.
|
||||
#[doc(hidden)]
|
||||
pub mod wrappers {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
use custom_mutator_sys::afl_state;
|
||||
|
||||
use std::{
|
||||
any::Any,
|
||||
convert::TryInto,
|
||||
ffi::{c_void, CStr, OsStr},
|
||||
mem::ManuallyDrop,
|
||||
os::{raw::c_char, unix::ffi::OsStrExt},
|
||||
panic::catch_unwind,
|
||||
path::Path,
|
||||
process::abort,
|
||||
ptr::null,
|
||||
slice,
|
||||
};
|
||||
|
||||
use crate::RawCustomMutator;
|
||||
|
||||
/// A structure to be used as the data pointer for our custom mutator. This was used as additional storage and is kept for now in case its needed later.
|
||||
/// Also has some convenience functions for FFI conversions (from and to ptr) and tries to make misuse hard (see [`FFIContext::from`]).
|
||||
struct FFIContext<M: RawCustomMutator> {
|
||||
mutator: M,
|
||||
/// buffer for storing the description returned by [`RawCustomMutator::describe`] as a CString
|
||||
description_buffer: Vec<u8>,
|
||||
/// buffer for storing the introspection returned by [`RawCustomMutator::introspect`] as a CString
|
||||
introspection_buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<M: RawCustomMutator> FFIContext<M> {
|
||||
fn from(ptr: *mut c_void) -> ManuallyDrop<Box<Self>> {
|
||||
assert!(!ptr.is_null());
|
||||
ManuallyDrop::new(unsafe { Box::from_raw(ptr as *mut Self) })
|
||||
}
|
||||
|
||||
fn into_ptr(self: Box<Self>) -> *const c_void {
|
||||
Box::into_raw(self) as *const c_void
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn new(afl: &'static afl_state, seed: u32) -> Box<Self> {
|
||||
Box::new(Self {
|
||||
mutator: M::init(afl, seed),
|
||||
description_buffer: Vec::new(),
|
||||
introspection_buffer: Vec::new(),
|
||||
})
|
||||
}
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn new(seed: u32) -> Box<Self> {
|
||||
Box::new(Self {
|
||||
mutator: M::init(seed),
|
||||
description_buffer: Vec::new(),
|
||||
introspection_buffer: Vec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// panic handler called for every panic
|
||||
fn panic_handler(method: &str, panic_info: Box<dyn Any + Send + 'static>) -> ! {
|
||||
use std::ops::Deref;
|
||||
let cause = panic_info
|
||||
.downcast_ref::<String>()
|
||||
.map(String::deref)
|
||||
.unwrap_or_else(|| {
|
||||
panic_info
|
||||
.downcast_ref::<&str>()
|
||||
.copied()
|
||||
.unwrap_or("<cause unknown>")
|
||||
});
|
||||
eprintln!("A panic occurred at {}: {}", method, cause);
|
||||
abort()
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
pub fn afl_custom_init_<M: RawCustomMutator>(seed: u32) -> *const c_void {
|
||||
match catch_unwind(|| FFIContext::<M>::new(seed).into_ptr()) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_init", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
#[cfg(feature = "afl_internals")]
|
||||
pub fn afl_custom_init_<M: RawCustomMutator>(
|
||||
afl: Option<&'static afl_state>,
|
||||
seed: u32,
|
||||
) -> *const c_void {
|
||||
match catch_unwind(|| {
|
||||
let afl = afl.expect("mutator func called with NULL afl");
|
||||
FFIContext::<M>::new(afl, seed).into_ptr()
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_init", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub unsafe fn afl_custom_fuzz_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
buf: *mut u8,
|
||||
buf_size: usize,
|
||||
out_buf: *mut *const u8,
|
||||
add_buf: *mut u8,
|
||||
add_buf_size: usize,
|
||||
max_size: usize,
|
||||
) -> usize {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
if buf.is_null() {
|
||||
panic!("null buf passed to afl_custom_fuzz")
|
||||
}
|
||||
if out_buf.is_null() {
|
||||
panic!("null out_buf passed to afl_custom_fuzz")
|
||||
}
|
||||
let buff_slice = slice::from_raw_parts_mut(buf, buf_size);
|
||||
let add_buff_slice = if add_buf.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(slice::from_raw_parts(add_buf, add_buf_size))
|
||||
};
|
||||
match context
|
||||
.mutator
|
||||
.fuzz(buff_slice, add_buff_slice, max_size.try_into().unwrap())
|
||||
{
|
||||
Some(buffer) => {
|
||||
*out_buf = buffer.as_ptr();
|
||||
buffer.len().try_into().unwrap()
|
||||
}
|
||||
None => {
|
||||
// return the input buffer with 0-length to let AFL skip this mutation attempt
|
||||
*out_buf = buf;
|
||||
0
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_fuzz", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub unsafe fn afl_custom_fuzz_count_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
buf: *const u8,
|
||||
buf_size: usize,
|
||||
) -> u32 {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
if buf.is_null() {
|
||||
panic!("null buf passed to afl_custom_fuzz")
|
||||
}
|
||||
let buf_slice = slice::from_raw_parts(buf, buf_size);
|
||||
// see https://doc.rust-lang.org/nomicon/borrow-splitting.html
|
||||
let ctx = &mut **context;
|
||||
let mutator = &mut ctx.mutator;
|
||||
mutator.fuzz_count(buf_slice)
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_fuzz_count", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
filename_new_queue: *const c_char,
|
||||
filename_orig_queue: *const c_char,
|
||||
) {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
if filename_new_queue.is_null() {
|
||||
panic!("received null filename_new_queue in afl_custom_queue_new_entry");
|
||||
}
|
||||
let filename_new_queue = Path::new(OsStr::from_bytes(
|
||||
unsafe { CStr::from_ptr(filename_new_queue) }.to_bytes(),
|
||||
));
|
||||
let filename_orig_queue = if !filename_orig_queue.is_null() {
|
||||
Some(Path::new(OsStr::from_bytes(
|
||||
unsafe { CStr::from_ptr(filename_orig_queue) }.to_bytes(),
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
context
|
||||
.mutator
|
||||
.queue_new_entry(filename_new_queue, filename_orig_queue);
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_queue_new_entry", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub unsafe fn afl_custom_deinit_<M: RawCustomMutator>(data: *mut c_void) {
|
||||
match catch_unwind(|| {
|
||||
// drop the context
|
||||
ManuallyDrop::into_inner(FFIContext::<M>::from(data));
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_deinit", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub fn afl_custom_introspection_<M: RawCustomMutator>(data: *mut c_void) -> *const c_char {
|
||||
match catch_unwind(|| {
|
||||
let context = &mut *FFIContext::<M>::from(data);
|
||||
if let Some(res) = context.mutator.introspection() {
|
||||
let buf = &mut context.introspection_buffer;
|
||||
buf.clear();
|
||||
buf.extend_from_slice(res.as_bytes());
|
||||
buf.push(0);
|
||||
// unwrapping here, as the error case should be extremely rare
|
||||
CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
|
||||
} else {
|
||||
null()
|
||||
}
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_introspection", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub fn afl_custom_describe_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
max_description_len: usize,
|
||||
) -> *const c_char {
|
||||
match catch_unwind(|| {
|
||||
let context = &mut *FFIContext::<M>::from(data);
|
||||
if let Some(res) = context.mutator.describe(max_description_len) {
|
||||
let buf = &mut context.description_buffer;
|
||||
buf.clear();
|
||||
buf.extend_from_slice(res.as_bytes());
|
||||
buf.push(0);
|
||||
// unwrapping here, as the error case should be extremely rare
|
||||
CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
|
||||
} else {
|
||||
null()
|
||||
}
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_describe", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub fn afl_custom_queue_get_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
filename: *const c_char,
|
||||
) -> u8 {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
assert!(!filename.is_null());
|
||||
|
||||
context.mutator.queue_get(Path::new(OsStr::from_bytes(
|
||||
unsafe { CStr::from_ptr(filename) }.to_bytes(),
|
||||
))) as u8
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_queue_get", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate custom_mutator;
|
||||
/// # #[cfg(feature = "afl_internals")]
|
||||
/// # use custom_mutator::afl_state;
|
||||
/// # use custom_mutator::CustomMutator;
|
||||
/// struct MyMutator;
|
||||
/// impl CustomMutator for MyMutator {
|
||||
/// /// ...
|
||||
/// # type Error = ();
|
||||
/// # #[cfg(feature = "afl_internals")]
|
||||
/// # fn init(_afl_state: &afl_state, _seed: u32) -> Result<Self,()> {unimplemented!()}
|
||||
/// # #[cfg(not(feature = "afl_internals"))]
|
||||
/// # fn init(_seed: u32) -> Result<Self, Self::Error> {unimplemented!()}
|
||||
/// # 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> {unimplemented!()}
|
||||
/// }
|
||||
/// export_mutator!(MyMutator);
|
||||
/// ```
|
||||
#[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)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_fuzz_count(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
buf: *const u8,
|
||||
buf_size: usize,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
$crate::wrappers::afl_custom_fuzz_count_::<$mutator_type>(data, buf, buf_size)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_fuzz(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
buf: *mut u8,
|
||||
buf_size: usize,
|
||||
out_buf: *mut *const u8,
|
||||
add_buf: *mut u8,
|
||||
add_buf_size: usize,
|
||||
max_size: usize,
|
||||
) -> usize {
|
||||
unsafe {
|
||||
$crate::wrappers::afl_custom_fuzz_::<$mutator_type>(
|
||||
data,
|
||||
buf,
|
||||
buf_size,
|
||||
out_buf,
|
||||
add_buf,
|
||||
add_buf_size,
|
||||
max_size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_queue_new_entry(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
filename_new_queue: *const ::std::os::raw::c_char,
|
||||
filename_orig_queue: *const ::std::os::raw::c_char,
|
||||
) {
|
||||
$crate::wrappers::afl_custom_queue_new_entry_::<$mutator_type>(
|
||||
data,
|
||||
filename_new_queue,
|
||||
filename_orig_queue,
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_queue_get(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
filename: *const ::std::os::raw::c_char,
|
||||
) -> u8 {
|
||||
$crate::wrappers::afl_custom_queue_get_::<$mutator_type>(data, filename)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_introspection(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
) -> *const ::std::os::raw::c_char {
|
||||
$crate::wrappers::afl_custom_introspection_::<$mutator_type>(data)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_describe(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
max_description_len: usize,
|
||||
) -> *const ::std::os::raw::c_char {
|
||||
$crate::wrappers::afl_custom_describe_::<$mutator_type>(data, max_description_len)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_deinit(data: *mut ::std::os::raw::c_void) {
|
||||
unsafe { $crate::wrappers::afl_custom_deinit_::<$mutator_type>(data) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// this sanity test is supposed to just find out whether an empty mutator being exported by the macro compiles
|
||||
mod sanity_test {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
use super::afl_state;
|
||||
|
||||
use super::{export_mutator, RawCustomMutator};
|
||||
|
||||
struct ExampleMutator;
|
||||
|
||||
impl RawCustomMutator for ExampleMutator {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn init(_afl: &afl_state, _seed: u32) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn init(_seed: u32) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
_buffer: &'b mut [u8],
|
||||
_add_buff: Option<&[u8]>,
|
||||
_max_size: usize,
|
||||
) -> Option<&'b [u8]> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
export_mutator!(ExampleMutator);
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
/// A custom mutator.
|
||||
/// [`CustomMutator::handle_error`] will be called in case any method returns an [`Result::Err`].
|
||||
pub trait CustomMutator {
|
||||
/// The error type. All methods must return the same error type.
|
||||
type Error: Debug;
|
||||
|
||||
/// The method which handles errors.
|
||||
/// By default, this method will log the error to stderr if the environment variable "`AFL_CUSTOM_MUTATOR_DEBUG`" is set and non-empty.
|
||||
/// After logging the error, execution will continue on a best-effort basis.
|
||||
///
|
||||
/// This default behaviour can be customized by implementing this method.
|
||||
fn handle_error(err: Self::Error) {
|
||||
if std::env::var("AFL_CUSTOM_MUTATOR_DEBUG")
|
||||
.map(|v| !v.is_empty())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
eprintln!("Error in custom mutator: {:?}", err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn init(afl: &'static afl_state, seed: u32) -> Result<Self, Self::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn init(seed: u32) -> Result<Self, Self::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn fuzz_count(&mut self, buffer: &[u8]) -> Result<u32, Self::Error> {
|
||||
Ok(1)
|
||||
}
|
||||
|
||||
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>;
|
||||
|
||||
fn queue_new_entry(
|
||||
&mut self,
|
||||
filename_new_queue: &Path,
|
||||
filename_orig_queue: Option<&Path>,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn queue_get(&mut self, filename: &Path) -> Result<bool, Self::Error> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn describe(&mut self, max_description: usize) -> Result<Option<&str>, Self::Error> {
|
||||
Ok(Some(default_mutator_describe::<Self>(max_description)))
|
||||
}
|
||||
|
||||
fn introspection(&mut self) -> Result<Option<&str>, Self::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> RawCustomMutator for M
|
||||
where
|
||||
M: CustomMutator,
|
||||
M::Error: Debug,
|
||||
{
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn init(afl: &'static afl_state, seed: u32) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match Self::init(afl, seed) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
panic!("Error in afl_custom_init")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn init(seed: u32) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match Self::init(seed) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
panic!("Error in afl_custom_init")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz_count(&mut self, buffer: &[u8]) -> u32 {
|
||||
match self.fuzz_count(buffer) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Option<&'b [u8]> {
|
||||
match self.fuzz(buffer, add_buff, max_size) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn queue_new_entry(&mut self, filename_new_queue: &Path, filename_orig_queue: Option<&Path>) {
|
||||
match self.queue_new_entry(filename_new_queue, filename_orig_queue) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn queue_get(&mut self, filename: &Path) -> bool {
|
||||
match self.queue_get(filename) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn describe(&mut self, max_description: usize) -> Option<&str> {
|
||||
match self.describe(max_description) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn introspection(&mut self) -> Option<&str> {
|
||||
match self.introspection() {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// the default value to return from [`CustomMutator::describe`].
|
||||
fn default_mutator_describe<T: ?Sized>(max_len: usize) -> &'static str {
|
||||
truncate_str_unicode_safe(std::any::type_name::<T>(), max_len)
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(feature = "afl_internals")))]
|
||||
mod default_mutator_describe {
|
||||
struct MyMutator;
|
||||
use super::CustomMutator;
|
||||
impl CustomMutator for MyMutator {
|
||||
type Error = ();
|
||||
|
||||
fn init(_: u32) -> Result<Self, Self::Error> {
|
||||
Ok(Self)
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
_: &'b mut [u8],
|
||||
_: Option<&[u8]>,
|
||||
_: usize,
|
||||
) -> Result<Option<&'b [u8]>, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_describe() {
|
||||
assert_eq!(
|
||||
MyMutator::init(0).unwrap().describe(64).unwrap().unwrap(),
|
||||
"custom_mutator::default_mutator_describe::MyMutator"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// little helper function to truncate a `str` to a maximum of bytes while retaining unicode safety
|
||||
fn truncate_str_unicode_safe(s: &str, max_len: usize) -> &str {
|
||||
if s.len() <= max_len {
|
||||
s
|
||||
} else {
|
||||
if let Some((last_index, _)) = s
|
||||
.char_indices()
|
||||
.take_while(|(index, _)| *index <= max_len)
|
||||
.last()
|
||||
{
|
||||
&s[..last_index]
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod truncate_test {
|
||||
use super::truncate_str_unicode_safe;
|
||||
|
||||
#[test]
|
||||
fn test_truncate() {
|
||||
for (max_len, input, expected_output) in &[
|
||||
(0usize, "a", ""),
|
||||
(1, "a", "a"),
|
||||
(1, "ä", ""),
|
||||
(2, "ä", "ä"),
|
||||
(3, "äa", "äa"),
|
||||
(4, "äa", "äa"),
|
||||
(1, "👎", ""),
|
||||
(2, "👎", ""),
|
||||
(3, "👎", ""),
|
||||
(4, "👎", "👎"),
|
||||
(1, "abc", "a"),
|
||||
(2, "abc", "ab"),
|
||||
] {
|
||||
let actual_output = truncate_str_unicode_safe(input, *max_len);
|
||||
assert_eq!(
|
||||
&actual_output, expected_output,
|
||||
"{:#?} truncated to {} bytes should be {:#?}, but is {:#?}",
|
||||
input, max_len, expected_output, actual_output
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
15
custom_mutators/rust/example/Cargo.toml
Normal file
15
custom_mutators/rust/example/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "example_mutator"
|
||||
version = "0.1.0"
|
||||
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
custom_mutator = { path = "../custom_mutator" }
|
||||
|
||||
[[example]]
|
||||
name = "example_mutator"
|
||||
path = "./src/example_mutator.rs"
|
||||
crate-type = ["cdylib"]
|
50
custom_mutators/rust/example/src/example_mutator.rs
Normal file
50
custom_mutators/rust/example/src/example_mutator.rs
Normal file
@ -0,0 +1,50 @@
|
||||
#![cfg(unix)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use custom_mutator::{export_mutator, CustomMutator};
|
||||
|
||||
struct ExampleMutator;
|
||||
|
||||
impl CustomMutator for ExampleMutator {
|
||||
type Error = ();
|
||||
|
||||
fn init(seed: u32) -> Result<Self, Self::Error> {
|
||||
Ok(Self)
|
||||
}
|
||||
|
||||
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> {
|
||||
buffer.reverse();
|
||||
Ok(Some(buffer))
|
||||
}
|
||||
}
|
||||
|
||||
struct OwnBufferExampleMutator {
|
||||
own_buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CustomMutator for OwnBufferExampleMutator {
|
||||
type Error = ();
|
||||
|
||||
fn init(seed: u32) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
own_buffer: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Result<Option<&'b [u8]>, ()> {
|
||||
self.own_buffer.reverse();
|
||||
Ok(Some(self.own_buffer.as_slice()))
|
||||
}
|
||||
}
|
||||
|
||||
export_mutator!(ExampleMutator);
|
16
custom_mutators/rust/example_lain/Cargo.toml
Normal file
16
custom_mutators/rust/example_lain/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "example_lain"
|
||||
version = "0.1.0"
|
||||
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
custom_mutator = { path = "../custom_mutator" }
|
||||
lain="0.5"
|
||||
|
||||
[[example]]
|
||||
name = "example_lain"
|
||||
path = "./src/lain_mutator.rs"
|
||||
crate-type = ["cdylib"]
|
1
custom_mutators/rust/example_lain/rust-toolchain
Normal file
1
custom_mutators/rust/example_lain/rust-toolchain
Normal file
@ -0,0 +1 @@
|
||||
nightly
|
61
custom_mutators/rust/example_lain/src/lain_mutator.rs
Normal file
61
custom_mutators/rust/example_lain/src/lain_mutator.rs
Normal file
@ -0,0 +1,61 @@
|
||||
#![cfg(unix)]
|
||||
|
||||
use custom_mutator::{export_mutator, CustomMutator};
|
||||
use lain::{
|
||||
mutator::Mutator,
|
||||
prelude::*,
|
||||
rand::{rngs::StdRng, SeedableRng},
|
||||
};
|
||||
|
||||
#[derive(Debug, Mutatable, NewFuzzed, BinarySerialize)]
|
||||
struct MyStruct {
|
||||
field_1: u8,
|
||||
|
||||
#[lain(bits = 3)]
|
||||
field_2: u8,
|
||||
|
||||
#[lain(bits = 5)]
|
||||
field_3: u8,
|
||||
|
||||
#[lain(min = 5, max = 10000)]
|
||||
field_4: u32,
|
||||
|
||||
#[lain(ignore)]
|
||||
ignored_field: u64,
|
||||
}
|
||||
|
||||
struct LainMutator {
|
||||
mutator: Mutator<StdRng>,
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CustomMutator for LainMutator {
|
||||
type Error = ();
|
||||
|
||||
fn init(seed: u32) -> Result<Self, ()> {
|
||||
Ok(Self {
|
||||
mutator: Mutator::new(StdRng::seed_from_u64(seed as u64)),
|
||||
buffer: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
_buffer: &'b mut [u8],
|
||||
_add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Result<Option<&'b [u8]>, ()> {
|
||||
// we just sample an instance of MyStruct, ignoring the current input
|
||||
let instance = MyStruct::new_fuzzed(&mut self.mutator, None);
|
||||
let size = instance.serialized_size();
|
||||
if size > max_size {
|
||||
return Err(());
|
||||
}
|
||||
self.buffer.clear();
|
||||
self.buffer.reserve(size);
|
||||
instance.binary_serialize::<_, BigEndian>(&mut self.buffer);
|
||||
Ok(Some(self.buffer.as_slice()))
|
||||
}
|
||||
}
|
||||
|
||||
export_mutator!(LainMutator);
|
@ -8,46 +8,166 @@
|
||||
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.13c (release)
|
||||
- Note: plot_data switched to relative time from unix time in 3.10
|
||||
- frida_mode - new mode that uses frida to fuzz binary-only targets,
|
||||
it currently supports persistent mode and cmplog.
|
||||
thanks to @WorksButNotTested!
|
||||
- create a fuzzing dictionary with the help of CodeQL thanks to
|
||||
@microsvuln! see utils/autodict_ql
|
||||
- afl-fuzz:
|
||||
- added patch by @realmadsci to support @@ as part of command line
|
||||
options, e.g. `afl-fuzz ... -- ./target --infile=@@`
|
||||
- add recording of previous fuzz attempts for persistent mode
|
||||
to allow replay of non-reproducable crashes, see
|
||||
AFL_PERSISTENT_RECORD in config.h and docs/envs.h
|
||||
- fixed a bug when trimming for stdin targets
|
||||
- cmplog -l: default cmplog level is now 2, better efficiency.
|
||||
level 3 now performs redqueen on everything. use with care.
|
||||
- better fuzzing strategy yield display for enabled options
|
||||
- ensure one fuzzer sync per cycle
|
||||
- fix afl_custom_queue_new_entry original file name when syncing
|
||||
from fuzzers
|
||||
- fixed a crash when more than one custom mutator was used together
|
||||
with afl_custom_post_process
|
||||
- on a crashing seed potentially the wrong input was disabled
|
||||
- added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in
|
||||
-i dir crashes the target or results in a timeout. By default
|
||||
afl++ ignores these and uses them for splicing instead.
|
||||
- added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing
|
||||
after no new paths have been found for n seconds
|
||||
- when AFL_FAST_CAL is set a variable path will now be calibrated
|
||||
8 times instead of originally 40. Long calibration is now 20.
|
||||
- added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if
|
||||
it fails
|
||||
- afl-cc:
|
||||
- We do not support llvm versions prior 6.0 anymore
|
||||
- added thread safe counters to all modes (`AFL_LLVM_THREADSAFE_INST`),
|
||||
note that this disables NeverZero counters.
|
||||
- Fix for -pie compiled binaries with default afl-clang-fast PCGUARD
|
||||
- Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks!
|
||||
- Removed InsTrim instrumentation as it is not as good as PCGUARD
|
||||
- Removed automatic linking with -lc++ for LTO mode
|
||||
- Fixed a crash in llvm dict2file when a strncmp length was -1
|
||||
- added --afl-noopt support
|
||||
- utils/aflpp_driver:
|
||||
- aflpp_qemu_driver_hook fixed to work with qemu_mode
|
||||
- aflpp_driver now compiled with -fPIC
|
||||
- unicornafl:
|
||||
- fix MIPS delay slot caching, thanks @JackGrence
|
||||
- fixed aarch64 exit address
|
||||
- execution no longer stops at address 0x0
|
||||
- updated afl-system-config to support Arch Linux weirdness and increase
|
||||
MacOS shared memory
|
||||
- updated the grammar custom mutator to the newest version
|
||||
- add -d (add dead fuzzer stats) to afl-whatsup
|
||||
- added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the
|
||||
current filename
|
||||
- afl-showmap/cmin will now process queue items in alphabetical order
|
||||
|
||||
### Version ++3.01a (dev)
|
||||
### Version ++3.12c (release)
|
||||
- afl-fuzz:
|
||||
- added AFL_TARGET_ENV variable to pass extra env vars to the target
|
||||
(for things like LD_LIBRARY_PATH)
|
||||
- fix map detection, AFL_MAP_SIZE not needed anymore for most cases
|
||||
- fix counting favorites (just a display thing)
|
||||
- afl-cc:
|
||||
- fix cmplog rtn (rare crash and not being able to gather ptr data)
|
||||
- fix our own PCGUARD implementation to compile with llvm 10.0.1
|
||||
- link runtime not to shared libs
|
||||
- ensure shared libraries are properly built and instrumented
|
||||
- AFL_LLVM_INSTRUMENT_ALLOW/DENY were not implemented for LTO, added
|
||||
- show correct LLVM PCGUARD NATIVE mode when auto switching to it
|
||||
and keep fsanitize-coverage-*list=...
|
||||
Short mnemnonic NATIVE is now also accepted.
|
||||
- qemu_mode (thanks @realmadsci):
|
||||
- move AFL_PRELOAD and AFL_USE_QASAN logic inside afl-qemu-trace
|
||||
- add AFL_QEMU_CUSTOM_BIN
|
||||
- unicorn_mode
|
||||
- accidently removed the subfolder from github, re-added
|
||||
- added DEFAULT_PERMISSION to config.h for all files created, default
|
||||
to 0600
|
||||
|
||||
### Version ++3.11c (release)
|
||||
- afl-fuzz:
|
||||
- better auto detection of map size
|
||||
- fix sanitizer settings (bug since 3.10c)
|
||||
- fix an off-by-one overwrite in cmplog
|
||||
- add non-unicode variants from unicode-looking dictionary entries
|
||||
- Rust custom mutator API improvements
|
||||
- Imported crash stats painted yellow on resume (only new ones are red)
|
||||
- afl-cc:
|
||||
- added AFL_NOOPT that will just pass everything to the normal
|
||||
gcc/clang compiler without any changes - to pass weird configure
|
||||
scripts
|
||||
- fixed a crash that can occur with ASAN + CMPLOG together plus
|
||||
better support for unicode (thanks to @stbergmann for reporting!)
|
||||
- fixed a crash in LAF transform for empty strings
|
||||
- handle erroneous setups in which multiple afl-compiler-rt are
|
||||
compiled into the target. This now also supports dlopen()
|
||||
instrumented libs loaded before the forkserver and even after the
|
||||
forkserver is started (then with collisions though)
|
||||
- the compiler rt was added also in object building (-c) which
|
||||
should have been fixed years ago but somewhere got lost :(
|
||||
- Renamed CTX to CALLER, added correct/real CTX implementation to
|
||||
CLASSIC
|
||||
- qemu_mode:
|
||||
- added AFL_QEMU_EXCLUDE_RANGES env by @realmadsci, thanks!
|
||||
- if no new/updated checkout is wanted, build with:
|
||||
NO_CHECKOUT=1 ./build_qemu_support.sh
|
||||
- we no longer perform a "git drop"
|
||||
- afl-cmin: support filenames with spaces
|
||||
|
||||
### Version ++3.10c (release)
|
||||
- Mac OS ARM64 support
|
||||
- Android support fixed and updated by Joey Jiaojg - thanks!
|
||||
- New selective instrumentation option with __AFL_COVERAGE_* commands
|
||||
to be placed in the source code.
|
||||
Check out instrumentation/README.instrument_list.md
|
||||
- afl-fuzz
|
||||
- Making AFL_MAP_SIZE (mostly) obsolete - afl-fuzz now learns on start
|
||||
the target map size
|
||||
- Making AFL_MAP_SIZE (mostly) obsolete - afl-fuzz now learns on
|
||||
start the target map size
|
||||
- upgraded cmplog/redqueen: solving for floating point, solving
|
||||
transformations (e.g. toupper, tolower, to/from hex, xor,
|
||||
arithmetics, etc.). this is costly hence new command line option
|
||||
-l that sets the intensity (values 1 to 3). recommended is 1 or 2.
|
||||
- added `AFL_CMPLOG_ONLY_NEW` to not use cmplog on initial testcases from
|
||||
`-i` or resumes (as these have most likely already been done)
|
||||
arithmetics, etc.). This is costly hence new command line option
|
||||
`-l` that sets the intensity (values 1 to 3). Recommended is 2.
|
||||
- added `AFL_CMPLOG_ONLY_NEW` to not use cmplog on initial seeds
|
||||
from `-i` or resumes (these have most likely already been done)
|
||||
- fix crash for very, very fast targets+systems (thanks to mhlakhani
|
||||
for reporting)
|
||||
- on restarts (-i)/autoresume (AFL_AUTORESUME) the stats are now
|
||||
- on restarts (`-i`)/autoresume (AFL_AUTORESUME) the stats are now
|
||||
reloaded and used, thanks to Vimal Joseph for this patch!
|
||||
- if determinstic mode is active (-D, or -M without -d) then we sync
|
||||
after every queue entry as this can take very long time otherwise
|
||||
- changed the meaning of '+' of the '-t' option, it now means to
|
||||
auto-calculate the timeout with the value given being the max
|
||||
timeout. The original meaning of skipping timeouts instead of
|
||||
abort is now inherent to the -t option.
|
||||
- if deterministic mode is active (`-D`, or `-M` without `-d`) then
|
||||
we sync after every queue entry as this can take very long time
|
||||
otherwise
|
||||
- added minimum SYNC_TIME to include/config.h (30 minutes default)
|
||||
- better detection if a target needs a large shared map
|
||||
- fix for -Z
|
||||
- fix for `-Z`
|
||||
- fixed a few crashes
|
||||
- switched to an even faster RNG
|
||||
- added hghwng's patch for faster trace map analysis
|
||||
- printing suggestions for mistyped `AFL_` env variables
|
||||
- added Rust bindings for custom mutators (thanks @julihoh)
|
||||
- afl-cc
|
||||
- allow instrumenting LLVMFuzzerTestOneInput
|
||||
- fixed endless loop for allow/blocklist lines starting with a
|
||||
comment (thanks to Zherya for reporting)
|
||||
- cmplog/redqueen now also tracks floating point, _ExtInt() + 128bit
|
||||
- cmplog/redqueen can now process basic libc++ and libstdc++
|
||||
std::string comparisons (though no position or length type variants)
|
||||
- added support for __afl_coverage_interesting() for LTO and
|
||||
and our own PCGUARD (llvm 10.0.1+), read more about this function
|
||||
and selective coverage in instrumentation/README.instrument_list.md
|
||||
std::string comparisons (no position or length type variants)
|
||||
- added support for __afl_coverage_interesting() for LTO and our
|
||||
own PCGUARD (llvm 10.0.1+), read more about this function and
|
||||
selective coverage in instrumentation/README.instrument_list.md
|
||||
- added AFL_LLVM_INSTRUMENT option NATIVE for native clang pc-guard
|
||||
support (less performant than our own), GCC for old afl-gcc and
|
||||
CLANG for old afl-clang
|
||||
- fixed a potential crash in the LAF feature
|
||||
- workaround for llvm bitcast lto bug
|
||||
- workaround for llvm 13
|
||||
- qemuafl
|
||||
- QASan (address sanitizer for Qemu) ported to qemuafl!
|
||||
See qemu_mode/libqasan/README.md
|
||||
@ -55,14 +175,17 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
- solved an issue when dumping the memory maps (thanks wizche)
|
||||
- Android support for QASan
|
||||
- unicornafl
|
||||
- Substential speed gains in python bindings for certain use cases
|
||||
- Substantial speed gains in python bindings for certain use cases
|
||||
- Improved rust bindings
|
||||
- Added a new example harness to compare python, c, and rust bindings
|
||||
- Added a new example harness to compare python, c and rust bindings
|
||||
- afl-cmin and afl-showmap now support the -f option
|
||||
- afl_plot now also generates a graph on the discovered edges
|
||||
- changed default: no memory limit for afl-cmin and afl-cmin.bash
|
||||
- warn on any _AFL and __AFL env vars
|
||||
- warn on any _AFL and __AFL env vars.
|
||||
- set AFL_IGNORE_UNKNOWN_ENVS to not warn on unknown AFL_... env vars
|
||||
- added dummy Makefile to instrumentation/
|
||||
- Updated utils/afl_frida to be 5% faster, 7% on x86_x64
|
||||
- Added AFL_KILL_SIGNAL env variable (thanks @v-p-b)
|
||||
- Added `AFL_KILL_SIGNAL` env variable (thanks @v-p-b)
|
||||
- @Edznux added a nice documentation on how to use rpc.statsd with
|
||||
afl++ in docs/rpc_statsd.md, thanks!
|
||||
|
||||
|
@ -103,6 +103,41 @@ The llvm instrumentation requires a fully-operational installation of clang. The
|
||||
comes with Xcode is missing some of the essential headers and helper tools.
|
||||
See README.llvm.md for advice on how to build the compiler from scratch.
|
||||
|
||||
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 be:
|
||||
|
||||
```bash
|
||||
$ ipcs -M
|
||||
IPC status from <running system> as of XXX
|
||||
shminfo:
|
||||
shmmax: 4194304 (max shared memory segment size)
|
||||
shmmin: 1 (min shared memory segment size)
|
||||
shmmni: 32 (max number of shared memory identifiers)
|
||||
shmseg: 8 (max shared memory segments per process)
|
||||
shmall: 1024 (max amount of shared memory in pages)
|
||||
```
|
||||
|
||||
To temporarily change your settings to something minimally usable with AFL++,
|
||||
run these commands as root:
|
||||
|
||||
```bash
|
||||
sysctl kern.sysv.shmmax=8388608
|
||||
sysctl kern.sysv.shmall=4096
|
||||
```
|
||||
|
||||
If you're running more than one instance of AFL you likely want to make `shmall`
|
||||
bigger and increase `shmseg` as well:
|
||||
|
||||
```bash
|
||||
sysctl kern.sysv.shmmax=8388608
|
||||
sysctl kern.sysv.shmseg=48
|
||||
sysctl kern.sysv.shmall=98304
|
||||
```
|
||||
|
||||
See http://www.spy-hill.com/help/apple/SharedMemory.html for documentation for
|
||||
these settings and how to make them permanent.
|
||||
|
||||
## 4. Linux or *BSD on non-x86 systems
|
||||
|
||||
Standard build will fail on non-x86 systems, but you should be able to
|
||||
|
@ -1,43 +0,0 @@
|
||||
# Applied Patches
|
||||
|
||||
The following patches from https://github.com/vanhauser-thc/afl-patches
|
||||
have been installed or not installed:
|
||||
|
||||
|
||||
## INSTALLED
|
||||
```
|
||||
afl-llvm-fix.diff by kcwu(at)csie(dot)org
|
||||
afl-sort-all_uniq-fix.diff by legarrec(dot)vincent(at)gmail(dot)com
|
||||
laf-intel.diff by heiko(dot)eissfeldt(at)hexco(dot)de
|
||||
afl-llvm-optimize.diff by mh(at)mh-sec(dot)de
|
||||
afl-fuzz-tmpdir.diff by mh(at)mh-sec(dot)de
|
||||
afl-fuzz-79x24.diff by heiko(dot)eissfeldt(at)hexco(dot)de
|
||||
afl-fuzz-fileextensionopt.diff tbd
|
||||
afl-as-AFL_INST_RATIO.diff by legarrec(dot)vincent(at)gmail(dot)com
|
||||
afl-qemu-ppc64.diff by william(dot)barsse(at)airbus(dot)com
|
||||
afl-qemu-optimize-entrypoint.diff by mh(at)mh-sec(dot)de
|
||||
afl-qemu-speed.diff by abiondo on github
|
||||
afl-qemu-optimize-map.diff by mh(at)mh-sec(dot)de
|
||||
```
|
||||
|
||||
+ llvm_mode ngram prev_loc coverage (github.com/adrianherrera/afl-ngram-pass)
|
||||
+ Custom mutator (native library) (by kyakdan)
|
||||
+ unicorn_mode (modernized and updated by domenukk)
|
||||
+ instrim (https://github.com/csienslab/instrim) was integrated
|
||||
+ MOpt (github.com/puppet-meteor/MOpt-AFL) was imported
|
||||
+ AFLfast additions (github.com/mboehme/aflfast) were incorporated.
|
||||
+ Qemu 3.1 upgrade with enhancement patches (github.com/andreafioraldi/afl)
|
||||
+ Python mutator modules support (github.com/choller/afl)
|
||||
+ Instrument file list in LLVM mode (github.com/choller/afl)
|
||||
+ forkserver patch for afl-tmin (github.com/nccgroup/TriforceAFL)
|
||||
|
||||
|
||||
## NOT INSTALLED
|
||||
|
||||
```
|
||||
afl-fuzz-context_sensitive.diff - changes too much of the behaviour
|
||||
afl-tmpfs.diff - same as afl-fuzz-tmpdir.diff but more complex
|
||||
afl-cmin-reduce-dataset.diff - unsure of the impact
|
||||
afl-llvm-fix2.diff - not needed with the other patches
|
||||
```
|
||||
|
@ -1,6 +1,6 @@
|
||||
# AFL quick start guide
|
||||
|
||||
You should read [README.md](README.md) - it's pretty short. If you really can't, here's
|
||||
You should read [README.md](../README.md) - it's pretty short. If you really can't, here's
|
||||
how to hit the ground running:
|
||||
|
||||
1) Compile AFL with 'make'. If build fails, see [INSTALL.md](INSTALL.md) for tips.
|
||||
|
@ -41,6 +41,33 @@
|
||||
|
||||
As it is included in afl++ this needs no URL.
|
||||
|
||||
If you like to code a customized fuzzer without much work, we highly
|
||||
recommend to check out our sister project libafl which will support QEMU
|
||||
too:
|
||||
[https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL)
|
||||
|
||||
|
||||
## AFL FRIDA
|
||||
|
||||
In frida_mode you can fuzz binary-only targets easily like with QEMU,
|
||||
with the advantage that frida_mode also works on MacOS (both intel and M1).
|
||||
|
||||
If you want to fuzz a binary-only library then you can fuzz it with
|
||||
frida-gum via utils/afl_frida/, you will have to write a harness to
|
||||
call the target function in the library, use afl-frida.c as a template.
|
||||
|
||||
Both come with afl++ so this needs no URL.
|
||||
|
||||
You can also perform remote fuzzing with frida, e.g. if you want to fuzz
|
||||
on iPhone or Android devices, for this you can use
|
||||
[https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/)
|
||||
as an intermediate that uses afl++ for fuzzing.
|
||||
|
||||
If you like to code a customized fuzzer without much work, we highly
|
||||
recommend 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 :-)
|
||||
|
||||
|
||||
## WINE+QEMU
|
||||
|
||||
@ -62,13 +89,6 @@
|
||||
As it is included in afl++ this needs no URL.
|
||||
|
||||
|
||||
## AFL FRIDA
|
||||
|
||||
If you want to fuzz a binary-only shared library then you can fuzz it with
|
||||
frida-gum via utils/afl_frida/, you will have to write a harness to
|
||||
call the target function in the library, use afl-frida.c as a template.
|
||||
|
||||
|
||||
## AFL UNTRACER
|
||||
|
||||
If you want to fuzz a binary-only shared library then you can fuzz it with
|
||||
@ -157,19 +177,6 @@
|
||||
If anyone finds any coresight implementation for afl please ping me: vh@thc.org
|
||||
|
||||
|
||||
## FRIDA
|
||||
|
||||
Frida is a dynamic instrumentation engine like Pintool, Dyninst and Dynamorio.
|
||||
What is special is that it is written Python, and scripted with Javascript.
|
||||
It is mostly used to reverse binaries on mobile phones however can be used
|
||||
everywhere.
|
||||
|
||||
There is a WIP fuzzer available at [https://github.com/andreafioraldi/frida-fuzzer](https://github.com/andreafioraldi/frida-fuzzer)
|
||||
|
||||
There is also an early implementation in an AFL++ test branch:
|
||||
[https://github.com/AFLplusplus/AFLplusplus/tree/frida](https://github.com/AFLplusplus/AFLplusplus/tree/frida)
|
||||
|
||||
|
||||
## PIN & DYNAMORIO
|
||||
|
||||
Pintool and Dynamorio are dynamic instrumentation engines, and they can be
|
||||
@ -205,7 +212,8 @@
|
||||
* QSYM: [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym)
|
||||
* Manticore: [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore)
|
||||
* S2E: [https://github.com/S2E](https://github.com/S2E)
|
||||
* Tinyinst [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only)
|
||||
* Tinyinst: [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only)
|
||||
* Jackalope: [https://github.com/googleprojectzero/Jackalope](https://github.com/googleprojectzero/Jackalope)
|
||||
* ... please send me any missing that are good
|
||||
|
||||
|
||||
|
@ -4,6 +4,11 @@ This file describes how you can implement custom mutations to be used in AFL.
|
||||
For now, we support C/C++ library and Python module, collectivelly named as the
|
||||
custom mutator.
|
||||
|
||||
There is also experimental support for Rust in `custom_mutators/rust`.
|
||||
Please refer to that directory for documentation.
|
||||
Run ```cargo doc -p custom_mutator --open``` in that directory to view the
|
||||
documentation in your web browser.
|
||||
|
||||
Implemented by
|
||||
- C/C++ library (`*.so`): Khaled Yakdan from Code Intelligence (<yakdan@code-intelligence.de>)
|
||||
- Python module: Christian Holler from Mozilla (<choller@mozilla.com>)
|
||||
@ -84,11 +89,14 @@ def queue_get(filename):
|
||||
|
||||
def queue_new_entry(filename_new_queue, filename_orig_queue):
|
||||
pass
|
||||
```
|
||||
|
||||
def introspection():
|
||||
return string
|
||||
|
||||
def deinit(): # optional for Python
|
||||
pass
|
||||
```
|
||||
|
||||
### Custom Mutation
|
||||
|
||||
- `init`:
|
||||
@ -115,6 +123,7 @@ def introspection():
|
||||
Note that this function is optional - but it makes sense to use it.
|
||||
You would only skip this if `post_process` is used to fix checksums etc.
|
||||
so if you are using it e.g. as a post processing library.
|
||||
Note that a length > 0 *must* be returned!
|
||||
|
||||
- `describe` (optional):
|
||||
|
||||
@ -280,8 +289,8 @@ afl-fuzz /path/to/program
|
||||
|
||||
## 4) Example
|
||||
|
||||
Please see [example.c](../utils/custom_mutators/example.c) and
|
||||
[example.py](../utils/custom_mutators/example.py)
|
||||
Please see [example.c](../custom_mutators/examples/example.c) and
|
||||
[example.py](../custom_mutators/examples/example.py)
|
||||
|
||||
## 5) Other Resources
|
||||
|
||||
|
122
docs/docs.md
Normal file
122
docs/docs.md
Normal file
@ -0,0 +1,122 @@
|
||||
# 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.
|
@ -5,6 +5,10 @@
|
||||
users or for some types of custom fuzzing setups. See [README.md](README.md) for the general
|
||||
instruction manual.
|
||||
|
||||
Note that most tools will warn on any unknown AFL environment variables.
|
||||
This is for warning on typos that can happen. If you want to disable this
|
||||
check then set the `AFL_IGNORE_UNKNOWN_ENVS` environment variable.
|
||||
|
||||
## 1) Settings for all compilers
|
||||
|
||||
Starting with afl++ 3.0 there is only one compiler: afl-cc
|
||||
@ -18,11 +22,21 @@ To select the different instrumentation modes this can be done by
|
||||
`MODE` can be one of `LTO` (afl-clang-lto*), `LLVM` (afl-clang-fast*), `GCC_PLUGIN`
|
||||
(afl-g*-fast) or `GCC` (afl-gcc/afl-g++).
|
||||
|
||||
|
||||
Because (with the exception of the --afl-MODE command line option) the
|
||||
compile-time tools do not accept afl specific command-line options, they
|
||||
make fairly broad use of environmental variables instead:
|
||||
|
||||
- Some build/configure scripts break with afl++ compilers. To be able to
|
||||
pass them, do:
|
||||
```
|
||||
export CC=afl-cc
|
||||
export CXX=afl-c++
|
||||
export AFL_NOOPT=1
|
||||
./configure --disable-shared --disabler-werror
|
||||
unset AFL_NOOPT
|
||||
make
|
||||
```
|
||||
|
||||
- Most afl tools do not print any output if stdout/stderr are redirected.
|
||||
If you want to get the output into a file then set the `AFL_DEBUG`
|
||||
environment variable.
|
||||
@ -41,7 +55,7 @@ make fairly broad use of environmental variables instead:
|
||||
overridden.
|
||||
|
||||
- Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your
|
||||
compiler supports that. Note that fuzzing with ASAN is mildly challenging
|
||||
compiler supports it. Note that fuzzing with ASAN is mildly challenging
|
||||
- see [notes_for_asan.md](notes_for_asan.md).
|
||||
|
||||
(You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the
|
||||
@ -50,6 +64,13 @@ make fairly broad use of environmental variables instead:
|
||||
there is the Control Flow Integrity sanitizer that can be activated by
|
||||
`AFL_USE_CFISAN=1`)
|
||||
|
||||
- Setting `AFL_USE_LSAN` automatically enables Leak-Sanitizer, provided
|
||||
that your compiler supports it. To perform a leak check 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=suppressions option to supress some known leaks).
|
||||
|
||||
- Setting `AFL_CC`, `AFL_CXX`, and `AFL_AS` lets you use alternate downstream
|
||||
compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries
|
||||
in your `$PATH`.
|
||||
@ -116,16 +137,15 @@ Then there are a few specific features that are only available in instrumentatio
|
||||
PCGUARD - our own pcgard based instrumentation (default)
|
||||
NATIVE - clang's original pcguard based instrumentation
|
||||
CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default)
|
||||
CFG - InsTrim instrumentation (see below)
|
||||
LTO - LTO instrumentation (see below)
|
||||
CTX - context sensitive instrumentation (see below)
|
||||
NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
|
||||
GCC - outdated gcc instrumentation
|
||||
CLANG - outdated clang instrumentation
|
||||
In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or
|
||||
NGRAM, seperate the options with a comma "," then, e.g.:
|
||||
`AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4`
|
||||
Not that this is a good idea to use both CTX and NGRAM :)
|
||||
In CLASSIC you can also specify CTX and/or NGRAM, seperate the options
|
||||
with a comma "," then, e.g.:
|
||||
`AFL_LLVM_INSTRUMENT=CLASSIC,CTX,NGRAM-4`
|
||||
Note that this is actually not a good idea to use both CTX and NGRAM :)
|
||||
|
||||
### LTO
|
||||
|
||||
@ -159,24 +179,6 @@ Then there are a few specific features that are only available in instrumentatio
|
||||
|
||||
See [instrumentation/README.lto.md](../instrumentation/README.lto.md) for more information.
|
||||
|
||||
### INSTRIM
|
||||
|
||||
This feature increases the speed by ~15% without any disadvantages to the
|
||||
classic instrumentation.
|
||||
|
||||
Note that there is also an LTO version (if you have llvm 11 or higher) -
|
||||
that is the best instrumentation we have. Use `afl-clang-lto` to activate.
|
||||
The InsTrim LTO version additionally has all the options and features of
|
||||
LTO (see above).
|
||||
|
||||
- Setting `AFL_LLVM_INSTRIM` or `AFL_LLVM_INSTRUMENT=CFG` activates this mode
|
||||
|
||||
- Setting `AFL_LLVM_INSTRIM_LOOPHEAD=1` expands on INSTRIM to optimize loops.
|
||||
afl-fuzz will only be able to see the path the loop took, but not how
|
||||
many times it was called (unless it is a complex loop).
|
||||
|
||||
See [instrumentation/README.instrim.md](../instrumentation/README.instrim.md)
|
||||
|
||||
### NGRAM
|
||||
|
||||
- Setting `AFL_LLVM_NGRAM_SIZE` or `AFL_LLVM_INSTRUMENT=NGRAM-{value}`
|
||||
@ -229,6 +231,12 @@ Then there are a few specific features that are only available in instrumentatio
|
||||
|
||||
See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information.
|
||||
|
||||
### Thread safe instrumentation counters (in all modes)
|
||||
|
||||
- Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread
|
||||
safe counters. The overhead is a little bit higher compared to the older
|
||||
non-thread safe case. Note that this disables neverzero (see below).
|
||||
|
||||
### NOT_ZERO
|
||||
|
||||
- Setting `AFL_LLVM_NOT_ZERO=1` during compilation will use counters
|
||||
@ -282,6 +290,13 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
normally indicated by the cycle counter in the UI turning green. May be
|
||||
convenient for some types of automated jobs.
|
||||
|
||||
- `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were
|
||||
found within a specified period of time (in seconds). May be convenient
|
||||
for some types of automated jobs.
|
||||
|
||||
- `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour
|
||||
which does not allow crashes or timeout seeds in the initial -i corpus.
|
||||
|
||||
- `AFL_MAP_SIZE` sets the size of the shared map that afl-fuzz, afl-showmap,
|
||||
afl-tmin and afl-analyze create to gather instrumentation data from
|
||||
the target. This must be equal or larger than the size the target was
|
||||
@ -303,14 +318,12 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
on Linux systems. This slows things down, but lets you run more instances
|
||||
of afl-fuzz than would be prudent (if you really want to).
|
||||
|
||||
- Setting `AFL_TRY_AFFINITY` tries to attempt binding to a specific CPU core
|
||||
on Linux systems, but will not terminate if that fails.
|
||||
|
||||
- Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary
|
||||
that is compiled into the target.
|
||||
|
||||
- `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input
|
||||
queue. This can help with rare situations where a program crashes only
|
||||
intermittently, but it's not really recommended under normal operating
|
||||
conditions.
|
||||
|
||||
- Setting `AFL_HANG_TMOUT` allows you to specify a different timeout for
|
||||
deciding if a particular test case is a "hang". The default is 1 second
|
||||
or the value of the `-t` parameter, whichever is larger. Dialing the value
|
||||
@ -346,6 +359,7 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
and shell scripts; and `AFL_DUMB_FORKSRV` in conjunction with the `-n`
|
||||
setting to instruct afl-fuzz to still follow the fork server protocol
|
||||
without expecting any instrumentation data in return.
|
||||
Note that this also turns off auto map size detection.
|
||||
|
||||
- When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the
|
||||
fuzzer to import test cases from other instances before doing anything
|
||||
@ -377,7 +391,12 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
may complain of high load prematurely, especially on systems with low core
|
||||
counts. To avoid the alarming red color, you can set `AFL_NO_CPU_RED`.
|
||||
|
||||
- In QEMU mode (-Q), `AFL_PATH` will be searched for afl-qemu-trace.
|
||||
- In QEMU mode (-Q) and Frida mode (-O), `AFL_PATH` will
|
||||
be searched for afl-qemu-trace and afl-frida-trace.so.
|
||||
|
||||
- In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip
|
||||
prepending `afl-qemu-trace` to your command line. Use this if you wish to use a
|
||||
custom afl-qemu-trace or if you need to modify the afl-qemu-trace arguments.
|
||||
|
||||
- Setting `AFL_CYCLE_SCHEDULES` will switch to a different schedule everytime
|
||||
a cycle is finished.
|
||||
@ -390,6 +409,12 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
without disrupting the afl-fuzz process itself. This is useful, among other
|
||||
things, for bootstrapping libdislocator.so.
|
||||
|
||||
- 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++).
|
||||
|
||||
- Setting `AFL_NO_UI` inhibits the UI altogether, and just periodically prints
|
||||
some basic stats. This behavior is also automatically triggered when the
|
||||
output from afl-fuzz is redirected to a file or to a pipe.
|
||||
@ -400,8 +425,19 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
- Setting `AFL_FORCE_UI` will force painting the UI on the screen even if
|
||||
no valid terminal was detected (for virtual consoles)
|
||||
|
||||
- If you are using persistent mode (you should, see [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md))
|
||||
some targets keep inherent state due which a detected crash testcase does
|
||||
not crash the target again when the testcase is given. To be able to still
|
||||
re-trigger these crashes you can use the `AFL_PERSISTENT_RECORD` variable
|
||||
with a value of how many previous fuzz cases to keep prio a crash.
|
||||
if set to e.g. 10, then the 9 previous inputs are written to
|
||||
out/default/crashes as RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008
|
||||
and RECORD:000000,cnt:000009 being the crash case.
|
||||
NOTE: This option needs to be enabled in config.h first!
|
||||
|
||||
- If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`.
|
||||
Others need not apply.
|
||||
Others need not apply, unless they also want to disable the
|
||||
`/proc/sys/kernel/core_pattern` check.
|
||||
|
||||
- Benchmarking only: `AFL_BENCH_JUST_ONE` causes the fuzzer to exit after
|
||||
processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to
|
||||
@ -448,6 +484,7 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
`banner` corresponds to the name of the fuzzer provided through `-M/-S`.
|
||||
`afl_version` corresponds to the currently running afl version (e.g `++3.0c`).
|
||||
Default (empty/non present) will add no tags to the metrics.
|
||||
See [rpc_statsd.md](rpc_statsd.md) for more information.
|
||||
|
||||
- Setting `AFL_CRASH_EXITCODE` sets the exit code afl treats as crash.
|
||||
For example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting
|
||||
@ -517,7 +554,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
- With `AFL_USE_QASAN` you can enable QEMU AddressSanitizer for dynamically
|
||||
linked binaries.
|
||||
|
||||
- With `AFL_QEMU_FORCE_DFL` you force QEMU to ignore the registered singal
|
||||
- With `AFL_QEMU_FORCE_DFL` you force QEMU to ignore the registered signal
|
||||
handlers of the target.
|
||||
|
||||
## 6) Settings for afl-cmin
|
||||
@ -535,6 +572,9 @@ The corpus minimization script offers very little customization:
|
||||
a modest security risk on multi-user systems with rogue users, but should
|
||||
be safe on dedicated fuzzing boxes.
|
||||
|
||||
- `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed.
|
||||
This can help when embedding `afl-cmin` or `afl-showmap` in other scripts scripting.
|
||||
|
||||
## 7) Settings for afl-tmin
|
||||
|
||||
Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be
|
||||
@ -588,7 +628,7 @@ optimal values if not already present in the environment:
|
||||
override this by setting `LD_BIND_LAZY` beforehand, but it is almost
|
||||
certainly pointless.
|
||||
|
||||
- By default, `ASAN_OPTIONS` are set to:
|
||||
- By default, `ASAN_OPTIONS` are set to (among others):
|
||||
```
|
||||
abort_on_error=1
|
||||
detect_leaks=0
|
||||
@ -609,7 +649,14 @@ optimal values if not already present in the environment:
|
||||
msan_track_origins=0
|
||||
allocator_may_return_null=1
|
||||
```
|
||||
Be sure to include the first one when customizing anything, since some
|
||||
MSAN versions don't call `abort()` on error, and we need a way to detect
|
||||
faults.
|
||||
- Similarly, the default `LSAN_OPTIONS` are set to:
|
||||
```
|
||||
exit_code=23
|
||||
fast_unwind_on_malloc=0
|
||||
symbolize=0
|
||||
print_suppressions=0
|
||||
```
|
||||
Be sure to include the first ones for LSAN and MSAN when customizing
|
||||
anything, since some MSAN and LSAN versions don't call `abort()` on
|
||||
error, and we need a way to detect faults.
|
||||
|
||||
|
@ -3,40 +3,6 @@
|
||||
In the following, we describe a variety of ideas that could be implemented
|
||||
for future AFL++ versions.
|
||||
|
||||
# GSoC 2021
|
||||
|
||||
All GSoC 2021 projects will be in the Rust development language!
|
||||
|
||||
## UI for libaflrs
|
||||
|
||||
Write a user interface to libaflrs, the upcoming backend of afl++.
|
||||
This might look like the afl-fuzz UI, but you can improve on it - and should!
|
||||
|
||||
## Schedulers for libaflrs
|
||||
|
||||
Schedulers is a mechanism that selects items from the fuzzing corpus based
|
||||
on strategy and randomness. One scheduler might focus on long paths,
|
||||
another on rarity of edges disocvered, still another on a combination on
|
||||
things. Some of the schedulers in afl++ have to be ported, but you are free
|
||||
to come up with your own if you want to - and see how it performs.
|
||||
|
||||
## Forkserver support for libaflrs
|
||||
|
||||
The current libaflrs implementation fuzzes in-memory, however obviously we
|
||||
want to support afl instrumented binaries as well.
|
||||
Hence a forkserver support needs to be implemented - forking off the target
|
||||
and talking to the target via a socketpair and the communication protocol
|
||||
within.
|
||||
|
||||
## More Observers for libaflrs
|
||||
|
||||
An observer is measuring functionality that looks at the target being fuzzed
|
||||
and documents something about it. In traditional fuzzing this is the coverage
|
||||
in the target, however we want to add various more observers, e.g. stack depth,
|
||||
heap usage, etc. - this is a topic for an experienced Rust developer.
|
||||
|
||||
# Generic ideas and wishlist
|
||||
|
||||
## Analysis software
|
||||
|
||||
Currently analysis is done by using afl-plot, which is rather outdated.
|
||||
@ -63,6 +29,13 @@ 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, ...
|
||||
|
||||
Mentor: vanhauser-thc
|
||||
|
||||
## Machine Learning
|
||||
|
||||
Something with machine learning, better than [NEUZZ](https://github.com/dongdongshe/neuzz) :-)
|
||||
|
@ -83,5 +83,5 @@ You can find a simple solution in utils/argv_fuzzing.
|
||||
## Attacking a format that uses checksums?
|
||||
|
||||
Remove the checksum-checking code or use a postprocessor!
|
||||
See utils/custom_mutators/ for more.
|
||||
See `afl_custom_post_process` in custom_mutators/examples/example.c for more.
|
||||
|
||||
|
@ -28,6 +28,13 @@ Note that ASAN is incompatible with -static, so be mindful of that.
|
||||
|
||||
(You can also use AFL_USE_MSAN=1 to enable MSAN instead.)
|
||||
|
||||
When compiling with AFL_USE_LSAN, the leak sanitizer will normally run
|
||||
when the program exits. In order to utilize this check at different times,
|
||||
such as at the end of a loop, you may use the macro __AFL_LEAK_CHECK();.
|
||||
This macro will report a crash in afl-fuzz if any memory is left leaking
|
||||
at this stage. You can also use LSAN_OPTIONS and a supressions file
|
||||
for more fine-tuned checking, however make sure you keep exitcode=23.
|
||||
|
||||
NOTE: if you run several secondary instances, only one should run the target
|
||||
compiled with ASAN (and UBSAN, CFISAN), the others should run the target with
|
||||
no sanitizers compiled in.
|
||||
|
@ -69,9 +69,6 @@ If you are only interested in specific parts of the code being fuzzed, you can
|
||||
instrument_files the files that are actually relevant. This improves the speed and
|
||||
accuracy of afl. See instrumentation/README.instrument_list.md
|
||||
|
||||
Also use the InsTrim mode on larger binaries, this improves performance and
|
||||
coverage a lot.
|
||||
|
||||
## 4. Profile and optimize the binary
|
||||
|
||||
Check for any parameters or settings that obviously improve performance. For
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Remote monitoring with StatsD
|
||||
|
||||
StatsD allows you to receive and aggregate metrics from a wide range of application and retransmit them to the backend of your choice.
|
||||
StatsD allows you to receive and aggregate metrics from a wide range of applications and retransmit them to the backend of your choice.
|
||||
This enables you to create nice and readable dashboards containing all the information you need on your fuzzer instances.
|
||||
No need to write your own statistics parsing system, deploy and maintain it to all your instances, sync with your graph rendering system...
|
||||
|
||||
@ -45,7 +45,7 @@ For more information on these env vars, check out `docs/env_variables.md`.
|
||||
|
||||
The simplest way of using this feature is to use any metric provider and change the host/port of your StatsD daemon,
|
||||
with `AFL_STATSD_HOST` and `AFL_STATSD_PORT`, if required (defaults are `localhost` and port `8125`).
|
||||
To get started, here are some instruction with free and open source tools.
|
||||
To get started, here are some instructions with free and open source tools.
|
||||
The following setup is based on Prometheus, statsd_exporter and Grafana.
|
||||
Grafana here is not mandatory, but gives you some nice graphs and features.
|
||||
|
||||
@ -131,7 +131,7 @@ mappings:
|
||||
|
||||
Run `docker-compose up -d`.
|
||||
|
||||
Everything should be now setup, you are now able to run your fuzzers with
|
||||
Everything should now be setup, you are now able to run your fuzzers with
|
||||
|
||||
```
|
||||
AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -M test-fuzzer-1 -i i -o o ./bin/my-application @@
|
||||
@ -139,5 +139,5 @@ AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -S test-fuzzer-2 -i i -o
|
||||
...
|
||||
```
|
||||
|
||||
This setup may be modified before use in production environment. Depending on your needs: addind passwords, creating volumes for storage,
|
||||
This setup may be modified before use in a production environment. Depending on your needs: adding passwords, creating volumes for storage,
|
||||
tweaking the metrics gathering to get host metrics (CPU, RAM ...).
|
||||
|
@ -251,8 +251,9 @@ exceed it by a margin sufficient to be classified as hangs.
|
||||
| arithmetics : 53/2.54M, 0/537k, 0/55.2k |
|
||||
| known ints : 8/322k, 12/1.32M, 10/1.70M |
|
||||
| dictionary : 9/52k, 1/53k, 1/24k |
|
||||
| havoc : 1903/20.0M, 0/0 |
|
||||
| trim : 20.31%/9201, 17.05% |
|
||||
|havoc/splice : 1903/20.0M, 0/0 |
|
||||
|py/custom/rq : unused, 53/2.54M, unused |
|
||||
| trim/eff : 20.31%/9201, 17.05% |
|
||||
+-----------------------------------------------------+
|
||||
```
|
||||
|
||||
@ -268,6 +269,12 @@ goal. Finally, the third number shows the proportion of bytes that, although
|
||||
not possible to remove, were deemed to have no effect and were excluded from
|
||||
some of the more expensive deterministic fuzzing steps.
|
||||
|
||||
Note that when deterministic mutation mode is off (which is the default
|
||||
because it is not very efficient) the first five lines display
|
||||
"disabled (default, enable with -D)".
|
||||
|
||||
Only what is activated will have counter shown.
|
||||
|
||||
### Path geometry
|
||||
|
||||
```
|
||||
|
@ -5,6 +5,44 @@
|
||||
"__afl_auto_init";
|
||||
"__afl_area_initial";
|
||||
"__afl_prev_loc";
|
||||
"__afl_prev_caller";
|
||||
"__afl_prev_ctx";
|
||||
"__afl_final_loc";
|
||||
"__afl_map_addr";
|
||||
"__afl_dictionary";
|
||||
"__afl_dictionary_len";
|
||||
"__afl_selective_coverage";
|
||||
"__afl_selective_coverage_start_off";
|
||||
"__afl_selective_coverage_temp";
|
||||
"__afl_coverage_discard";
|
||||
"__afl_coverage_skip";
|
||||
"__afl_coverage_on";
|
||||
"__afl_coverage_off";
|
||||
"__afl_coverage_interesting";
|
||||
"__afl_fuzz_len";
|
||||
"__afl_fuzz_ptr";
|
||||
"__afl_sharedmem_fuzzing";
|
||||
"__sanitizer_cov_trace_pc_guard";
|
||||
"__sanitizer_cov_trace_pc_guard_init";
|
||||
"__cmplog_ins_hook1";
|
||||
"__cmplog_ins_hook2";
|
||||
"__cmplog_ins_hook4";
|
||||
"__cmplog_ins_hookN";
|
||||
"__cmplog_ins_hook16";
|
||||
"__sanitizer_cov_trace_cmp1";
|
||||
"__sanitizer_cov_trace_const_cmp1";
|
||||
"__sanitizer_cov_trace_cmp2";
|
||||
"__sanitizer_cov_trace_const_cmp2";
|
||||
"__sanitizer_cov_trace_cmp4";
|
||||
"__sanitizer_cov_trace_const_cmp4";
|
||||
"__sanitizer_cov_trace_cmp8";
|
||||
"__sanitizer_cov_trace_const_cmp8";
|
||||
"__sanitizer_cov_trace_cmp16";
|
||||
"__sanitizer_cov_trace_const_cmp16";
|
||||
"__sanitizer_cov_trace_switch";
|
||||
"__cmplog_rtn_hook";
|
||||
"__cmplog_rtn_gcc_stdstring_cstring";
|
||||
"__cmplog_rtn_gcc_stdstring_stdstring";
|
||||
"__cmplog_rtn_llvm_stdstring_cstring";
|
||||
"__cmplog_rtn_llvm_stdstring_stdstring";
|
||||
};
|
||||
|
5
frida_mode/.gitignore
vendored
Normal file
5
frida_mode/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
build/
|
||||
frida_test.dat
|
||||
qemu_test.dat
|
||||
frida_out/**
|
||||
qemu_out/**
|
188
frida_mode/GNUmakefile
Normal file
188
frida_mode/GNUmakefile
Normal file
@ -0,0 +1,188 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)..)/
|
||||
INC_DIR:=$(PWD)include/
|
||||
SRC_DIR:=$(PWD)src/
|
||||
INCLUDES:=$(wildcard $(INC_DIR)*.h)
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
OBJ_DIR:=$(BUILD_DIR)obj/
|
||||
|
||||
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
|
||||
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
|
||||
CFLAGS+=-fPIC \
|
||||
-D_GNU_SOURCE \
|
||||
-D_FORTIFY_SOURCE=2 \
|
||||
-g \
|
||||
-O3 \
|
||||
-funroll-loops \
|
||||
|
||||
RT_CFLAGS:=-Wno-unused-parameter \
|
||||
-Wno-sign-compare \
|
||||
-Wno-unused-function \
|
||||
-Wno-unused-result \
|
||||
-Wno-int-to-pointer-cast \
|
||||
|
||||
LDFLAGS+=-shared \
|
||||
-lpthread \
|
||||
-lresolv \
|
||||
-ldl \
|
||||
-z noexecstack \
|
||||
|
||||
ifdef DEBUG
|
||||
CFLAGS+=-Werror \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wpointer-arith
|
||||
else
|
||||
CFLAGS+=-Wno-pointer-arith
|
||||
endif
|
||||
|
||||
FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/
|
||||
FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so
|
||||
FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded
|
||||
|
||||
ifndef ARCH
|
||||
|
||||
ARCH=$(shell uname -m)
|
||||
ifeq "$(ARCH)" "aarch64"
|
||||
ARCH:=arm64
|
||||
endif
|
||||
|
||||
ifeq "$(ARCH)" "i686"
|
||||
ARCH:=x86
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
OS:=macos
|
||||
RT_CFLAGS:=$(RT_CFLAGS) -Wno-deprecated-declarations
|
||||
else
|
||||
ifdef DEBUG
|
||||
RT_CFLAGS:=$(RT_CFLAGS) -Wno-prio-ctor-dtor
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "Linux"
|
||||
OS:=linux
|
||||
endif
|
||||
|
||||
ifndef OS
|
||||
$(error "Operating system unsupported")
|
||||
endif
|
||||
|
||||
GUM_DEVKIT_VERSION=14.2.18
|
||||
GUM_DEVKIT_FILENAME=frida-gum-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)
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a
|
||||
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h
|
||||
|
||||
FRIDA_DIR:=$(PWD)build/frida-source/
|
||||
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
|
||||
FRIDA_GUM:=$(FRIDA_DIR)build/frida-linux-x86_64/lib/libfrida-gum-1.0.a
|
||||
FRIDA_GUM_DEVKIT_DIR:=$(FRIDA_DIR)build/gum-devkit/
|
||||
FRIDA_GUM_DEVKIT_HEADER:=$(FRIDA_GUM_DEVKIT_DIR)frida-gum.h
|
||||
FRIDA_GUM_DEVKIT_TARBALL:=$(FRIDA_DIR)build/frida-gum-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
|
||||
|
||||
.PHONY: all 32 clean format $(FRIDA_GUM)
|
||||
|
||||
############################## ALL #############################################
|
||||
|
||||
all: $(FRIDA_TRACE)
|
||||
|
||||
32:
|
||||
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(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-gum 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 $< $@
|
||||
else
|
||||
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
|
||||
wget -O $@ $(GUM_DEVKIT_URL)
|
||||
endif
|
||||
|
||||
$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL)
|
||||
tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
|
||||
|
||||
$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL)
|
||||
tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
|
||||
|
||||
############################## AFL #############################################
|
||||
$(AFL_COMPILER_RT_OBJ): $(AFL_COMPILER_RT_SRC)
|
||||
$(CC) \
|
||||
$(CFLAGS) \
|
||||
$(RT_CFLAGS) \
|
||||
-I $(ROOT) \
|
||||
-I $(ROOT)include \
|
||||
-o $@ \
|
||||
-c $<
|
||||
|
||||
############################# SOURCE ###########################################
|
||||
|
||||
define BUILD_SOURCE
|
||||
$(2): $(1) $(INCLUDES) GNUmakefile | $(OBJ_DIR)
|
||||
$(CC) \
|
||||
$(CFLAGS) \
|
||||
-I $(ROOT)include \
|
||||
-I $(FRIDA_BUILD_DIR) \
|
||||
-I $(INC_DIR) \
|
||||
-c $1 \
|
||||
-o $2
|
||||
endef
|
||||
|
||||
$(foreach src,$(SOURCES),$(eval $(call BUILD_SOURCE,$(src),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))))
|
||||
|
||||
######################## AFL-FRIDA-TRACE #######################################
|
||||
|
||||
$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR)
|
||||
$(CC) \
|
||||
$(OBJS) \
|
||||
$(GUM_DEVIT_LIBRARY) \
|
||||
$(AFL_COMPILER_RT_OBJ) \
|
||||
$(LDFLAGS) \
|
||||
-o $@ \
|
||||
|
||||
cp -v $(FRIDA_TRACE) $(ROOT)
|
||||
|
||||
############################# CLEAN ############################################
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
|
||||
############################# FORMAT ###########################################
|
||||
format:
|
||||
cd $(ROOT) && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i
|
||||
cd $(ROOT) && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i
|
||||
|
||||
############################# RUN #############################################
|
13
frida_mode/Makefile
Normal file
13
frida_mode/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
all:
|
||||
@echo trying to use GNU make...
|
||||
@gmake all || echo please install GNUmake
|
||||
|
||||
32:
|
||||
@echo trying to use GNU make...
|
||||
@gmake 32 || echo please install GNUmake
|
||||
|
||||
clean:
|
||||
@gmake clean
|
||||
|
||||
format:
|
||||
@gmake format
|
294
frida_mode/README.md
Normal file
294
frida_mode/README.md
Normal file
@ -0,0 +1,294 @@
|
||||
# FRIDA MODE
|
||||
|
||||
The purpose of FRIDA mode is to provide an alternative binary only fuzzer for
|
||||
AFL just like that provided by QEMU mode. The intention is to provide a very
|
||||
similar user experience, right down to the options provided through environment
|
||||
variables.
|
||||
|
||||
Whilst AFLplusplus already has some support for running on FRIDA [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida)
|
||||
this requires the code to be fuzzed to be provided as a shared library, it
|
||||
cannot be used to fuzz executables. Additionally, it requires the user to write
|
||||
a small harness around their target code of interest.
|
||||
FRIDA mode instead takes a different approach to avoid these limitations.
|
||||
In Frida mode binary programs are instrumented, similarly to QEMU mode.
|
||||
|
||||
## Current Progress
|
||||
|
||||
As FRIDA mode is new, it is missing a lot of features. The design is such that it
|
||||
should be possible to add these features in a similar manner to QEMU mode and
|
||||
perhaps leverage some of its design and implementation.
|
||||
|
||||
| Feature/Instrumentation | frida-mode | Notes |
|
||||
| -------------------------|:----------:|:--------------------------------------------:|
|
||||
| NeverZero | x | |
|
||||
| Persistent Mode | x | (x86/x64 only)(Only on function boundaries) |
|
||||
| LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) |
|
||||
| CMPLOG | x | (x86/x64 only) |
|
||||
| Selective Instrumentation| x | |
|
||||
| Non-Colliding Coverage | - | (Not possible in binary-only instrumentation |
|
||||
| Ngram prev_loc Coverage | - | |
|
||||
| Context Coverage | - | |
|
||||
| Auto Dictionary | - | |
|
||||
| Snapshot LKM Support | - | |
|
||||
| In-Memory Test Cases | x | (x86/x64 only) |
|
||||
|
||||
## Compatibility
|
||||
Currently FRIDA mode supports Linux and macOS targets on both x86/x64
|
||||
architecture and aarch64. Later releases may add support for aarch32 and Windows
|
||||
targets as well as embedded linux environments.
|
||||
|
||||
FRIDA has been used on various embedded targets using both uClibc and musl C
|
||||
runtime libraries, so porting should be possible. However, the current build
|
||||
system does not support cross compilation.
|
||||
|
||||
## Getting Started
|
||||
|
||||
To build everything run `make`. To build for x86 run `make 32`. Note that in
|
||||
x86 bit mode, it is not necessary for afl-fuzz to be built for 32-bit. However,
|
||||
the shared library for frida_mode must be since it is injected into the target
|
||||
process.
|
||||
|
||||
Various tests can be found in subfolders within the `test/` directory. To use
|
||||
these, first run `make` to build any dependencies. Then run `make qemu` or
|
||||
`make frida` to run on either QEMU of FRIDA mode respectively. To run frida
|
||||
tests in 32-bit mode, run `make ARCH=x86 frida`. When switching between
|
||||
architectures it may be necessary to run `make clean` first for a given build
|
||||
target to remove previously generated binaries for a different architecture.
|
||||
|
||||
## Usage
|
||||
|
||||
FRIDA mode added some small modifications to `afl-fuzz` and similar tools
|
||||
in AFLplusplus. The intention was that it behaves identically to QEMU, but it uses
|
||||
the 'O' switch rather than 'Q'. Whilst the options 'f', 'F', 's' or 'S' may have
|
||||
made more sense for a mode powered by FRIDA Stalker, they were all taken, so
|
||||
instead we use 'O' in hommage to the [author](https://github.com/oleavr) of
|
||||
FRIDA.
|
||||
|
||||
Similarly, the intention is to mimic the use of environment variables used by
|
||||
QEMU where possible (by replacing `s/QEMU/FRIDA/g`). Accordingly, the
|
||||
following options are currently supported:
|
||||
|
||||
* `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS`
|
||||
* `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES`
|
||||
* `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES`
|
||||
* `AFL_FRIDA_PERSISTENT_ADDR` - See `AFL_QEMU_PERSISTENT_ADDR`
|
||||
* `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT`
|
||||
* `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK`
|
||||
* `AFL_FRIDA_PERSISTENT_RET` - See `AFL_QEMU_PERSISTENT_RET`
|
||||
* `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` - See `AFL_QEMU_PERSISTENT_RETADDR_OFFSET`
|
||||
|
||||
To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`.
|
||||
|
||||
## Performance
|
||||
|
||||
Additionally, the intention is to be able to make a direct performance
|
||||
comparison between the two approaches. Accordingly, FRIDA mode includes various
|
||||
test targets based on the [libpng](https://libpng.sourceforge.io/) benchmark
|
||||
used by [fuzzbench](https://google.github.io/fuzzbench/) and integrated with the
|
||||
[StandaloneFuzzTargetMain](https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c)
|
||||
from the llvm project. These tests include basic fork-server support, persistent
|
||||
mode and persistent mode with in-memory test-cases. These are built and linked
|
||||
without any special modifications to suit FRIDA or QEMU. The test data provided
|
||||
with libpng is used as the corpus.
|
||||
|
||||
The intention is to add support for FRIDA mode to the FuzzBench project and
|
||||
perform a like-for-like comparison with QEMU mode to get an accurate
|
||||
appreciation of its performance.
|
||||
|
||||
## Design
|
||||
|
||||
FRIDA mode is supported by using `LD_PRELOAD` (`DYLD_INSERT_LIBRARIES` on macOS)
|
||||
to inject a shared library (`afl-frida-trace.so`) into the target. This shared
|
||||
library is built using the [frida-gum](https://github.com/frida/frida-gum)
|
||||
devkit from the [FRIDA](https://github.com/frida/frida) project. One of the
|
||||
components of frida-gum is [Stalker](https://medium.com/@oleavr/anatomy-of-a-code-tracer-b081aadb0df8),
|
||||
this allows the dynamic instrumentation of running code for AARCH32, AARCH64,
|
||||
x86 and x64 architectures. Implementation details can be found
|
||||
[here](https://frida.re/docs/stalker/).
|
||||
|
||||
Dynamic instrumentation is used to augment the target application with similar
|
||||
coverage information to that inserted by `afl-gcc` or `afl-clang`. The shared
|
||||
library is also linked to the `compiler-rt` component of AFLplusplus to feedback
|
||||
this coverage information to AFL++ and also provide a fork server. It also makes
|
||||
use of the FRIDA [prefetch](https://github.com/frida/frida-gum/blob/56dd9ba3ee9a5511b4b0c629394bf122775f1ab7/gum/gumstalker.h#L115)
|
||||
support to feedback instrumented blocks from the child to the parent using a
|
||||
shared memory region to avoid the need to regenerate instrumented blocks on each
|
||||
fork.
|
||||
|
||||
Whilst FRIDA allows for a normal C function to be used to augment instrumented
|
||||
code, FRIDA mode instead makes use of optimized assembly instead on AARCH64 and
|
||||
x86/64 targets. By injecting these small snippets of assembly, we avoid having
|
||||
to push and pop the full register context. Note that since this instrumentation
|
||||
is used on every basic block to generate coverage, it has a large impact on
|
||||
performance.
|
||||
|
||||
CMPLOG support also adds code to the assembly, however, at present this code
|
||||
makes use of a basic C function and is yet to be optimized. Since not all
|
||||
instances run CMPLOG mode and instrumentation of the binary is less frequent
|
||||
(only on CMP, SUB and CALL instructions) performance is not quite so critical.
|
||||
|
||||
## Advanced configuration options
|
||||
|
||||
* `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
|
||||
|
||||
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_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
|
||||
instrumentation (the default where available). Required to use
|
||||
`AFL_FRIDA_INST_TRACE`.
|
||||
* `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.
|
||||
* `AFL_FRIDA_INST_TRACE` - Log to stdout the address of executed blocks
|
||||
`AFL_FRIDA_INST_NO_OPTIMIZE`.
|
||||
* `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target
|
||||
application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`)
|
||||
* `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target
|
||||
application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`)
|
||||
* `AFL_FRIDA_PERSISTENT_DEBUG` - Insert a Breakpoint into the instrumented code
|
||||
at `AFL_FRIDA_PERSISTENT_HOOK` and `AFL_FRIDA_PERSISTENT_RET` to allow the user
|
||||
to determine the value of `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` using a
|
||||
debugger.
|
||||
|
||||
```
|
||||
|
||||
gdb \
|
||||
--ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=XXXXXXXXXX' \
|
||||
--ex 'set environment AFL_FRIDA_PERSISTENT_RET=XXXXXXXXXX' \
|
||||
--ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \
|
||||
--ex 'set environment AFL_DEBUG_CHILD=1' \
|
||||
--ex 'set environment LD_PRELOAD=afl-frida-trace.so' \
|
||||
--args <my-executable> [my arguments]
|
||||
|
||||
```
|
||||
* `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
|
||||
`AFL_FRIDA_STATS_INTERVAL` has expired). Note that simply because a new path is
|
||||
found does not mean a new block needs to be compiled. It could simply be that
|
||||
the existing blocks instrumented have been executed in a different order.
|
||||
```
|
||||
stats
|
||||
-----
|
||||
Index: 2
|
||||
Pid: 1815944
|
||||
Time: 2021-05-28 15:26:41
|
||||
Blocks: 1985
|
||||
Instructions: 9192
|
||||
Avg Instructions / Block: 4
|
||||
|
||||
Call Immediates: 391 (4.25%)
|
||||
Call Immediates Excluded: 65 (0.71%)
|
||||
Call Register: 0 (0.00%)
|
||||
Call Memory: 0 (0.00%)
|
||||
|
||||
Jump Immediates: 202 (2.20%)
|
||||
Jump Register: 10 (0.11%)
|
||||
Jump Memory: 12 (0.13%)
|
||||
|
||||
Conditional Jump Immediates: 1210 (13.16%)
|
||||
Conditional Jump CX Immediate: 0 (0.00%)
|
||||
Conditional Jump Register: 0 (0.00%)
|
||||
Conditional Jump Memory: 0 (0.00%)
|
||||
|
||||
Returns: 159 (0.00%)
|
||||
|
||||
Rip Relative: 247 (0.00%)
|
||||
|
||||
```
|
||||
* `AFL_FRIDA_STATS_INTERVAL` - The maximum frequency to output statistics
|
||||
information. Stats will be written whenever they are updated if the given
|
||||
interval has elapsed since last time they were written.
|
||||
* `AFL_FRIDA_STATS_TRANSITIONS` - Also dump the internal stalker counters to
|
||||
stderr when the regular stats are written. Note that these stats are reset in
|
||||
the child each time a new fork occurs since they are not stored in shared
|
||||
memory. Unfortunately, these stats are internal to stalker, so this is the best
|
||||
we can do for now.
|
||||
```
|
||||
stats
|
||||
-----
|
||||
Index: 2
|
||||
Pid: 1816794
|
||||
Time: 2021-05-28 15:26:41
|
||||
|
||||
|
||||
total_transitions: 786
|
||||
call_imms: 97
|
||||
call_regs: 0
|
||||
call_mems: 0
|
||||
post_call_invokes: 86
|
||||
excluded_call_imms: 29
|
||||
ret_slow_paths: 23
|
||||
|
||||
jmp_imms: 58
|
||||
jmp_mems: 7
|
||||
jmp_regs: 26
|
||||
|
||||
jmp_cond_imms: 460
|
||||
jmp_cond_mems: 0
|
||||
jmp_cond_regs: 0
|
||||
jmp_cond_jcxzs: 0
|
||||
|
||||
jmp_continuations: 0
|
||||
```
|
||||
## FASAN - Frida Address Sanitizer Mode
|
||||
Frida mode also supports FASAN. The design of this is actually quite simple and
|
||||
very similar to that used when instrumenting applications compiled from source.
|
||||
|
||||
### Address Sanitizer Basics
|
||||
|
||||
When Address Sanitizer is used to instrument programs built from source, the
|
||||
compiler first adds a dependency (`DT_NEEDED` entry) for the Address Sanitizer
|
||||
dynamic shared object (DSO). This shared object contains the main logic for Address
|
||||
Sanitizer, including setting and managing up the shadow memory. It also provides
|
||||
replacement implementations for a number of functions in standard libraries.
|
||||
|
||||
These replacements include things like `malloc` and `free` which allows for those
|
||||
allocations to be marked in the shadow memory, but also a number of other fuctions.
|
||||
Consider `memcpy` for example, this is instrumented to validate the paramters
|
||||
(test the source and destination buffers against the shadow memory. This is much
|
||||
easier than instrumenting those standard libraries since, first it would require
|
||||
you to re-compile them and secondly it would mean that the instrumentation would
|
||||
be applied at a more expensive granular level. Lastly, load-widening (typically
|
||||
found in highy optimized code) can also make this instrumentation more difficult.
|
||||
|
||||
Since the DSO is loaded before all of the standard libraries (in fact it insists
|
||||
on being first), the dynamic loader will use it to resolve imports from other
|
||||
modules which depend on it.
|
||||
|
||||
### FASAN Implementation
|
||||
|
||||
FASAN takes a similar approach. It requires the user to add the Address Sanitizer
|
||||
DSO to the `AFL_PRELOAD` environment variable such that it is loaded into the target.
|
||||
Again, it must be first in the list. This means that it is not necessary to
|
||||
instrument the standard libraries to detect when an application has provided an
|
||||
incorrect argument to `memcpy` for example. This avoids issues with load-widening
|
||||
and should also mean a huge improvement in performance.
|
||||
|
||||
FASAN then adds instrumentation for any instrucutions which use memory operands and
|
||||
then calls into the `__asan_loadN` and `__asan_storeN` functions provided by the DSO
|
||||
to validate memory accesses against the shadow memory.
|
||||
|
||||
## TODO
|
||||
|
||||
The next features to be added are Aarch64 and 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.
|
13
frida_mode/include/asan.h
Normal file
13
frida_mode/include/asan.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef _ASAN_H
|
||||
#define _ASAN_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
extern gboolean asan_initialized;
|
||||
|
||||
void asan_init(void);
|
||||
void asan_arch_init(void);
|
||||
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator);
|
||||
|
||||
#endif
|
||||
|
11
frida_mode/include/ctx.h
Normal file
11
frida_mode/include/ctx.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _CTX_H
|
||||
#define _CTX_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
gsize ctx_read_reg(GumCpuContext *ctx, x86_reg reg);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
15
frida_mode/include/entry.h
Normal file
15
frida_mode/include/entry.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _ENTRY_H
|
||||
#define _ENTRY_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
extern guint64 entry_start;
|
||||
|
||||
void entry_init(void);
|
||||
|
||||
void entry_run(void);
|
||||
|
||||
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output);
|
||||
|
||||
#endif
|
||||
|
14
frida_mode/include/frida_cmplog.h
Normal file
14
frida_mode/include/frida_cmplog.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _CMPLOG_H
|
||||
#define _CMPLOG_H
|
||||
|
||||
extern struct cmp_map *__afl_cmp_map;
|
||||
|
||||
void cmplog_init(void);
|
||||
|
||||
/* Functions to be implemented by the different architectures */
|
||||
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator);
|
||||
|
||||
gboolean cmplog_is_readable(guint64 addr, size_t size);
|
||||
|
||||
#endif
|
||||
|
27
frida_mode/include/instrument.h
Normal file
27
frida_mode/include/instrument.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef _INSTRUMENT_H
|
||||
#define _INSTRUMENT_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
extern __thread uint64_t previous_pc;
|
||||
extern uint8_t * __afl_area_ptr;
|
||||
extern uint32_t __afl_map_size;
|
||||
|
||||
void instrument_init(void);
|
||||
|
||||
GumStalkerTransformer *instrument_get_transformer(void);
|
||||
|
||||
/* Functions to be implemented by the different architectures */
|
||||
gboolean instrument_is_coverage_optimize_supported(void);
|
||||
|
||||
void instrument_coverage_optimize(const cs_insn * instr,
|
||||
GumStalkerOutput *output);
|
||||
|
||||
void instrument_debug_init(void);
|
||||
void instrument_debug_start(uint64_t address, GumStalkerOutput *output);
|
||||
void instrument_debug_instruction(uint64_t address, uint16_t size);
|
||||
void instrument_debug_end(GumStalkerOutput *output);
|
||||
#endif
|
||||
|
11
frida_mode/include/interceptor.h
Normal file
11
frida_mode/include/interceptor.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _INTERCEPTOR_H
|
||||
#define _INTERCEPTOR_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
void intercept(void *address, gpointer replacement, gpointer user_data);
|
||||
void unintercept(void *address);
|
||||
void unintercept_self(void);
|
||||
|
||||
#endif
|
||||
|
13
frida_mode/include/lib.h
Normal file
13
frida_mode/include/lib.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef _LIB_H
|
||||
#define _LIB_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
void lib_init(void);
|
||||
|
||||
guint64 lib_get_text_base(void);
|
||||
|
||||
guint64 lib_get_text_limit(void);
|
||||
|
||||
#endif
|
||||
|
9
frida_mode/include/output.h
Normal file
9
frida_mode/include/output.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef _OUTPUT_H
|
||||
#define _OUTPUT_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
void output_init(void);
|
||||
|
||||
#endif
|
||||
|
35
frida_mode/include/persistent.h
Normal file
35
frida_mode/include/persistent.h
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
#ifndef _PERSISTENT_H
|
||||
#define _PERSISTENT_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
#include "config.h"
|
||||
|
||||
typedef struct arch_api_regs api_regs;
|
||||
|
||||
typedef void (*afl_persistent_hook_fn)(api_regs *regs, uint64_t guest_base,
|
||||
uint8_t *input_buf,
|
||||
uint32_t input_buf_len);
|
||||
|
||||
extern int __afl_persistent_loop(unsigned int max_cnt);
|
||||
|
||||
extern unsigned int * __afl_fuzz_len;
|
||||
extern unsigned char *__afl_fuzz_ptr;
|
||||
|
||||
extern guint64 persistent_start;
|
||||
extern guint64 persistent_count;
|
||||
extern guint64 persistent_ret;
|
||||
extern guint64 persistent_ret_offset;
|
||||
extern gboolean persistent_debug;
|
||||
extern afl_persistent_hook_fn hook;
|
||||
|
||||
void persistent_init(void);
|
||||
|
||||
/* Functions to be implemented by the different architectures */
|
||||
gboolean persistent_is_supported(void);
|
||||
|
||||
void persistent_prologue(GumStalkerOutput *output);
|
||||
void persistent_epilogue(GumStalkerOutput *output);
|
||||
|
||||
#endif
|
||||
|
11
frida_mode/include/prefetch.h
Normal file
11
frida_mode/include/prefetch.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _PREFETCH_H
|
||||
#define _PREFETCH_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
void prefetch_init(void);
|
||||
void prefetch_write(void *addr);
|
||||
void prefetch_read(void);
|
||||
|
||||
#endif
|
||||
|
13
frida_mode/include/ranges.h
Normal file
13
frida_mode/include/ranges.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef _RANGES_H
|
||||
#define _RANGES_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
void ranges_init(void);
|
||||
|
||||
gboolean range_is_excluded(gpointer address);
|
||||
|
||||
void ranges_exclude();
|
||||
|
||||
#endif
|
||||
|
11
frida_mode/include/stalker.h
Normal file
11
frida_mode/include/stalker.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _STALKER_H
|
||||
#define _STALKER_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
void stalker_init(void);
|
||||
GumStalker *stalker_get(void);
|
||||
void stalker_start(void);
|
||||
|
||||
#endif
|
||||
|
28
frida_mode/include/stats.h
Normal file
28
frida_mode/include/stats.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef _STATS_H
|
||||
#define _STATS_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
guint64 num_blocks;
|
||||
guint64 num_instructions;
|
||||
guint64 stats_last_time;
|
||||
guint64 stats_idx;
|
||||
guint64 transitions_idx;
|
||||
|
||||
} stats_data_header_t;
|
||||
|
||||
extern stats_data_header_t *stats_data;
|
||||
|
||||
void stats_init(void);
|
||||
void stats_collect(const cs_insn *instr, gboolean begin);
|
||||
void stats_print(char *format, ...);
|
||||
|
||||
gboolean stats_is_supported_arch(void);
|
||||
size_t stats_data_size_arch(void);
|
||||
void stats_collect_arch(const cs_insn *instr);
|
||||
void stats_write_arch(void);
|
||||
|
||||
#endif
|
||||
|
14
frida_mode/include/util.h
Normal file
14
frida_mode/include/util.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _UTIL_H
|
||||
#define _UTIL_H
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
#define UNUSED_PARAMETER(x) (void)(x)
|
||||
#define IGNORED_RETURN(x) (void)!(x)
|
||||
|
||||
guint64 util_read_address(char *key);
|
||||
|
||||
guint64 util_read_num(char *key);
|
||||
|
||||
#endif
|
||||
|
24
frida_mode/src/asan/asan.c
Normal file
24
frida_mode/src/asan/asan.c
Normal file
@ -0,0 +1,24 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "asan.h"
|
||||
|
||||
gboolean asan_initialized = FALSE;
|
||||
|
||||
void asan_init(void) {
|
||||
|
||||
if (getenv("AFL_USE_FASAN") != NULL) {
|
||||
|
||||
OKF("Frida ASAN mode enabled");
|
||||
asan_arch_init();
|
||||
asan_initialized = TRUE;
|
||||
|
||||
} else {
|
||||
|
||||
OKF("Frida ASAN mode disabled");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
28
frida_mode/src/asan/asan_arm.c
Normal file
28
frida_mode/src/asan/asan_arm.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "asan.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__arm__)
|
||||
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(iterator);
|
||||
if (asan_initialized) {
|
||||
|
||||
FATAL("ASAN mode not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void asan_arch_init(void) {
|
||||
|
||||
FATAL("ASAN mode not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
28
frida_mode/src/asan/asan_arm64.c
Normal file
28
frida_mode/src/asan/asan_arm64.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "asan.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__aarch64__)
|
||||
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(iterator);
|
||||
if (asan_initialized) {
|
||||
|
||||
FATAL("ASAN mode not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void asan_arch_init(void) {
|
||||
|
||||
FATAL("ASAN mode not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
93
frida_mode/src/asan/asan_x64.c
Normal file
93
frida_mode/src/asan/asan_x64.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include <dlfcn.h>
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "asan.h"
|
||||
#include "ctx.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
typedef void (*asan_loadN_t)(uint64_t address, uint8_t size);
|
||||
typedef void (*asan_storeN_t)(uint64_t address, uint8_t size);
|
||||
|
||||
asan_loadN_t asan_loadN = NULL;
|
||||
asan_storeN_t asan_storeN = NULL;
|
||||
|
||||
static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(user_data);
|
||||
|
||||
cs_x86_op * operand = (cs_x86_op *)user_data;
|
||||
x86_op_mem *mem = &operand->mem;
|
||||
gsize base = 0;
|
||||
gsize index = 0;
|
||||
gsize address;
|
||||
uint8_t size;
|
||||
|
||||
if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); }
|
||||
|
||||
if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); }
|
||||
|
||||
address = base + (mem->scale * index) + mem->disp;
|
||||
size = operand->size;
|
||||
|
||||
if (operand->access == CS_AC_READ) {
|
||||
|
||||
asan_loadN(address, size);
|
||||
|
||||
} else if (operand->access == CS_AC_WRITE) {
|
||||
|
||||
asan_storeN(address, size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
|
||||
UNUSED_PARAMETER(iterator);
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
cs_x86_op * operand;
|
||||
x86_op_mem *mem;
|
||||
cs_x86_op * ctx;
|
||||
|
||||
if (!asan_initialized) return;
|
||||
|
||||
if (instr->id == X86_INS_LEA) return;
|
||||
|
||||
if (instr->id == X86_INS_NOP) return;
|
||||
|
||||
for (uint8_t i = 0; i < x86.op_count; i++) {
|
||||
|
||||
operand = &x86.operands[i];
|
||||
|
||||
if (operand->type != X86_OP_MEM) { continue; }
|
||||
|
||||
mem = &operand->mem;
|
||||
if (mem->segment != X86_REG_INVALID) { continue; }
|
||||
|
||||
ctx = g_malloc0(sizeof(cs_x86_op));
|
||||
memcpy(ctx, operand, sizeof(cs_x86_op));
|
||||
gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void asan_arch_init(void) {
|
||||
|
||||
asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN");
|
||||
asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN");
|
||||
if (asan_loadN == NULL || asan_storeN == NULL) {
|
||||
|
||||
FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
93
frida_mode/src/asan/asan_x86.c
Normal file
93
frida_mode/src/asan/asan_x86.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include <dlfcn.h>
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "asan.h"
|
||||
#include "ctx.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
typedef void (*asan_loadN_t)(gsize address, uint8_t size);
|
||||
typedef void (*asan_storeN_t)(gsize address, uint8_t size);
|
||||
|
||||
asan_loadN_t asan_loadN = NULL;
|
||||
asan_storeN_t asan_storeN = NULL;
|
||||
|
||||
static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(user_data);
|
||||
|
||||
cs_x86_op * operand = (cs_x86_op *)user_data;
|
||||
x86_op_mem *mem = &operand->mem;
|
||||
gsize base = 0;
|
||||
gsize index = 0;
|
||||
gsize address;
|
||||
uint8_t size;
|
||||
|
||||
if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); }
|
||||
|
||||
if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); }
|
||||
|
||||
address = base + (mem->scale * index) + mem->disp;
|
||||
size = operand->size;
|
||||
|
||||
if (operand->access == CS_AC_READ) {
|
||||
|
||||
asan_loadN(address, size);
|
||||
|
||||
} else if (operand->access == CS_AC_WRITE) {
|
||||
|
||||
asan_storeN(address, size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
|
||||
UNUSED_PARAMETER(iterator);
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
cs_x86_op * operand;
|
||||
x86_op_mem *mem;
|
||||
cs_x86_op * ctx;
|
||||
|
||||
if (!asan_initialized) return;
|
||||
|
||||
if (instr->id == X86_INS_LEA) return;
|
||||
|
||||
if (instr->id == X86_INS_NOP) return;
|
||||
|
||||
for (uint8_t i = 0; i < x86.op_count; i++) {
|
||||
|
||||
operand = &x86.operands[i];
|
||||
|
||||
if (operand->type != X86_OP_MEM) { continue; }
|
||||
|
||||
mem = &operand->mem;
|
||||
if (mem->segment != X86_REG_INVALID) { continue; }
|
||||
|
||||
ctx = g_malloc0(sizeof(cs_x86_op));
|
||||
memcpy(ctx, operand, sizeof(cs_x86_op));
|
||||
gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void asan_arch_init(void) {
|
||||
|
||||
asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN");
|
||||
asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN");
|
||||
if (asan_loadN == NULL || asan_storeN == NULL) {
|
||||
|
||||
FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
87
frida_mode/src/cmplog/cmplog.c
Normal file
87
frida_mode/src/cmplog/cmplog.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define DEFAULT_MMAP_MIN_ADDR (32UL << 10)
|
||||
|
||||
extern struct cmp_map *__afl_cmp_map;
|
||||
|
||||
static GArray *cmplog_ranges = NULL;
|
||||
|
||||
static gboolean cmplog_range(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(user_data);
|
||||
GumMemoryRange range = *details->range;
|
||||
g_array_append_val(cmplog_ranges, range);
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static gint cmplog_sort(gconstpointer a, gconstpointer b) {
|
||||
|
||||
return ((GumMemoryRange *)b)->base_address -
|
||||
((GumMemoryRange *)a)->base_address;
|
||||
|
||||
}
|
||||
|
||||
void cmplog_init(void) {
|
||||
|
||||
if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); }
|
||||
|
||||
cmplog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100);
|
||||
gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, NULL);
|
||||
g_array_sort(cmplog_ranges, cmplog_sort);
|
||||
|
||||
for (guint i = 0; i < cmplog_ranges->len; i++) {
|
||||
|
||||
GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i);
|
||||
OKF("CMPLOG Range - 0x%016" G_GINT64_MODIFIER "X - 0x%016" G_GINT64_MODIFIER
|
||||
"X",
|
||||
range->base_address, range->base_address + range->size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit,
|
||||
GumAddress outer_base, GumAddress outer_limit) {
|
||||
|
||||
return (inner_base >= outer_base && inner_limit <= outer_limit);
|
||||
|
||||
}
|
||||
|
||||
gboolean cmplog_is_readable(guint64 addr, size_t size) {
|
||||
|
||||
if (cmplog_ranges == NULL) FATAL("CMPLOG not initialized");
|
||||
|
||||
/*
|
||||
* The Linux kernel prevents mmap from allocating from the very bottom of the
|
||||
* address space to mitigate NULL pointer dereference attacks. The exact size
|
||||
* is set by sysctl by setting mmap_min_addr and 64k is suggested on most
|
||||
* platforms with 32k on ARM systems. We therefore fail fast if the address
|
||||
* is lower than this. This should avoid some overhead when functions are
|
||||
* called where one of the parameters is a size, or a some other small value.
|
||||
*/
|
||||
if (addr < DEFAULT_MMAP_MIN_ADDR) { return false; }
|
||||
|
||||
GumAddress inner_base = addr;
|
||||
GumAddress inner_limit = inner_base + size;
|
||||
|
||||
for (guint i = 0; i < cmplog_ranges->len; i++) {
|
||||
|
||||
GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i);
|
||||
GumAddress outer_base = range->base_address;
|
||||
GumAddress outer_limit = outer_base + range->size;
|
||||
|
||||
if (cmplog_contains(inner_base, inner_limit, outer_base, outer_limit))
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
19
frida_mode/src/cmplog/cmplog_arm.c
Normal file
19
frida_mode/src/cmplog/cmplog_arm.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "frida_cmplog.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__arm__)
|
||||
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(iterator);
|
||||
if (__afl_cmp_map == NULL) { return; }
|
||||
FATAL("CMPLOG mode not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
19
frida_mode/src/cmplog/cmplog_arm64.c
Normal file
19
frida_mode/src/cmplog/cmplog_arm64.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "frida_cmplog.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__aarch64__)
|
||||
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(iterator);
|
||||
if (__afl_cmp_map == NULL) { return; }
|
||||
FATAL("CMPLOG mode not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
272
frida_mode/src/cmplog/cmplog_x64.c
Normal file
272
frida_mode/src/cmplog/cmplog_x64.c
Normal file
@ -0,0 +1,272 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "cmplog.h"
|
||||
|
||||
#include "ctx.h"
|
||||
#include "frida_cmplog.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
typedef struct {
|
||||
|
||||
x86_op_type type;
|
||||
uint8_t size;
|
||||
|
||||
union {
|
||||
|
||||
x86_op_mem mem;
|
||||
x86_reg reg;
|
||||
int64_t imm;
|
||||
|
||||
};
|
||||
|
||||
} cmplog_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
cmplog_ctx_t operand1;
|
||||
cmplog_ctx_t operand2;
|
||||
|
||||
} cmplog_pair_ctx_t;
|
||||
|
||||
static gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size,
|
||||
x86_op_mem *mem, gsize *val) {
|
||||
|
||||
gsize base = 0;
|
||||
gsize index = 0;
|
||||
gsize address;
|
||||
|
||||
if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base);
|
||||
|
||||
if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index);
|
||||
|
||||
address = base + (index * mem->scale) + mem->disp;
|
||||
|
||||
if (!cmplog_is_readable(address, size)) { return FALSE; }
|
||||
|
||||
switch (size) {
|
||||
|
||||
case 1:
|
||||
*val = *((guint8 *)GSIZE_TO_POINTER(address));
|
||||
return TRUE;
|
||||
case 2:
|
||||
*val = *((guint16 *)GSIZE_TO_POINTER(address));
|
||||
return TRUE;
|
||||
case 4:
|
||||
*val = *((guint32 *)GSIZE_TO_POINTER(address));
|
||||
return TRUE;
|
||||
case 8:
|
||||
*val = *((guint64 *)GSIZE_TO_POINTER(address));
|
||||
return TRUE;
|
||||
default:
|
||||
FATAL("Invalid operand size: %d\n", size);
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
static gboolean cmplog_get_operand_value(GumCpuContext *context,
|
||||
cmplog_ctx_t *ctx, gsize *val) {
|
||||
|
||||
switch (ctx->type) {
|
||||
|
||||
case X86_OP_REG:
|
||||
*val = ctx_read_reg(context, ctx->reg);
|
||||
return TRUE;
|
||||
case X86_OP_IMM:
|
||||
*val = ctx->imm;
|
||||
return TRUE;
|
||||
case X86_OP_MEM:
|
||||
return cmplog_read_mem(context, ctx->size, &ctx->mem, val);
|
||||
default:
|
||||
FATAL("Invalid operand type: %d\n", ctx->type);
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(user_data);
|
||||
|
||||
gsize address = ctx_read_reg(context, X86_REG_RIP);
|
||||
gsize rdi = ctx_read_reg(context, X86_REG_RDI);
|
||||
gsize rsi = ctx_read_reg(context, X86_REG_RSI);
|
||||
|
||||
if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return;
|
||||
|
||||
if (!cmplog_is_readable(rdi, 32) || !cmplog_is_readable(rsi, 32)) return;
|
||||
|
||||
void *ptr1 = GSIZE_TO_POINTER(rdi);
|
||||
void *ptr2 = GSIZE_TO_POINTER(rsi);
|
||||
|
||||
uintptr_t k = address;
|
||||
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
|
||||
|
||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 31;
|
||||
|
||||
hits &= CMP_MAP_RTN_H - 1;
|
||||
gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, ptr1,
|
||||
32);
|
||||
gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, ptr2,
|
||||
32);
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
|
||||
cs_x86_op * operand) {
|
||||
|
||||
ctx->type = operand->type;
|
||||
ctx->size = operand->size;
|
||||
switch (operand->type) {
|
||||
|
||||
case X86_OP_REG:
|
||||
gum_memcpy(&ctx->reg, &operand->reg, sizeof(x86_reg));
|
||||
break;
|
||||
case X86_OP_IMM:
|
||||
gum_memcpy(&ctx->imm, &operand->imm, sizeof(int64_t));
|
||||
break;
|
||||
case X86_OP_MEM:
|
||||
gum_memcpy(&ctx->mem, &operand->mem, sizeof(x86_op_mem));
|
||||
break;
|
||||
default:
|
||||
FATAL("Invalid operand type: %d\n", operand->type);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_call(const cs_insn * instr,
|
||||
GumStalkerIterator *iterator) {
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
cs_x86_op *operand;
|
||||
|
||||
if (instr->id != X86_INS_CALL) return;
|
||||
|
||||
if (x86.op_count != 1) return;
|
||||
|
||||
operand = &x86.operands[0];
|
||||
|
||||
if (operand->type == X86_OP_INVALID) return;
|
||||
if (operand->type == X86_OP_MEM && operand->mem.segment != X86_REG_INVALID)
|
||||
return;
|
||||
|
||||
gum_stalker_iterator_put_callout(iterator, cmplog_call_callout, NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
|
||||
gsize operand2, uint8_t size) {
|
||||
|
||||
gsize address = ctx_read_reg(context, X86_REG_RIP);
|
||||
|
||||
register uintptr_t k = (uintptr_t)address;
|
||||
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
|
||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
||||
|
||||
__afl_cmp_map->headers[k].shape = (size - 1);
|
||||
|
||||
hits &= CMP_MAP_H - 1;
|
||||
__afl_cmp_map->log[k][hits].v0 = operand1;
|
||||
__afl_cmp_map->log[k][hits].v1 = operand2;
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
|
||||
|
||||
cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data;
|
||||
gsize operand1;
|
||||
gsize operand2;
|
||||
|
||||
if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch");
|
||||
|
||||
if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; }
|
||||
if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; }
|
||||
|
||||
cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size);
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
|
||||
cs_x86_op * operand1,
|
||||
cs_x86_op *operand2) {
|
||||
|
||||
cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
|
||||
if (ctx == NULL) return;
|
||||
|
||||
cmplog_instrument_put_operand(&ctx->operand1, operand1);
|
||||
cmplog_instrument_put_operand(&ctx->operand2, operand2);
|
||||
|
||||
gum_stalker_iterator_put_callout(iterator, cmplog_cmp_sub_callout, ctx,
|
||||
g_free);
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_cmp_sub(const cs_insn * instr,
|
||||
GumStalkerIterator *iterator) {
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
cs_x86_op *operand1;
|
||||
cs_x86_op *operand2;
|
||||
|
||||
switch (instr->id) {
|
||||
|
||||
case X86_INS_CMP:
|
||||
case X86_INS_SUB:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (x86.op_count != 2) return;
|
||||
|
||||
operand1 = &x86.operands[0];
|
||||
operand2 = &x86.operands[1];
|
||||
|
||||
if (operand1->type == X86_OP_INVALID) return;
|
||||
if (operand2->type == X86_OP_INVALID) return;
|
||||
|
||||
if ((operand1->type == X86_OP_MEM) &&
|
||||
(operand1->mem.segment != X86_REG_INVALID))
|
||||
return;
|
||||
|
||||
if ((operand2->type == X86_OP_MEM) &&
|
||||
(operand2->mem.segment != X86_REG_INVALID))
|
||||
return;
|
||||
|
||||
cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2);
|
||||
|
||||
}
|
||||
|
||||
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
|
||||
if (__afl_cmp_map == NULL) return;
|
||||
|
||||
cmplog_instrument_call(instr, iterator);
|
||||
cmplog_instrument_cmp_sub(instr, iterator);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user