mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
364 Commits
Author | SHA1 | Date | |
---|---|---|---|
3e2986dd78 | |||
1f06b55a8b | |||
7b6ee28291 | |||
94fe62ad8d | |||
608ea5f8ab | |||
00b5d3792d | |||
e9cb939956 | |||
7b6743f14c | |||
4b9c560b07 | |||
9d5a2d1b8e | |||
1e524d1f43 | |||
7c50ec5d05 | |||
7bdb22c70c | |||
3562de440e | |||
98e8838755 | |||
a2f3c3ee51 | |||
6056d4b140 | |||
d745da0c93 | |||
4fdd64d6d6 | |||
f2b7104cd6 | |||
c6af98bc35 | |||
67fabcb0be | |||
7b7914e1d6 | |||
9551be3f8e | |||
f22d28333b | |||
d8d6ea93cf | |||
0540d30274 | |||
9657b700b1 | |||
6c26434a63 | |||
42c677aa7b | |||
0373628adf | |||
d090232452 | |||
4d20b2d28b | |||
c67f98865e | |||
ca4a8c0f92 | |||
c57988e672 | |||
b847e0f414 | |||
338f1ae2f8 | |||
1f4b45b5bf | |||
30736ab7d6 | |||
46fed1f43f | |||
662662c15d | |||
d088c26045 | |||
3d2a095f2e | |||
9abae56a37 | |||
1f17aa082d | |||
c7c7476453 | |||
b883faa942 | |||
b1e0d6e640 | |||
ada61204f3 | |||
72344a2f5f | |||
0bb8cc46b4 | |||
05080f32ee | |||
32c4be4773 | |||
1759859ae2 | |||
e6f27c2645 | |||
c90dd00fc9 | |||
0da935183f | |||
4848c8d24c | |||
250000ee79 | |||
fc520a2bde | |||
6c9c8fdc65 | |||
24458ae285 | |||
36a0ab1193 | |||
1334851e7c | |||
b077a7963b | |||
3e65e1a029 | |||
e21738a248 | |||
4094750803 | |||
92352951d7 | |||
bb509765df | |||
6705953a49 | |||
b3edb657c2 | |||
a1889db9bf | |||
c83635e1d2 | |||
fd404194f2 | |||
5fa7861149 | |||
e969972c97 | |||
80e829f79d | |||
73db4fe993 | |||
22c3b519fa | |||
88077d4136 | |||
cfb0257c99 | |||
9a93688e3e | |||
48c2d51689 | |||
1dac69b1eb | |||
0da7ddb738 | |||
6e960f78d6 | |||
3282023047 | |||
c7db5b67f9 | |||
fc98d53e27 | |||
a5822c7c2f | |||
01cb84051a | |||
d9c2487c3e | |||
a7f3f87f41 | |||
1a4c0d2ecd | |||
eb37cec76e | |||
5ed993d74e | |||
5d5d1f70fc | |||
85b1ce00a8 | |||
51a88b17b3 | |||
b0e58baca2 | |||
f23cac854a | |||
0c3ba7d227 | |||
605f2bf969 | |||
dc3e2e8200 | |||
47d4f16189 | |||
74f70d0c74 | |||
be79ee7072 | |||
bf6a0159a9 | |||
fc3b483450 | |||
0dd1c39b5a | |||
60702fef7a | |||
a96f9a349a | |||
4fdd1129f0 | |||
4990823840 | |||
3d1a57deed | |||
47d8947471 | |||
80892b8fc5 | |||
ba21e20695 | |||
5b471986b8 | |||
da1b041098 | |||
95aa81045b | |||
b595727f2f | |||
d798a90f04 | |||
35d49c7c5c | |||
83f32c5248 | |||
683dcc4710 | |||
59bb4a6cc4 | |||
6afccdebcd | |||
7413316496 | |||
ad2a1b0574 | |||
942b85bb77 | |||
50c6031cc3 | |||
066d65d846 | |||
1441503c43 | |||
c96238d85f | |||
4103ee43e2 | |||
ba3c7bfe40 | |||
5ad760a77b | |||
6dfc9aaab0 | |||
ffdbe8a2fb | |||
c5083f8982 | |||
ca721404ef | |||
c563faa076 | |||
a2eb1f1412 | |||
c08eeb95ca | |||
7c755a675f | |||
4c0281adc8 | |||
022f364661 | |||
3dc72ffb6b | |||
ca361e1b6a | |||
b36d0adb46 | |||
2a4d77abc6 | |||
dfe03a346a | |||
1605291154 | |||
f180109d1a | |||
927cb770f0 | |||
82c6c8e563 | |||
79099a01f8 | |||
7c8246f18f | |||
51942b605d | |||
47dae21f4a | |||
ba12c7fc09 | |||
229a45c6a6 | |||
45219dee80 | |||
13e0fd3e1a | |||
68e8467859 | |||
293e255734 | |||
0b228fb0f5 | |||
01594dc416 | |||
46d5452c86 | |||
c7bb0a9638 | |||
ee409d18a6 | |||
5d5aa430d2 | |||
5792d492ed | |||
9ac3c53104 | |||
ee50f41d29 | |||
aeeca164b5 | |||
b2c96f66ee | |||
7f26d13345 | |||
5798c686b2 | |||
f53e6a6cf2 | |||
630eb943a5 | |||
4f42ecd815 | |||
1d00bde6c5 | |||
b1da7500b2 | |||
223c52827a | |||
e1c4a4ea7e | |||
b092ee4986 | |||
494c55df15 | |||
35cf1fa906 | |||
6e790552fe | |||
8971c9a5ce | |||
57db3e7f4f | |||
0540382c41 | |||
2263989e12 | |||
6aa470d641 | |||
0db57c3eec | |||
ce1fc4b27d | |||
5d4b0938d5 | |||
c208dcf9c5 | |||
d8317182ef | |||
e9288bcfad | |||
396de6fc9c | |||
891f4d3c8e | |||
9933a6f3ab | |||
3261e86a3a | |||
3ccebbf9c5 | |||
9c2c35b233 | |||
bf5b90f95a | |||
8385bc794a | |||
ac80678592 | |||
3c5edab724 | |||
9887f636ba | |||
fc48951468 | |||
0e9d0ebbfe | |||
84e03e4a4d | |||
044d3e823e | |||
3fc03d4b6b | |||
15b43e6ce1 | |||
d9fa6af1b1 | |||
ef5543680a | |||
881aef21fd | |||
26f3ec28ee | |||
657e4cc812 | |||
29f0bb1c6a | |||
c4363dd8b3 | |||
ff5882f415 | |||
7f56a93f5d | |||
2d7ac5f69c | |||
285a5cb38b | |||
51dbd0e957 | |||
772e33d550 | |||
77a3abfa5e | |||
a436ef47e5 | |||
b34751efbf | |||
d2ea1141eb | |||
3f0d642f9b | |||
7598efb8e6 | |||
0dca6ee038 | |||
a601b56627 | |||
ce0db35f18 | |||
d012358748 | |||
d4734f6d9b | |||
bcf123e1ee | |||
9a87e83bf4 | |||
c2ae24ab96 | |||
13c8a27faa | |||
a133aa9106 | |||
fa2b040476 | |||
69c9a176eb | |||
bdfac291ba | |||
90fd61d14a | |||
3d1be62c96 | |||
d1f59435ca | |||
1bea949f34 | |||
3c11a37757 | |||
e4f201707f | |||
59eaed2f70 | |||
1a65df2bee | |||
c08304ad3d | |||
2b8fea083e | |||
34d7a6357e | |||
ae9897ff7b | |||
d297738255 | |||
981a04eb27 | |||
2a00f32666 | |||
c2229b506e | |||
70cc32dc6d | |||
5385cc7618 | |||
2eeba2dbf0 | |||
09123d8617 | |||
713b069f40 | |||
0f7419fc91 | |||
7c9b7c0bc0 | |||
544b68044a | |||
33e43b11f8 | |||
a2d54218ad | |||
899fa59ab6 | |||
f2831419f5 | |||
d325fa5db8 | |||
7e67545b9d | |||
d84a8da1e9 | |||
f70760896c | |||
c9504867da | |||
744ad172e1 | |||
5e9286b9ea | |||
d22532d8d3 | |||
cd02f635db | |||
819a1539a6 | |||
ba7ec51232 | |||
1840c27b6f | |||
e996112fbc | |||
9b799aeddd | |||
fee1acf7e6 | |||
675d17d737 | |||
05119990b6 | |||
914eb79cbc | |||
92db443635 | |||
852c036cae | |||
a5943dc782 | |||
fc7bf33fb1 | |||
fcd06fa99c | |||
5f45f380c3 | |||
cb1256499f | |||
dd8ad4dfa3 | |||
8fc249d210 | |||
1d4f1e4879 | |||
de7058b75b | |||
5e8da2b85c | |||
056ebbff15 | |||
cf853fb249 | |||
fa628865c1 | |||
05a36f10ba | |||
cbf3d1bdee | |||
64cc345ec2 | |||
8dbc4a1423 | |||
452eb9f75b | |||
a5dc067331 | |||
27dc0e09e0 | |||
bcd802e6fd | |||
958a059477 | |||
c8bfce21ab | |||
d178b325ab | |||
077a3e32e0 | |||
fa3c0d8a37 | |||
d5b9cd4b73 | |||
ce5032cc29 | |||
04d693721b | |||
9eb66cccf4 | |||
9b72fe4880 | |||
1a89d428c9 | |||
d4c01c057b | |||
80543a809e | |||
104c0e29e9 | |||
7d36609722 | |||
119a0e0dce | |||
f336aa463b | |||
5f6bbc7dea | |||
17fc44d995 | |||
055af82026 | |||
e2f76dd41e | |||
1c79b82ab8 | |||
c38b05c80a | |||
bb186a2ece | |||
60e126c615 | |||
dd9003e59b | |||
2d9325aed9 | |||
53eb5ba2fb | |||
267dd634f1 | |||
7ab7862e4d | |||
59a7337bf1 | |||
c75124aefa | |||
2861f695ba | |||
43a7c0d601 | |||
311649f458 | |||
a5eafbff6c | |||
1d339527bb | |||
707b1701c3 | |||
b2465a05eb | |||
aa5f59b501 | |||
08c39c1552 | |||
f75535807a |
@ -19,40 +19,22 @@ import subprocess
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
||||
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use
|
||||
|
||||
with open(".clang-format") as f:
|
||||
fmt = f.read()
|
||||
|
||||
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
|
||||
if CLANG_FORMAT_BIN is None:
|
||||
o = 0
|
||||
try:
|
||||
p = subprocess.Popen(["clang-format-11", "--version"], stdout=subprocess.PIPE)
|
||||
o, _ = p.communicate()
|
||||
o = str(o, "utf-8")
|
||||
o = re.sub(r".*ersion ", "", o)
|
||||
# o = o[len("clang-format version "):].strip()
|
||||
o = o[: o.find(".")]
|
||||
o = int(o)
|
||||
except:
|
||||
print("clang-format-11 is needed. Aborted.")
|
||||
exit(1)
|
||||
# if o < 7:
|
||||
# if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-7'
|
||||
# elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-8'
|
||||
# elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-9'
|
||||
# elif subprocess.call(['which', 'clang-format-11'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-11'
|
||||
# else:
|
||||
# print ("clang-format 7 or above is needed. Aborted.")
|
||||
# exit(1)
|
||||
else:
|
||||
CLANG_FORMAT_BIN = "clang-format-11"
|
||||
CURRENT_LLVM = os.getenv('LLVM_VERSION', 14)
|
||||
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
|
||||
|
||||
if shutil.which(CLANG_FORMAT_BIN) is None:
|
||||
CLANG_FORMAT_BIN = f"clang-format-{CURRENT_LLVM}"
|
||||
|
||||
if shutil.which(CLANG_FORMAT_BIN) is None:
|
||||
print(f"[!] clang-format-{CURRENT_LLVM} is needed. Aborted.")
|
||||
exit(1)
|
||||
|
||||
COLUMN_LIMIT = 80
|
||||
for line in fmt.split("\n"):
|
||||
|
@ -1,65 +1,75 @@
|
||||
!/coresight_mode
|
||||
*.dSYM
|
||||
*.o
|
||||
*.pyc
|
||||
*.so
|
||||
.sync_tmp
|
||||
.test
|
||||
.test2
|
||||
.sync_tmp
|
||||
*.o
|
||||
*.so
|
||||
*.pyc
|
||||
*.dSYM
|
||||
as
|
||||
ld
|
||||
in
|
||||
out
|
||||
core*
|
||||
.git
|
||||
.dockerignore
|
||||
.github
|
||||
CITATION.cff
|
||||
CONTRIBUTING.md
|
||||
Changelog.md
|
||||
Dockerfile
|
||||
LICENSE
|
||||
TODO.md
|
||||
afl-analyze
|
||||
afl-as
|
||||
afl-clang
|
||||
afl-clang\+\+
|
||||
afl-clang-fast
|
||||
afl-clang-fast\+\+
|
||||
afl-clang-lto
|
||||
afl-clang-lto\+\+
|
||||
afl-fuzz
|
||||
afl-g\+\+
|
||||
afl-gcc
|
||||
afl-gcc-fast
|
||||
afl-g\+\+-fast
|
||||
afl-gotcpu
|
||||
afl-ld
|
||||
afl-ld-lto
|
||||
afl-qemu-trace
|
||||
afl-showmap
|
||||
afl-tmin
|
||||
afl-analyze.8
|
||||
afl-as
|
||||
afl-as.8
|
||||
afl-clang-fast\+\+.8
|
||||
afl-clang
|
||||
afl-clang-fast
|
||||
afl-clang-fast.8
|
||||
afl-clang-fast\+\+
|
||||
afl-clang-fast\+\+.8
|
||||
afl-clang-lto
|
||||
afl-clang-lto.8
|
||||
afl-clang-lto\+\+
|
||||
afl-clang-lto\+\+.8
|
||||
afl-clang\+\+
|
||||
afl-cmin.8
|
||||
afl-cmin.bash.8
|
||||
afl-fuzz
|
||||
afl-fuzz.8
|
||||
afl-gcc.8
|
||||
afl-gcc-fast.8
|
||||
afl-g\+\+
|
||||
afl-g\+\+-fast
|
||||
afl-g\+\+-fast.8
|
||||
afl-gcc
|
||||
afl-gcc-fast
|
||||
afl-gcc-fast.8
|
||||
afl-gcc.8
|
||||
afl-gotcpu
|
||||
afl-gotcpu.8
|
||||
afl-ld
|
||||
afl-ld-lto
|
||||
afl-plot.8
|
||||
afl-qemu-trace
|
||||
afl-showmap
|
||||
afl-showmap.8
|
||||
afl-system-config.8
|
||||
afl-tmin
|
||||
afl-tmin.8
|
||||
afl-whatsup.8
|
||||
as
|
||||
core*
|
||||
examples/afl_frida/afl-frida
|
||||
examples/afl_frida/frida-gum-example.c
|
||||
examples/afl_frida/frida-gum.h
|
||||
examples/afl_frida/libtestinstr.so
|
||||
examples/afl_network_proxy/afl-network-client
|
||||
examples/afl_network_proxy/afl-network-server
|
||||
in
|
||||
ld
|
||||
out
|
||||
qemu_mode/libcompcov/compcovtest
|
||||
qemu_mode/qemu-*
|
||||
test/unittests/unit_hash
|
||||
test/unittests/unit_list
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_rand
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
unicorn_mode/samples/*/output
|
||||
unicorn_mode/unicornafl
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_list
|
||||
test/unittests/unit_rand
|
||||
test/unittests/unit_hash
|
||||
examples/afl_network_proxy/afl-network-server
|
||||
examples/afl_network_proxy/afl-network-client
|
||||
examples/afl_frida/afl-frida
|
||||
examples/afl_frida/libtestinstr.so
|
||||
examples/afl_frida/frida-gum-example.c
|
||||
examples/afl_frida/frida-gum.h
|
25
.github/workflows/build_aflplusplus_docker.yaml
vendored
25
.github/workflows/build_aflplusplus_docker.yaml
vendored
@ -1,25 +0,0 @@
|
||||
name: Publish Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ stable ]
|
||||
# paths:
|
||||
# - Dockerfile
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
name: Push Docker images to Dockerhub
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Login to Dockerhub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
- name: Publish aflpp to Registry
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: aflplusplus/aflplusplus:latest
|
17
.github/workflows/ci.yml
vendored
17
.github/workflows/ci.yml
vendored
@ -2,21 +2,24 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ stable, dev ]
|
||||
branches:
|
||||
- stable
|
||||
- dev
|
||||
pull_request:
|
||||
branches: [ stable, dev ]
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: '${{ matrix.os }}'
|
||||
runs-on: "${{ matrix.os }}"
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04]
|
||||
os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04]
|
||||
env:
|
||||
AFL_SKIP_CPUFREQ: 1
|
||||
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: debug
|
||||
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
|
||||
- name: update
|
||||
@ -38,9 +41,9 @@ jobs:
|
||||
AFL_SKIP_CPUFREQ: 1
|
||||
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: install
|
||||
run: brew install make gcc
|
||||
run: brew install make gcc llvm
|
||||
- name: fix install
|
||||
run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v
|
||||
- name: build
|
||||
|
33
.github/workflows/code-format.yml
vendored
Normal file
33
.github/workflows/code-format.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
name: Formatting
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- stable
|
||||
- dev
|
||||
pull_request:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
jobs:
|
||||
code-format-check:
|
||||
name: Check code format
|
||||
if: ${{ 'false' == 'true' }} # Disable the job
|
||||
runs-on: ubuntu-22.04
|
||||
container: docker.io/aflplusplus/aflplusplus:dev
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Format
|
||||
run: |
|
||||
git config --global --add safe.directory /__w/AFLplusplus/AFLplusplus
|
||||
apt-get update
|
||||
apt-get install -y clang-format-${LLVM_VERSION}
|
||||
make code-format
|
||||
- name: Check if code needed formatting
|
||||
run: |
|
||||
git --no-pager -c color.ui=always diff HEAD
|
||||
if ! git diff HEAD --quiet; then
|
||||
echo "[!] Please run 'make code-format' and push its changes."
|
||||
exit 1
|
||||
fi
|
43
.github/workflows/codeql-analysis.yml
vendored
43
.github/workflows/codeql-analysis.yml
vendored
@ -2,31 +2,32 @@ name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ stable, dev ]
|
||||
branches:
|
||||
- stable
|
||||
- dev
|
||||
pull_request:
|
||||
branches: [ stable, dev ]
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
|
||||
container: # We use a previous image as it's expected to have all the dependencies
|
||||
image: docker.io/aflplusplus/aflplusplus:dev
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
- name: Fix for using external repo in container build # https://github.com/actions/checkout/issues/760
|
||||
run: git config --global --add safe.directory /__w/AFLplusplus/AFLplusplus
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: cpp, python
|
||||
- name: Build AFLplusplus # Rebuild because CodeQL needs to monitor the build process
|
||||
env:
|
||||
CC: gcc # These are symlinked to the version used in the container build
|
||||
CXX: g++
|
||||
run: make -i all # Best effort using -i
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
75
.github/workflows/container.yml
vendored
Normal file
75
.github/workflows/container.yml
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
name: Container
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- stable
|
||||
- dev
|
||||
tags:
|
||||
- "*"
|
||||
pull_request:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
jobs:
|
||||
build-and-test-amd64:
|
||||
name: Test amd64 image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Build amd64
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
tags: aflplusplus:test-amd64
|
||||
load: true
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
TEST_BUILD=1
|
||||
- name: Test amd64
|
||||
run: >
|
||||
docker run --rm aflplusplus:test-amd64 bash -c "
|
||||
apt-get update &&
|
||||
apt-get install -y libcmocka-dev &&
|
||||
make -i tests
|
||||
"
|
||||
|
||||
push:
|
||||
name: Push amd64 and arm64 images
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build-and-test-amd64
|
||||
if: ${{ github.event_name == 'push' && github.repository == 'AFLplusplus/AFLplusplus' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
with:
|
||||
platforms: arm64
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to docker.io
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
- name: Set tags to push
|
||||
id: push-tags
|
||||
run: |
|
||||
PUSH_TAGS=docker.io/aflplusplus/aflplusplus:${GITHUB_REF_NAME}
|
||||
if [ "${GITHUB_REF_NAME}" = "stable" ]; then
|
||||
PUSH_TAGS=${PUSH_TAGS},docker.io/aflplusplus/aflplusplus:latest
|
||||
fi
|
||||
export PUSH_TAGS
|
||||
echo "::set-output name=PUSH_TAGS::${PUSH_TAGS}"
|
||||
- name: Push to docker.io registry
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.push-tags.outputs.PUSH_TAGS }}
|
||||
cache-from: type=gha
|
13
.github/workflows/rust_custom_mutator.yml
vendored
13
.github/workflows/rust_custom_mutator.yml
vendored
@ -2,9 +2,12 @@ name: Rust Custom Mutators
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ stable, dev ]
|
||||
branches:
|
||||
- stable
|
||||
- dev
|
||||
pull_request:
|
||||
branches: [ stable, dev ]
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@ -15,9 +18,9 @@ jobs:
|
||||
working-directory: custom_mutators/rust
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04]
|
||||
os: [ubuntu-22.04, ubuntu-20.04]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust Toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@ -27,4 +30,4 @@ jobs:
|
||||
- name: Run General Tests
|
||||
run: cargo test
|
||||
- name: Run Tests for afl_internals feature flag
|
||||
run: cd custom_mutator && cargo test --features=afl_internals
|
||||
run: cd custom_mutator && cargo test --features=afl_internals
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -97,3 +97,4 @@ utils/persistent_mode/persistent_demo_new
|
||||
utils/persistent_mode/test-instr
|
||||
!coresight_mode
|
||||
!coresight_mode/coresight-trace
|
||||
vuln_prog
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -10,9 +10,6 @@
|
||||
[submodule "custom_mutators/gramatron/json-c"]
|
||||
path = custom_mutators/gramatron/json-c
|
||||
url = https://github.com/json-c/json-c
|
||||
[submodule "utils/optimin/EvalMaxSAT"]
|
||||
path = utils/optimin/EvalMaxSAT
|
||||
url = https://github.com/FlorentAvellaneda/EvalMaxSAT
|
||||
[submodule "coresight_mode/patchelf"]
|
||||
path = coresight_mode/patchelf
|
||||
url = https://github.com/NixOS/patchelf.git
|
||||
|
@ -76,6 +76,7 @@ cc_binary {
|
||||
srcs: [
|
||||
"src/afl-fuzz*.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-performance.c",
|
||||
|
@ -11,12 +11,12 @@ authors:
|
||||
family-names: Fioraldi
|
||||
email: andreafioraldi@gmail.com
|
||||
- given-names: Dominik
|
||||
family-names: Meier
|
||||
family-names: Maier
|
||||
email: mail@dmnk.co
|
||||
title: "AFL++"
|
||||
version: 3.14
|
||||
version: 4.00c
|
||||
type: software
|
||||
date-released: 2021-07-19
|
||||
date-released: 2022-01-26
|
||||
url: "https://github.com/AFLplusplus/AFLplusplus"
|
||||
keywords:
|
||||
- fuzzing
|
||||
|
123
Dockerfile
123
Dockerfile
@ -1,75 +1,88 @@
|
||||
#
|
||||
# This Dockerfile for AFLplusplus uses Ubuntu 20.04 focal and
|
||||
# installs LLVM 11 from llvm.org for afl-clang-lto support :-)
|
||||
# It also installs gcc/g++ 10 from the Ubuntu development platform
|
||||
# since focal has gcc-10 but not g++-10 ...
|
||||
# This Dockerfile for AFLplusplus uses Ubuntu 22.04 jammy and
|
||||
# installs LLVM 14 for afl-clang-lto support.
|
||||
#
|
||||
# GCC 11 is used instead of 12 because genhtml for afl-cov doesn't like it.
|
||||
#
|
||||
|
||||
FROM ubuntu:20.04 AS aflplusplus
|
||||
FROM ubuntu:22.04 AS aflplusplus
|
||||
LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
|
||||
LABEL "about"="AFLplusplus docker image"
|
||||
LABEL "about"="AFLplusplus container image"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
env NO_ARCH_OPT 1
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||
automake \
|
||||
cmake \
|
||||
meson \
|
||||
ninja-build \
|
||||
bison flex \
|
||||
build-essential \
|
||||
git \
|
||||
python3 python3-dev python3-setuptools python-is-python3 \
|
||||
libtool libtool-bin \
|
||||
libglib2.0-dev \
|
||||
wget vim jupp nano bash-completion less \
|
||||
apt-utils apt-transport-https ca-certificates gnupg dialog \
|
||||
libpixman-1-dev \
|
||||
gnuplot-nox \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main" >> /etc/apt/sources.list && \
|
||||
wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
|
||||
RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main" >> /etc/apt/sources.list && \
|
||||
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1E9377A2BA9EF27F
|
||||
ENV NO_ARCH_OPT=1
|
||||
ENV IS_DOCKER=1
|
||||
|
||||
RUN apt-get update && apt-get full-upgrade -y && \
|
||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||
gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gcc-multilib gdb lcov \
|
||||
clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
|
||||
libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
|
||||
libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
|
||||
liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
|
||||
libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
apt-get install -y --no-install-recommends wget ca-certificates && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 0
|
||||
RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
|
||||
ENV LLVM_VERSION=14
|
||||
ENV GCC_VERSION=11
|
||||
|
||||
ENV LLVM_CONFIG=llvm-config-12
|
||||
RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \
|
||||
wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install --no-install-recommends \
|
||||
make cmake automake meson ninja-build bison flex \
|
||||
git xz-utils bzip2 wget jupp nano bash-completion less vim joe ssh psmisc \
|
||||
python3 python3-dev python3-setuptools python-is-python3 \
|
||||
libtool libtool-bin libglib2.0-dev \
|
||||
apt-utils apt-transport-https gnupg dialog \
|
||||
gnuplot-nox libpixman-1-dev \
|
||||
gcc-${GCC_VERSION} g++-${GCC_VERSION} gcc-${GCC_VERSION}-plugin-dev gdb lcov \
|
||||
clang-${LLVM_VERSION} clang-tools-${LLVM_VERSION} libc++1-${LLVM_VERSION} \
|
||||
libc++-${LLVM_VERSION}-dev libc++abi1-${LLVM_VERSION} libc++abi-${LLVM_VERSION}-dev \
|
||||
libclang1-${LLVM_VERSION} libclang-${LLVM_VERSION}-dev \
|
||||
libclang-common-${LLVM_VERSION}-dev libclang-cpp${LLVM_VERSION} \
|
||||
libclang-cpp${LLVM_VERSION}-dev liblld-${LLVM_VERSION} \
|
||||
liblld-${LLVM_VERSION}-dev liblldb-${LLVM_VERSION} liblldb-${LLVM_VERSION}-dev \
|
||||
libllvm${LLVM_VERSION} libomp-${LLVM_VERSION}-dev libomp5-${LLVM_VERSION} \
|
||||
lld-${LLVM_VERSION} lldb-${LLVM_VERSION} llvm-${LLVM_VERSION} \
|
||||
llvm-${LLVM_VERSION}-dev llvm-${LLVM_VERSION}-runtime llvm-${LLVM_VERSION}-tools \
|
||||
$([ "$(dpkg --print-architecture)" = "amd64" ] && echo gcc-${GCC_VERSION}-multilib gcc-multilib) \
|
||||
$([ "$(dpkg --print-architecture)" = "arm64" ] && echo libcapstone-dev) && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
# gcc-multilib is only used for -m32 support on x86
|
||||
# libcapstone-dev is used for coresight_mode on arm64
|
||||
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0 && \
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} 0 && \
|
||||
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 0 && \
|
||||
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_VERSION} 0
|
||||
|
||||
RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path
|
||||
ENV PATH=$PATH:/etc/cargo/bin
|
||||
|
||||
ENV LLVM_CONFIG=llvm-config-${LLVM_VERSION}
|
||||
ENV AFL_SKIP_CPUFREQ=1
|
||||
ENV AFL_TRY_AFFINITY=1
|
||||
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
|
||||
RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov
|
||||
RUN cd /afl-cov && make install && cd ..
|
||||
RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov && \
|
||||
(cd afl-cov && make install) && rm -rf afl-cov
|
||||
|
||||
# Build currently broken
|
||||
ENV NO_CORESIGHT=1
|
||||
ENV NO_UNICORN_ARM64=1
|
||||
|
||||
COPY . /AFLplusplus
|
||||
WORKDIR /AFLplusplus
|
||||
COPY . .
|
||||
|
||||
RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \
|
||||
make distrib && make install && make clean
|
||||
ARG CC=gcc-$GCC_VERSION
|
||||
ARG CXX=g++-$GCC_VERSION
|
||||
|
||||
RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc'
|
||||
RUN echo '. /etc/bash_completion' >> ~/.bashrc
|
||||
RUN echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc
|
||||
RUN echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc
|
||||
ENV IS_DOCKER="1"
|
||||
# Used in CI to prevent a 'make clean' which would remove the binaries to be tested
|
||||
ARG TEST_BUILD
|
||||
|
||||
# Disabled until we have the container ready
|
||||
#COPY --from=aflplusplus/afl-dyninst /usr/local/lib/libdyninstAPI_RT.so /usr/local/lib/libdyninstAPI_RT.so
|
||||
#COPY --from=aflplusplus/afl-dyninst /afl-dyninst/libAflDyninst.so /usr/local/lib/libAflDyninst.so
|
||||
RUN sed -i.bak 's/^ -/ /g' GNUmakefile && \
|
||||
make clean && make distrib && \
|
||||
([ "${TEST_BUILD}" ] || (make install && make clean)) && \
|
||||
mv GNUmakefile.bak GNUmakefile
|
||||
|
||||
RUN echo "set encoding=utf-8" > /root/.vimrc && \
|
||||
echo ". /etc/bash_completion" >> ~/.bashrc && \
|
||||
echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc && \
|
||||
echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc
|
||||
|
79
GNUmakefile
79
GNUmakefile
@ -76,9 +76,9 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
|
||||
endif
|
||||
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
# SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
|
||||
#endif
|
||||
|
||||
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
# ifndef SOURCE_DATE_EPOCH
|
||||
@ -92,9 +92,13 @@ ifneq "$(SYS)" "Darwin"
|
||||
# SPECIAL_PERFORMANCE += -march=native
|
||||
#endif
|
||||
# OS X does not like _FORTIFY_SOURCE=2
|
||||
ifndef DEBUG
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
ifndef DEBUG
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
else
|
||||
# On some odd MacOS system configurations, the Xcode sdk path is not set correctly
|
||||
SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib
|
||||
LDFLAGS += $(SDK_LD)
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "SunOS"
|
||||
@ -138,12 +142,13 @@ ifdef DEBUG
|
||||
$(info Compiling DEBUG version of binaries)
|
||||
override CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror $(CFLAGS_OPT)
|
||||
else
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
CFLAGS ?= -O2 $(CFLAGS_OPT) # -funroll-loops is slower on modern compilers
|
||||
endif
|
||||
|
||||
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \
|
||||
-I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
||||
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wno-pointer-arith \
|
||||
-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
||||
# -fstack-protector
|
||||
|
||||
ifeq "$(SYS)" "FreeBSD"
|
||||
override CFLAGS += -I /usr/local/include/
|
||||
@ -167,9 +172,9 @@ endif
|
||||
|
||||
ifeq "$(SYS)" "Haiku"
|
||||
SHMAT_OK=0
|
||||
override CFLAGS += -DUSEMMAP=1 -Wno-error=format -fPIC
|
||||
override CFLAGS += -DUSEMMAP=1 -Wno-error=format
|
||||
override LDFLAGS += -Wno-deprecated-declarations -lgnu -lnetwork
|
||||
SPECIAL_PERFORMANCE += -DUSEMMAP=1
|
||||
#SPECIAL_PERFORMANCE += -DUSEMMAP=1
|
||||
endif
|
||||
|
||||
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
|
||||
@ -241,9 +246,6 @@ else
|
||||
endif
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(SYS))" ""
|
||||
ifndef DEBUG
|
||||
override CFLAGS += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
override LDFLAGS += -ldl -lrt -lm
|
||||
endif
|
||||
|
||||
@ -310,7 +312,7 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
|
||||
|
||||
.PHONY: llvm
|
||||
llvm:
|
||||
-$(MAKE) -j4 -f GNUmakefile.llvm
|
||||
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
|
||||
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
|
||||
|
||||
.PHONY: gcc_plugin
|
||||
@ -365,14 +367,18 @@ help:
|
||||
@echo Known build environment options:
|
||||
@echo "=========================================="
|
||||
@echo STATIC - compile AFL++ static
|
||||
@echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
|
||||
@echo ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
|
||||
@echo UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes
|
||||
@echo DEBUG - no optimization, -ggdb3, all warnings and -Werror
|
||||
@echo PROFILING - compile afl-fuzz with profiling information
|
||||
@echo INTROSPECTION - compile afl-fuzz with mutation introspection
|
||||
@echo NO_PYTHON - disable python support
|
||||
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
@echo NO_NYX - disable building nyx mode dependencies
|
||||
@echo "NO_CORESIGHT - disable building coresight (arm64 only)"
|
||||
@echo NO_UNICORN_ARM64 - disable building unicorn on arm64
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)"
|
||||
@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)"
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
|
||||
@ -384,7 +390,7 @@ test_x86:
|
||||
@echo "[*] Testing the PATH environment variable..."
|
||||
@test "$${PATH}" != "$${PATH#.:}" && { echo "Please remove current directory '.' from PATH to avoid recursion of 'as', thanks!"; echo; exit 1; } || :
|
||||
@echo "[*] Checking for the ability to compile x86 code..."
|
||||
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@echo 'int main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) $(LDFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@rm -f .test1
|
||||
else
|
||||
test_x86:
|
||||
@ -420,7 +426,7 @@ afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
||||
@ln -sf afl-as as
|
||||
|
||||
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
|
||||
$(CC) $(CFLAGS) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
|
||||
$(CC) $(CFLAGS) $(CFLAGS_OPT) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
|
||||
|
||||
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
||||
@ -528,7 +534,7 @@ code-format:
|
||||
ifndef AFL_NO_X86
|
||||
test_build: afl-cc afl-gcc afl-as afl-showmap
|
||||
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
|
||||
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
|
||||
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@ -564,12 +570,12 @@ all_done: test_build
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(PROGS) afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-cs-proxy afl-qemu-trace afl-gcc-fast afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM
|
||||
rm -rf $(PROGS) afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-cs-proxy afl-qemu-trace afl-gcc-fast afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM lib*.a
|
||||
-$(MAKE) -f GNUmakefile.llvm clean
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin clean
|
||||
-$(MAKE) -C utils/libdislocator clean
|
||||
-$(MAKE) -C utils/libtokencap clean
|
||||
$(MAKE) -C utils/aflpp_driver clean
|
||||
-$(MAKE) -C utils/aflpp_driver clean
|
||||
-$(MAKE) -C utils/afl_network_proxy clean
|
||||
-$(MAKE) -C utils/socket_fuzzing clean
|
||||
-$(MAKE) -C utils/argv_fuzzing clean
|
||||
@ -607,7 +613,7 @@ endif
|
||||
|
||||
.PHONY: distrib
|
||||
distrib: all
|
||||
-$(MAKE) -j4 -f GNUmakefile.llvm
|
||||
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
endif
|
||||
@ -620,13 +626,23 @@ endif
|
||||
-$(MAKE) -C frida_mode
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
ifeq "$(ARCH)" "aarch64"
|
||||
ifndef NO_CORESIGHT
|
||||
-$(MAKE) -C coresight_mode
|
||||
endif
|
||||
endif
|
||||
ifeq "$(SYS)" "Linux"
|
||||
ifndef NO_NYX
|
||||
-cd nyx_mode && ./build_nyx_support.sh
|
||||
endif
|
||||
endif
|
||||
-cd qemu_mode && sh ./build_qemu_support.sh
|
||||
ifeq "$(ARCH)" "aarch64"
|
||||
ifndef NO_UNICORN_ARM64
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
endif
|
||||
else
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: binary-only
|
||||
@ -640,18 +656,28 @@ binary-only: test_shm test_python ready $(PROGS)
|
||||
-$(MAKE) -C frida_mode
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
ifeq "$(ARCH)" "aarch64"
|
||||
ifndef NO_CORESIGHT
|
||||
-$(MAKE) -C coresight_mode
|
||||
endif
|
||||
endif
|
||||
ifeq "$(SYS)" "Linux"
|
||||
ifndef NO_NYX
|
||||
-cd nyx_mode && ./build_nyx_support.sh
|
||||
endif
|
||||
endif
|
||||
-cd qemu_mode && sh ./build_qemu_support.sh
|
||||
ifeq "$(ARCH)" "aarch64"
|
||||
ifndef NO_UNICORN_ARM64
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
endif
|
||||
else
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: source-only
|
||||
source-only: all
|
||||
-$(MAKE) -j4 -f GNUmakefile.llvm
|
||||
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
endif
|
||||
@ -659,8 +685,10 @@ endif
|
||||
-$(MAKE) -C utils/libtokencap
|
||||
# -$(MAKE) -C utils/plot_ui
|
||||
ifeq "$(SYS)" "Linux"
|
||||
ifndef NO_NYX
|
||||
-cd nyx_mode && ./build_nyx_support.sh
|
||||
endif
|
||||
endif
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@ -687,6 +715,7 @@ install: all $(MANPAGES)
|
||||
@rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
|
||||
@rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
|
||||
@for i in afl-llvm-dict2file.so afl-llvm-lto-instrumentlist.so afl-llvm-pass.so cmplog-instructions-pass.so cmplog-routines-pass.so cmplog-switches-pass.so compare-transform-pass.so libcompcov.so libdislocator.so libnyx.so libqasan.so libtokencap.so SanitizerCoverageLTO.so SanitizerCoveragePCGUARD.so split-compares-pass.so split-switches-pass.so; do echo rm -fv $${DESTDIR}$(HELPER_PATH)/$${i}; done
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
@if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
@if [ -f utils/plot_ui/afl-plot-ui ]; then install -m 755 utils/plot_ui/afl-plot-ui $${DESTDIR}$(BIN_PATH); fi
|
||||
|
@ -100,7 +100,9 @@ ifeq "$(SYS)" "SunOS"
|
||||
endif
|
||||
|
||||
|
||||
PROGS = ./afl-gcc-pass.so ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
PASSES = ./afl-gcc-pass.so ./afl-gcc-cmplog-pass.so ./afl-gcc-cmptrs-pass.so
|
||||
|
||||
PROGS = $(PASSES) ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
|
||||
.PHONY: all
|
||||
all: test_shm test_deps $(PROGS) test_build all_done
|
||||
@ -135,11 +137,13 @@ afl-common.o: ./src/afl-common.c
|
||||
|
||||
./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c
|
||||
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
|
||||
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-32.o afl-llvm-rt-32.o; else echo "failed (that's fine)"; fi
|
||||
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
|
||||
./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c
|
||||
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
|
||||
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-64.o afl-llvm-rt-64.o; else echo "failed (that's fine)"; fi
|
||||
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
|
||||
$(PASSES): instrumentation/afl-gcc-common.h
|
||||
|
||||
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
@ -148,6 +152,12 @@ afl-common.o: ./src/afl-common.c
|
||||
ln -sf afl-cc.8 afl-gcc-fast.8
|
||||
ln -sf afl-cc.8 afl-g++-fast.8
|
||||
|
||||
./afl-gcc-cmplog-pass.so: instrumentation/afl-gcc-cmplog-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
|
||||
./afl-gcc-cmptrs-pass.so: instrumentation/afl-gcc-cmptrs-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
|
||||
.PHONY: test_build
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
@ -190,6 +200,8 @@ install: all
|
||||
ln -sf afl-c++ $${DESTDIR}$(BIN_PATH)/afl-g++-fast
|
||||
ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
|
||||
install -m 755 ./afl-gcc-pass.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 755 ./afl-gcc-cmplog-pass.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 755 ./afl-gcc-cmptrs-pass.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T instrumentation/README.gcc_plugin.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
|
||||
|
||||
.PHONY: clean
|
||||
|
@ -46,7 +46,7 @@ LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's
|
||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
|
||||
LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 )
|
||||
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[4-9]' && echo 1 || echo 0 )
|
||||
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[5-9]' && echo 1 || echo 0 )
|
||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
|
||||
LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
|
||||
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
|
||||
@ -86,6 +86,12 @@ ifeq "$(LLVM_TOO_OLD)" "1"
|
||||
$(shell sleep 1)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "15"
|
||||
$(info [!] llvm_mode detected llvm 15, which is currently broken for LTO plugins.)
|
||||
LLVM_LTO = 0
|
||||
LLVM_HAVE_LTO = 0
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_HAVE_LTO)" "1"
|
||||
$(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
|
||||
LLVM_LTO = 1
|
||||
@ -93,7 +99,7 @@ ifeq "$(LLVM_HAVE_LTO)" "1"
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_LTO)" "0"
|
||||
$(info [+] llvm_mode detected llvm < 11, afl-lto LTO will not be build.)
|
||||
$(info [+] llvm_mode detected llvm < 11 or llvm 15, afl-lto LTO will not be build.)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_APPLE_XCODE)" "1"
|
||||
@ -394,7 +400,7 @@ endif
|
||||
|
||||
./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
ifeq "$(LLVM_10_OK)" "1"
|
||||
-$(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
-$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
|
||||
endif
|
||||
|
||||
./afl-llvm-lto-instrumentlist.so: instrumentation/afl-llvm-lto-instrumentlist.so.cc instrumentation/afl-llvm-common.o
|
||||
@ -407,7 +413,7 @@ ifeq "$(LLVM_LTO)" "1"
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
|
||||
endif
|
||||
|
||||
./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc
|
||||
./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc instrumentation/afl-llvm-common.o
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o
|
||||
@ -447,11 +453,11 @@ document:
|
||||
|
||||
./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c
|
||||
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
|
||||
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-32.o afl-llvm-rt-32.o; else echo "failed (that's fine)"; fi
|
||||
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
|
||||
./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c
|
||||
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
|
||||
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-64.o afl-llvm-rt-64.o; else echo "failed (that's fine)"; fi
|
||||
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
|
||||
.PHONY: test_build
|
||||
test_build: $(PROGS)
|
||||
@ -474,11 +480,11 @@ install: all
|
||||
@install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
@if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi
|
||||
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt*.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt*.o
|
||||
@if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o ;fi
|
||||
@if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
|
||||
@if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o ;fi
|
||||
@if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o ; fi
|
||||
@if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi
|
||||
@if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi
|
||||
@ -520,4 +526,4 @@ endif
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo
|
||||
rm -f $(PROGS) afl-common.o ./afl-c++ ./afl-lto ./afl-lto++ ./afl-clang-lto* ./afl-clang-fast* ./afl-clang*.8 ./ld ./afl-ld ./afl-llvm-rt*.o instrumentation/*.o
|
||||
rm -f $(PROGS) afl-common.o ./afl-c++ ./afl-lto ./afl-lto++ ./afl-clang-lto* ./afl-clang-fast* ./afl-clang*.8 ./ld ./afl-ld ./afl-compiler-rt*.o ./afl-llvm-rt*.o instrumentation/*.o
|
||||
|
19
README.md
19
README.md
@ -2,9 +2,9 @@
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/master/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250">
|
||||
|
||||
Release version: [4.00c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
Release version: [4.02c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
GitHub version: 4.00c
|
||||
GitHub version: 4.02c
|
||||
|
||||
Repository:
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
@ -50,18 +50,21 @@ Here is some information to get you started:
|
||||
## Building and installing AFL++
|
||||
|
||||
To have AFL++ easily available with everything compiled, pull the image directly
|
||||
from the Docker Hub:
|
||||
from the Docker Hub (available for both x86_64 and arm64):
|
||||
|
||||
```shell
|
||||
docker pull aflplusplus/aflplusplus
|
||||
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
|
||||
```
|
||||
|
||||
This image is automatically generated when a push to the stable repo happens
|
||||
(see [branches](#branches)). You will find your target source code in `/src` in
|
||||
the container.
|
||||
This image is automatically published when a push to the stable branch happens
|
||||
(see [branches](#branches)). If you use the command above, you will find your
|
||||
target source code in `/src` in the container.
|
||||
|
||||
To build AFL++ yourself - which we recommend - continue at
|
||||
Note: you can also pull `aflplusplus/aflplusplus:dev` which is the most current
|
||||
development state of AFL++.
|
||||
|
||||
To build AFL++ yourself - *which we recommend* - continue at
|
||||
[docs/INSTALL.md](docs/INSTALL.md).
|
||||
|
||||
## Quick start: Fuzzing with AFL++
|
||||
@ -112,7 +115,7 @@ Step-by-step quick start:
|
||||
|
||||
5. You will find found crashes and hangs in the subdirectories `crashes/` and
|
||||
`hangs/` in the `-o output_dir` directory. You can replay the crashes by
|
||||
feeding them to the target, e.g.:
|
||||
feeding them to the target, e.g. if your target is using stdin:
|
||||
|
||||
```
|
||||
cat output_dir/crashes/id:000000,* | /path/to/tested/program [...program's cmdline...]
|
||||
|
6
TODO.md
6
TODO.md
@ -2,6 +2,8 @@
|
||||
|
||||
## Should
|
||||
|
||||
- makefiles should show provide a build summary success/failure
|
||||
- better documentation for custom mutators
|
||||
- better autodetection of shifting runtime timeout values
|
||||
- Update afl->pending_not_fuzzed for MOpt
|
||||
- afl-plot to support multiple plot_data
|
||||
@ -10,6 +12,8 @@
|
||||
|
||||
## Maybe
|
||||
|
||||
- forkserver tells afl-fuzz if cmplog is supported and if so enable
|
||||
it by default, with AFL_CMPLOG_NO=1 (?) set to skip?
|
||||
- afl_custom_fuzz_splice_optin()
|
||||
- afl_custom_splice()
|
||||
- cmdline option from-to range for mutations
|
||||
@ -29,4 +33,4 @@ QEMU mode/FRIDA mode:
|
||||
using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow up
|
||||
edge numbers that both following cmp paths have been found and then disable
|
||||
working on this edge id -> cmplog_intelligence branch
|
||||
- use cmplog colorization taint result for havoc locations?
|
||||
- use cmplog colorization taint result for havoc locations?
|
||||
|
16
afl-cmin
16
afl-cmin
@ -135,6 +135,12 @@ function exists_and_is_executable(binarypath) {
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
if (0 != system( "test -t 1")) {
|
||||
redirected = 1
|
||||
} else {
|
||||
redirected = 0
|
||||
}
|
||||
|
||||
print "corpus minimization tool for afl++ (awk version)\n"
|
||||
|
||||
# defaults
|
||||
@ -217,7 +223,7 @@ BEGIN {
|
||||
for (; Optind < ARGC; Optind++) {
|
||||
prog_args[i++] = ARGV[Optind]
|
||||
if (i > 1)
|
||||
prog_args_string = prog_args_string" "ARGV[Optind]
|
||||
prog_args_string = prog_args_string" '"ARGV[Optind]"'"
|
||||
}
|
||||
|
||||
# sanity checks
|
||||
@ -463,7 +469,8 @@ BEGIN {
|
||||
while (cur < in_count) {
|
||||
fn = infilesSmallToBig[cur]
|
||||
++cur
|
||||
printf "\r Processing file "cur"/"in_count
|
||||
if (redirected == 0) { printf "\r Processing file "cur"/"in_count }
|
||||
else { print " Processing file "cur"/"in_count }
|
||||
# create path for the trace file from afl-showmap
|
||||
tracefile_path = trace_dir"/"fn
|
||||
# gather all keys, and count them
|
||||
@ -502,7 +509,9 @@ BEGIN {
|
||||
key = field[nrFields]
|
||||
|
||||
++tcnt;
|
||||
printf "\r Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..."
|
||||
if (redirected == 0) { printf "\r Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..." }
|
||||
else { print " Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..." }
|
||||
|
||||
if (key in keyAlreadyKnown) {
|
||||
continue
|
||||
}
|
||||
@ -525,7 +534,6 @@ BEGIN {
|
||||
}
|
||||
}
|
||||
close(sortedKeys)
|
||||
print ""
|
||||
print "[+] Found "tuple_count" unique tuples across "in_count" files."
|
||||
|
||||
if (out_count == 1) {
|
||||
|
@ -76,6 +76,9 @@ EOF
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "OpenBSD" ] ; then
|
||||
doas sysctl vm.malloc_conf=
|
||||
echo 'Freecheck on allocation in particular can be detrimental to performance.'
|
||||
echo 'Also we might not want necessarily to abort at any allocation failure.'
|
||||
echo 'System security features cannot be disabled on OpenBSD.'
|
||||
echo
|
||||
DONE=1
|
||||
@ -115,7 +118,7 @@ if [ "$PLATFORM" = "Darwin" ] ; then
|
||||
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist >/dev/null 2>&1
|
||||
echo
|
||||
fi
|
||||
echo It is recommended to disable System Integration Protection for increased performance.
|
||||
echo It is recommended to disable System Integrity Protection for increased performance.
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
|
@ -54,7 +54,7 @@ $(GLIBC_LDSO): | $(GLIBC_NAME).tar.xz
|
||||
$(MAKE) install
|
||||
|
||||
$(GLIBC_NAME).tar.xz:
|
||||
wget -O $@ $(GLIBC_URL_BASE)/$@
|
||||
wget -qO $@ $(GLIBC_URL_BASE)/$@
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(CS_TRACE) clean
|
||||
|
Submodule coresight_mode/patchelf updated: 7ec8edbe09...be0cc30a59
@ -352,7 +352,7 @@ uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
|
||||
* @return if the file contents was modified return 1 (True), 0 (False)
|
||||
* otherwise
|
||||
*/
|
||||
uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
uint8_t afl_custom_queue_new_entry(my_mutator_t *data,
|
||||
const uint8_t *filename_new_queue,
|
||||
const uint8_t *filename_orig_queue) {
|
||||
|
||||
|
@ -72,6 +72,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "alloc-inl.h"
|
||||
|
||||
/* Header that must be present at the beginning of every test case: */
|
||||
|
||||
@ -127,9 +128,11 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
|
||||
}
|
||||
|
||||
/* Allocate memory for new buffer, reusing previous allocation if
|
||||
possible. */
|
||||
possible. Note we have to use afl-fuzz's own realloc!
|
||||
Note that you should only do this if you need to grow the buffer,
|
||||
otherwise work with in_buf, and assign it to *out_buf instead. */
|
||||
|
||||
*out_buf = realloc(data->buf, len);
|
||||
*out_buf = afl_realloc(out_buf, len);
|
||||
|
||||
/* If we're out of memory, the most graceful thing to do is to return the
|
||||
original buffer and give up on modifying it. Let AFL handle OOM on its
|
||||
@ -142,9 +145,9 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
|
||||
|
||||
}
|
||||
|
||||
/* Copy the original data to the new location. */
|
||||
|
||||
memcpy(*out_buf, in_buf, len);
|
||||
if (len > strlen(HEADER))
|
||||
memcpy(*out_buf + strlen(HEADER), in_buf + strlen(HEADER),
|
||||
len - strlen(HEADER));
|
||||
|
||||
/* Insert the new header. */
|
||||
|
||||
|
@ -29,8 +29,8 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include "alloc-inl.h"
|
||||
|
||||
/* A macro to round an integer up to 4 kB. */
|
||||
|
||||
@ -70,9 +70,6 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
|
||||
unsigned int len,
|
||||
const unsigned char **out_buf) {
|
||||
|
||||
unsigned char *new_buf = (unsigned char *)in_buf;
|
||||
unsigned int pos = 8;
|
||||
|
||||
/* Don't do anything if there's not enough room for the PNG header
|
||||
(8 bytes). */
|
||||
|
||||
@ -83,6 +80,22 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
|
||||
|
||||
}
|
||||
|
||||
/* This is not a good way to do it, if you do not need to grow the buffer
|
||||
then just work with in_buf instead for speed reasons.
|
||||
But we want to show how to grow a buffer, so this is how it's done: */
|
||||
|
||||
unsigned int pos = 8;
|
||||
unsigned char *new_buf = afl_realloc(out_buf, UP4K(len));
|
||||
|
||||
if (!new_buf) {
|
||||
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
memcpy(new_buf, in_buf, len);
|
||||
|
||||
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
|
||||
don't have that, we can bail out. */
|
||||
|
||||
@ -111,33 +124,6 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
|
||||
|
||||
if (real_cksum != file_cksum) {
|
||||
|
||||
/* First modification? Make a copy of the input buffer. Round size
|
||||
up to 4 kB to minimize the number of reallocs needed. */
|
||||
|
||||
if (new_buf == in_buf) {
|
||||
|
||||
if (len <= data->size) {
|
||||
|
||||
new_buf = data->buf;
|
||||
|
||||
} else {
|
||||
|
||||
new_buf = realloc(data->buf, UP4K(len));
|
||||
if (!new_buf) {
|
||||
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
data->buf = new_buf;
|
||||
data->size = UP4K(len);
|
||||
memcpy(new_buf, in_buf, len);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
|
||||
|
||||
}
|
||||
|
@ -115,9 +115,9 @@ if [ $? -eq 0 ]; then
|
||||
git submodule update ./json-c 2>/dev/null # ignore errors
|
||||
else
|
||||
echo "[*] cloning json-c"
|
||||
test -d json-c || {
|
||||
test -d json-c/.git || {
|
||||
CNT=1
|
||||
while [ '!' -d json-c -a "$CNT" -lt 4 ]; do
|
||||
while [ '!' -d json-c/.git -a "$CNT" -lt 4 ]; do
|
||||
echo "Trying to clone json-c (attempt $CNT/3)"
|
||||
git clone "$JSONC_REPO"
|
||||
CNT=`expr "$CNT" + 1`
|
||||
@ -125,7 +125,7 @@ else
|
||||
}
|
||||
fi
|
||||
|
||||
test -d json-c || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||
test -d json-c/.git || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||
echo "[+] Got json-c."
|
||||
|
||||
test -e json-c/.libs/libjson-c.a || {
|
||||
|
Submodule custom_mutators/gramatron/json-c updated: af8dd4a307...11546bfd07
@ -1 +1 @@
|
||||
cbe5e32
|
||||
ff4e5a2
|
||||
|
@ -109,9 +109,9 @@ if [ $? -eq 0 ]; then
|
||||
git submodule update ./grammar_mutator 2>/dev/null # ignore errors
|
||||
else
|
||||
echo "[*] cloning grammar mutator"
|
||||
test -d grammar_mutator || {
|
||||
test -d grammar_mutator/.git || {
|
||||
CNT=1
|
||||
while [ '!' -d grammar_mutator -a "$CNT" -lt 4 ]; do
|
||||
while [ '!' -d grammar_mutator/.git -a "$CNT" -lt 4 ]; do
|
||||
echo "Trying to clone grammar_mutator (attempt $CNT/3)"
|
||||
git clone "$GRAMMAR_REPO"
|
||||
CNT=`expr "$CNT" + 1`
|
||||
@ -119,15 +119,16 @@ else
|
||||
}
|
||||
fi
|
||||
|
||||
test -d grammar_mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||
test -f grammar_mutator/.git || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||
echo "[+] Got grammar mutator."
|
||||
|
||||
cd "grammar_mutator" || exit 1
|
||||
echo "[*] Checking out $GRAMMAR_VERSION"
|
||||
git pull >/dev/null 2>&1
|
||||
sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
|
||||
git checkout "$GRAMMAR_VERSION" || exit 1
|
||||
echo "[*] Downloading antlr..."
|
||||
wget -c https://www.antlr.org/download/antlr-4.8-complete.jar
|
||||
wget -q https://www.antlr.org/download/antlr-4.8-complete.jar
|
||||
cd ..
|
||||
|
||||
echo
|
||||
|
Submodule custom_mutators/grammar_mutator/grammar_mutator updated: cbe5e32752...ff4e5a265d
10
custom_mutators/libafl_base/.gitignore
vendored
Normal file
10
custom_mutators/libafl_base/.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
|
14
custom_mutators/libafl_base/Cargo.toml
Normal file
14
custom_mutators/libafl_base/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "libafl_base"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "62614ce1016c86e3f00f35b56399292ceabd486b" }
|
||||
custom_mutator = { path = "../rust/custom_mutator", features = ["afl_internals"] }
|
||||
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
9
custom_mutators/libafl_base/Makefile
Normal file
9
custom_mutators/libafl_base/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
all: target/release/liblibafl_base.so
|
||||
cp target/release/liblibafl_base.so libafl_base.so
|
||||
|
||||
target/release/liblibafl_base.so: src/lib.rs
|
||||
cargo build --release
|
||||
|
||||
clean:
|
||||
cargo clean
|
||||
rm -f libafl_base.so
|
11
custom_mutators/libafl_base/README.md
Normal file
11
custom_mutators/libafl_base/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# libafl basic havoc + token mutator
|
||||
|
||||
This uses the [libafl](https://github.com/AFLplusplus/libafl) StdScheduledMutator with `havoc_mutations` and `token_mutations`.
|
||||
|
||||
Make sure to have [cargo installed](https://rustup.rs/) and just type `make` to build.
|
||||
|
||||
Run with:
|
||||
|
||||
```
|
||||
AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/libafl_base/libafl_base.so AFL_CUSTOM_MUTATOR_ONLY=1 afl-fuzz ...
|
||||
```
|
238
custom_mutators/libafl_base/src/lib.rs
Normal file
238
custom_mutators/libafl_base/src/lib.rs
Normal file
@ -0,0 +1,238 @@
|
||||
#![cfg(unix)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::{
|
||||
cell::{RefCell, UnsafeCell},
|
||||
collections::HashMap,
|
||||
ffi::CStr,
|
||||
};
|
||||
|
||||
use custom_mutator::{afl_state, export_mutator, CustomMutator};
|
||||
|
||||
use libafl::{
|
||||
bolts::{rands::StdRand, serdeany::SerdeAnyMap, tuples::Merge},
|
||||
corpus::{Corpus, Testcase},
|
||||
inputs::{BytesInput, HasBytesVec},
|
||||
mutators::{
|
||||
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
|
||||
Mutator,
|
||||
},
|
||||
state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State},
|
||||
Error,
|
||||
};
|
||||
|
||||
const MAX_FILE: usize = 1 * 1024 * 1024;
|
||||
|
||||
static mut AFL: Option<&'static afl_state> = None;
|
||||
static mut CURRENT_ENTRY: Option<usize> = None;
|
||||
|
||||
fn afl() -> &'static afl_state {
|
||||
unsafe { AFL.unwrap() }
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct AFLCorpus {
|
||||
entries: UnsafeCell<HashMap<usize, RefCell<Testcase<BytesInput>>>>,
|
||||
}
|
||||
|
||||
impl Clone for AFLCorpus {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
Self {
|
||||
entries: UnsafeCell::new(self.entries.get().as_ref().unwrap().clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for AFLCorpus {
|
||||
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for AFLCorpus {
|
||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl Corpus<BytesInput> for AFLCorpus {
|
||||
#[inline]
|
||||
fn count(&self) -> usize {
|
||||
afl().queued_items as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<BytesInput>>, Error> {
|
||||
unsafe {
|
||||
let entries = self.entries.get().as_mut().unwrap();
|
||||
entries.entry(idx).or_insert_with(|| {
|
||||
let queue_buf = std::slice::from_raw_parts_mut(afl().queue_buf, self.count());
|
||||
let entry = queue_buf[idx].as_mut().unwrap();
|
||||
let fname = CStr::from_ptr((entry.fname as *mut i8).as_ref().unwrap())
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
let mut testcase = Testcase::with_filename(BytesInput::new(vec![]), fname);
|
||||
*testcase.input_mut() = None;
|
||||
RefCell::new(testcase)
|
||||
});
|
||||
Ok(&self.entries.get().as_ref().unwrap()[&idx])
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn current(&self) -> &Option<usize> {
|
||||
unsafe {
|
||||
CURRENT_ENTRY = Some(afl().current_entry as usize);
|
||||
&CURRENT_ENTRY
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn current_mut(&mut self) -> &mut Option<usize> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct AFLState {
|
||||
rand: StdRand,
|
||||
corpus: AFLCorpus,
|
||||
metadata: SerdeAnyMap,
|
||||
max_size: usize,
|
||||
}
|
||||
|
||||
impl AFLState {
|
||||
pub fn new(seed: u32) -> Self {
|
||||
Self {
|
||||
rand: StdRand::with_seed(seed as u64),
|
||||
corpus: AFLCorpus::default(),
|
||||
metadata: SerdeAnyMap::new(),
|
||||
max_size: MAX_FILE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl State for AFLState {}
|
||||
|
||||
impl HasRand for AFLState {
|
||||
type Rand = StdRand;
|
||||
|
||||
#[inline]
|
||||
fn rand(&self) -> &Self::Rand {
|
||||
&self.rand
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rand_mut(&mut self) -> &mut Self::Rand {
|
||||
&mut self.rand
|
||||
}
|
||||
}
|
||||
|
||||
impl HasCorpus<BytesInput> for AFLState {
|
||||
type Corpus = AFLCorpus;
|
||||
|
||||
#[inline]
|
||||
fn corpus(&self) -> &Self::Corpus {
|
||||
&self.corpus
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn corpus_mut(&mut self) -> &mut Self::Corpus {
|
||||
&mut self.corpus
|
||||
}
|
||||
}
|
||||
|
||||
impl HasMetadata for AFLState {
|
||||
#[inline]
|
||||
fn metadata(&self) -> &SerdeAnyMap {
|
||||
&self.metadata
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn metadata_mut(&mut self) -> &mut SerdeAnyMap {
|
||||
&mut self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
impl HasMaxSize for AFLState {
|
||||
fn max_size(&self) -> usize {
|
||||
self.max_size
|
||||
}
|
||||
|
||||
fn set_max_size(&mut self, max_size: usize) {
|
||||
self.max_size = max_size;
|
||||
}
|
||||
}
|
||||
|
||||
struct LibAFLBaseCustomMutator {
|
||||
state: AFLState,
|
||||
input: BytesInput,
|
||||
}
|
||||
|
||||
impl CustomMutator for LibAFLBaseCustomMutator {
|
||||
type Error = libafl::Error;
|
||||
|
||||
fn init(afl: &'static afl_state, seed: u32) -> Result<Self, Self::Error> {
|
||||
unsafe {
|
||||
AFL = Some(afl);
|
||||
let mut state = AFLState::new(seed);
|
||||
let extras = std::slice::from_raw_parts(afl.extras, afl.extras_cnt as usize);
|
||||
let mut tokens = vec![];
|
||||
for extra in extras {
|
||||
let data = std::slice::from_raw_parts(extra.data, extra.len as usize);
|
||||
tokens.push(data.to_vec());
|
||||
}
|
||||
if !tokens.is_empty() {
|
||||
state.add_metadata(Tokens::new(tokens));
|
||||
}
|
||||
Ok(Self {
|
||||
state,
|
||||
input: BytesInput::new(vec![]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Result<Option<&'b [u8]>, Self::Error> {
|
||||
self.state.set_max_size(max_size);
|
||||
|
||||
// TODO avoid copy
|
||||
self.input.bytes_mut().clear();
|
||||
self.input.bytes_mut().extend_from_slice(buffer);
|
||||
|
||||
let mut mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||
mutator.mutate(&mut self.state, &mut self.input, 0)?;
|
||||
Ok(Some(self.input.bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
export_mutator!(LibAFLBaseCustomMutator);
|
@ -358,6 +358,36 @@ pub mod wrappers {
|
||||
}
|
||||
}
|
||||
|
||||
/// An exported macro to defined afl_custom_init meant for insternal usage
|
||||
#[cfg(feature = "afl_internals")]
|
||||
#[macro_export]
|
||||
macro_rules! _define_afl_custom_init {
|
||||
($mutator_type:ty) => {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_init(
|
||||
afl: ::std::option::Option<&'static $crate::afl_state>,
|
||||
seed: ::std::os::raw::c_uint,
|
||||
) -> *const ::std::os::raw::c_void {
|
||||
$crate::wrappers::afl_custom_init_::<$mutator_type>(afl, seed as u32)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// An exported macro to defined afl_custom_init meant for insternal usage
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
#[macro_export]
|
||||
macro_rules! _define_afl_custom_init {
|
||||
($mutator_type:ty) => {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_init(
|
||||
_afl: *const ::std::os::raw::c_void,
|
||||
seed: ::std::os::raw::c_uint,
|
||||
) -> *const ::std::os::raw::c_void {
|
||||
$crate::wrappers::afl_custom_init_::<$mutator_type>(seed as u32)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// exports the given Mutator as a custom mutator as the C interface that AFL++ expects.
|
||||
/// It is not possible to call this macro multiple times, because it would define the custom mutator symbols multiple times.
|
||||
/// # Example
|
||||
@ -381,23 +411,7 @@ pub mod wrappers {
|
||||
#[macro_export]
|
||||
macro_rules! export_mutator {
|
||||
($mutator_type:ty) => {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_init(
|
||||
afl: ::std::option::Option<&'static $crate::afl_state>,
|
||||
seed: ::std::os::raw::c_uint,
|
||||
) -> *const ::std::os::raw::c_void {
|
||||
$crate::wrappers::afl_custom_init_::<$mutator_type>(afl, seed as u32)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_init(
|
||||
_afl: *const ::std::os::raw::c_void,
|
||||
seed: ::std::os::raw::c_uint,
|
||||
) -> *const ::std::os::raw::c_void {
|
||||
$crate::wrappers::afl_custom_init_::<$mutator_type>(seed as u32)
|
||||
}
|
||||
$crate::_define_afl_custom_init!($mutator_type);
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn afl_custom_fuzz_count(
|
||||
|
@ -1,6 +1,9 @@
|
||||
# custum mutator: symcc
|
||||
|
||||
This uses the excellent symcc to find new paths into the target.
|
||||
This uses the symcc to find new paths into the target.
|
||||
|
||||
Note that this is a just a proof of concept example! It is better to use
|
||||
the fuzzing helpers of symcc, symqemu, Fuzzolic, etc. rather than this.
|
||||
|
||||
To use this custom mutator follow the steps in the symcc repository
|
||||
[https://github.com/eurecom-s3/symcc/](https://github.com/eurecom-s3/symcc/)
|
||||
|
@ -8,6 +8,62 @@
|
||||
Want to stay in the loop on major new features? Join our mailing list by
|
||||
sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
|
||||
### Version ++4.02c (release)
|
||||
- afl-cc:
|
||||
- important fix for the default pcguard mode when LLVM IR vector
|
||||
selects are produced, thanks to @juppytt for reporting!
|
||||
- gcc_plugin:
|
||||
- Adacore submitted CMPLOG support to the gcc_plugin! :-)
|
||||
- llvm_mode:
|
||||
- laf cmp splitting fixed for more comparison types
|
||||
- frida_mode:
|
||||
- now works on Android!
|
||||
- afl-fuzz:
|
||||
- change post_process hook to allow returning NULL and 0 length to
|
||||
tell afl-fuzz to skip this mutated input
|
||||
|
||||
|
||||
### Version ++4.01c (release)
|
||||
- fixed */build_...sh scripts to work outside of git
|
||||
- new custom_mutator: libafl with token fuzzing :)
|
||||
- afl-fuzz:
|
||||
- when you just want to compile once and set CMPLOG, then just
|
||||
set -c 0 to tell afl-fuzz that the fuzzing binary is also for
|
||||
CMPLOG.
|
||||
- new commandline options -g/G to set min/max length of generated
|
||||
fuzz inputs
|
||||
- you can set the time for syncing to other fuzzer now with
|
||||
AFL_SYNC_TIME
|
||||
- reintroduced AFL_PERSISTENT and AFL_DEFER_FORKSRV to allow
|
||||
persistent mode and manual forkserver support if these are not
|
||||
in the target binary (e.g. are in a shared library)
|
||||
- add AFL_EARLY_FORKSERVER to install the forkserver as earliest as
|
||||
possible in the target (for afl-gcc-fast/afl-clang-fast/
|
||||
afl-clang-lto)
|
||||
- "saved timeouts" was wrong information, timeouts are still thrown
|
||||
away by default even if they have new coverage (hangs are always
|
||||
kept), unless AFL_KEEP_TIMEOUTS are set
|
||||
- AFL never implemented auto token inserts (but user token inserts,
|
||||
user token overwrite and auto token overwrite), added now!
|
||||
- fixed a mutation type in havoc mode
|
||||
- Mopt fix to always select the correct algorithm
|
||||
- fix effector map calculation (deterministic mode)
|
||||
- fix custom mutator post_process functionality
|
||||
- document and auto-activate pizza mode on condition
|
||||
- afl-cc:
|
||||
- due a bug in lld of llvm 15 LTO instrumentation wont work atm :-(
|
||||
- converted all passed to use the new llvm pass manager for llvm 11+
|
||||
- AFL++ PCGUARD mode is not available for 10.0.1 anymore (11+ only)
|
||||
- trying to stay on top on all these #$&§!! changes in llvm 15 ...
|
||||
- frida_mode:
|
||||
- update to new frida release, handles now c++ throw/catch
|
||||
- unicorn_mode:
|
||||
- update unicorn engine, fix C example
|
||||
- utils:
|
||||
- removed optimin because it looses coverage due to a bug and is
|
||||
unmaintained :-(
|
||||
|
||||
|
||||
### Version ++4.00c (release)
|
||||
- complete documentation restructuring, made possible by Google Season
|
||||
of Docs :) thank you Jana!
|
||||
@ -53,7 +109,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
- fix bug where targets are not killed on timeouts
|
||||
- moved hidden afl-showmap -A option to -H to be used for
|
||||
coresight_mode
|
||||
- Prevent accidentaly killing non-afl/fuzz services when aborting
|
||||
- Prevent accidentally killing non-afl/fuzz services when aborting
|
||||
afl-showmap and other tools.
|
||||
- afl-cc:
|
||||
- detect overflow reads on initial input buffer for asan
|
||||
|
@ -3,26 +3,33 @@
|
||||
## Linux on x86
|
||||
|
||||
An easy way to install AFL++ with everything compiled is available via docker:
|
||||
You can use the [Dockerfile](../Dockerfile) (which has gcc-10 and clang-11 -
|
||||
hence afl-clang-lto is available!) or just pull directly from the Docker Hub:
|
||||
You can use the [Dockerfile](../Dockerfile) (which has gcc-10 and clang-12 -
|
||||
hence afl-clang-lto is available) or just pull directly from the Docker Hub
|
||||
(for x86_64 and arm64):
|
||||
|
||||
```shell
|
||||
docker pull aflplusplus/aflplusplus
|
||||
docker pull aflplusplus/aflplusplus:
|
||||
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
|
||||
```
|
||||
|
||||
This image is automatically generated when a push to the stable repo happens.
|
||||
This image is automatically generated when a push to the stable branch happens.
|
||||
You will find your target source code in `/src` in the container.
|
||||
|
||||
Note: you can also pull `aflplusplus/aflplusplus:dev` which is the most current
|
||||
development state of AFL++.
|
||||
|
||||
If you want to build AFL++ yourself, you have many options. The easiest choice
|
||||
is to build and install everything:
|
||||
|
||||
NOTE: depending on your Debian/Ubuntu/Kali/... version release `-12` with
|
||||
whatever llvm version is available!
|
||||
|
||||
```shell
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential python3-dev automake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools
|
||||
# try to install llvm 11 and install the distro default if that fails
|
||||
sudo apt-get install -y lld-11 llvm-11 llvm-11-dev clang-11 || sudo apt-get install -y lld llvm llvm-dev clang
|
||||
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-dev
|
||||
sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools cargo libgtk-3-dev
|
||||
# try to install llvm 12 and install the distro default if that fails
|
||||
sudo apt-get install -y lld-12 llvm-12 llvm-12-dev clang-12 || sudo apt-get install -y lld llvm llvm-dev clang
|
||||
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev
|
||||
sudo apt-get install -y ninja-build # for QEMU mode
|
||||
git clone https://github.com/AFLplusplus/AFLplusplus
|
||||
cd AFLplusplus
|
||||
@ -72,18 +79,23 @@ make STATIC=1
|
||||
These build options exist:
|
||||
|
||||
* STATIC - compile AFL++ static
|
||||
* ASAN_BUILD - compiles with memory sanitizer for debug purposes
|
||||
* ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
|
||||
* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for
|
||||
debug purposes
|
||||
* DEBUG - no optimization, -ggdb3, all warnings and -Werror
|
||||
* PROFILING - compile with profiling information (gprof)
|
||||
* PROFILING - compile afl-fuzz with profiling information
|
||||
* INTROSPECTION - compile afl-fuzz with mutation introspection
|
||||
* NO_PYTHON - disable python support
|
||||
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for
|
||||
normal fuzzing
|
||||
* NO_NYX - disable building nyx mode dependencies
|
||||
* NO_CORESIGHT - disable building coresight (arm64 only)
|
||||
* NO_UNICORN_ARM64 - disable building unicorn on arm64
|
||||
* AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config
|
||||
(e.g., Debian)
|
||||
|
||||
e.g.: `make ASAN_BUILD=1`
|
||||
e.g.: `make LLVM_CONFIG=llvm-config-14`
|
||||
|
||||
## MacOS X on x86 and arm64 (M1)
|
||||
|
||||
@ -140,7 +152,7 @@ and definitely don't look POSIX-compliant. This means two things:
|
||||
environment before starting afl-fuzz.
|
||||
|
||||
User emulation mode of QEMU does not appear to be supported on MacOS X, so
|
||||
black-box instrumentation mode (`-Q`) will not work. However, Frida mode (`-O`)
|
||||
black-box instrumentation mode (`-Q`) will not work. However, FRIDA mode (`-O`)
|
||||
works on both x86 and arm64 MacOS boxes.
|
||||
|
||||
MacOS X supports SYSV shared memory used by AFL's instrumentation, but the
|
||||
|
@ -38,6 +38,11 @@ performed with the custom mutator.
|
||||
|
||||
## 2) APIs
|
||||
|
||||
**IMPORTANT NOTE**: If you use our C/C++ API and you want to increase the size
|
||||
of an **out_buf buffer, you have to use `afl_realloc()` for this, so include
|
||||
`include/alloc-inl.h` - otherwise afl-fuzz will crash when trying to free
|
||||
your buffers.
|
||||
|
||||
C/C++:
|
||||
|
||||
```c
|
||||
@ -159,6 +164,10 @@ def deinit(): # optional for Python
|
||||
This can return any python object that implements the buffer protocol and
|
||||
supports PyBUF_SIMPLE. These include bytes, bytearray, etc.
|
||||
|
||||
You can decide in the post_process mutator to not send the mutated data
|
||||
to the target, e.g. if it is too short, too corrupted, etc. If so,
|
||||
return a NULL buffer and zero length (or a 0 length string in Python).
|
||||
|
||||
- `queue_new_entry` (optional):
|
||||
|
||||
This methods is called after adding a new test case to the queue. If the
|
||||
|
@ -160,6 +160,8 @@ Available options:
|
||||
Setting `AFL_LLVM_CMPLOG=1` during compilation will tell afl-clang-fast to
|
||||
produce a CmpLog binary.
|
||||
|
||||
For afl-gcc-fast, set `AFL_GCC_CMPLOG=1` instead.
|
||||
|
||||
For more information, see
|
||||
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
|
||||
|
||||
@ -349,6 +351,9 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
- Setting `AFL_DISABLE_TRIM` tells afl-fuzz not to trim test cases. This is
|
||||
usually a bad idea!
|
||||
|
||||
- Setting `AFL_KEEP_TIMEOUTS` will keep longer running inputs if they reach
|
||||
new coverage
|
||||
|
||||
- `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behavior which
|
||||
does not allow crashes or timeout seeds in the initial -i corpus.
|
||||
|
||||
@ -400,6 +405,10 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
This makes the "own finds" counter in the UI more accurate. Beyond counter
|
||||
aesthetics, not much else should change.
|
||||
|
||||
- Setting `AFL_INPUT_LEN_MIN` and `AFL_INPUT_LEN_MAX` are an alternative to
|
||||
the afl-fuzz -g/-G command line option to control the minimum/maximum
|
||||
of fuzzing input generated.
|
||||
|
||||
- `AFL_KILL_SIGNAL`: Set the signal ID to be delivered to child processes on
|
||||
timeout. Unless you implement your own targets or instrumentation, you
|
||||
likely don't have to set it. By default, on timeout and on exit, `SIGKILL`
|
||||
@ -453,7 +462,7 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
some basic stats. This behavior is also automatically triggered when the
|
||||
output from afl-fuzz is redirected to a file or to a pipe.
|
||||
|
||||
- In QEMU mode (-Q) and Frida mode (-O), `AFL_PATH` will be searched for
|
||||
- In QEMU mode (-Q) and FRIDA mode (-O), `AFL_PATH` will be searched for
|
||||
afl-qemu-trace and afl-frida-trace.so.
|
||||
|
||||
- If you are using persistent mode (you should, see
|
||||
@ -510,11 +519,20 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
(empty/non present) will add no tags to the metrics. For more information,
|
||||
see [rpc_statsd.md](rpc_statsd.md).
|
||||
|
||||
- `AFL_SYNC_TIME` allows you to specify a different minimal time (in minutes)
|
||||
between fuzzing instances synchronization. Default sync time is 30 minutes,
|
||||
note that time is halved for -M main nodes.
|
||||
|
||||
- Setting `AFL_TARGET_ENV` causes AFL++ to set extra environment variables for
|
||||
the target binary. Example: `AFL_TARGET_ENV="VAR1=1 VAR2='a b c'" afl-fuzz
|
||||
... `. This exists mostly for things like `LD_LIBRARY_PATH` but it would
|
||||
theoretically allow fuzzing of AFL++ itself (with 'target' AFL++ using some
|
||||
AFL_ vars that would disrupt work of 'fuzzer' AFL++).
|
||||
AFL_ vars that would disrupt work of 'fuzzer' AFL++). Note that when using
|
||||
QEMU mode, the `AFL_TARGET_ENV` environment variables will apply to QEMU, as
|
||||
well as the target binary. Therefore, in this case, you might want to use
|
||||
QEMU's `QEMU_SET_ENV` environment variable (see QEMU's documentation because
|
||||
the format is different from `AFL_TARGET_ENV`) to apply the environment
|
||||
variables to the target and not QEMU.
|
||||
|
||||
- `AFL_TESTCACHE_SIZE` allows you to override the size of `#define
|
||||
TESTCASE_CACHE` in config.h. Recommended values are 50-250MB - or more if
|
||||
@ -528,9 +546,20 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
- Setting `AFL_TRY_AFFINITY` tries to attempt binding to a specific CPU core
|
||||
on Linux systems, but will not terminate if that fails.
|
||||
|
||||
- Outdated environment variables that are not supported anymore:
|
||||
- `AFL_DEFER_FORKSRV`
|
||||
- `AFL_PERSISTENT`
|
||||
- The following environment variables are only needed if you implemented
|
||||
your own forkserver or persistent mode, or if __AFL_LOOP or __AFL_INIT
|
||||
are in a shared library and not the main binary:
|
||||
- `AFL_DEFER_FORKSRV` enforces a deferred forkserver even if none was
|
||||
detected in the target binary
|
||||
- `AFL_PERSISTENT` enforces persistent mode even if none was detected
|
||||
in the target binary
|
||||
|
||||
- If you need an early forkserver in your target because of early
|
||||
constructors in your target, you can set `AFL_EARLY_FORKSERVER`.
|
||||
Note that this is not a compile time option but a runtime option :-)
|
||||
|
||||
- Set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to 0
|
||||
to disable although it is 1st of April.
|
||||
|
||||
## 5) Settings for afl-qemu-trace
|
||||
|
||||
@ -592,6 +621,10 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
emulation" variables (e.g., `QEMU_STACK_SIZE`), but there should be no
|
||||
reason to touch them.
|
||||
|
||||
- Normally a `README.txt` is written to the `crashes/` directory when a first
|
||||
crash is found. Setting `AFL_NO_CRASH_README` will prevent this. Useful when
|
||||
counting crashes based on a file count in that directory.
|
||||
|
||||
## 7) Settings for afl-frida-trace
|
||||
|
||||
The FRIDA wrapper used to instrument binary-only code supports many of the same
|
||||
|
@ -12,7 +12,7 @@ QEMU 5.1 with laf-intel and Redqueen, FRIDA mode, unicorn mode, gcc plugin, full
|
||||
| NeverZero [B] | x86[_64] | x(1) | x | x | x | x | | |
|
||||
| Persistent Mode [C] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | |
|
||||
| LAF-Intel / CompCov [D] | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | |
|
||||
| CmpLog [E] | | x | | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
|
||||
| CmpLog [E] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
|
||||
| Selective Instrumentation [F] | | x | x | x | x | | | |
|
||||
| Non-Colliding Coverage [G] | | x(4) | | | (x)(5) | | | |
|
||||
| Ngram prev_loc Coverage [H] | | x(6) | | | | | | |
|
||||
|
@ -48,11 +48,12 @@ The following setup to use QEMU mode is recommended:
|
||||
|
||||
Then run as many instances as you have cores left with either -Q mode or - even
|
||||
better - use a binary rewriter like Dyninst, RetroWrite, ZAFL, etc.
|
||||
The binary rewriters all have their own advantages and caveats.
|
||||
ZAFL is the best but cannot be used in a business/commercial context.
|
||||
|
||||
If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for your
|
||||
binary, then you can use afl-fuzz normally and it will have twice the speed
|
||||
compared to QEMU mode (but slower than QEMU persistent mode). Note that several
|
||||
other binary rewriters exist, all with their advantages and caveats.
|
||||
If a binary rewriter works for your target then you can use afl-fuzz normally
|
||||
and it will have twice the speed compared to QEMU mode (but slower than QEMU
|
||||
persistent mode).
|
||||
|
||||
The speed decrease of QEMU mode is at about 50%. However, various options exist
|
||||
to increase the speed:
|
||||
|
@ -333,6 +333,27 @@ is a non-standard way to set this, otherwise set up the build normally and edit
|
||||
the generated build environment afterwards manually to point it to the right
|
||||
compiler (and/or `RANLIB` and `AR`).
|
||||
|
||||
In complex, weird, alien build systems you can try this neat project:
|
||||
[https://github.com/fuzzah/exeptor](https://github.com/fuzzah/exeptor)
|
||||
|
||||
#### Linker scripts
|
||||
|
||||
If the project uses linker scripts to hide the symbols exported by the
|
||||
binary, then you may see errors such as:
|
||||
|
||||
```
|
||||
undefined symbol: __afl_area_ptr
|
||||
```
|
||||
|
||||
The solution is to modify the linker script to add:
|
||||
|
||||
```
|
||||
{
|
||||
global:
|
||||
__afl_*;
|
||||
}
|
||||
```
|
||||
|
||||
### f) Better instrumentation
|
||||
|
||||
If you just fuzz a target program as-is, you are wasting a great opportunity for
|
||||
@ -817,9 +838,10 @@ Here are some of the most important caveats for AFL++:
|
||||
|
||||
- There is no direct support for fuzzing network services, background daemons,
|
||||
or interactive apps that require UI interaction to work. You may need to make
|
||||
simple code changes to make them behave in a more traditional way. Preeny may
|
||||
offer a relatively simple option, too - see:
|
||||
[https://github.com/zardus/preeny](https://github.com/zardus/preeny)
|
||||
simple code changes to make them behave in a more traditional way. Preeny or
|
||||
libdesock may offer a relatively simple option, too - see:
|
||||
[https://github.com/zardus/preeny](https://github.com/zardus/preeny) or
|
||||
[https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
|
||||
|
||||
Some useful tips for modifying network-based services can be also found at:
|
||||
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
|
||||
@ -893,16 +915,17 @@ normal fuzzing campaigns as these are much shorter runnings.
|
||||
* Keep the generated corpus, use afl-cmin and reuse it every time!
|
||||
|
||||
2. Additionally randomize the AFL++ compilation options, e.g.:
|
||||
* 40% for `AFL_LLVM_CMPLOG`
|
||||
* 10% for `AFL_LLVM_LAF_ALL`
|
||||
* 30% for `AFL_LLVM_CMPLOG`
|
||||
* 5% for `AFL_LLVM_LAF_ALL`
|
||||
|
||||
3. Also randomize the afl-fuzz runtime options, e.g.:
|
||||
* 65% for `AFL_DISABLE_TRIM`
|
||||
* 50% for `AFL_KEEP_TIMEOUTS`
|
||||
* 50% use a dictionary generated by `AFL_LLVM_DICT2FILE`
|
||||
* 40% use MOpt (`-L 0`)
|
||||
* 40% for `AFL_EXPAND_HAVOC_NOW`
|
||||
* 20% for old queue processing (`-Z`)
|
||||
* for CMPLOG targets, 60% for `-l 2`, 40% for `-l 3`
|
||||
* for CMPLOG targets, 70% for `-l 2`, 10% for `-l 3`, 20% for `-l 2AT`
|
||||
|
||||
4. Do *not* run any `-M` modes, just running `-S` modes is better for CI
|
||||
fuzzing. `-M` enables old queue handling etc. which is good for a fuzzing
|
||||
|
@ -19,18 +19,18 @@ Mentor: vanhauser-thc
|
||||
## WASM Instrumentation
|
||||
|
||||
Currently, AFL++ can be used for source code fuzzing and traditional binaries.
|
||||
With the rise of WASM as a compile target, however, a novel way of instrumentation
|
||||
needs to be implemented for binaries compiled to Webassembly. This can either be
|
||||
done by inserting instrumentation directly into the WASM AST, or by patching
|
||||
feedback into a WASM VM of choice, similar to the current Unicorn
|
||||
With the rise of WASM as a compile target, however, a novel way of
|
||||
instrumentation needs to be implemented for binaries compiled to Webassembly.
|
||||
This can either be done by inserting instrumentation directly into the WASM AST,
|
||||
or by patching feedback into a WASM VM of choice, similar to the current Unicorn
|
||||
instrumentation.
|
||||
|
||||
Mentor: any
|
||||
|
||||
## Support other programming languages
|
||||
|
||||
Other programming languages also use llvm hence they could be (easily?) supported
|
||||
for fuzzing, e.g., mono, swift, go, kotlin native, fortran, ...
|
||||
Other programming languages also use llvm hence they could be (easily?)
|
||||
supported for fuzzing, e.g., mono, swift, go, kotlin native, fortran, ...
|
||||
|
||||
GCC also supports: Objective-C, Fortran, Ada, Go, and D (according to
|
||||
[Gcc homepage](https://gcc.gnu.org/))
|
||||
|
@ -1,11 +1,13 @@
|
||||
# Tools that help fuzzing with AFL++
|
||||
|
||||
Speeding up fuzzing:
|
||||
## Speeding up fuzzing
|
||||
|
||||
* [libfiowrapper](https://github.com/marekzmyslowski/libfiowrapper) - if the
|
||||
function you want to fuzz requires loading a file, this allows using the
|
||||
shared memory test case feature :-) - recommended.
|
||||
|
||||
Minimization of test cases:
|
||||
## Minimization of test cases
|
||||
|
||||
* [afl-pytmin](https://github.com/ilsani/afl-pytmin) - a wrapper for afl-tmin
|
||||
that tries to speed up the process of minimization of a single test case by
|
||||
using many CPU cores.
|
||||
@ -14,7 +16,8 @@ Minimization of test cases:
|
||||
* [halfempty](https://github.com/googleprojectzero/halfempty) - is a fast
|
||||
utility for minimizing test cases by Tavis Ormandy based on parallelization.
|
||||
|
||||
Distributed execution:
|
||||
## Distributed execution
|
||||
|
||||
* [disfuzz-afl](https://github.com/MartijnB/disfuzz-afl) - distributed fuzzing
|
||||
for AFL.
|
||||
* [AFLDFF](https://github.com/quantumvm/AFLDFF) - AFL distributed fuzzing
|
||||
@ -26,7 +29,8 @@ Distributed execution:
|
||||
* [afl-in-the-cloud](https://github.com/abhisek/afl-in-the-cloud) - another
|
||||
script for running AFL in AWS.
|
||||
|
||||
Deployment, management, monitoring, reporting
|
||||
## Deployment, management, monitoring, reporting
|
||||
|
||||
* [afl-utils](https://gitlab.com/rc0r/afl-utils) - a set of utilities for
|
||||
automatic processing/analysis of crashes and reducing the number of test
|
||||
cases.
|
||||
@ -44,7 +48,8 @@ Deployment, management, monitoring, reporting
|
||||
* [afl-extras](https://github.com/fekir/afl-extras) - shell scripts to
|
||||
parallelize afl-tmin, startup, and data collection.
|
||||
|
||||
Crash processing
|
||||
## Crash processing
|
||||
|
||||
* [AFLTriage](https://github.com/quic/AFLTriage) -
|
||||
triage crashing input files using gdb.
|
||||
* [afl-crash-analyzer](https://github.com/floyd-fuh/afl-crash-analyzer) -
|
||||
|
@ -1,5 +1,9 @@
|
||||
# Tutorials
|
||||
|
||||
If you are a total newbie, try this guide:
|
||||
|
||||
* [https://github.com/alex-maleno/Fuzzing-Module](https://github.com/alex-maleno/Fuzzing-Module)
|
||||
|
||||
Here are some good write-ups to show how to effectively use AFL++:
|
||||
|
||||
* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
|
||||
@ -17,7 +21,7 @@ training, then we can highly recommend the following:
|
||||
* [https://github.com/antonio-morales/Fuzzing101](https://github.com/antonio-morales/Fuzzing101)
|
||||
|
||||
If you are interested in fuzzing structured data (where you define what the
|
||||
structure is), these links have you covered:
|
||||
structure is), these links have you covered (some are outdated though):
|
||||
|
||||
* libprotobuf for AFL++:
|
||||
[https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator)
|
||||
@ -29,6 +33,7 @@ structure is), these links have you covered:
|
||||
[https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
|
||||
|
||||
## Video Tutorials
|
||||
|
||||
* [Install AFL++ Ubuntu](https://www.youtube.com/watch?v=5dCvhkbi3RA)
|
||||
* [[Fuzzing with AFLplusplus] Installing AFLPlusplus and fuzzing a simple C program](https://www.youtube.com/watch?v=9wRVo0kYSlc)
|
||||
* [[Fuzzing with AFLplusplus] How to fuzz a binary with no source code on Linux in persistent mode](https://www.youtube.com/watch?v=LGPJdEO02p4)
|
||||
|
@ -13,6 +13,16 @@ JS_SRC:=$(BUILD_DIR)api.c
|
||||
JS_OBJ:=$(BUILD_DIR)api.o
|
||||
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
|
||||
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
|
||||
|
||||
TARGET_CC?=$(CC)
|
||||
TARGET_CXX?=$(CXX)
|
||||
HOST_CC?=$(CC)
|
||||
HOST_CXX?=$(CXX)
|
||||
IS_ANDROID:=$(findstring android, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
IS_x86:=$(findstring i686, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
IS_x86_64:=$(findstring x86_64, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
IS_ARM:=$(findstring arm, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
IS_ARM64:=$(findstring aarch64, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
CFLAGS+=-fPIC \
|
||||
-D_GNU_SOURCE \
|
||||
-D_FORTIFY_SOURCE=2 \
|
||||
@ -21,6 +31,10 @@ CFLAGS+=-fPIC \
|
||||
-funroll-loops \
|
||||
-ffunction-sections \
|
||||
|
||||
ifdef IS_ANDROID
|
||||
CFLAGS+=-DANDROID
|
||||
endif
|
||||
|
||||
AFL_CFLAGS:=-Wno-unused-parameter \
|
||||
-Wno-sign-compare \
|
||||
-Wno-unused-function \
|
||||
@ -28,9 +42,16 @@ AFL_CFLAGS:=-Wno-unused-parameter \
|
||||
-Wno-int-to-pointer-cast \
|
||||
-Wno-pointer-sign
|
||||
|
||||
ifdef IS_ANDROID
|
||||
LDFLAGS+= -static-libstdc++ \
|
||||
-DANDROID \
|
||||
-llog \
|
||||
-shared
|
||||
else
|
||||
LDFLAGS+=-shared \
|
||||
-lpthread \
|
||||
-lresolv
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
CFLAGS+=-Werror \
|
||||
@ -43,10 +64,12 @@ endif
|
||||
|
||||
FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/
|
||||
FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so
|
||||
FRIDA_TRACE_LIB:=$(BUILD_DIR)libafl-frida-trace.a
|
||||
FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded
|
||||
|
||||
TARGET_CC?=$(CC)
|
||||
TARGET_CXX?=$(CXX)
|
||||
TARGET_AR?=$(AR)
|
||||
HOST_CC?=$(CC)
|
||||
HOST_CXX?=$(CXX)
|
||||
|
||||
@ -66,18 +89,21 @@ ifeq "$(ARCH)" "i686"
|
||||
endif
|
||||
endif
|
||||
|
||||
GUM_ARCH="-$(ARCH)"
|
||||
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
OS:=macos
|
||||
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-deprecated-declarations
|
||||
GUM_ARCH:=""
|
||||
else
|
||||
ifdef DEBUG
|
||||
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-prio-ctor-dtor
|
||||
endif
|
||||
|
||||
LDFLAGS+= -z noexecstack \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,--exclude-libs,ALL \
|
||||
-ldl \
|
||||
-lrt
|
||||
-ldl
|
||||
LDSCRIPT:=-Wl,--version-script=$(PWD)frida.map
|
||||
endif
|
||||
|
||||
@ -88,38 +114,41 @@ ifeq "$(shell uname)" "Linux"
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
|
||||
ifdef IS_ANDROID
|
||||
OS:=android
|
||||
ifneq "$(findstring aarch64, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ARCH:=arm64
|
||||
ifdef IS_x86
|
||||
ARCH:=x86
|
||||
endif
|
||||
ifneq "$(findstring arm, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifdef IS_x86
|
||||
ARCH:=x86_64
|
||||
endif
|
||||
ifdef IS_ARM
|
||||
ARCH:=arm
|
||||
endif
|
||||
ifneq "$(findstring x86_64, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ARCH:=x86_64
|
||||
endif
|
||||
ifneq "$(findstring i686, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ARCH:=x86
|
||||
ifdef IS_ARM64
|
||||
ARCH:=arm64
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(ARCH)" "armhf"
|
||||
TARGET_CC:=arm-linux-gnueabihf-gcc
|
||||
TARGET_CXX:=arm-linux-gnueabihf-g++
|
||||
TARGET_AR:=arm-linux-gnueabihf-ar
|
||||
endif
|
||||
|
||||
ifndef OS
|
||||
$(error "Operating system unsupported")
|
||||
endif
|
||||
|
||||
GUM_DEVKIT_VERSION=15.1.13
|
||||
GUM_DEVKIT_VERSION=15.2.1
|
||||
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
|
||||
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
|
||||
|
||||
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
|
||||
ifdef FRIDA_SOURCE
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_DIR)build/frida-linux-$(ARCH)/lib/libfrida-gumjs-1.0.a
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gumjs-1.0.a
|
||||
else
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
|
||||
endif
|
||||
@ -154,7 +183,7 @@ BIN2C_SRC:=$(PWD)util/bin2c.c
|
||||
|
||||
############################## ALL #############################################
|
||||
|
||||
all: $(FRIDA_TRACE) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN)
|
||||
all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN)
|
||||
|
||||
32:
|
||||
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
@ -177,7 +206,7 @@ $(FRIDA_MAKEFILE): | $(BUILD_DIR)
|
||||
.PHONY: $(GUM_DEVIT_LIBRARY)
|
||||
|
||||
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE)
|
||||
cd $(FRIDA_DIR) && make gum-linux-$(ARCH)
|
||||
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH)
|
||||
|
||||
$(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
|
||||
echo "#include <stdio.h>" > $@
|
||||
@ -189,65 +218,99 @@ $(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
|
||||
echo "#include <gum/gumlibc.h>" >> $@
|
||||
echo "#include <gumjs/gumscriptbackend.h>" >> $@
|
||||
|
||||
ifeq "$(ARCH)" "arm64"
|
||||
ifeq "$(OS)" "macos"
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida_thin-linux-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/include/json-glib-1.0/ \
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-linux-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libunwind-*.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-linux-$(ARCH)/lib/libz.a \
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libiconv.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libv8-8.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgmodule-2.0.a \
|
||||
|
||||
else ifeq "$(ARCH)" "arm64"
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida_thin-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
else
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-linux-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-linux-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-linux-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-linux-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-linux-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libunwind-*.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-linux-$(ARCH)/lib/libz.a \
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida_thin-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
|
||||
else
|
||||
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
|
||||
wget -O $@ $(GUM_DEVKIT_URL) || curl -L -o $@ $(GUM_DEVKIT_URL)
|
||||
wget -qO $@ $(GUM_DEVKIT_URL) || curl -L -o $@ $(GUM_DEVKIT_URL)
|
||||
|
||||
$(GUM_DEVIT_LIBRARY): $(GUM_DEVKIT_TARBALL)
|
||||
tar Jxvfm $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
|
||||
@ -325,6 +388,15 @@ $(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL
|
||||
|
||||
cp -v $(FRIDA_TRACE) $(ROOT)
|
||||
|
||||
$(FRIDA_TRACE_LIB): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL_COMPILER_RT_OBJ) $(AFL_PERFORMANCE_OBJ) GNUmakefile | $(BUILD_DIR)
|
||||
$(TARGET_AR) \
|
||||
-rcs \
|
||||
$@ \
|
||||
$(OBJS) \
|
||||
$(JS_OBJ) \
|
||||
$(AFL_COMPILER_RT_OBJ) \
|
||||
$(AFL_PERFORMANCE_OBJ) \
|
||||
|
||||
############################# HOOK #############################################
|
||||
|
||||
$(AFLPP_FRIDA_DRIVER_HOOK_OBJ): $(AFLPP_FRIDA_DRIVER_HOOK_SRC) $(GUM_DEVIT_HEADER) | $(BUILD_DIR)
|
||||
@ -336,6 +408,7 @@ $(AFLPP_QEMU_DRIVER_HOOK_OBJ): $(AFLPP_QEMU_DRIVER_HOOK_SRC) | $(BUILD_DIR)
|
||||
hook: $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ)
|
||||
|
||||
############################# ADDR #############################################
|
||||
ifneq "$(OS)" "android"
|
||||
$(ADDR_BIN): $(ADDR_SRC) | $(BUILD_DIR)
|
||||
-$(TARGET_CC) \
|
||||
$(CFLAGS) \
|
||||
@ -349,7 +422,20 @@ $(ADDR_BIN): $(ADDR_SRC) | $(BUILD_DIR)
|
||||
-ldl \
|
||||
-lrt \
|
||||
$< -o $@
|
||||
|
||||
else
|
||||
$(ADDR_BIN): $(ADDR_SRC) | $(BUILD_DIR)
|
||||
-$(TARGET_CC) \
|
||||
$(CFLAGS) \
|
||||
-Werror \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wpointer-arith \
|
||||
-z noexecstack \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,--exclude-libs,ALL \
|
||||
-ldl \
|
||||
$< -o $@
|
||||
endif
|
||||
addr: $(ADDR_BIN)
|
||||
|
||||
############################# CLEAN ############################################
|
||||
|
@ -146,36 +146,45 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
|
||||
QEMU driver to provide a `main` loop for a user provided
|
||||
`LLVMFuzzerTestOneInput`, this option configures the driver to read input from
|
||||
`stdin` rather than using in-memory test cases.
|
||||
* `AFL_FRIDA_INST_COVERAGE_ABSOLUTE` - Generate coverage files using absolute
|
||||
virtual addresses rather than relative virtual addresses.
|
||||
* `AFL_FRIDA_INST_COVERAGE_FILE` - File to write DynamoRIO format coverage
|
||||
information (e.g., to be loaded within IDA lighthouse).
|
||||
* `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks
|
||||
and their instrumented counterparts during block compilation.
|
||||
|
||||
```
|
||||
***
|
||||
```
|
||||
Creating block for 0x7ffff7953313:
|
||||
0x7ffff7953313 mov qword ptr [rax], 0
|
||||
0x7ffff795331a add rsp, 8
|
||||
0x7ffff795331e ret
|
||||
|
||||
Creating block for 0x7ffff7953313:
|
||||
0x7ffff7953313 mov qword ptr [rax], 0
|
||||
0x7ffff795331a add rsp, 8
|
||||
0x7ffff795331e ret
|
||||
Generated block 0x7ffff75e98e2
|
||||
0x7ffff75e98e2 mov qword ptr [rax], 0
|
||||
0x7ffff75e98e9 add rsp, 8
|
||||
0x7ffff75e98ed lea rsp, [rsp - 0x80]
|
||||
0x7ffff75e98f5 push rcx
|
||||
0x7ffff75e98f6 movabs rcx, 0x7ffff795331e
|
||||
0x7ffff75e9900 jmp 0x7ffff75e9384
|
||||
|
||||
Generated block 0x7ffff75e98e2
|
||||
0x7ffff75e98e2 mov qword ptr [rax], 0
|
||||
0x7ffff75e98e9 add rsp, 8
|
||||
0x7ffff75e98ed lea rsp, [rsp - 0x80]
|
||||
0x7ffff75e98f5 push rcx
|
||||
0x7ffff75e98f6 movabs rcx, 0x7ffff795331e
|
||||
0x7ffff75e9900 jmp 0x7ffff75e9384
|
||||
|
||||
***
|
||||
```
|
||||
|
||||
```
|
||||
* `AFL_FRIDA_INST_CACHE_SIZE` - Set the size of the instrumentation cache used
|
||||
as a look-up table to cache real to instrumented address block translations.
|
||||
Default is 256Mb.
|
||||
* `AFL_FRIDA_INST_INSN` - Generate instrumentation for conditional
|
||||
instructions (e.g. `CMOV` instructions on x64).
|
||||
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
|
||||
code. Code is considered to be JIT if the executable segment is not backed by
|
||||
a file.
|
||||
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
|
||||
instrumentation (the default where available). Required to use
|
||||
* `AFL_FRIDA_INST_REGS_FILE` - File to write raw register contents at the start
|
||||
of each block.
|
||||
`AFL_FRIDA_INST_TRACE`.
|
||||
* `AFL_FRIDA_INST_NO_CACHE` - Don't use a look-up table to cache real to
|
||||
instrumented address block translations.
|
||||
* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default, the child will
|
||||
report instrumented blocks back to the parent so that it can also instrument
|
||||
them and they be inherited by the next child on fork, implies
|
||||
|
@ -850,6 +850,14 @@ class Afl {
|
||||
static setInstrumentNoOptimize() {
|
||||
Afl.jsApiSetInstrumentNoOptimize();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_REGS_FILE`. This function takes a single `string` as
|
||||
* an argument.
|
||||
*/
|
||||
public static setInstrumentRegsFile(file: string): void {
|
||||
const buf = Memory.allocUtf8String(file);
|
||||
Afl.jsApiSetInstrumentRegsFile(buf);
|
||||
}
|
||||
/*
|
||||
* See `AFL_FRIDA_INST_SEED`
|
||||
*/
|
||||
|
@ -9,13 +9,18 @@
|
||||
js_api_done;
|
||||
js_api_error;
|
||||
js_api_set_backpatch_disable;
|
||||
js_api_set_cache_disable;
|
||||
js_api_set_debug_maps;
|
||||
js_api_set_entrypoint;
|
||||
js_api_set_instrument_cache_size;
|
||||
js_api_set_instrument_coverage_absolute;
|
||||
js_api_set_instrument_coverage_file;
|
||||
js_api_set_instrument_debug_file;
|
||||
js_api_set_instrument_jit;
|
||||
js_api_set_instrument_libraries;
|
||||
js_api_set_instrument_instructions;
|
||||
js_api_set_instrument_no_optimize;
|
||||
js_api_set_instrument_regs_file;
|
||||
js_api_set_instrument_seed;
|
||||
js_api_set_instrument_trace;
|
||||
js_api_set_instrument_trace_unique;
|
||||
|
@ -31,7 +31,7 @@ __attribute__((visibility("default"))) void afl_persistent_hook(
|
||||
// do a length check matching the target!
|
||||
|
||||
void **esp = (void **)regs->esp;
|
||||
void * arg1 = esp[0];
|
||||
void *arg1 = esp[0];
|
||||
void **arg2 = &esp[1];
|
||||
memcpy(arg1, input_buf, input_buf_len);
|
||||
*arg2 = (void *)input_buf_len;
|
||||
@ -50,6 +50,16 @@ __attribute__((visibility("default"))) void afl_persistent_hook(
|
||||
|
||||
}
|
||||
|
||||
#elif defined(__arm__)
|
||||
|
||||
__attribute__((visibility("default"))) void afl_persistent_hook(
|
||||
GumCpuContext *regs, uint8_t *input_buf, uint32_t input_buf_len) {
|
||||
// do a length check matching the target!
|
||||
|
||||
memcpy((void *)regs->r[0], input_buf, input_buf_len);
|
||||
regs->r[1] = input_buf_len;
|
||||
}
|
||||
|
||||
#else
|
||||
#pragma error "Unsupported architecture"
|
||||
#endif
|
||||
|
@ -5,13 +5,16 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
extern char * instrument_debug_filename;
|
||||
extern char * instrument_coverage_filename;
|
||||
extern char *instrument_debug_filename;
|
||||
extern char *instrument_coverage_filename;
|
||||
extern bool instrument_coverage_absolute;
|
||||
extern gboolean instrument_tracing;
|
||||
extern gboolean instrument_optimize;
|
||||
extern gboolean instrument_unique;
|
||||
extern guint64 instrument_hash_zero;
|
||||
extern char * instrument_coverage_unstable_filename;
|
||||
extern char *instrument_coverage_unstable_filename;
|
||||
extern gboolean instrument_coverage_insn;
|
||||
extern char *instrument_regs_filename;
|
||||
|
||||
extern gboolean instrument_use_fixed_seed;
|
||||
extern guint64 instrument_fixed_seed;
|
||||
@ -21,6 +24,9 @@ extern uint32_t __afl_map_size;
|
||||
|
||||
extern __thread guint64 *instrument_previous_pc_addr;
|
||||
|
||||
extern gboolean instrument_cache_enabled;
|
||||
extern gsize instrument_cache_size;
|
||||
|
||||
void instrument_config(void);
|
||||
|
||||
void instrument_init(void);
|
||||
@ -31,8 +37,10 @@ GumStalkerTransformer *instrument_get_transformer(void);
|
||||
gboolean instrument_is_coverage_optimize_supported(void);
|
||||
|
||||
void instrument_coverage_optimize_init(void);
|
||||
void instrument_coverage_optimize(const cs_insn * instr,
|
||||
void instrument_coverage_optimize(const cs_insn *instr,
|
||||
GumStalkerOutput *output);
|
||||
void instrument_coverage_optimize_insn(const cs_insn *instr,
|
||||
GumStalkerOutput *output);
|
||||
|
||||
void instrument_debug_config(void);
|
||||
void instrument_debug_init(void);
|
||||
@ -56,5 +64,12 @@ void instrument_on_fork(void);
|
||||
|
||||
guint64 instrument_get_offset_hash(GumAddress current_rip);
|
||||
|
||||
void instrument_cache_config(void);
|
||||
void instrument_cache_init(void);
|
||||
void instrument_cache_insert(gpointer real_address, gpointer code_address);
|
||||
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output);
|
||||
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data);
|
||||
void instrument_regs_format(int fd, char *format, ...);
|
||||
|
||||
#endif
|
||||
|
||||
|
11
frida_mode/include/module.h
Normal file
11
frida_mode/include/module.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _MODULE_H
|
||||
#define _MODULE_H
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
void module_config(void);
|
||||
|
||||
void module_init(void);
|
||||
|
||||
#endif
|
||||
|
@ -13,7 +13,7 @@ typedef void (*afl_persistent_hook_fn)(api_regs *regs, uint64_t guest_base,
|
||||
|
||||
extern int __afl_persistent_loop(unsigned int max_cnt);
|
||||
|
||||
extern unsigned int * __afl_fuzz_len;
|
||||
extern unsigned int *__afl_fuzz_len;
|
||||
extern unsigned char *__afl_fuzz_ptr;
|
||||
|
||||
extern guint64 persistent_start;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _SECCOMP_H
|
||||
#define _SECCOMP_H
|
||||
|
||||
#ifndef __APPLE__
|
||||
#if !defined(__APPLE__) && !defined(__ANDROID__)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <linux/filter.h>
|
||||
@ -401,9 +401,9 @@ enum {
|
||||
|
||||
typedef void (*seccomp_child_func_t)(int event_fd, void *ctx);
|
||||
|
||||
typedef void (*seccomp_filter_callback_t)(struct seccomp_notif * req,
|
||||
typedef void (*seccomp_filter_callback_t)(struct seccomp_notif *req,
|
||||
struct seccomp_notif_resp *resp,
|
||||
GumReturnAddressArray * frames);
|
||||
GumReturnAddressArray *frames);
|
||||
|
||||
void seccomp_atomic_set(volatile bool *ptr, bool val);
|
||||
bool seccomp_atomic_try_set(volatile bool *ptr, bool val);
|
||||
|
9
frida_mode/include/shm.h
Normal file
9
frida_mode/include/shm.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef _SHM_H
|
||||
#define _SHM_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void *shm_create(size_t size);
|
||||
|
||||
#endif
|
||||
|
@ -43,7 +43,7 @@ typedef struct {
|
||||
G_DECLARE_FINAL_TYPE(GumAflStalkerStats, gum_afl_stalker_stats, GUM,
|
||||
AFL_STALKER_STATS, GObject)
|
||||
|
||||
extern char * stats_filename;
|
||||
extern char *stats_filename;
|
||||
extern guint64 stats_interval;
|
||||
|
||||
void stats_config(void);
|
||||
|
@ -5,6 +5,14 @@
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef MAP_FIXED_NOREPLACE
|
||||
#ifdef MAP_EXCL
|
||||
#define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
|
||||
#else
|
||||
#define MAP_FIXED_NOREPLACE MAP_FIXED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define UNUSED_PARAMETER(x) (void)(x)
|
||||
#define IGNORED_RETURN(x) (void)!(x)
|
||||
|
||||
|
@ -30,12 +30,21 @@ void asan_init(void) {
|
||||
static gboolean asan_exclude_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
gchar * symbol_name = (gchar *)user_data;
|
||||
gchar *symbol_name = (gchar *)user_data;
|
||||
GumAddress address;
|
||||
|
||||
address = gum_module_find_export_by_name(details->name, symbol_name);
|
||||
if (address == 0) { return TRUE; }
|
||||
|
||||
/* If the reported address of the symbol is outside of the range of the module
|
||||
* then ignore it */
|
||||
if (address < details->range->base_address) { return TRUE; }
|
||||
if (address > (details->range->base_address + details->range->size)) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
ranges_add_exclude((GumMemoryRange *)details->range);
|
||||
return FALSE;
|
||||
|
||||
|
@ -22,8 +22,8 @@ asan_storeN_t asan_storeN = NULL;
|
||||
|
||||
static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
|
||||
|
||||
asan_ctx_t * asan_ctx = (asan_ctx_t *)user_data;
|
||||
cs_arm64_op * operand = &asan_ctx->operand;
|
||||
asan_ctx_t *asan_ctx = (asan_ctx_t *)user_data;
|
||||
cs_arm64_op *operand = &asan_ctx->operand;
|
||||
arm64_op_mem *mem = &operand->mem;
|
||||
gsize base = 0;
|
||||
gsize index = 0;
|
||||
@ -59,7 +59,7 @@ void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
|
||||
cs_arm64 arm64 = instr->detail->arm64;
|
||||
cs_arm64_op *operand;
|
||||
asan_ctx_t * ctx;
|
||||
asan_ctx_t *ctx;
|
||||
|
||||
if (!asan_initialized) return;
|
||||
|
||||
|
@ -17,7 +17,7 @@ static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(user_data);
|
||||
|
||||
cs_x86_op * operand = (cs_x86_op *)user_data;
|
||||
cs_x86_op *operand = (cs_x86_op *)user_data;
|
||||
x86_op_mem *mem = &operand->mem;
|
||||
gsize base = 0;
|
||||
gsize index = 0;
|
||||
@ -48,9 +48,9 @@ void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
UNUSED_PARAMETER(iterator);
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
cs_x86_op * operand;
|
||||
cs_x86_op *operand;
|
||||
x86_op_mem *mem;
|
||||
cs_x86_op * ctx;
|
||||
cs_x86_op *ctx;
|
||||
|
||||
if (!asan_initialized) return;
|
||||
|
||||
|
@ -17,7 +17,7 @@ static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(user_data);
|
||||
|
||||
cs_x86_op * operand = (cs_x86_op *)user_data;
|
||||
cs_x86_op *operand = (cs_x86_op *)user_data;
|
||||
x86_op_mem *mem = &operand->mem;
|
||||
gsize base = 0;
|
||||
gsize index = 0;
|
||||
@ -48,9 +48,9 @@ void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||
UNUSED_PARAMETER(iterator);
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
cs_x86_op * operand;
|
||||
cs_x86_op *operand;
|
||||
x86_op_mem *mem;
|
||||
cs_x86_op * ctx;
|
||||
cs_x86_op *ctx;
|
||||
|
||||
if (!asan_initialized) return;
|
||||
|
||||
|
@ -13,9 +13,9 @@
|
||||
#define MAX_MEMFD_SIZE (64UL << 10)
|
||||
|
||||
extern struct cmp_map *__afl_cmp_map;
|
||||
static GArray * cmplog_ranges = NULL;
|
||||
static GHashTable * hash_yes = NULL;
|
||||
static GHashTable * hash_no = NULL;
|
||||
static GArray *cmplog_ranges = NULL;
|
||||
static GHashTable *hash_yes = NULL;
|
||||
static GHashTable *hash_no = NULL;
|
||||
|
||||
static long page_size = 0;
|
||||
static long page_offset_mask = 0;
|
||||
@ -24,7 +24,7 @@ static long page_mask = 0;
|
||||
static gboolean cmplog_range(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
GArray * cmplog_ranges = (GArray *)user_data;
|
||||
GArray *cmplog_ranges = (GArray *)user_data;
|
||||
GumMemoryRange range = *details->range;
|
||||
g_array_append_val(cmplog_ranges, range);
|
||||
return TRUE;
|
||||
@ -118,7 +118,7 @@ gboolean cmplog_test_addr(guint64 addr, size_t size) {
|
||||
if (g_hash_table_contains(hash_yes, GSIZE_TO_POINTER(addr))) { return true; }
|
||||
if (g_hash_table_contains(hash_no, GSIZE_TO_POINTER(addr))) { return false; }
|
||||
|
||||
void * page_addr = GSIZE_TO_POINTER(addr & page_mask);
|
||||
void *page_addr = GSIZE_TO_POINTER(addr & page_mask);
|
||||
size_t page_offset = addr & page_offset_mask;
|
||||
|
||||
/* If it spans a page, then bail */
|
||||
|
@ -148,7 +148,7 @@ static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
|
||||
cs_arm64_op * operand) {
|
||||
cs_arm64_op *operand) {
|
||||
|
||||
ctx->type = operand->type;
|
||||
switch (operand->type) {
|
||||
@ -169,7 +169,7 @@ static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_call(const cs_insn * instr,
|
||||
static void cmplog_instrument_call(const cs_insn *instr,
|
||||
GumStalkerIterator *iterator) {
|
||||
|
||||
cs_arm64 arm64 = instr->detail->arm64;
|
||||
@ -247,8 +247,8 @@ static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
|
||||
cs_arm64_op * operand1,
|
||||
cs_arm64_op * operand2,
|
||||
cs_arm64_op *operand1,
|
||||
cs_arm64_op *operand2,
|
||||
size_t size) {
|
||||
|
||||
cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
|
||||
@ -263,7 +263,7 @@ static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_cmp_sub(const cs_insn * instr,
|
||||
static void cmplog_instrument_cmp_sub(const cs_insn *instr,
|
||||
GumStalkerIterator *iterator) {
|
||||
|
||||
cs_arm64 arm64 = instr->detail->arm64;
|
||||
|
@ -141,7 +141,7 @@ static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
|
||||
cs_x86_op * operand) {
|
||||
cs_x86_op *operand) {
|
||||
|
||||
ctx->type = operand->type;
|
||||
ctx->size = operand->size;
|
||||
@ -163,7 +163,7 @@ static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_call(const cs_insn * instr,
|
||||
static void cmplog_instrument_call(const cs_insn *instr,
|
||||
GumStalkerIterator *iterator) {
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
@ -230,7 +230,7 @@ static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
|
||||
cs_x86_op * operand1,
|
||||
cs_x86_op *operand1,
|
||||
cs_x86_op *operand2) {
|
||||
|
||||
cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
|
||||
@ -244,7 +244,7 @@ static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_cmp_sub(const cs_insn * instr,
|
||||
static void cmplog_instrument_cmp_sub(const cs_insn *instr,
|
||||
GumStalkerIterator *iterator) {
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
|
@ -146,7 +146,7 @@ static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
|
||||
cs_x86_op * operand) {
|
||||
cs_x86_op *operand) {
|
||||
|
||||
ctx->type = operand->type;
|
||||
ctx->size = operand->size;
|
||||
@ -168,7 +168,7 @@ static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_call(const cs_insn * instr,
|
||||
static void cmplog_instrument_call(const cs_insn *instr,
|
||||
GumStalkerIterator *iterator) {
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
@ -238,7 +238,7 @@ static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
|
||||
cs_x86_op * operand1,
|
||||
cs_x86_op *operand1,
|
||||
cs_x86_op *operand2) {
|
||||
|
||||
cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
|
||||
@ -252,7 +252,7 @@ static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
|
||||
|
||||
}
|
||||
|
||||
static void cmplog_instrument_cmp_sub(const cs_insn * instr,
|
||||
static void cmplog_instrument_cmp_sub(const cs_insn *instr,
|
||||
GumStalkerIterator *iterator) {
|
||||
|
||||
cs_x86 x86 = instr->detail->x86;
|
||||
|
@ -78,6 +78,13 @@ void entry_init(void) {
|
||||
|
||||
void entry_start(void) {
|
||||
|
||||
if (persistent_start == 0) {
|
||||
|
||||
ranges_exclude();
|
||||
stalker_trust();
|
||||
|
||||
}
|
||||
|
||||
if (entry_point == 0) { entry_launch(); }
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
@ -16,10 +15,13 @@
|
||||
#include "persistent.h"
|
||||
#include "prefetch.h"
|
||||
#include "ranges.h"
|
||||
#include "shm.h"
|
||||
#include "stalker.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
|
||||
#define FRIDA_DEFAULT_MAP_SIZE (64UL << 10)
|
||||
|
||||
gboolean instrument_tracing = false;
|
||||
gboolean instrument_optimize = false;
|
||||
gboolean instrument_unique = false;
|
||||
@ -28,13 +30,17 @@ guint64 instrument_hash_seed = 0;
|
||||
|
||||
gboolean instrument_use_fixed_seed = FALSE;
|
||||
guint64 instrument_fixed_seed = 0;
|
||||
char * instrument_coverage_unstable_filename = NULL;
|
||||
char *instrument_coverage_unstable_filename = NULL;
|
||||
gboolean instrument_coverage_insn = FALSE;
|
||||
char *instrument_regs_filename = NULL;
|
||||
|
||||
static GumStalkerTransformer *transformer = NULL;
|
||||
|
||||
static GumAddress previous_rip = 0;
|
||||
static GumAddress previous_end = 0;
|
||||
static u8 * edges_notified = NULL;
|
||||
static u8 *edges_notified = NULL;
|
||||
|
||||
static int regs_fd = -1;
|
||||
|
||||
__thread guint64 instrument_previous_pc;
|
||||
__thread guint64 *instrument_previous_pc_addr = NULL;
|
||||
@ -148,7 +154,7 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context,
|
||||
}
|
||||
|
||||
static void instrument_basic_block(GumStalkerIterator *iterator,
|
||||
GumStalkerOutput * output,
|
||||
GumStalkerOutput *output,
|
||||
gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(user_data);
|
||||
@ -156,7 +162,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
|
||||
const cs_insn *instr;
|
||||
gboolean begin = TRUE;
|
||||
gboolean excluded;
|
||||
block_ctx_t * ctx = NULL;
|
||||
block_ctx_t *ctx = NULL;
|
||||
|
||||
while (gum_stalker_iterator_next(iterator, &instr)) {
|
||||
|
||||
@ -229,11 +235,22 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(instrument_regs_filename != NULL)) {
|
||||
|
||||
gum_stalker_iterator_put_callout(iterator, instrument_write_regs,
|
||||
(void *)(size_t)regs_fd, NULL);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
instrument_debug_instruction(instr->address, instr->size, output);
|
||||
if (instrument_coverage_insn) {
|
||||
|
||||
instrument_coverage_optimize_insn(instr, output);
|
||||
|
||||
}
|
||||
|
||||
if (likely(!excluded)) {
|
||||
|
||||
@ -242,6 +259,8 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
|
||||
|
||||
}
|
||||
|
||||
instrument_cache(instr, output);
|
||||
|
||||
if (js_stalker_callback(instr, begin, excluded, output)) {
|
||||
|
||||
gum_stalker_iterator_keep(iterator);
|
||||
@ -269,16 +288,21 @@ void instrument_config(void) {
|
||||
instrument_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED", 0);
|
||||
instrument_coverage_unstable_filename =
|
||||
(getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE"));
|
||||
instrument_coverage_insn = (getenv("AFL_FRIDA_INST_INSN") != NULL);
|
||||
instrument_regs_filename = getenv("AFL_FRIDA_INST_REGS_FILE");
|
||||
|
||||
instrument_debug_config();
|
||||
instrument_coverage_config();
|
||||
asan_config();
|
||||
cmplog_config();
|
||||
instrument_cache_config();
|
||||
|
||||
}
|
||||
|
||||
void instrument_init(void) {
|
||||
|
||||
if (__afl_map_size == MAP_SIZE) __afl_map_size = FRIDA_DEFAULT_MAP_SIZE;
|
||||
|
||||
if (!instrument_is_coverage_optimize_supported()) instrument_optimize = false;
|
||||
|
||||
FOKF(cBLU "Instrumentation" cRST " - " cGRN "optimize:" cYEL " [%c]",
|
||||
@ -294,6 +318,8 @@ void instrument_init(void) {
|
||||
instrument_coverage_unstable_filename == NULL
|
||||
? " "
|
||||
: instrument_coverage_unstable_filename);
|
||||
FOKF(cBLU "Instrumentation" cRST " - " cGRN "instructions:" cYEL " [%c]",
|
||||
instrument_coverage_insn ? 'X' : ' ');
|
||||
|
||||
if (instrument_tracing && instrument_optimize) {
|
||||
|
||||
@ -321,29 +347,7 @@ void instrument_init(void) {
|
||||
transformer = gum_stalker_transformer_make_from_callback(
|
||||
instrument_basic_block, NULL, NULL);
|
||||
|
||||
if (instrument_unique) {
|
||||
|
||||
int shm_id =
|
||||
shmget(IPC_PRIVATE, __afl_map_size, IPC_CREAT | IPC_EXCL | 0600);
|
||||
if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); }
|
||||
|
||||
edges_notified = shmat(shm_id, NULL, 0);
|
||||
g_assert(edges_notified != MAP_FAILED);
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process
|
||||
* dies.
|
||||
*/
|
||||
if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
|
||||
|
||||
FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(edges_notified, '\0', __afl_map_size);
|
||||
|
||||
}
|
||||
if (instrument_unique) { edges_notified = shm_create(__afl_map_size); }
|
||||
|
||||
if (instrument_use_fixed_seed) {
|
||||
|
||||
@ -377,11 +381,31 @@ void instrument_init(void) {
|
||||
instrument_hash_seed);
|
||||
instrument_hash_zero = instrument_get_offset_hash(0);
|
||||
|
||||
FOKF(cBLU "Instrumentation" cRST " - " cGRN "regs:" cYEL " [%s]",
|
||||
instrument_regs_filename == NULL ? " " : instrument_regs_filename);
|
||||
|
||||
if (instrument_regs_filename != NULL) {
|
||||
|
||||
char *path =
|
||||
g_canonicalize_filename(instrument_regs_filename, g_get_current_dir());
|
||||
|
||||
FOKF(cBLU "Instrumentation" cRST " - " cGRN "path:" cYEL " [%s]", path);
|
||||
|
||||
regs_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
|
||||
if (regs_fd < 0) { FFATAL("Failed to open regs file '%s'", path); }
|
||||
|
||||
g_free(path);
|
||||
|
||||
}
|
||||
|
||||
asan_init();
|
||||
cmplog_init();
|
||||
instrument_coverage_init();
|
||||
instrument_coverage_optimize_init();
|
||||
instrument_debug_init();
|
||||
instrument_cache_init();
|
||||
|
||||
}
|
||||
|
||||
@ -402,3 +426,22 @@ void instrument_on_fork() {
|
||||
|
||||
}
|
||||
|
||||
void instrument_regs_format(int fd, char *format, ...) {
|
||||
|
||||
va_list ap;
|
||||
char buffer[4096] = {0};
|
||||
int ret;
|
||||
int len;
|
||||
|
||||
va_start(ap, format);
|
||||
ret = vsnprintf(buffer, sizeof(buffer) - 1, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (ret < 0) { return; }
|
||||
|
||||
len = strnlen(buffer, sizeof(buffer));
|
||||
|
||||
IGNORED_RETURN(write(fd, buffer, len));
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,24 +5,193 @@
|
||||
|
||||
#if defined(__arm__)
|
||||
|
||||
gboolean instrument_is_coverage_optimize_supported(void) {
|
||||
#define PAGE_MASK (~(GUM_ADDRESS(0xfff)))
|
||||
#define PAGE_ALIGNED(x) ((GUM_ADDRESS(x) & PAGE_MASK) == GUM_ADDRESS(x))
|
||||
|
||||
return false;
|
||||
gboolean instrument_cache_enabled = FALSE;
|
||||
gsize instrument_cache_size = 0;
|
||||
|
||||
extern __thread guint64 instrument_previous_pc;
|
||||
|
||||
__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_SIZE];
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
|
||||
// cur_location = (block_address >> 4) ^ (block_address << 8);
|
||||
// shared_mem[cur_location ^ prev_location]++;
|
||||
// prev_location = cur_location >> 1;
|
||||
|
||||
/* We can remove this branch when we add support for branch suppression */
|
||||
uint32_t b_code; /* b imm */
|
||||
uint8_t *shared_mem;
|
||||
uint64_t *prev_location;
|
||||
|
||||
/* code */
|
||||
|
||||
/* save regs */
|
||||
uint32_t str_r0_sp_rz; /* str r0, [sp - RED_ZONE] */
|
||||
uint32_t str_r1_sp_rz_4; /* str r1, [sp - (RED_ZONE + 4)] */
|
||||
|
||||
/* load prev */
|
||||
uint32_t ldr_r0_pprev; /* ldr r0, [pc-x] */
|
||||
uint32_t ldrh_r1_r0; /* ldrh r1, [r0] */
|
||||
|
||||
/* load curr */
|
||||
uint32_t mov_r0_block_id; /* mov r0, #imm16 */
|
||||
|
||||
/* calculate new */
|
||||
uint32_t eor_r0_r0_r1; /* eor r0, r0, r1 */
|
||||
|
||||
/* load map */
|
||||
uint32_t ldr_r1_pmap; /* ldr r1, [pc-x] */
|
||||
|
||||
/* calculate offset */
|
||||
uint32_t add_r1_r1_r0; /* add r1, r1, r0 */
|
||||
|
||||
/* Load the value */
|
||||
uint32_t ldrb_r0_r1; /* ldrb r0, [r1] */
|
||||
|
||||
/* Increment the value */
|
||||
uint32_t add_r0_r0_1; /* add r0, r0, #1 */
|
||||
uint32_t add_r0_r0_r0_lsr_8; /* add r0, r0, r0, lsr #8 */
|
||||
|
||||
/* Save the value */
|
||||
uint32_t strb_r0_r1; /* strb r0, [r1] */
|
||||
|
||||
/* load curr shifted */
|
||||
uint32_t mov_r0_block_id_shr_1; /* mov r0, #imm16 >> 1*/
|
||||
|
||||
/* Update prev */
|
||||
uint32_t ldr_r1_pprev; /* ldr r1, [pc-x] */
|
||||
uint32_t strh_r0_r1; /* strh r0, [r1] */
|
||||
|
||||
/* restore regs */
|
||||
uint32_t ldr_r1_sp_rz_4; /* ldr r1, [sp - (RED_ZONE + 4)] */
|
||||
uint32_t ldr_r0_sp_rz; /* ldr r0, [sp - RED_ZONE] */
|
||||
|
||||
} afl_log_code_asm_t;
|
||||
|
||||
typedef union {
|
||||
|
||||
afl_log_code_asm_t code;
|
||||
uint8_t bytes[0];
|
||||
|
||||
} afl_log_code;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static const afl_log_code_asm_t template =
|
||||
{
|
||||
|
||||
.b_code = GUINT32_TO_LE(0xea000001),
|
||||
.shared_mem = (uint8_t *)GUINT32_TO_LE(0xcefaadde),
|
||||
.prev_location = (uint64_t *)GUINT32_TO_LE(0xadba0df0),
|
||||
.str_r0_sp_rz = GUINT32_TO_LE(0xe50d0080),
|
||||
.str_r1_sp_rz_4 = GUINT32_TO_LE(0xe50d1084),
|
||||
.ldr_r0_pprev = GUINT32_TO_LE(0xe51f0014),
|
||||
.ldrh_r1_r0 = GUINT32_TO_LE(0xe1d010b0),
|
||||
.mov_r0_block_id = GUINT32_TO_LE(0xe3000000),
|
||||
.eor_r0_r0_r1 = GUINT32_TO_LE(0xe0200001),
|
||||
.ldr_r1_pmap = GUINT32_TO_LE(0xe51f1028),
|
||||
.add_r1_r1_r0 = GUINT32_TO_LE(0xe0811000),
|
||||
.ldrb_r0_r1 = GUINT32_TO_LE(0xe5d10000),
|
||||
.add_r0_r0_1 = GUINT32_TO_LE(0xe2800001),
|
||||
.add_r0_r0_r0_lsr_8 = GUINT32_TO_LE(0xe0800420),
|
||||
.strb_r0_r1 = GUINT32_TO_LE(0xe5c10000),
|
||||
.mov_r0_block_id_shr_1 = GUINT32_TO_LE(0xe3000000),
|
||||
.ldr_r1_pprev = GUINT32_TO_LE(0xe51f1040),
|
||||
.strh_r0_r1 = GUINT32_TO_LE(0xe1c100b0),
|
||||
.ldr_r1_sp_rz_4 = GUINT32_TO_LE(0xe51d1084),
|
||||
.ldr_r0_sp_rz = GUINT32_TO_LE(0xe51d0080),
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize(const cs_insn * instr,
|
||||
;
|
||||
|
||||
gboolean instrument_is_coverage_optimize_supported(void) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static void patch_t3_insn(uint32_t *insn, uint16_t val) {
|
||||
|
||||
uint32_t orig = GUINT32_FROM_LE(*insn);
|
||||
uint32_t imm12 = (val & 0xfff);
|
||||
uint32_t imm4 = (val >> 12);
|
||||
orig |= imm12;
|
||||
orig |= (imm4 << 16);
|
||||
*insn = GUINT32_TO_LE(orig);
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize(const cs_insn *instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
afl_log_code code = {0};
|
||||
GumArmWriter *cw = output->writer.arm;
|
||||
gpointer block_start;
|
||||
guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
|
||||
gsize map_size_pow2;
|
||||
gsize area_offset_ror;
|
||||
GumAddress code_addr = 0;
|
||||
|
||||
// gum_arm64_writer_put_brk_imm(cw, 0x0);
|
||||
|
||||
code_addr = cw->pc;
|
||||
|
||||
block_start = GSIZE_TO_POINTER(GUM_ADDRESS(cw->code));
|
||||
|
||||
code.code = template;
|
||||
|
||||
g_assert(PAGE_ALIGNED(__afl_area_ptr));
|
||||
|
||||
map_size_pow2 = util_log2(__afl_map_size);
|
||||
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
|
||||
|
||||
code.code.shared_mem = __afl_area_ptr;
|
||||
code.code.prev_location = instrument_previous_pc_addr;
|
||||
|
||||
patch_t3_insn(&code.code.mov_r0_block_id, (uint16_t)area_offset);
|
||||
patch_t3_insn(&code.code.mov_r0_block_id_shr_1, (uint16_t)area_offset_ror);
|
||||
|
||||
// gum_arm_writer_put_breakpoint(cw);
|
||||
gum_arm_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize_insn(const cs_insn *instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(output);
|
||||
FFATAL("Optimized coverage not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize_init(void) {
|
||||
|
||||
FWARNF("Optimized coverage not supported on this architecture");
|
||||
char *shm_env = getenv(SHM_ENV_VAR);
|
||||
FVERBOSE("SHM_ENV_VAR: %s", shm_env);
|
||||
|
||||
if (shm_env == NULL) {
|
||||
|
||||
FWARNF("SHM_ENV_VAR not set, using dummy for debugging purposes");
|
||||
|
||||
__afl_area_ptr = area_ptr_dummy;
|
||||
memset(area_ptr_dummy, '\0', sizeof(area_ptr_dummy));
|
||||
|
||||
}
|
||||
|
||||
FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr);
|
||||
|
||||
if (instrument_previous_pc_addr == NULL) {
|
||||
|
||||
instrument_previous_pc_addr = &instrument_previous_pc;
|
||||
*instrument_previous_pc_addr = instrument_hash_zero;
|
||||
FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -46,5 +215,48 @@ gpointer instrument_cur(GumStalkerOutput *output) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_config(void) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_init(void) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
|
||||
|
||||
UNUSED_PARAMETER(real_address);
|
||||
UNUSED_PARAMETER(code_address);
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(output);
|
||||
|
||||
}
|
||||
|
||||
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
|
||||
|
||||
int fd = (int)user_data;
|
||||
instrument_regs_format(fd,
|
||||
"r0 : 0x%08x, r1 : 0x%08x, r2 : 0x%08x, r3 : 0x%08x\n",
|
||||
cpu_context->r[0], cpu_context->r[2],
|
||||
cpu_context->r[1], cpu_context->r[3]);
|
||||
instrument_regs_format(fd,
|
||||
"r4 : 0x%08x, r5 : 0x%08x, r6 : 0x%08x, r7 : 0x%08x\n",
|
||||
cpu_context->r[4], cpu_context->r[5],
|
||||
cpu_context->r[6], cpu_context->r[7]);
|
||||
instrument_regs_format(
|
||||
fd, "r8 : 0x%08x, r9 : 0x%08x, r10: 0x%08x, r11: 0x%08x\n",
|
||||
cpu_context->r8, cpu_context->r9, cpu_context->r10, cpu_context->r11);
|
||||
instrument_regs_format(
|
||||
fd, "r12: 0x%08x, sp : 0x%08x, lr : 0x%08x, pc : 0x%08x\n",
|
||||
cpu_context->r12, cpu_context->sp, cpu_context->lr, cpu_context->pc);
|
||||
instrument_regs_format(fd, "cpsr: 0x%08x\n\n", cpu_context->cpsr);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -14,9 +14,14 @@
|
||||
|
||||
#define PAGE_MASK (~(GUM_ADDRESS(0xfff)))
|
||||
#define PAGE_ALIGNED(x) ((GUM_ADDRESS(x) & PAGE_MASK) == GUM_ADDRESS(x))
|
||||
#define GUM_RESTORATION_PROLOG_SIZE 4
|
||||
|
||||
#if defined(__aarch64__)
|
||||
|
||||
gboolean instrument_cache_enabled = FALSE;
|
||||
gsize instrument_cache_size = 0;
|
||||
static GHashTable *coverage_blocks = NULL;
|
||||
|
||||
__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_SIZE];
|
||||
|
||||
#pragma pack(push, 1)
|
||||
@ -44,6 +49,9 @@ typedef struct {
|
||||
// b 0x7fb6f0dee4
|
||||
// ldp x16, x17, [sp], #144
|
||||
|
||||
uint32_t b_imm8; /* br #68 */
|
||||
uint32_t restoration_prolog; /* ldp x16, x17, [sp], #0x90 */
|
||||
|
||||
uint32_t stp_x0_x1; /* stp x0, x1, [sp, #-0xa0] */
|
||||
|
||||
uint32_t adrp_x0_prev_loc1; /* adrp x0, #0xXXXX */
|
||||
@ -66,9 +74,6 @@ typedef struct {
|
||||
|
||||
uint32_t ldp_x0_x1; /* ldp x0, x1, [sp, #-0xa0] */
|
||||
|
||||
uint32_t b_imm8; /* br #8 */
|
||||
uint32_t restoration_prolog; /* ldp x16, x17, [sp], #0x90 */
|
||||
|
||||
} afl_log_code_asm_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
@ -83,6 +88,9 @@ typedef union {
|
||||
static const afl_log_code_asm_t template =
|
||||
{
|
||||
|
||||
.b_imm8 = 0x14000011,
|
||||
|
||||
.restoration_prolog = 0xa8c947f0,
|
||||
.stp_x0_x1 = 0xa93607e0,
|
||||
|
||||
.adrp_x0_prev_loc1 = 0x90000000,
|
||||
@ -107,9 +115,6 @@ static const afl_log_code_asm_t template =
|
||||
|
||||
.ldp_x0_x1 = 0xa97607e0,
|
||||
|
||||
.b_imm8 = 0x14000002,
|
||||
.restoration_prolog = 0xa8c947f0,
|
||||
|
||||
}
|
||||
|
||||
;
|
||||
@ -120,6 +125,112 @@ gboolean instrument_is_coverage_optimize_supported(void) {
|
||||
|
||||
}
|
||||
|
||||
static gboolean instrument_is_deterministic(const cs_insn *from_insn) {
|
||||
|
||||
cs_arm64 *arm64;
|
||||
arm64_cc cc;
|
||||
|
||||
if (from_insn == NULL) { return FALSE; }
|
||||
|
||||
arm64 = &from_insn->detail->arm64;
|
||||
cc = arm64->cc;
|
||||
|
||||
switch (from_insn->id) {
|
||||
|
||||
case ARM64_INS_B:
|
||||
case ARM64_INS_BL:
|
||||
if (cc == ARM64_CC_INVALID) { return TRUE; }
|
||||
break;
|
||||
|
||||
case ARM64_INS_RET:
|
||||
case ARM64_INS_RETAA:
|
||||
case ARM64_INS_RETAB:
|
||||
if (arm64->op_count == 0) { return TRUE; }
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
static void instrument_coverage_switch(GumStalkerObserver *self,
|
||||
gpointer from_address,
|
||||
gpointer start_address,
|
||||
const cs_insn *from_insn,
|
||||
gpointer *target) {
|
||||
|
||||
UNUSED_PARAMETER(self);
|
||||
UNUSED_PARAMETER(from_address);
|
||||
UNUSED_PARAMETER(start_address);
|
||||
|
||||
gsize fixup_offset;
|
||||
|
||||
if (!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target)) &&
|
||||
!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target + 4))) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (instrument_is_deterministic(from_insn)) { return; }
|
||||
|
||||
/*
|
||||
* Since each block is prefixed with a restoration prologue, we need to be
|
||||
* able to begin execution at an offset into the block and execute both this
|
||||
* restoration prologue and the instrumented block without the coverage code.
|
||||
* We therefore layout our block as follows:
|
||||
*
|
||||
* +-----+------------------+-----+--------------------------+-------------+
|
||||
* | LDP | BR <TARGET CODE> | LDP | COVERAGE INSTRUMENTATION | TARGET CODE |
|
||||
* +-----+------------------+-----+--------------------------+-------------+
|
||||
*
|
||||
* ^ ^ ^ ^
|
||||
* | | | |
|
||||
* A B C D
|
||||
*
|
||||
* Without instrumentation suppression, the block is either executed at point
|
||||
* (C) if it is reached by an indirect branch (and registers need to be
|
||||
* restored) or point (D) if it is reached by an direct branch (and hence the
|
||||
* registers don't need restoration). Similarly, we can start execution of the
|
||||
* block at points (A) or (B) to achieve the same functionality, but without
|
||||
* executing the coverage instrumentation.
|
||||
*
|
||||
* In either case, Stalker will call us back with the address of the target
|
||||
* block to be executed as the destination. We can then check if the branch is
|
||||
* a deterministic one and if so branch to point (C) or (D) rather than (A)
|
||||
* or (B). We lay the code out in this fashion so that in the event we can't
|
||||
* suppress coverage (the most likely), we can vector directly to the coverage
|
||||
* instrumentation code and execute entirely without any branches. If we
|
||||
* suppress the coverage, we simply branch beyond it instead.
|
||||
*/
|
||||
fixup_offset = GUM_RESTORATION_PROLOG_SIZE +
|
||||
G_STRUCT_OFFSET(afl_log_code_asm_t, restoration_prolog);
|
||||
*target += fixup_offset;
|
||||
|
||||
}
|
||||
|
||||
static void instrument_coverage_suppress_init(void) {
|
||||
|
||||
static gboolean initialized = false;
|
||||
if (initialized) { return; }
|
||||
initialized = true;
|
||||
|
||||
GumStalkerObserver *observer = stalker_get_observer();
|
||||
GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer);
|
||||
iface->switch_callback = instrument_coverage_switch;
|
||||
|
||||
coverage_blocks = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
if (coverage_blocks == NULL) {
|
||||
|
||||
FATAL("Failed to g_hash_table_new, errno: %d", errno);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static gboolean instrument_coverage_in_range(gssize offset) {
|
||||
|
||||
return (offset >= G_MININT33 && offset <= G_MAXINT33);
|
||||
@ -146,11 +257,12 @@ static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize(const cs_insn * instr,
|
||||
void instrument_coverage_optimize(const cs_insn *instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
afl_log_code code = {0};
|
||||
GumArm64Writer *cw = output->writer.arm64;
|
||||
gpointer block_start;
|
||||
guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
|
||||
gsize map_size_pow2;
|
||||
gsize area_offset_ror;
|
||||
@ -160,9 +272,10 @@ void instrument_coverage_optimize(const cs_insn * instr,
|
||||
|
||||
GumAddressSpec spec = {.near_address = cw->code,
|
||||
.max_distance = 1ULL << 30};
|
||||
guint page_size = gum_query_page_size();
|
||||
|
||||
instrument_previous_pc_addr = gum_memory_allocate_near(
|
||||
&spec, sizeof(guint64), 0x1000, GUM_PAGE_READ | GUM_PAGE_WRITE);
|
||||
&spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE);
|
||||
*instrument_previous_pc_addr = instrument_hash_zero;
|
||||
FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
|
||||
FVERBOSE("code_addr: %p", cw->code);
|
||||
@ -171,8 +284,32 @@ void instrument_coverage_optimize(const cs_insn * instr,
|
||||
|
||||
// gum_arm64_writer_put_brk_imm(cw, 0x0);
|
||||
|
||||
instrument_coverage_suppress_init();
|
||||
|
||||
code_addr = cw->pc;
|
||||
|
||||
/*
|
||||
* On AARCH64, immediate branches can only be encoded with a 28-bit offset. To
|
||||
* make a longer branch, it is necessary to load a register with the target
|
||||
* address, this register must be saved beyond the red-zone before the branch
|
||||
* is taken. To restore this register each block is prefixed by Stalker with
|
||||
* an instruction to load x16,x17 from beyond the red-zone on the stack. A
|
||||
* pair of registers are saved/restored because on AARCH64, the stack pointer
|
||||
* must be 16 byte aligned. This instruction is emitted into the block before
|
||||
* the tranformer (from which we are called) is executed. If is is possible
|
||||
* for Stalker to make a direct branch (the target block is close enough), it
|
||||
* can forego pushing the registers and instead branch at an offset into the
|
||||
* block to skip this restoration prolog.
|
||||
*/
|
||||
block_start =
|
||||
GSIZE_TO_POINTER(GUM_ADDRESS(cw->code) - GUM_RESTORATION_PROLOG_SIZE);
|
||||
|
||||
if (!g_hash_table_add(coverage_blocks, block_start)) {
|
||||
|
||||
FATAL("Failed - g_hash_table_add");
|
||||
|
||||
}
|
||||
|
||||
code.code = template;
|
||||
|
||||
/*
|
||||
@ -209,6 +346,14 @@ void instrument_coverage_optimize(const cs_insn * instr,
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize_insn(const cs_insn *instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(output);
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize_init(void) {
|
||||
|
||||
char *shm_env = getenv(SHM_ENV_VAR);
|
||||
@ -239,5 +384,65 @@ gpointer instrument_cur(GumStalkerOutput *output) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_config(void) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_init(void) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
|
||||
|
||||
UNUSED_PARAMETER(real_address);
|
||||
UNUSED_PARAMETER(code_address);
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(output);
|
||||
|
||||
}
|
||||
|
||||
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
|
||||
|
||||
int fd = (int)(size_t)user_data;
|
||||
instrument_regs_format(
|
||||
fd, "x0 : 0x%016x, x1 : 0x%016x, x2 : 0x%016x, x3 : 0x%016x\n",
|
||||
cpu_context->x[0], cpu_context->x[1], cpu_context->x[2],
|
||||
cpu_context->x[3]);
|
||||
instrument_regs_format(
|
||||
fd, "x4 : 0x%016x, x5 : 0x%016x, x6 : 0x%016x, x7 : 0x%016x\n",
|
||||
cpu_context->x[4], cpu_context->x[5], cpu_context->x[6],
|
||||
cpu_context->x[7]);
|
||||
instrument_regs_format(
|
||||
fd, "x8 : 0x%016x, x9 : 0x%016x, x10: 0x%016x, x11: 0x%016x\n",
|
||||
cpu_context->x[8], cpu_context->x[9], cpu_context->x[10],
|
||||
cpu_context->x[11]);
|
||||
instrument_regs_format(
|
||||
fd, "x12: 0x%016x, x13: 0x%016x, x14: 0x%016x, x15: 0x%016x\n",
|
||||
cpu_context->x[12], cpu_context->x[13], cpu_context->x[14],
|
||||
cpu_context->x[15]);
|
||||
instrument_regs_format(
|
||||
fd, "x16: 0x%016x, x17: 0x%016x, x18: 0x%016x, x19: 0x%016x\n",
|
||||
cpu_context->x[16], cpu_context->x[17], cpu_context->x[18],
|
||||
cpu_context->x[19]);
|
||||
instrument_regs_format(
|
||||
fd, "x20: 0x%016x, x21: 0x%016x, x22: 0x%016x, x23: 0x%016x\n",
|
||||
cpu_context->x[20], cpu_context->x[21], cpu_context->x[22],
|
||||
cpu_context->x[23]);
|
||||
instrument_regs_format(
|
||||
fd, "x24: 0x%016x, x25: 0x%016x, x26: 0x%016x, x27: 0x%016x\n",
|
||||
cpu_context->x[24], cpu_context->x[25], cpu_context->x[26],
|
||||
cpu_context->x[27]);
|
||||
instrument_regs_format(
|
||||
fd, "x28: 0x%016x, fp : 0x%016x, lr : 0x%016x, sp : 0x%016x\n",
|
||||
cpu_context->x[28], cpu_context->fp, cpu_context->lr, cpu_context->sp);
|
||||
instrument_regs_format(fd, "pc : 0x%016x\n\n", cpu_context->pc);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "util.h"
|
||||
|
||||
char *instrument_coverage_filename = NULL;
|
||||
bool instrument_coverage_absolute = false;
|
||||
|
||||
static int normal_coverage_fd = -1;
|
||||
static int normal_coverage_pipes[2] = {-1, -1};
|
||||
@ -17,7 +18,7 @@ static int unstable_coverage_fd = -1;
|
||||
static int unstable_coverage_pipes[2] = {-1, -1};
|
||||
|
||||
static uint64_t normal_coverage_last_start = 0;
|
||||
static gchar * unstable_coverage_fuzzer_stats = NULL;
|
||||
static gchar *unstable_coverage_fuzzer_stats = NULL;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@ -68,7 +69,7 @@ typedef struct {
|
||||
static gboolean coverage_range(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
GArray * coverage_ranges = (GArray *)user_data;
|
||||
GArray *coverage_ranges = (GArray *)user_data;
|
||||
coverage_range_t coverage = {0};
|
||||
|
||||
if (details->file == NULL) { return TRUE; }
|
||||
@ -210,8 +211,8 @@ static GArray *coverage_get_modules(void) {
|
||||
static void instrument_coverage_mark(void *key, void *value, void *user_data) {
|
||||
|
||||
UNUSED_PARAMETER(key);
|
||||
coverage_mark_ctx_t * ctx = (coverage_mark_ctx_t *)user_data;
|
||||
GArray * coverage_modules = ctx->modules;
|
||||
coverage_mark_ctx_t *ctx = (coverage_mark_ctx_t *)user_data;
|
||||
GArray *coverage_modules = ctx->modules;
|
||||
normal_coverage_data_t *val = (normal_coverage_data_t *)value;
|
||||
guint i;
|
||||
|
||||
@ -237,6 +238,18 @@ static void instrument_coverage_mark(void *key, void *value, void *user_data) {
|
||||
|
||||
}
|
||||
|
||||
static void instrument_coverage_mark_first(void *key, void *value,
|
||||
void *user_data) {
|
||||
|
||||
UNUSED_PARAMETER(key);
|
||||
coverage_range_t *module = (coverage_range_t *)user_data;
|
||||
normal_coverage_data_t *val = (normal_coverage_data_t *)value;
|
||||
|
||||
val->module = module;
|
||||
module->count++;
|
||||
|
||||
}
|
||||
|
||||
static void coverage_write(int fd, void *data, size_t size) {
|
||||
|
||||
ssize_t written;
|
||||
@ -289,9 +302,9 @@ static void coverage_write_modules(int fd, GArray *coverage_modules) {
|
||||
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", module->base_address);
|
||||
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", module->limit);
|
||||
/* entry */
|
||||
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0);
|
||||
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0UL);
|
||||
/* checksum */
|
||||
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0);
|
||||
coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0UL);
|
||||
/* timestamp */
|
||||
coverage_format(fd, "%08" G_GINT32_MODIFIER "X, ", 0);
|
||||
coverage_format(fd, "%s\n", module->path);
|
||||
@ -317,6 +330,12 @@ static void coverage_write_events(void *key, void *value, void *user_data) {
|
||||
|
||||
};
|
||||
|
||||
#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
evt.offset = __builtin_bswap32(evt.offset);
|
||||
evt.length = __builtin_bswap16(evt.length);
|
||||
evt.module = __builtin_bswap16(evt.module);
|
||||
#endif
|
||||
|
||||
coverage_write(fd, &evt, sizeof(coverage_event_t));
|
||||
|
||||
}
|
||||
@ -398,35 +417,76 @@ static void instrument_coverage_normal_run() {
|
||||
|
||||
instrument_coverage_print("Coverage - Preparing\n");
|
||||
|
||||
GArray *coverage_modules = coverage_get_modules();
|
||||
if (instrument_coverage_absolute) {
|
||||
|
||||
guint size = g_hash_table_size(coverage_hash);
|
||||
instrument_coverage_print("Coverage - Total Entries: %u\n", size);
|
||||
guint size = g_hash_table_size(coverage_hash);
|
||||
instrument_coverage_print("Coverage - Total Entries: %u\n", size);
|
||||
|
||||
coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
|
||||
coverage_range_t module = {
|
||||
|
||||
g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx);
|
||||
instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
|
||||
.base_address = GUM_ADDRESS(0),
|
||||
.limit = GUM_ADDRESS(-1),
|
||||
.size = GUM_ADDRESS(-1),
|
||||
.path = "absolute",
|
||||
.offset = 0,
|
||||
.is_executable = true,
|
||||
.count = size,
|
||||
.id = 0,
|
||||
|
||||
guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
|
||||
instrument_coverage_print("Coverage - Marked Modules: %u\n",
|
||||
coverage_marked_modules);
|
||||
};
|
||||
|
||||
coverage_write_header(normal_coverage_fd, coverage_marked_modules);
|
||||
coverage_write_modules(normal_coverage_fd, coverage_modules);
|
||||
coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", ctx.count);
|
||||
g_hash_table_foreach(coverage_hash, coverage_write_events,
|
||||
&normal_coverage_fd);
|
||||
instrument_coverage_print("Coverage Module - 0x%016" G_GINT64_MODIFIER
|
||||
"X - 0x%016" G_GINT64_MODIFIER "X (%s)\n",
|
||||
module.base_address, module.limit, module.path);
|
||||
|
||||
GArray *coverage_modules =
|
||||
g_array_sized_new(false, false, sizeof(coverage_range_t), 1);
|
||||
g_array_append_val(coverage_modules, module);
|
||||
|
||||
g_hash_table_foreach(coverage_hash, instrument_coverage_mark_first,
|
||||
&module);
|
||||
|
||||
coverage_write_header(normal_coverage_fd, 1);
|
||||
coverage_write_modules(normal_coverage_fd, coverage_modules);
|
||||
coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", size);
|
||||
g_hash_table_foreach(coverage_hash, coverage_write_events,
|
||||
&normal_coverage_fd);
|
||||
|
||||
} else {
|
||||
|
||||
GArray *coverage_modules = coverage_get_modules();
|
||||
|
||||
guint size = g_hash_table_size(coverage_hash);
|
||||
instrument_coverage_print("Coverage - Total Entries: %u\n", size);
|
||||
|
||||
coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
|
||||
|
||||
/* For each coverage event in the hashtable associate it with a module and
|
||||
* count the number of entries per module */
|
||||
g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx);
|
||||
instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
|
||||
|
||||
/* For each module with coverage events assign it an incrementing number */
|
||||
guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
|
||||
instrument_coverage_print("Coverage - Marked Modules: %u\n",
|
||||
coverage_marked_modules);
|
||||
|
||||
coverage_write_header(normal_coverage_fd, coverage_marked_modules);
|
||||
coverage_write_modules(normal_coverage_fd, coverage_modules);
|
||||
coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", ctx.count);
|
||||
g_hash_table_foreach(coverage_hash, coverage_write_events,
|
||||
&normal_coverage_fd);
|
||||
|
||||
}
|
||||
|
||||
g_hash_table_unref(coverage_hash);
|
||||
|
||||
instrument_coverage_print("Coverage - Completed\n");
|
||||
|
||||
}
|
||||
|
||||
static GArray *instrument_coverage_unstable_read_unstable_ids(void) {
|
||||
|
||||
gchar * contents = NULL;
|
||||
gchar *contents = NULL;
|
||||
gsize length = 0;
|
||||
GArray *unstable_edge_ids =
|
||||
g_array_sized_new(false, false, sizeof(gpointer), 100);
|
||||
@ -533,7 +593,7 @@ static GHashTable *instrument_collect_unstable_blocks(
|
||||
while (g_hash_table_iter_next(&iter, NULL, &value)) {
|
||||
|
||||
unstable_coverage_data_t *unstable = (unstable_coverage_data_t *)value;
|
||||
normal_coverage_data_t * from =
|
||||
normal_coverage_data_t *from =
|
||||
gum_malloc0(sizeof(normal_coverage_data_t));
|
||||
normal_coverage_data_t *to = gum_malloc0(sizeof(normal_coverage_data_t));
|
||||
from->start = unstable->from;
|
||||
@ -616,8 +676,6 @@ static void instrument_coverage_unstable_run(void) {
|
||||
|
||||
instrument_coverage_print("Coverage - Preparing\n");
|
||||
|
||||
GArray *coverage_modules = coverage_get_modules();
|
||||
|
||||
instrument_coverage_print("Found edges: %u\n", edges);
|
||||
|
||||
GArray *unstable_edge_ids = instrument_coverage_unstable_read_unstable_ids();
|
||||
@ -628,20 +686,60 @@ static void instrument_coverage_unstable_run(void) {
|
||||
guint size = g_hash_table_size(unstable_blocks);
|
||||
instrument_coverage_print("Unstable blocks: %u\n", size);
|
||||
|
||||
coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
|
||||
if (instrument_coverage_absolute) {
|
||||
|
||||
g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx);
|
||||
instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
|
||||
instrument_coverage_print("Coverage - Total Entries: %u\n", size);
|
||||
|
||||
guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
|
||||
instrument_coverage_print("Coverage - Marked Modules: %u\n",
|
||||
coverage_marked_modules);
|
||||
coverage_range_t module = {
|
||||
|
||||
coverage_write_header(unstable_coverage_fd, coverage_marked_modules);
|
||||
coverage_write_modules(unstable_coverage_fd, coverage_modules);
|
||||
coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", ctx.count);
|
||||
g_hash_table_foreach(unstable_blocks, coverage_write_events,
|
||||
&unstable_coverage_fd);
|
||||
.base_address = GUM_ADDRESS(0),
|
||||
.limit = GUM_ADDRESS(-1),
|
||||
.size = GUM_ADDRESS(-1),
|
||||
.path = "absolute",
|
||||
.offset = 0,
|
||||
.is_executable = true,
|
||||
.count = size,
|
||||
.id = 0,
|
||||
|
||||
};
|
||||
|
||||
instrument_coverage_print("Coverage Module - 0x%016" G_GINT64_MODIFIER
|
||||
"X - 0x%016" G_GINT64_MODIFIER "X (%s)\n",
|
||||
module.base_address, module.limit, module.path);
|
||||
|
||||
GArray *coverage_modules =
|
||||
g_array_sized_new(false, false, sizeof(coverage_range_t), 1);
|
||||
g_array_append_val(coverage_modules, module);
|
||||
|
||||
g_hash_table_foreach(unstable_blocks, instrument_coverage_mark_first,
|
||||
&module);
|
||||
|
||||
coverage_write_header(unstable_coverage_fd, 1);
|
||||
coverage_write_modules(unstable_coverage_fd, coverage_modules);
|
||||
coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", size);
|
||||
g_hash_table_foreach(unstable_blocks, coverage_write_events,
|
||||
&unstable_coverage_fd);
|
||||
|
||||
} else {
|
||||
|
||||
GArray *coverage_modules = coverage_get_modules();
|
||||
|
||||
coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
|
||||
|
||||
g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx);
|
||||
instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
|
||||
|
||||
guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
|
||||
instrument_coverage_print("Coverage - Marked Modules: %u\n",
|
||||
coverage_marked_modules);
|
||||
|
||||
coverage_write_header(unstable_coverage_fd, coverage_marked_modules);
|
||||
coverage_write_modules(unstable_coverage_fd, coverage_modules);
|
||||
coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", ctx.count);
|
||||
g_hash_table_foreach(unstable_blocks, coverage_write_events,
|
||||
&unstable_coverage_fd);
|
||||
|
||||
}
|
||||
|
||||
g_hash_table_unref(unstable_blocks);
|
||||
g_array_free(unstable_edge_ids, TRUE);
|
||||
@ -654,6 +752,8 @@ static void instrument_coverage_unstable_run(void) {
|
||||
void instrument_coverage_config(void) {
|
||||
|
||||
instrument_coverage_filename = getenv("AFL_FRIDA_INST_COVERAGE_FILE");
|
||||
instrument_coverage_absolute =
|
||||
(getenv("AFL_FRIDA_INST_COVERAGE_ABSOLUTE") != NULL);
|
||||
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ static void instrument_disasm(guint8 *start, guint8 *end,
|
||||
|
||||
instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t* 0x%016" G_GSIZE_MODIFIER
|
||||
"x\n",
|
||||
curr, *(size_t *)curr);
|
||||
(uint64_t)(size_t)curr, *(size_t *)curr);
|
||||
|
||||
len += sizeof(size_t);
|
||||
continue;
|
||||
|
@ -23,13 +23,39 @@
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
#ifndef MAP_FIXED_NOREPLACE
|
||||
#ifdef MAP_EXCL
|
||||
#define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
|
||||
#else
|
||||
#define MAP_FIXED_NOREPLACE MAP_FIXED
|
||||
#endif
|
||||
#endif
|
||||
enum jcc_opcodes {
|
||||
|
||||
OPC_JO = 0x70,
|
||||
OPC_JNO = 0x71,
|
||||
OPC_JB = 0x72,
|
||||
OPC_JAE = 0x73,
|
||||
OPC_JE = 0x74,
|
||||
OPC_JNE = 0x75,
|
||||
OPC_JBE = 0x76,
|
||||
OPC_JA = 0x77,
|
||||
OPC_JS = 0x78,
|
||||
OPC_JNS = 0x79,
|
||||
OPC_JP = 0x7a,
|
||||
OPC_JNP = 0x7b,
|
||||
OPC_JL = 0x7c,
|
||||
OPC_JGE = 0x7d,
|
||||
OPC_JLE = 0x7e,
|
||||
OPC_JG = 0x7f,
|
||||
|
||||
};
|
||||
|
||||
typedef union {
|
||||
|
||||
struct {
|
||||
|
||||
uint8_t opcode;
|
||||
uint8_t distance;
|
||||
|
||||
};
|
||||
|
||||
uint8_t bytes[0];
|
||||
|
||||
} jcc_insn;
|
||||
|
||||
static GHashTable *coverage_blocks = NULL;
|
||||
|
||||
@ -45,8 +71,7 @@ static gboolean instrument_coverage_in_range(gssize offset) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#pragma pack(push, 1)
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
|
||||
@ -54,21 +79,28 @@ typedef struct {
|
||||
// shared_mem[cur_location ^ prev_location]++;
|
||||
// prev_location = cur_location >> 1;
|
||||
|
||||
// mov QWORD PTR [rsp-0x80],rax
|
||||
// lahf
|
||||
// mov QWORD PTR [rsp-0x88],rax
|
||||
// mov QWORD PTR [rsp-0x90],rbx
|
||||
// mov eax,DWORD PTR [rip+0x333d5a] # 0x7ffff6ff2740
|
||||
// mov DWORD PTR [rip+0x333d3c],0x9fbb # 0x7ffff6ff2740
|
||||
// lea rax,[rip + 0x103f77]
|
||||
// mov bl,BYTE PTR [rax]
|
||||
// add bl,0x1
|
||||
// adc bl,0x0
|
||||
// mov BYTE PTR [rax],bl
|
||||
// mov rbx,QWORD PTR [rsp-0x90]
|
||||
// mov rax,QWORD PTR [rsp-0x88]
|
||||
// sahf
|
||||
// mov rax,QWORD PTR [rsp-0x80]
|
||||
// mov QWORD PTR [rsp-0x88],rax
|
||||
// lahf
|
||||
// mov QWORD PTR [rsp-0x90],rax
|
||||
// mov QWORD PTR [rsp-0x98],rbx
|
||||
|
||||
// mov eax,DWORD PTR [rip+0x1312334]
|
||||
// xor eax,0x3f77
|
||||
|
||||
// lea rbx,[rip+0x132338]
|
||||
// add rax,rbx
|
||||
|
||||
// mov bl,BYTE PTR [rax]
|
||||
// add bl,0x1
|
||||
// adc bl,0x0
|
||||
// mov BYTE PTR [rax],bl
|
||||
|
||||
// mov rbx,QWORD PTR [rsp-0x98]
|
||||
// mov rax,QWORD PTR [rsp-0x90]
|
||||
// sahf
|
||||
// mov rax,QWORD PTR [rsp-0x88]
|
||||
|
||||
// mov DWORD PTR [rip+0x13122f8],0x9fbb
|
||||
|
||||
uint8_t mov_rax_rsp_88[8];
|
||||
uint8_t lahf;
|
||||
@ -76,84 +108,11 @@ typedef struct {
|
||||
uint8_t mov_rbx_rsp_98[8];
|
||||
|
||||
uint8_t mov_eax_prev_loc[6];
|
||||
uint8_t mov_prev_loc_curr_loc_shr1[10];
|
||||
|
||||
uint8_t leax_eax_curr_loc[7];
|
||||
|
||||
uint8_t mov_rbx_ptr_rax[2];
|
||||
uint8_t add_bl_1[3];
|
||||
uint8_t adc_bl_0[3];
|
||||
uint8_t mov_ptr_rax_rbx[2];
|
||||
|
||||
uint8_t mov_rsp_98_rbx[8];
|
||||
uint8_t mov_rsp_90_rax[8];
|
||||
uint8_t sahf;
|
||||
uint8_t mov_rsp_88_rax[8];
|
||||
|
||||
} afl_log_code_asm_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static const afl_log_code_asm_t template =
|
||||
{
|
||||
|
||||
.mov_rax_rsp_88 = {0x48, 0x89, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
|
||||
.lahf = 0x9f,
|
||||
.mov_rax_rsp_90 = {0x48, 0x89, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF},
|
||||
.mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
|
||||
|
||||
.mov_eax_prev_loc = {0x8b, 0x05},
|
||||
.mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05},
|
||||
|
||||
.leax_eax_curr_loc = {0x48, 0x8d, 0x05},
|
||||
.mov_rbx_ptr_rax = {0x8a, 0x18},
|
||||
.add_bl_1 = {0x80, 0xc3, 0x01},
|
||||
.adc_bl_0 = {0x80, 0xd3, 0x00},
|
||||
.mov_ptr_rax_rbx = {0x88, 0x18},
|
||||
|
||||
.mov_rsp_98_rbx = {0x48, 0x8B, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
|
||||
.mov_rsp_90_rax = {0x48, 0x8B, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF},
|
||||
.sahf = 0x9e,
|
||||
.mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
|
||||
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
|
||||
// cur_location = (block_address >> 4) ^ (block_address << 8);
|
||||
// shared_mem[cur_location ^ prev_location]++;
|
||||
// prev_location = cur_location >> 1;
|
||||
|
||||
// mov QWORD PTR [rsp-0x80],rax
|
||||
// lahf
|
||||
// mov QWORD PTR [rsp-0x88],rax
|
||||
// mov QWORD PTR [rsp-0x90],rbx
|
||||
// mov eax,DWORD PTR [rip+0x333d5a] # 0x7ffff6ff2740
|
||||
// mov DWORD PTR [rip+0x333d3c],0x9fbb # 0x7ffff6ff2740
|
||||
// xor eax,0x103f77
|
||||
// mov bl,BYTE PTR [rax]
|
||||
// add bl,0x1
|
||||
// adc bl,0x0
|
||||
// mov BYTE PTR [rax],bl
|
||||
// mov rbx,QWORD PTR [rsp-0x90]
|
||||
// mov rax,QWORD PTR [rsp-0x88]
|
||||
// sahf
|
||||
// mov rax,QWORD PTR [rsp-0x80]
|
||||
|
||||
uint8_t mov_rax_rsp_88[8];
|
||||
uint8_t lahf;
|
||||
uint8_t mov_rax_rsp_90[8];
|
||||
uint8_t mov_rbx_rsp_98[8];
|
||||
|
||||
uint8_t mov_eax_prev_loc[6];
|
||||
uint8_t mov_prev_loc_curr_loc_shr1[10];
|
||||
|
||||
uint8_t xor_eax_curr_loc[5];
|
||||
|
||||
uint8_t lea_rbx_area_ptr[7];
|
||||
uint8_t add_rax_rbx[3];
|
||||
|
||||
uint8_t mov_rbx_ptr_rax[2];
|
||||
uint8_t add_bl_1[3];
|
||||
uint8_t adc_bl_0[3];
|
||||
@ -164,9 +123,11 @@ typedef struct {
|
||||
uint8_t sahf;
|
||||
uint8_t mov_rsp_88_rax[8];
|
||||
|
||||
uint8_t mov_prev_loc_curr_loc_shr1[10];
|
||||
|
||||
} afl_log_code_asm_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
#pragma pack(pop)
|
||||
|
||||
static const afl_log_code_asm_t template =
|
||||
{
|
||||
@ -177,9 +138,10 @@ static const afl_log_code_asm_t template =
|
||||
.mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
|
||||
|
||||
.mov_eax_prev_loc = {0x8b, 0x05},
|
||||
.mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05},
|
||||
|
||||
.xor_eax_curr_loc = {0x35},
|
||||
.lea_rbx_area_ptr = {0x48, 0x8d, 0x1d},
|
||||
.add_rax_rbx = {0x48, 0x01, 0xd8},
|
||||
|
||||
.mov_rbx_ptr_rax = {0x8a, 0x18},
|
||||
.add_bl_1 = {0x80, 0xc3, 0x01},
|
||||
.adc_bl_0 = {0x80, 0xd3, 0x00},
|
||||
@ -190,10 +152,11 @@ static const afl_log_code_asm_t template =
|
||||
.sahf = 0x9e,
|
||||
.mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
|
||||
|
||||
.mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05},
|
||||
|
||||
}
|
||||
|
||||
;
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
|
||||
@ -202,180 +165,22 @@ typedef union {
|
||||
|
||||
} afl_log_code;
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
void instrument_coverage_optimize_init(void) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static gboolean instrument_coverage_find_low(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
static GumAddress last_limit = (64ULL << 10);
|
||||
gpointer * address = (gpointer *)user_data;
|
||||
|
||||
last_limit = GUM_ALIGN_SIZE(last_limit, __afl_map_size);
|
||||
|
||||
if ((details->range->base_address - last_limit) > __afl_map_size) {
|
||||
|
||||
*address = GSIZE_TO_POINTER(last_limit);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
if (details->range->base_address > ((2ULL << 30) - __afl_map_size)) {
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Align our buffer on a 64k boundary so that the low 16-bits of the address
|
||||
* are zero, then we can just XOR the base address in, when we XOR with the
|
||||
* current block ID.
|
||||
*/
|
||||
last_limit = GUM_ALIGN_SIZE(
|
||||
details->range->base_address + details->range->size, __afl_map_size);
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static void instrument_coverage_optimize_map_mmap_anon(gpointer address) {
|
||||
|
||||
__afl_area_ptr =
|
||||
mmap(address, __afl_map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if (__afl_area_ptr != address) {
|
||||
|
||||
FATAL("Failed to map mmap __afl_area_ptr: %d", errno);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void instrument_coverage_optimize_map_mmap(char * shm_file_path,
|
||||
gpointer address) {
|
||||
|
||||
int shm_fd = -1;
|
||||
|
||||
if (munmap(__afl_area_ptr, __afl_map_size) != 0) {
|
||||
|
||||
FATAL("Failed to unmap previous __afl_area_ptr");
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr = NULL;
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
|
||||
if (shm_fd == -1) { FATAL("shm_open() failed\n"); }
|
||||
#else
|
||||
shm_fd = open("/dev/ashmem", O_RDWR);
|
||||
if (shm_fd == -1) { FATAL("open() failed\n"); }
|
||||
if (ioctl(shm_fd, ASHMEM_SET_NAME, shm_file_path) == -1) {
|
||||
|
||||
FATAL("ioctl(ASHMEM_SET_NAME) failed");
|
||||
|
||||
}
|
||||
|
||||
if (ioctl(shm_fd, ASHMEM_SET_SIZE, __afl_map_size) == -1) {
|
||||
|
||||
FATAL("ioctl(ASHMEM_SET_SIZE) failed");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
__afl_area_ptr = mmap(address, __afl_map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED_NOREPLACE | MAP_SHARED, shm_fd, 0);
|
||||
if (__afl_area_ptr != address) {
|
||||
|
||||
FATAL("Failed to map mmap __afl_area_ptr: %d", errno);
|
||||
|
||||
}
|
||||
|
||||
if (close(shm_fd) != 0) { FATAL("Failed to close shm_fd"); }
|
||||
|
||||
}
|
||||
|
||||
static void instrument_coverage_optimize_map_shm(guint64 shm_env_val,
|
||||
gpointer address) {
|
||||
|
||||
if (shmdt(__afl_area_ptr) != 0) {
|
||||
|
||||
FATAL("Failed to detach previous __afl_area_ptr");
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr = shmat(shm_env_val, address, 0);
|
||||
if (__afl_area_ptr != address) {
|
||||
|
||||
FATAL("Failed to map shm __afl_area_ptr: %d", errno);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize_init(void) {
|
||||
|
||||
gpointer low_address = NULL;
|
||||
|
||||
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, instrument_coverage_find_low,
|
||||
&low_address);
|
||||
|
||||
FVERBOSE("Low address: %p", low_address);
|
||||
|
||||
if (low_address == 0 ||
|
||||
GPOINTER_TO_SIZE(low_address) > ((2UL << 30) - __afl_map_size)) {
|
||||
|
||||
FATAL("Invalid low_address: %p", low_address);
|
||||
|
||||
}
|
||||
|
||||
ranges_print_debug_maps();
|
||||
|
||||
char *shm_env = getenv(SHM_ENV_VAR);
|
||||
FVERBOSE("SHM_ENV_VAR: %s", shm_env);
|
||||
|
||||
if (shm_env == NULL) {
|
||||
|
||||
FWARNF("SHM_ENV_VAR not set, using anonymous map for debugging purposes");
|
||||
|
||||
instrument_coverage_optimize_map_mmap_anon(low_address);
|
||||
|
||||
} else {
|
||||
|
||||
guint64 shm_env_val = g_ascii_strtoull(shm_env, NULL, 10);
|
||||
|
||||
if (shm_env_val == 0) {
|
||||
|
||||
instrument_coverage_optimize_map_mmap(shm_env, low_address);
|
||||
|
||||
} else {
|
||||
|
||||
instrument_coverage_optimize_map_shm(shm_env_val, low_address);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void instrument_coverage_switch(GumStalkerObserver *self,
|
||||
gpointer from_address,
|
||||
gpointer start_address,
|
||||
const cs_insn * from_insn,
|
||||
gpointer * target) {
|
||||
const cs_insn *from_insn,
|
||||
gpointer *target) {
|
||||
|
||||
UNUSED_PARAMETER(self);
|
||||
UNUSED_PARAMETER(start_address);
|
||||
UNUSED_PARAMETER(from_address);
|
||||
|
||||
cs_x86 * x86;
|
||||
cs_x86 *x86;
|
||||
cs_x86_op *op;
|
||||
if (from_insn == NULL) { return; }
|
||||
|
||||
@ -398,10 +203,17 @@ static void instrument_coverage_switch(GumStalkerObserver *self,
|
||||
|
||||
}
|
||||
|
||||
if (op[0].type != X86_OP_IMM) { return; }
|
||||
if (op[0].type != X86_OP_IMM) {
|
||||
|
||||
instrument_cache_insert(start_address, *target);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
case X86_INS_RET:
|
||||
instrument_cache_insert(start_address,
|
||||
(guint8 *)*target + sizeof(afl_log_code));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -418,7 +230,7 @@ static void instrument_coverage_suppress_init(void) {
|
||||
if (initialized) { return; }
|
||||
initialized = true;
|
||||
|
||||
GumStalkerObserver * observer = stalker_get_observer();
|
||||
GumStalkerObserver *observer = stalker_get_observer();
|
||||
GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer);
|
||||
iface->switch_callback = instrument_coverage_switch;
|
||||
|
||||
@ -431,48 +243,19 @@ static void instrument_coverage_suppress_init(void) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize(const cs_insn * instr,
|
||||
GumStalkerOutput *output) {
|
||||
static void instrument_coverage_write(GumAddress address,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
afl_log_code code = {0};
|
||||
GumX86Writer *cw = output->writer.x86;
|
||||
guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
|
||||
gsize map_size_pow2;
|
||||
gsize area_offset_ror;
|
||||
GumAddress code_addr = 0;
|
||||
if (instrument_previous_pc_addr == NULL) {
|
||||
|
||||
GumAddressSpec spec = {.near_address = cw->code,
|
||||
.max_distance = 1ULL << 30};
|
||||
|
||||
instrument_previous_pc_addr = gum_memory_allocate_near(
|
||||
&spec, sizeof(guint64), 0x1000, GUM_PAGE_READ | GUM_PAGE_WRITE);
|
||||
*instrument_previous_pc_addr = instrument_hash_zero;
|
||||
FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
|
||||
FVERBOSE("code_addr: %p", cw->code);
|
||||
|
||||
}
|
||||
|
||||
instrument_coverage_suppress_init();
|
||||
|
||||
// gum_x86_writer_put_breakpoint(cw);
|
||||
code_addr = cw->pc;
|
||||
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
|
||||
|
||||
FATAL("Failed - g_hash_table_add");
|
||||
|
||||
}
|
||||
guint64 area_offset = instrument_get_offset_hash(address);
|
||||
gsize map_size_pow2;
|
||||
gsize area_offset_ror;
|
||||
GumAddress code_addr = cw->pc;
|
||||
|
||||
code.code = template;
|
||||
|
||||
gssize curr_loc_shr_1_offset =
|
||||
offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
|
||||
sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32);
|
||||
|
||||
map_size_pow2 = util_log2(__afl_map_size);
|
||||
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
|
||||
|
||||
*((guint32 *)&code.bytes[curr_loc_shr_1_offset]) = (guint32)(area_offset_ror);
|
||||
/* mov_prev_loc_curr_loc_shr1 */
|
||||
|
||||
gssize prev_loc_value =
|
||||
GPOINTER_TO_SIZE(instrument_previous_pc_addr) -
|
||||
@ -490,6 +273,8 @@ void instrument_coverage_optimize(const cs_insn * instr,
|
||||
|
||||
*((gint *)&code.bytes[prev_loc_value_offset]) = (gint)prev_loc_value;
|
||||
|
||||
/* mov_eax_prev_loc */
|
||||
|
||||
gssize prev_loc_value2 =
|
||||
GPOINTER_TO_SIZE(instrument_previous_pc_addr) -
|
||||
(code_addr + offsetof(afl_log_code, code.mov_eax_prev_loc) +
|
||||
@ -505,40 +290,172 @@ void instrument_coverage_optimize(const cs_insn * instr,
|
||||
|
||||
*((gint *)&code.bytes[prev_loc_value_offset2]) = (gint)prev_loc_value2;
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
gssize xor_curr_loc_offset = offsetof(afl_log_code, code.leax_eax_curr_loc) +
|
||||
sizeof(code.code.leax_eax_curr_loc) -
|
||||
sizeof(guint32);
|
||||
|
||||
gssize xor_curr_loc_value =
|
||||
((GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset) -
|
||||
(code_addr + offsetof(afl_log_code, code.mov_eax_prev_loc) +
|
||||
sizeof(code.code.mov_eax_prev_loc)));
|
||||
|
||||
if (!instrument_coverage_in_range(xor_curr_loc_value)) {
|
||||
|
||||
FATAL("Patch out of range (xor_curr_loc_value): 0x%016lX",
|
||||
xor_curr_loc_value);
|
||||
|
||||
}
|
||||
|
||||
*((guint32 *)&code.bytes[xor_curr_loc_offset]) = xor_curr_loc_value;
|
||||
|
||||
#else
|
||||
/* xor_eax_curr_loc */
|
||||
|
||||
gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) +
|
||||
sizeof(code.code.xor_eax_curr_loc) -
|
||||
sizeof(guint32);
|
||||
|
||||
*((guint32 *)&code.bytes[xor_curr_loc_offset]) =
|
||||
(guint32)(GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset);
|
||||
#endif
|
||||
*((guint32 *)&code.bytes[xor_curr_loc_offset]) = area_offset;
|
||||
|
||||
/* lea_rbx_area_ptr */
|
||||
|
||||
gssize lea_rbx_area_ptr_offset =
|
||||
offsetof(afl_log_code, code.lea_rbx_area_ptr) +
|
||||
sizeof(code.code.lea_rbx_area_ptr) - sizeof(guint32);
|
||||
|
||||
gssize lea_rbx_area_ptr_value =
|
||||
(GPOINTER_TO_SIZE(__afl_area_ptr) -
|
||||
(code_addr + offsetof(afl_log_code, code.lea_rbx_area_ptr) +
|
||||
sizeof(code.code.lea_rbx_area_ptr)));
|
||||
|
||||
if (!instrument_coverage_in_range(lea_rbx_area_ptr_value)) {
|
||||
|
||||
FATAL("Patch out of range (lea_rbx_area_ptr_value): 0x%016lX",
|
||||
lea_rbx_area_ptr_value);
|
||||
|
||||
}
|
||||
|
||||
*((guint32 *)&code.bytes[lea_rbx_area_ptr_offset]) = lea_rbx_area_ptr_value;
|
||||
|
||||
/* mov_prev_loc_curr_loc_shr1 */
|
||||
|
||||
gssize curr_loc_shr_1_offset =
|
||||
offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
|
||||
sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32);
|
||||
|
||||
map_size_pow2 = util_log2(__afl_map_size);
|
||||
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
|
||||
|
||||
*((guint32 *)&code.bytes[curr_loc_shr_1_offset]) = (guint32)(area_offset_ror);
|
||||
|
||||
gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize(const cs_insn *instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
GumX86Writer *cw = output->writer.x86;
|
||||
if (instrument_previous_pc_addr == NULL) {
|
||||
|
||||
GumAddressSpec spec = {.near_address = cw->code,
|
||||
.max_distance = 1ULL << 30};
|
||||
guint page_size = gum_query_page_size();
|
||||
|
||||
instrument_previous_pc_addr = gum_memory_allocate_near(
|
||||
&spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE);
|
||||
*instrument_previous_pc_addr = instrument_hash_zero;
|
||||
FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
|
||||
FVERBOSE("code_addr: %p", cw->code);
|
||||
|
||||
}
|
||||
|
||||
instrument_coverage_suppress_init();
|
||||
|
||||
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
|
||||
|
||||
FATAL("Failed - g_hash_table_add");
|
||||
|
||||
}
|
||||
|
||||
instrument_coverage_write(GUM_ADDRESS(instr->address), output);
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize_insn(const cs_insn *instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
GumX86Writer *cw = output->writer.x86;
|
||||
jcc_insn taken, not_taken;
|
||||
|
||||
switch (instr->id) {
|
||||
|
||||
case X86_INS_CMOVA:
|
||||
taken.opcode = OPC_JA;
|
||||
not_taken.opcode = OPC_JBE;
|
||||
break;
|
||||
case X86_INS_CMOVAE:
|
||||
taken.opcode = OPC_JAE;
|
||||
not_taken.opcode = OPC_JB;
|
||||
break;
|
||||
case X86_INS_CMOVB:
|
||||
taken.opcode = OPC_JB;
|
||||
not_taken.opcode = OPC_JAE;
|
||||
break;
|
||||
case X86_INS_CMOVBE:
|
||||
taken.opcode = OPC_JBE;
|
||||
not_taken.opcode = OPC_JA;
|
||||
break;
|
||||
case X86_INS_CMOVE:
|
||||
taken.opcode = OPC_JE;
|
||||
not_taken.opcode = OPC_JNE;
|
||||
break;
|
||||
case X86_INS_CMOVG:
|
||||
taken.opcode = OPC_JG;
|
||||
not_taken.opcode = OPC_JLE;
|
||||
break;
|
||||
case X86_INS_CMOVGE:
|
||||
taken.opcode = OPC_JGE;
|
||||
not_taken.opcode = OPC_JL;
|
||||
break;
|
||||
case X86_INS_CMOVL:
|
||||
taken.opcode = OPC_JL;
|
||||
not_taken.opcode = OPC_JGE;
|
||||
break;
|
||||
case X86_INS_CMOVLE:
|
||||
taken.opcode = OPC_JLE;
|
||||
not_taken.opcode = OPC_JG;
|
||||
break;
|
||||
case X86_INS_CMOVNE:
|
||||
taken.opcode = OPC_JNE;
|
||||
not_taken.opcode = OPC_JE;
|
||||
break;
|
||||
case X86_INS_CMOVNO:
|
||||
taken.opcode = OPC_JNO;
|
||||
not_taken.opcode = OPC_JO;
|
||||
break;
|
||||
case X86_INS_CMOVNP:
|
||||
taken.opcode = OPC_JNP;
|
||||
not_taken.opcode = OPC_JP;
|
||||
break;
|
||||
case X86_INS_CMOVNS:
|
||||
taken.opcode = OPC_JNS;
|
||||
not_taken.opcode = OPC_JS;
|
||||
break;
|
||||
case X86_INS_CMOVO:
|
||||
taken.opcode = OPC_JO;
|
||||
not_taken.opcode = OPC_JNO;
|
||||
break;
|
||||
case X86_INS_CMOVP:
|
||||
taken.opcode = OPC_JP;
|
||||
not_taken.opcode = OPC_JNP;
|
||||
break;
|
||||
case X86_INS_CMOVS:
|
||||
taken.opcode = OPC_JS;
|
||||
not_taken.opcode = OPC_JNS;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
taken.distance = sizeof(afl_log_code);
|
||||
not_taken.distance = sizeof(afl_log_code);
|
||||
|
||||
// gum_x86_writer_put_breakpoint(cw);
|
||||
|
||||
gum_x86_writer_put_bytes(cw, taken.bytes, sizeof(jcc_insn));
|
||||
instrument_coverage_write(GUM_ADDRESS(instr->address), output);
|
||||
|
||||
gum_x86_writer_put_bytes(cw, not_taken.bytes, sizeof(jcc_insn));
|
||||
instrument_coverage_write(GUM_ADDRESS(instr->address + instr->size), output);
|
||||
|
||||
FVERBOSE("Instrument - 0x%016lx: %s %s", instr->address, instr->mnemonic,
|
||||
instr->op_str);
|
||||
|
||||
}
|
||||
|
||||
void instrument_flush(GumStalkerOutput *output) {
|
||||
|
||||
gum_x86_writer_flush(output->writer.x86);
|
||||
@ -551,5 +468,24 @@ gpointer instrument_cur(GumStalkerOutput *output) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
|
||||
|
||||
int fd = (int)(size_t)user_data;
|
||||
instrument_regs_format(
|
||||
fd, "rax: 0x%016x, rbx: 0x%016x, rcx: 0x%016x, rdx: 0x%016x\n",
|
||||
cpu_context->rax, cpu_context->rbx, cpu_context->rcx, cpu_context->rdx);
|
||||
instrument_regs_format(
|
||||
fd, "rdi: 0x%016x, rsi: 0x%016x, rbp: 0x%016x, rsp: 0x%016x\n",
|
||||
cpu_context->rdi, cpu_context->rsi, cpu_context->rbp, cpu_context->rsp);
|
||||
instrument_regs_format(
|
||||
fd, "r8 : 0x%016x, r9 : 0x%016x, r10: 0x%016x, r11: 0x%016x\n",
|
||||
cpu_context->r8, cpu_context->r9, cpu_context->r10, cpu_context->r11);
|
||||
instrument_regs_format(
|
||||
fd, "r12: 0x%016x, r13: 0x%016x, r14: 0x%016x, r15: 0x%016x\n",
|
||||
cpu_context->r12, cpu_context->r13, cpu_context->r14, cpu_context->r15);
|
||||
instrument_regs_format(fd, "rip: 0x%016x\n\n", cpu_context->rip);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
435
frida_mode/src/instrument/instrument_x64_cache.c
Normal file
435
frida_mode/src/instrument/instrument_x64_cache.c
Normal file
@ -0,0 +1,435 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "instrument.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
#define INVALID 1
|
||||
#define DEFAULT_CACHE_SIZE (256ULL << 20)
|
||||
|
||||
gboolean instrument_cache_enabled = TRUE;
|
||||
gsize instrument_cache_size = DEFAULT_CACHE_SIZE;
|
||||
static gpointer *map_base = MAP_FAILED;
|
||||
|
||||
void instrument_cache_config(void) {
|
||||
|
||||
instrument_cache_enabled = (getenv("AFL_FRIDA_INST_NO_CACHE") == NULL);
|
||||
|
||||
if (getenv("AFL_FRIDA_INST_CACHE_SIZE") != NULL) {
|
||||
|
||||
if (!instrument_cache_enabled) {
|
||||
|
||||
FFATAL(
|
||||
"AFL_FRIDA_INST_CACHE_SIZE incomatible with "
|
||||
"AFL_FRIDA_INST_NO_CACHE");
|
||||
|
||||
}
|
||||
|
||||
instrument_cache_size =
|
||||
util_read_address("AFL_FRIDA_INST_CACHE_SIZE", DEFAULT_CACHE_SIZE);
|
||||
util_log2(instrument_cache_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_init(void) {
|
||||
|
||||
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache:" cYEL " [%c]",
|
||||
instrument_cache_enabled ? 'X' : ' ');
|
||||
if (!instrument_cache_enabled) { return; }
|
||||
|
||||
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache size:" cYEL " [0x%016lX]",
|
||||
instrument_cache_size);
|
||||
|
||||
const struct rlimit data_limit = {.rlim_cur = RLIM_INFINITY,
|
||||
.rlim_max = RLIM_INFINITY};
|
||||
|
||||
if (setrlimit(RLIMIT_AS, &data_limit) != 0) {
|
||||
|
||||
FFATAL("Failed to setrlimit: %d", errno);
|
||||
|
||||
}
|
||||
|
||||
map_base =
|
||||
gum_memory_allocate(NULL, instrument_cache_size, instrument_cache_size,
|
||||
GUM_PAGE_READ | GUM_PAGE_WRITE);
|
||||
if (map_base == MAP_FAILED) { FFATAL("Failed to map segment: %d", errno); }
|
||||
|
||||
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache addr:" cYEL " [0x%016lX]",
|
||||
GUM_ADDRESS(map_base));
|
||||
|
||||
}
|
||||
|
||||
static gpointer *instrument_cache_get_addr(gpointer addr) {
|
||||
|
||||
gsize mask = (instrument_cache_size / sizeof(gpointer)) - 1;
|
||||
return &map_base[GPOINTER_TO_SIZE(addr) & mask];
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
|
||||
|
||||
if (!instrument_cache_enabled) { return; }
|
||||
|
||||
gpointer *target = instrument_cache_get_addr(real_address);
|
||||
if (*target == code_address) {
|
||||
|
||||
return;
|
||||
|
||||
} else if (*target == NULL) {
|
||||
|
||||
*target = code_address;
|
||||
|
||||
} else {
|
||||
|
||||
*target = GSIZE_TO_POINTER(INVALID);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static gboolean instrument_cache_relocate(GumAddress old_pc, GumAddress new_pc,
|
||||
gint32 old_offset,
|
||||
gint32 *new_offset) {
|
||||
|
||||
guint64 old_target = old_pc + old_offset;
|
||||
gint64 relocated = old_target - new_pc;
|
||||
|
||||
if (relocated > G_MAXINT32 || relocated < G_MININT32) { return FALSE; }
|
||||
|
||||
*new_offset = relocated;
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static void instrument_cache_rewrite_branch_insn(const cs_insn *instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
GumX86Writer *cw = output->writer.x86;
|
||||
cs_x86 *x86 = &instr->detail->x86;
|
||||
guint8 modified[sizeof(instr->bytes)] = {0};
|
||||
guint8 offset = 0;
|
||||
guint8 skip = 0;
|
||||
|
||||
g_assert(sizeof(x86->prefix) == 4);
|
||||
g_assert(sizeof(x86->opcode) == 4);
|
||||
|
||||
/*
|
||||
* If the target is simply RAX, we can skip writing the code to load the
|
||||
* RIP
|
||||
*/
|
||||
if (x86->operands[0].type == X86_OP_REG ||
|
||||
x86->operands[0].reg == X86_REG_RAX) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Write the prefix */
|
||||
for (gsize i = 0; i < sizeof(x86->prefix); i++) {
|
||||
|
||||
if (x86->prefix[i] != 0) {
|
||||
|
||||
if (x86->prefix[i] == 0xf2) {
|
||||
|
||||
skip++;
|
||||
|
||||
} else {
|
||||
|
||||
modified[offset++] = x86->prefix[i];
|
||||
skip++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Write the REX */
|
||||
if (x86->rex == 0) {
|
||||
|
||||
/*
|
||||
* CALL (near) and JMP (near) default to 64-bit operands, MOV does not,
|
||||
* write REX.W
|
||||
*/
|
||||
modified[offset++] = 0x48;
|
||||
|
||||
} else {
|
||||
|
||||
if ((x86->rex & 0xF8) != 0x40) {
|
||||
|
||||
FATAL("Unexpected REX byte: 0x%02x", x86->rex);
|
||||
|
||||
}
|
||||
|
||||
modified[offset++] = x86->rex | 0x08;
|
||||
skip++;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* CALL is FF /2, JMP is FF /4. The remaining op-code fields should thus be
|
||||
* unused
|
||||
*/
|
||||
|
||||
if (x86->opcode[0] != 0xFF || x86->opcode[1] != 0x00 ||
|
||||
x86->opcode[2] != 0x00 || x86->opcode[3] != 0x00) {
|
||||
|
||||
FFATAL("Unexpected Op-code: 0x%02x 0x%02x 0x%02x 0x%02x", x86->opcode[0],
|
||||
x86->opcode[1], x86->opcode[2], x86->opcode[3]);
|
||||
|
||||
}
|
||||
|
||||
/* The reg field of the ModRM should be set to 2 for CALL and 4 for JMP */
|
||||
guint8 reg = (x86->modrm >> 3) & 7;
|
||||
if (reg != 0x4 && reg != 0x2) {
|
||||
|
||||
FFATAL("Unexpected Reg: 0x%02x, ModRM: 0x%02x", reg, x86->modrm);
|
||||
|
||||
}
|
||||
|
||||
/* MOV */
|
||||
modified[offset++] = 0x8b;
|
||||
skip++;
|
||||
|
||||
/* Clear the reg field (RAX) */
|
||||
modified[offset++] = x86->modrm & 0xc7;
|
||||
skip++;
|
||||
|
||||
/* Operands */
|
||||
guint8 op_len = instr->size - skip;
|
||||
|
||||
/* If our branch was RIP relative, we'll need to fix-up the offset */
|
||||
if (x86->operands[0].type == X86_OP_MEM &&
|
||||
x86->operands[0].mem.base == X86_REG_RIP) {
|
||||
|
||||
/* RIP relative offsets should be 32-bits */
|
||||
if (op_len != sizeof(gint32)) {
|
||||
|
||||
FFATAL("Unexpected operand length: %d\n", op_len);
|
||||
|
||||
}
|
||||
|
||||
gint32 old_offset = *(gint32 *)&instr->bytes[skip];
|
||||
gint32 new_offset = 0;
|
||||
if (instrument_cache_relocate(instr->address, cw->pc, old_offset,
|
||||
&new_offset)) {
|
||||
|
||||
gint32 *output = (gint32 *)&modified[offset];
|
||||
*output = new_offset;
|
||||
offset += sizeof(gint32);
|
||||
|
||||
} else {
|
||||
|
||||
GumAddress target = instr->address + old_offset;
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, target);
|
||||
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_X86_RAX, GUM_X86_RAX);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (int i = 0; i < op_len; i++) {
|
||||
|
||||
guint8 val = instr->bytes[i + skip];
|
||||
modified[offset++] = val;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gum_x86_writer_put_bytes(cw, modified, offset);
|
||||
|
||||
}
|
||||
|
||||
static void instrument_cache_write_push_frame(GumX86Writer *cw) {
|
||||
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))),
|
||||
GUM_X86_XAX);
|
||||
gum_x86_writer_put_lahf(cw);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (2 * sizeof(gpointer))),
|
||||
GUM_X86_XAX);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (3 * sizeof(gpointer))),
|
||||
GUM_X86_XBX);
|
||||
|
||||
}
|
||||
|
||||
static void instrument_cache_write_pop_frame(GumX86Writer *cw) {
|
||||
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(
|
||||
cw, GUM_X86_XBX, GUM_X86_XSP,
|
||||
-(GUM_RED_ZONE_SIZE + (3 * sizeof(gpointer))));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(
|
||||
cw, GUM_X86_XAX, GUM_X86_XSP,
|
||||
-(GUM_RED_ZONE_SIZE + (2 * sizeof(gpointer))));
|
||||
gum_x86_writer_put_sahf(cw);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(
|
||||
cw, GUM_X86_XAX, GUM_X86_XSP,
|
||||
-(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))));
|
||||
|
||||
}
|
||||
|
||||
static void instrument_cache_write_lookup(GumX86Writer *cw) {
|
||||
|
||||
/* &map_base[GPOINTER_TO_SIZE(addr) & MAP_MASK]; */
|
||||
|
||||
gsize mask = (instrument_cache_size / sizeof(gpointer)) - 1;
|
||||
gum_x86_writer_put_mov_reg_u64(cw, GUM_X86_XBX, mask);
|
||||
gum_x86_writer_put_and_reg_reg(cw, GUM_X86_XAX, GUM_X86_XBX);
|
||||
gum_x86_writer_put_shl_reg_u8(cw, GUM_X86_XAX, util_log2(sizeof(gpointer)));
|
||||
gum_x86_writer_put_mov_reg_u64(cw, GUM_X86_XBX, GPOINTER_TO_SIZE(map_base));
|
||||
gum_x86_writer_put_add_reg_reg(cw, GUM_X86_XAX, GUM_X86_XBX);
|
||||
|
||||
/* Read the return address lookup */
|
||||
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_X86_XAX, GUM_X86_XAX);
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_jmp_call(const cs_insn *instr, GumStalkerOutput *output) {
|
||||
|
||||
GumX86Writer *cw = output->writer.x86;
|
||||
cs_x86 *x86 = &instr->detail->x86;
|
||||
|
||||
if (x86->op_count != 1) { FFATAL("Unexpected operand count"); }
|
||||
|
||||
if (x86->operands[0].type == X86_OP_IMM) { return; }
|
||||
|
||||
gconstpointer null = cw->code;
|
||||
|
||||
instrument_cache_write_push_frame(cw);
|
||||
|
||||
/*
|
||||
* We are about to re-write the CALL or JMP instruction, but replace the
|
||||
* op-code with that for a MOV into RAX. Since we are keeping the operand from
|
||||
* the JMP exactly the same, it is imperative that the target register state
|
||||
* be exactly the same as how the target left it. Since `LAHF` spoils `RAX` we
|
||||
* must restore it from the stack. We also must avoid adjusting `RSP`, so we
|
||||
* use `MOV` instructions to store our context into the stack beyond the
|
||||
* red-zone.
|
||||
*/
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(
|
||||
cw, GUM_X86_XAX, GUM_X86_XSP,
|
||||
-(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))));
|
||||
|
||||
instrument_cache_rewrite_branch_insn(instr, output);
|
||||
|
||||
instrument_cache_write_lookup(cw);
|
||||
|
||||
/* Test if its set*/
|
||||
gum_x86_writer_put_cmp_reg_i32(cw, GUM_X86_XAX, INVALID);
|
||||
gum_x86_writer_put_jcc_short_label(cw, X86_INS_JLE, null, GUM_UNLIKELY);
|
||||
|
||||
/* If it's set, then stash the address beyond the red-zone */
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (4 * sizeof(gpointer))),
|
||||
GUM_X86_XAX);
|
||||
|
||||
if (instr->id == X86_INS_JMP) {
|
||||
|
||||
instrument_cache_write_pop_frame(cw);
|
||||
gum_x86_writer_put_jmp_reg_offset_ptr(
|
||||
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + (4 * sizeof(gpointer))));
|
||||
|
||||
} else {
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(
|
||||
cw, GUM_X86_XAX, GUM_ADDRESS(instr->address + instr->size));
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_X86_XSP,
|
||||
-sizeof(gpointer), GUM_X86_XAX);
|
||||
|
||||
instrument_cache_write_pop_frame(cw);
|
||||
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_XSP, GUM_X86_XSP,
|
||||
-sizeof(gpointer));
|
||||
gum_x86_writer_put_jmp_reg_offset_ptr(
|
||||
cw, GUM_X86_XSP, -(GUM_RED_ZONE_SIZE + ((4 - 1) * sizeof(gpointer))));
|
||||
|
||||
}
|
||||
|
||||
/* Tidy up our mess and let FRIDA handle it */
|
||||
gum_x86_writer_put_label(cw, null);
|
||||
instrument_cache_write_pop_frame(cw);
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_ret(const cs_insn *instr, GumStalkerOutput *output) {
|
||||
|
||||
GumX86Writer *cw = output->writer.x86;
|
||||
cs_x86 *x86 = &instr->detail->x86;
|
||||
guint16 n = 0;
|
||||
|
||||
if (x86->op_count != 0) {
|
||||
|
||||
if (x86->operands[0].type != X86_OP_IMM) {
|
||||
|
||||
FFATAL("Unexpected operand type");
|
||||
|
||||
}
|
||||
|
||||
n = x86->operands[0].imm;
|
||||
|
||||
}
|
||||
|
||||
gconstpointer null = cw->code;
|
||||
|
||||
instrument_cache_write_push_frame(cw);
|
||||
|
||||
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_X86_XAX, GUM_X86_XSP);
|
||||
|
||||
instrument_cache_write_lookup(cw);
|
||||
|
||||
/* Test if its set*/
|
||||
gum_x86_writer_put_cmp_reg_i32(cw, GUM_X86_XAX, INVALID);
|
||||
gum_x86_writer_put_jcc_short_label(cw, X86_INS_JLE, null, GUM_UNLIKELY);
|
||||
|
||||
/* If it's set, then overwrite our return address and return */
|
||||
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_X86_XSP, GUM_X86_XAX);
|
||||
instrument_cache_write_pop_frame(cw);
|
||||
|
||||
if (n == 0) {
|
||||
|
||||
gum_x86_writer_put_ret(cw);
|
||||
|
||||
} else {
|
||||
|
||||
gum_x86_writer_put_ret_imm(cw, n);
|
||||
|
||||
}
|
||||
|
||||
/* Tidy up our mess and let FRIDA handle it */
|
||||
gum_x86_writer_put_label(cw, null);
|
||||
instrument_cache_write_pop_frame(cw);
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
|
||||
|
||||
if (!instrument_cache_enabled) { return; }
|
||||
|
||||
switch (instr->id) {
|
||||
|
||||
case X86_INS_RET:
|
||||
instrument_cache_ret(instr, output);
|
||||
break;
|
||||
|
||||
case X86_INS_CALL:
|
||||
case X86_INS_JMP:
|
||||
instrument_cache_jmp_call(instr, output);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
gboolean instrument_cache_enabled = FALSE;
|
||||
gsize instrument_cache_size = 0;
|
||||
|
||||
static GHashTable *coverage_blocks = NULL;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
@ -81,14 +84,16 @@ gboolean instrument_is_coverage_optimize_supported(void) {
|
||||
}
|
||||
|
||||
static void instrument_coverage_switch(GumStalkerObserver *self,
|
||||
gpointer from_address,
|
||||
gpointer start_address,
|
||||
const cs_insn * from_insn,
|
||||
gpointer * target) {
|
||||
const cs_insn *from_insn,
|
||||
gpointer *target) {
|
||||
|
||||
UNUSED_PARAMETER(self);
|
||||
UNUSED_PARAMETER(from_address);
|
||||
UNUSED_PARAMETER(start_address);
|
||||
|
||||
cs_x86 * x86;
|
||||
cs_x86 *x86;
|
||||
cs_x86_op *op;
|
||||
if (from_insn == NULL) { return; }
|
||||
|
||||
@ -131,7 +136,7 @@ static void instrument_coverage_suppress_init(void) {
|
||||
if (initialized) { return; }
|
||||
initialized = true;
|
||||
|
||||
GumStalkerObserver * observer = stalker_get_observer();
|
||||
GumStalkerObserver *observer = stalker_get_observer();
|
||||
GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer);
|
||||
iface->switch_callback = instrument_coverage_switch;
|
||||
|
||||
@ -144,7 +149,7 @@ static void instrument_coverage_suppress_init(void) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize(const cs_insn * instr,
|
||||
void instrument_coverage_optimize(const cs_insn *instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
afl_log_code code = {0};
|
||||
@ -157,9 +162,10 @@ void instrument_coverage_optimize(const cs_insn * instr,
|
||||
|
||||
GumAddressSpec spec = {.near_address = cw->code,
|
||||
.max_distance = 1ULL << 30};
|
||||
guint page_size = gum_query_page_size();
|
||||
|
||||
instrument_previous_pc_addr = gum_memory_allocate_near(
|
||||
&spec, sizeof(guint64), 0x1000, GUM_PAGE_READ | GUM_PAGE_WRITE);
|
||||
&spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE);
|
||||
*instrument_previous_pc_addr = instrument_hash_zero;
|
||||
FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
|
||||
FVERBOSE("code_addr: %p", cw->code);
|
||||
@ -218,6 +224,14 @@ void instrument_coverage_optimize(const cs_insn * instr,
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize_insn(const cs_insn *instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(output);
|
||||
|
||||
}
|
||||
|
||||
void instrument_coverage_optimize_init(void) {
|
||||
|
||||
}
|
||||
@ -234,5 +248,40 @@ gpointer instrument_cur(GumStalkerOutput *output) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_config(void) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_init(void) {
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
|
||||
|
||||
UNUSED_PARAMETER(real_address);
|
||||
UNUSED_PARAMETER(code_address);
|
||||
|
||||
}
|
||||
|
||||
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(output);
|
||||
|
||||
}
|
||||
|
||||
void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
|
||||
|
||||
int fd = (int)(size_t)user_data;
|
||||
instrument_regs_format(
|
||||
fd, "eax: 0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x\n",
|
||||
cpu_context->eax, cpu_context->ebx, cpu_context->ecx, cpu_context->edx);
|
||||
instrument_regs_format(
|
||||
fd, "esi: 0x%08x, edi: 0x%08x, ebp: 0x%08x, esp: 0x%08x\n",
|
||||
cpu_context->esi, cpu_context->edi, cpu_context->ebp, cpu_context->esp);
|
||||
instrument_regs_format(fd, "eip: 0x%08x\n\n", cpu_context->eip);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -7,8 +7,8 @@ void intercept_hook(void *address, gpointer replacement, gpointer user_data) {
|
||||
|
||||
GumInterceptor *interceptor = gum_interceptor_obtain();
|
||||
gum_interceptor_begin_transaction(interceptor);
|
||||
GumReplaceReturn ret =
|
||||
gum_interceptor_replace(interceptor, address, replacement, user_data);
|
||||
GumReplaceReturn ret = gum_interceptor_replace(interceptor, address,
|
||||
replacement, user_data, NULL);
|
||||
if (ret != GUM_REPLACE_OK) { FFATAL("gum_interceptor_attach: %d", ret); }
|
||||
gum_interceptor_end_transaction(interceptor);
|
||||
|
||||
|
@ -68,6 +68,12 @@ class Afl {
|
||||
static setBackpatchDisable() {
|
||||
Afl.jsApiSetBackpatchDisable();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_CACHE`.
|
||||
*/
|
||||
static setCacheDisable() {
|
||||
Afl.jsApiSetCacheDisable();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_DEBUG_MAPS`.
|
||||
*/
|
||||
@ -91,6 +97,19 @@ class Afl {
|
||||
static setInMemoryFuzzing() {
|
||||
Afl.jsApiAflSharedMemFuzzing.writeInt(1);
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_CACHE_SIZE`. This function takes a single `number`
|
||||
* as an argument.
|
||||
*/
|
||||
static setInstrumentCacheSize(size) {
|
||||
Afl.jsApiSetInstrumentCacheSize(size);
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_COVERAGE_ABSOLUTE`.
|
||||
*/
|
||||
static setInstrumentCoverageAbsolute() {
|
||||
Afl.jsApiSetInstrumentCoverageAbsolute();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
|
||||
* as an argument.
|
||||
@ -113,6 +132,12 @@ class Afl {
|
||||
static setInstrumentEnableTracing() {
|
||||
Afl.jsApiSetInstrumentTrace();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_INSN`
|
||||
*/
|
||||
static setInstrumentInstructions() {
|
||||
Afl.jsApiSetInstrumentInstructions();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_JIT`.
|
||||
*/
|
||||
@ -131,6 +156,14 @@ class Afl {
|
||||
static setInstrumentNoOptimize() {
|
||||
Afl.jsApiSetInstrumentNoOptimize();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_REGS_FILE`. This function takes a single `string` as
|
||||
* an argument.
|
||||
*/
|
||||
static setInstrumentRegsFile(file) {
|
||||
const buf = Memory.allocUtf8String(file);
|
||||
Afl.jsApiSetInstrumentRegsFile(buf);
|
||||
}
|
||||
/*
|
||||
* See `AFL_FRIDA_INST_SEED`
|
||||
*/
|
||||
@ -293,13 +326,18 @@ Afl.jsApiAflSharedMemFuzzing = Afl.jsApiGetSymbol("__afl_sharedmem_fuzzing");
|
||||
Afl.jsApiDone = Afl.jsApiGetFunction("js_api_done", "void", []);
|
||||
Afl.jsApiError = Afl.jsApiGetFunction("js_api_error", "void", ["pointer"]);
|
||||
Afl.jsApiSetBackpatchDisable = Afl.jsApiGetFunction("js_api_set_backpatch_disable", "void", []);
|
||||
Afl.jsApiSetCacheDisable = Afl.jsApiGetFunction("js_api_set_cache_disable", "void", []);
|
||||
Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []);
|
||||
Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
|
||||
Afl.jsApiSetInstrumentCacheSize = Afl.jsApiGetFunction("js_api_set_instrument_cache_size", "void", ["size_t"]);
|
||||
Afl.jsApiSetInstrumentCoverageAbsolute = Afl.jsApiGetFunction("js_api_set_instrument_coverage_absolute", "void", []);
|
||||
Afl.jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_coverage_file", "void", ["pointer"]);
|
||||
Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]);
|
||||
Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []);
|
||||
Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []);
|
||||
Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []);
|
||||
Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []);
|
||||
Afl.jsApiSetInstrumentRegsFile = Afl.jsApiGetFunction("js_api_set_instrument_regs_file", "void", ["pointer"]);
|
||||
Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", "void", ["uint64"]);
|
||||
Afl.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []);
|
||||
Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []);
|
||||
|
@ -7,16 +7,16 @@ gboolean js_done = FALSE;
|
||||
js_api_stalker_callback_t js_user_callback = NULL;
|
||||
js_main_hook_t js_main_hook = NULL;
|
||||
|
||||
static char * js_script = NULL;
|
||||
static gchar * filename = "afl.js";
|
||||
static gchar * contents;
|
||||
static GumScriptBackend * backend;
|
||||
static GCancellable * cancellable = NULL;
|
||||
static GError * error = NULL;
|
||||
static GumScript * script;
|
||||
static char *js_script = NULL;
|
||||
static gchar *filename = "afl.js";
|
||||
static gchar *contents;
|
||||
static GumScriptBackend *backend;
|
||||
static GCancellable *cancellable = NULL;
|
||||
static GError *error = NULL;
|
||||
static GumScript *script;
|
||||
static GumScriptScheduler *scheduler;
|
||||
static GMainContext * context;
|
||||
static GMainLoop * main_loop;
|
||||
static GMainContext *context;
|
||||
static GMainLoop *main_loop;
|
||||
|
||||
static void js_msg(GumScript *script, const gchar *message, GBytes *data,
|
||||
gpointer user_data) {
|
||||
|
@ -115,6 +115,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_libraries() {
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void
|
||||
js_api_set_instrument_coverage_absolute(void) {
|
||||
|
||||
instrument_coverage_absolute = true;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_instrument_coverage_file(
|
||||
char *path) {
|
||||
|
||||
@ -142,6 +149,13 @@ js_api_set_prefetch_backpatch_disable(void) {
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_instrument_instructions(
|
||||
void) {
|
||||
|
||||
instrument_coverage_insn = TRUE;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_instrument_no_optimize(
|
||||
void) {
|
||||
|
||||
@ -149,6 +163,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_no_optimize(
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_instrument_regs_file(
|
||||
char *path) {
|
||||
|
||||
instrument_regs_filename = g_strdup(path);
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_instrument_seed(
|
||||
guint64 seed) {
|
||||
|
||||
@ -255,6 +276,19 @@ __attribute__((visibility("default"))) void js_api_set_stalker_adjacent_blocks(
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_cache_disable(void) {
|
||||
|
||||
instrument_cache_enabled = FALSE;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_instrument_cache_size(
|
||||
gsize size) {
|
||||
|
||||
instrument_cache_size = size;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_js_main_hook(
|
||||
const js_main_hook_t hook) {
|
||||
|
||||
|
@ -69,8 +69,8 @@ static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) {
|
||||
Elf_Addr preferred_base;
|
||||
Elf_Shdr *shdr;
|
||||
Elf_Shdr *shstrtab;
|
||||
char * shstr;
|
||||
char * section_name;
|
||||
char *shstr;
|
||||
char *section_name;
|
||||
Elf_Shdr *curr;
|
||||
char text_name[] = ".text";
|
||||
|
||||
|
@ -16,9 +16,9 @@ static gboolean lib_get_main_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
GumDarwinModule **ret = (GumDarwinModule **)user_data;
|
||||
GumDarwinModule * module = gum_darwin_module_new_from_memory(
|
||||
details->path, mach_task_self(), details->range->base_address,
|
||||
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
|
||||
GumDarwinModule *module = gum_darwin_module_new_from_memory(
|
||||
details->path, mach_task_self(), details->range->base_address,
|
||||
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
|
||||
|
||||
FVERBOSE("Found main module: %s", module->name);
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "intercept.h"
|
||||
#include "js.h"
|
||||
#include "lib.h"
|
||||
#include "module.h"
|
||||
#include "output.h"
|
||||
#include "persistent.h"
|
||||
#include "prefetch.h"
|
||||
@ -35,6 +36,18 @@
|
||||
#ifdef __APPLE__
|
||||
extern mach_port_t mach_task_self();
|
||||
extern GumAddress gum_darwin_find_entrypoint(mach_port_t task);
|
||||
#elif defined(__ANDROID__)
|
||||
typedef struct {
|
||||
|
||||
void (**preinit_array)(void);
|
||||
void (**init_array)(void);
|
||||
void (**fini_array)(void);
|
||||
|
||||
} structors_array_t;
|
||||
|
||||
extern void __libc_init(void *raw_args, void (*onexit)(void) __unused,
|
||||
int (*slingshot)(int, char **, char **),
|
||||
structors_array_t const *const structors);
|
||||
#else
|
||||
extern int __libc_start_main(int (*main)(int, char **, char **), int argc,
|
||||
char **ubp_av, void (*init)(void),
|
||||
@ -68,7 +81,11 @@ static void on_main_os(int argc, char **argv, char **envp) {
|
||||
GumInterceptor *interceptor = gum_interceptor_obtain();
|
||||
|
||||
gum_interceptor_begin_transaction(interceptor);
|
||||
#if defined(__ANDROID__)
|
||||
gum_interceptor_revert(interceptor, __libc_init);
|
||||
#else
|
||||
gum_interceptor_revert(interceptor, __libc_start_main);
|
||||
#endif
|
||||
gum_interceptor_end_transaction(interceptor);
|
||||
gum_interceptor_flush(interceptor);
|
||||
|
||||
@ -91,7 +108,7 @@ static void embedded_init(void) {
|
||||
static void afl_print_cmdline(void) {
|
||||
|
||||
#if defined(__linux__)
|
||||
char * buffer = g_malloc0(PROC_MAX);
|
||||
char *buffer = g_malloc0(PROC_MAX);
|
||||
gchar *fname = g_strdup_printf("/proc/%d/cmdline", getppid());
|
||||
int fd = open(fname, O_RDONLY);
|
||||
|
||||
@ -143,7 +160,7 @@ static void afl_print_cmdline(void) {
|
||||
|
||||
static void afl_print_env(void) {
|
||||
|
||||
char * buffer = g_malloc0(PROC_MAX);
|
||||
char *buffer = g_malloc0(PROC_MAX);
|
||||
gchar *fname = g_strdup_printf("/proc/%d/environ", getppid());
|
||||
int fd = open(fname, O_RDONLY);
|
||||
|
||||
@ -197,6 +214,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
|
||||
instrument_config();
|
||||
js_config();
|
||||
lib_config();
|
||||
module_config();
|
||||
output_config();
|
||||
persistent_config();
|
||||
prefetch_config();
|
||||
@ -214,6 +232,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
|
||||
entry_init();
|
||||
instrument_init();
|
||||
lib_init();
|
||||
module_init();
|
||||
persistent_init();
|
||||
prefetch_init();
|
||||
seccomp_init();
|
||||
@ -274,6 +293,24 @@ static void intercept_main(void) {
|
||||
|
||||
}
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
static void on_libc_init(void *raw_args, void (*onexit)(void) __unused,
|
||||
int (*slingshot)(int, char **, char **),
|
||||
structors_array_t const *const structors) {
|
||||
|
||||
main_fn = slingshot;
|
||||
intercept_unhook_self();
|
||||
intercept_hook(slingshot, on_main, NULL);
|
||||
return __libc_init(raw_args, onexit, slingshot, structors);
|
||||
|
||||
}
|
||||
|
||||
static void intercept_main(void) {
|
||||
|
||||
intercept_hook(__libc_init, on_libc_init, NULL);
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static int on_libc_start_main(int (*main)(int, char **, char **), int argc,
|
||||
char **ubp_av, void (*init)(void),
|
||||
|
106
frida_mode/src/module.c
Normal file
106
frida_mode/src/module.c
Normal file
@ -0,0 +1,106 @@
|
||||
#include "intercept.h"
|
||||
#include "module.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <dlfcn.h>
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
static guint page_size = 0;
|
||||
static gboolean handle_dlclose = FALSE;
|
||||
|
||||
void module_config(void) {
|
||||
|
||||
#if defined(__linux__)
|
||||
handle_dlclose = (getenv("AFL_FRIDA_NO_MODULE") == NULL);
|
||||
#else
|
||||
FWARNF("AFL_FRIDA_MODULE not supported");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
||||
GumMemoryRange range;
|
||||
GumPageProtection protection;
|
||||
GumFileMapping file;
|
||||
|
||||
} gum_range_t;
|
||||
|
||||
gboolean found_range(const GumRangeDetails *details, gpointer user_data) {
|
||||
|
||||
gum_range_t range = {0};
|
||||
GArray *ranges = (GArray *)user_data;
|
||||
|
||||
range.range = *details->range;
|
||||
range.protection = details->protection;
|
||||
if (details->file != NULL) { range.file = *details->file; }
|
||||
|
||||
g_array_append_val(ranges, range);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
static int on_dlclose(void *handle) {
|
||||
|
||||
GArray *ranges = NULL;
|
||||
struct link_map *lm = NULL;
|
||||
gum_range_t *range = NULL;
|
||||
GumAddress base;
|
||||
GumAddress limit;
|
||||
gpointer mem;
|
||||
|
||||
if (dlinfo(handle, RTLD_DI_LINKMAP, &lm) < 0) {
|
||||
|
||||
FFATAL("Failed to dlinfo: %s", dlerror());
|
||||
|
||||
}
|
||||
|
||||
FVERBOSE("on_dlclose: %s", lm->l_name);
|
||||
|
||||
ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t));
|
||||
gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range,
|
||||
ranges);
|
||||
|
||||
int ret = dlclose(handle);
|
||||
if (ret != 0) {
|
||||
|
||||
FWARNF("dlclose returned: %d (%s)", ret, dlerror());
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
for (guint i = 0; i < ranges->len; i++) {
|
||||
|
||||
range = &g_array_index(ranges, gum_range_t, i);
|
||||
base = range->range.base_address;
|
||||
limit = base + range->range.size;
|
||||
FVERBOSE("Reserving range: 0x%016lx, 0x%016lX", base, limit);
|
||||
mem = gum_memory_allocate(GSIZE_TO_POINTER(base), range->range.size,
|
||||
page_size, GUM_PAGE_NO_ACCESS);
|
||||
if (mem == NULL) { FATAL("Failed to allocate %p (%d)", mem, errno); }
|
||||
|
||||
}
|
||||
|
||||
g_array_free(ranges, TRUE);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void module_init(void) {
|
||||
|
||||
FOKF(cBLU "Module" cRST " - " cYEL " [%c]", handle_dlclose ? 'X' : ' ');
|
||||
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
if (!handle_dlclose) { return; }
|
||||
|
||||
page_size = gum_query_page_size();
|
||||
intercept_hook(dlclose, on_dlclose, NULL);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -1,75 +1,294 @@
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
#include "instrument.h"
|
||||
#include "persistent.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__arm__)
|
||||
|
||||
struct arm_regs {
|
||||
// struct _GumArmCpuContext {
|
||||
|
||||
uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10;
|
||||
// guint32 pc;
|
||||
// guint32 sp;
|
||||
// guint32 cpsr;
|
||||
|
||||
union {
|
||||
// guint32 r8;
|
||||
// guint32 r9;
|
||||
// guint32 r10;
|
||||
// guint32 r11;
|
||||
// guint32 r12;
|
||||
|
||||
uint32_t r11;
|
||||
uint32_t fp;
|
||||
// GumArmVectorReg v[16];
|
||||
|
||||
};
|
||||
// guint32 _padding;
|
||||
|
||||
union {
|
||||
// guint32 r[8];
|
||||
// guint32 lr;
|
||||
// };
|
||||
|
||||
uint32_t r12;
|
||||
uint32_t ip;
|
||||
// r11 - fp
|
||||
// r12 - ip
|
||||
// r13 - sp
|
||||
// r14 - lr
|
||||
// r15 - pc
|
||||
|
||||
};
|
||||
|
||||
union {
|
||||
|
||||
uint32_t r13;
|
||||
uint32_t sp;
|
||||
|
||||
};
|
||||
|
||||
union {
|
||||
|
||||
uint32_t r14;
|
||||
uint32_t lr;
|
||||
|
||||
};
|
||||
|
||||
union {
|
||||
|
||||
uint32_t r15;
|
||||
uint32_t pc;
|
||||
|
||||
};
|
||||
|
||||
uint32_t cpsr;
|
||||
|
||||
uint8_t vfp_zregs[32][16];
|
||||
uint32_t vfp_xregs[16];
|
||||
|
||||
};
|
||||
|
||||
typedef struct arm_regs arch_api_regs;
|
||||
static GumCpuContext saved_regs = {0};
|
||||
static gpointer saved_lr = NULL;
|
||||
|
||||
gboolean persistent_is_supported(void) {
|
||||
|
||||
return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static void instrument_persitent_save_regs(GumArmWriter *cw,
|
||||
GumCpuContext *regs) {
|
||||
|
||||
/* Save Regs */
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE + sizeof(guint32));
|
||||
|
||||
gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(regs));
|
||||
|
||||
/* Save r1-r7 */
|
||||
for (size_t i = ARM_REG_R1; i < ARM_REG_R8; i++) {
|
||||
|
||||
gum_arm_writer_put_str_reg_reg_offset(
|
||||
cw, i, ARM_REG_R0, offsetof(GumCpuContext, r[i - ARM_REG_R0]));
|
||||
|
||||
}
|
||||
|
||||
/* Save r8-r12 */
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R8, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r8));
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R9, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r9));
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R10, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r10));
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R11, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r11));
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R12, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r12));
|
||||
|
||||
/* Save sp & lr */
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_SP, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, sp));
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, lr));
|
||||
|
||||
/* Save r0 (load from stack into r1) */
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r[0]));
|
||||
|
||||
/* Save CPSR */
|
||||
gum_arm_writer_put_mov_reg_cpsr(cw, ARM_REG_R1);
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, cpsr));
|
||||
|
||||
/* Save PC */
|
||||
gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R1,
|
||||
GUM_ADDRESS(persistent_start));
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, pc));
|
||||
|
||||
/* Restore Regs */
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE + sizeof(guint32));
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
|
||||
}
|
||||
|
||||
static void instrument_persitent_restore_regs(GumArmWriter *cw,
|
||||
GumCpuContext *regs) {
|
||||
|
||||
gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(regs));
|
||||
|
||||
/* Restore CPSR */
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, cpsr));
|
||||
gum_arm_writer_put_mov_cpsr_reg(cw, ARM_REG_R1);
|
||||
|
||||
/* Restore sp & lr */
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_SP, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, sp));
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, lr));
|
||||
|
||||
/* Restore r8-r12 */
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R8, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r8));
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R9, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r9));
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R10, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r10));
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R11, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r11));
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R12, ARM_REG_R0,
|
||||
offsetof(GumCpuContext, r12));
|
||||
|
||||
/* Restore r7-r0 */
|
||||
for (size_t i = ARM_REG_R7; i >= ARM_REG_R0; i--) {
|
||||
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(
|
||||
cw, i, ARM_REG_R0, offsetof(GumCpuContext, r[i - ARM_REG_R0]));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void instrument_exit(GumArmWriter *cw) {
|
||||
|
||||
gum_arm_writer_put_sub_reg_reg_reg(cw, ARM_REG_R0, ARM_REG_R0, ARM_REG_R0);
|
||||
gum_arm_writer_put_call_address_with_arguments(cw, GUM_ADDRESS(_exit), 1,
|
||||
GUM_ARG_REGISTER, ARM_REG_R0);
|
||||
|
||||
}
|
||||
|
||||
static int instrument_afl_persistent_loop_func(void) {
|
||||
|
||||
int ret = __afl_persistent_loop(persistent_count);
|
||||
if (instrument_previous_pc_addr == NULL) {
|
||||
|
||||
FATAL("instrument_previous_pc_addr uninitialized");
|
||||
|
||||
}
|
||||
|
||||
*instrument_previous_pc_addr = instrument_hash_zero;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void instrument_afl_persistent_loop(GumArmWriter *cw) {
|
||||
|
||||
gum_arm_writer_put_sub_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
gum_arm_writer_put_call_address_with_arguments(
|
||||
cw, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0);
|
||||
gum_arm_writer_put_add_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
|
||||
}
|
||||
|
||||
static void persistent_prologue_hook(GumArmWriter *cw, GumCpuContext *regs) {
|
||||
|
||||
if (persistent_hook == NULL) return;
|
||||
|
||||
gum_arm_writer_put_sub_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R2,
|
||||
GUM_ADDRESS(&__afl_fuzz_len));
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R2, ARM_REG_R2, 0);
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R2, ARM_REG_R2, 0);
|
||||
|
||||
gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R1,
|
||||
GUM_ADDRESS(&__afl_fuzz_ptr));
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R1, 0);
|
||||
|
||||
gum_arm_writer_put_call_address_with_arguments(
|
||||
cw, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS, GUM_ADDRESS(regs),
|
||||
GUM_ARG_REGISTER, ARM_REG_R1, GUM_ARG_REGISTER, ARM_REG_R2);
|
||||
|
||||
gum_arm_writer_put_add_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
|
||||
}
|
||||
|
||||
static void instrument_persitent_save_lr(GumArmWriter *cw) {
|
||||
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
|
||||
gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(&saved_lr));
|
||||
gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0, 0);
|
||||
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
|
||||
}
|
||||
|
||||
void persistent_prologue_arch(GumStalkerOutput *output) {
|
||||
|
||||
UNUSED_PARAMETER(output);
|
||||
FFATAL("Persistent mode not supported on this architecture");
|
||||
/*
|
||||
* SAVE REGS
|
||||
* SAVE RET
|
||||
* POP RET
|
||||
* loop:
|
||||
* CALL instrument_afl_persistent_loop
|
||||
* TEST EAX, EAX
|
||||
* JZ end:
|
||||
* call hook (optionally)
|
||||
* RESTORE REGS
|
||||
* call original
|
||||
* jmp loop:
|
||||
*
|
||||
* end:
|
||||
* JMP SAVED RET
|
||||
*
|
||||
* original:
|
||||
* INSTRUMENTED PERSISTENT FUNC
|
||||
*/
|
||||
|
||||
GumArmWriter *cw = output->writer.arm;
|
||||
|
||||
gconstpointer loop = cw->code + 1;
|
||||
|
||||
FVERBOSE("Persistent loop reached");
|
||||
|
||||
instrument_persitent_save_regs(cw, &saved_regs);
|
||||
|
||||
/* loop: */
|
||||
gum_arm_writer_put_label(cw, loop);
|
||||
|
||||
/* call instrument_prologue_func */
|
||||
instrument_afl_persistent_loop(cw);
|
||||
|
||||
/* jz done */
|
||||
gconstpointer done = cw->code + 1;
|
||||
gum_arm_writer_put_cmp_reg_imm(cw, ARM_REG_R0, 0);
|
||||
gum_arm_writer_put_b_cond_label(cw, ARM_CC_EQ, done);
|
||||
|
||||
/* Optionally call the persistent hook */
|
||||
persistent_prologue_hook(cw, &saved_regs);
|
||||
|
||||
instrument_persitent_restore_regs(cw, &saved_regs);
|
||||
gconstpointer original = cw->code + 1;
|
||||
/* call original */
|
||||
|
||||
gum_arm_writer_put_bl_label(cw, original);
|
||||
|
||||
/* jmp loop */
|
||||
gum_arm_writer_put_b_label(cw, loop);
|
||||
|
||||
/* done: */
|
||||
gum_arm_writer_put_label(cw, done);
|
||||
|
||||
instrument_exit(cw);
|
||||
|
||||
/* original: */
|
||||
gum_arm_writer_put_label(cw, original);
|
||||
|
||||
instrument_persitent_save_lr(cw);
|
||||
|
||||
if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); }
|
||||
|
||||
}
|
||||
|
||||
void persistent_epilogue_arch(GumStalkerOutput *output) {
|
||||
|
||||
UNUSED_PARAMETER(output);
|
||||
FFATAL("Persistent mode not supported on this architecture");
|
||||
GumArmWriter *cw = output->writer.arm;
|
||||
|
||||
if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); }
|
||||
|
||||
gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(&saved_lr));
|
||||
|
||||
gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_R0, 0);
|
||||
|
||||
gum_arm_writer_put_bx_reg(cw, ARM_REG_R0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ gboolean persistent_is_supported(void) {
|
||||
|
||||
}
|
||||
|
||||
static void instrument_persitent_save_regs(GumArm64Writer * cw,
|
||||
static void instrument_persitent_save_regs(GumArm64Writer *cw,
|
||||
persistent_ctx_t *regs) {
|
||||
|
||||
GumAddress regs_address = GUM_ADDRESS(regs);
|
||||
@ -105,18 +105,13 @@ static void instrument_persitent_save_regs(GumArm64Writer * cw,
|
||||
offsetof(persistent_ctx_t, rflags));
|
||||
|
||||
/* Q */
|
||||
gum_arm64_writer_put_stp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q0, ARM64_REG_Q1, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, q[0]), GUM_INDEX_SIGNED_OFFSET);
|
||||
gum_arm64_writer_put_stp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q2, ARM64_REG_Q3, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, q[16]), GUM_INDEX_SIGNED_OFFSET);
|
||||
gum_arm64_writer_put_stp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q4, ARM64_REG_Q5, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, q[32]), GUM_INDEX_SIGNED_OFFSET);
|
||||
gum_arm64_writer_put_stp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q6, ARM64_REG_Q7, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, q[48]), GUM_INDEX_SIGNED_OFFSET);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
|
||||
gum_arm64_writer_put_stp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q0 + (i * 2), ARM64_REG_Q0 + (i * 2) + 1, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, v[i]), GUM_INDEX_SIGNED_OFFSET);
|
||||
|
||||
}
|
||||
|
||||
/* x0 & x1 */
|
||||
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3,
|
||||
@ -136,7 +131,7 @@ static void instrument_persitent_save_regs(GumArm64Writer * cw,
|
||||
|
||||
}
|
||||
|
||||
static void instrument_persitent_restore_regs(GumArm64Writer * cw,
|
||||
static void instrument_persitent_restore_regs(GumArm64Writer *cw,
|
||||
persistent_ctx_t *regs) {
|
||||
|
||||
GumAddress regs_address = GUM_ADDRESS(regs);
|
||||
@ -201,18 +196,14 @@ static void instrument_persitent_restore_regs(GumArm64Writer * cw,
|
||||
offsetof(persistent_ctx_t, rflags));
|
||||
gum_arm64_writer_put_instruction(cw, msr_nzcv_x1);
|
||||
|
||||
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q0, ARM64_REG_Q1, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, q[0]), GUM_INDEX_SIGNED_OFFSET);
|
||||
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q2, ARM64_REG_Q3, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, q[16]), GUM_INDEX_SIGNED_OFFSET);
|
||||
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q4, ARM64_REG_Q5, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, q[32]), GUM_INDEX_SIGNED_OFFSET);
|
||||
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q6, ARM64_REG_Q7, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, q[48]), GUM_INDEX_SIGNED_OFFSET);
|
||||
/* Q */
|
||||
for (int i = 0; i < 16; i++) {
|
||||
|
||||
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_Q0 + (i * 2), ARM64_REG_Q0 + (i * 2) + 1, ARM64_REG_X0,
|
||||
offsetof(GumCpuContext, v[i]), GUM_INDEX_SIGNED_OFFSET);
|
||||
|
||||
}
|
||||
|
||||
/* x2 & x3 */
|
||||
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
|
||||
@ -258,7 +249,7 @@ static void instrument_afl_persistent_loop(GumArm64Writer *cw) {
|
||||
|
||||
}
|
||||
|
||||
static void persistent_prologue_hook(GumArm64Writer * cw,
|
||||
static void persistent_prologue_hook(GumArm64Writer *cw,
|
||||
persistent_ctx_t *regs) {
|
||||
|
||||
if (persistent_hook == NULL) return;
|
||||
|
@ -25,148 +25,148 @@ gboolean persistent_is_supported(void) {
|
||||
|
||||
}
|
||||
|
||||
static void instrument_persitent_save_regs(GumX86Writer * cw,
|
||||
static void instrument_persitent_save_regs(GumX86Writer *cw,
|
||||
persistent_ctx_t *regs) {
|
||||
|
||||
GumAddress regs_address = GUM_ADDRESS(regs);
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
-(GUM_RED_ZONE_SIZE));
|
||||
|
||||
/* Should be pushing FPU here, but meh */
|
||||
gum_x86_writer_put_pushfx(cw);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_RAX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_RAX);
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, regs_address);
|
||||
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, rbx), GUM_REG_RBX);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, rbx), GUM_X86_RBX);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, rcx), GUM_REG_RCX);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, rcx), GUM_X86_RCX);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, rdx), GUM_REG_RDX);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, rdx), GUM_X86_RDX);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, rdi), GUM_REG_RDI);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, rdi), GUM_X86_RDI);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, rsi), GUM_REG_RSI);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, rsi), GUM_X86_RSI);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, rbp), GUM_REG_RBP);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, rbp), GUM_X86_RBP);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, r8), GUM_REG_R8);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, r8), GUM_X86_R8);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, r9), GUM_REG_R9);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, r9), GUM_X86_R9);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, r10), GUM_REG_R10);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, r10), GUM_X86_R10);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, r11), GUM_REG_R11);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, r11), GUM_X86_R11);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, r12), GUM_REG_R12);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, r12), GUM_X86_R12);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, r13), GUM_REG_R13);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, r13), GUM_X86_R13);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, r14), GUM_REG_R14);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, r14), GUM_X86_R14);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, r15), GUM_REG_R15);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, r15), GUM_X86_R15);
|
||||
|
||||
/* Store RIP */
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RBX,
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RBX,
|
||||
GUM_ADDRESS(persistent_start));
|
||||
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, rip), GUM_REG_RBX);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, rip), GUM_X86_RBX);
|
||||
|
||||
/* Store adjusted RSP */
|
||||
gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_RBX, GUM_REG_RSP);
|
||||
gum_x86_writer_put_mov_reg_reg(cw, GUM_X86_RBX, GUM_X86_RSP);
|
||||
|
||||
/* RED_ZONE + Saved flags, RAX, alignment */
|
||||
gum_x86_writer_put_add_reg_imm(cw, GUM_REG_RBX,
|
||||
gum_x86_writer_put_add_reg_imm(cw, GUM_X86_RBX,
|
||||
GUM_RED_ZONE_SIZE + (0x8 * 2));
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, rsp), GUM_REG_RBX);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, rsp), GUM_X86_RBX);
|
||||
|
||||
/* Save the flags */
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x8);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RBX, GUM_X86_RSP, 0x8);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(persistent_ctx_t, rflags), GUM_REG_RBX);
|
||||
cw, GUM_X86_RAX, offsetof(persistent_ctx_t, rflags), GUM_X86_RBX);
|
||||
|
||||
/* Save the RAX */
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x0);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RBX, GUM_X86_RSP, 0x0);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_RAX, offsetof(GumCpuContext, rax), GUM_REG_RBX);
|
||||
cw, GUM_X86_RAX, offsetof(GumCpuContext, rax), GUM_X86_RBX);
|
||||
|
||||
/* Pop the saved values */
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 0x10);
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP, 0x10);
|
||||
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
(GUM_RED_ZONE_SIZE));
|
||||
|
||||
}
|
||||
|
||||
static void instrument_persitent_restore_regs(GumX86Writer * cw,
|
||||
static void instrument_persitent_restore_regs(GumX86Writer *cw,
|
||||
persistent_ctx_t *regs) {
|
||||
|
||||
GumAddress regs_address = GUM_ADDRESS(regs);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, regs_address);
|
||||
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RCX, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, rcx));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RDX, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, rdx));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDI, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RDI, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, rdi));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RSI, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, rsi));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBP, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RBP, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, rbp));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R8, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_R8, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, r8));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R9, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_R9, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, r9));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R10, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_R10, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, r10));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R11, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_R11, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, r11));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R12, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_R12, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, r12));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R13, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_R13, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, r13));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R14, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_R14, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, r14));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R15, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_R15, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, r15));
|
||||
|
||||
/* Don't restore RIP */
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSP, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RSP, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, rsp));
|
||||
|
||||
/* Restore RBX, RAX & Flags */
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
-(GUM_RED_ZONE_SIZE));
|
||||
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RBX, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, rbx));
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_RBX);
|
||||
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RBX, GUM_X86_RAX,
|
||||
offsetof(GumCpuContext, rax));
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX,
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_RBX);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RBX, GUM_X86_RAX,
|
||||
offsetof(persistent_ctx_t, rflags));
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_RBX);
|
||||
|
||||
gum_x86_writer_put_popfx(cw);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_X86_RAX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_X86_RBX);
|
||||
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
(GUM_RED_ZONE_SIZE));
|
||||
|
||||
}
|
||||
|
||||
static void instrument_exit(GumX86Writer *cw) {
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, GUM_ADDRESS(_exit));
|
||||
gum_x86_writer_put_mov_reg_u32(cw, GUM_REG_RDI, 0);
|
||||
gum_x86_writer_put_call_reg(cw, GUM_REG_RAX);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, GUM_ADDRESS(_exit));
|
||||
gum_x86_writer_put_mov_reg_u32(cw, GUM_X86_RDI, 0);
|
||||
gum_x86_writer_put_call_reg(cw, GUM_X86_RAX);
|
||||
|
||||
}
|
||||
|
||||
@ -186,13 +186,13 @@ static int instrument_afl_persistent_loop_func(void) {
|
||||
|
||||
static void instrument_afl_persistent_loop(GumX86Writer *cw) {
|
||||
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
-(GUM_RED_ZONE_SIZE));
|
||||
gum_x86_writer_put_call_address_with_arguments(
|
||||
cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0);
|
||||
gum_x86_writer_put_test_reg_reg(cw, GUM_REG_RAX, GUM_REG_RAX);
|
||||
gum_x86_writer_put_test_reg_reg(cw, GUM_X86_RAX, GUM_X86_RAX);
|
||||
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
(GUM_RED_ZONE_SIZE));
|
||||
|
||||
}
|
||||
@ -200,26 +200,26 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) {
|
||||
static void persistent_prologue_hook(GumX86Writer *cw, persistent_ctx_t *regs) {
|
||||
|
||||
if (persistent_hook == NULL) return;
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
-(GUM_RED_ZONE_SIZE));
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDX,
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RDX,
|
||||
GUM_ADDRESS(&__afl_fuzz_len));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0);
|
||||
gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_RDI, 0xffffffff);
|
||||
gum_x86_writer_put_and_reg_reg(cw, GUM_REG_RDX, GUM_REG_RDI);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RDX, GUM_X86_RDX, 0);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RDX, GUM_X86_RDX, 0);
|
||||
gum_x86_writer_put_mov_reg_u64(cw, GUM_X86_RDI, 0xffffffff);
|
||||
gum_x86_writer_put_and_reg_reg(cw, GUM_X86_RDX, GUM_X86_RDI);
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RSI,
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RSI,
|
||||
GUM_ADDRESS(&__afl_fuzz_ptr));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RSI, 0);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RSI, GUM_X86_RSI, 0);
|
||||
|
||||
gum_x86_writer_put_call_address_with_arguments(
|
||||
cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS,
|
||||
GUM_ADDRESS(®s->ctx), GUM_ARG_REGISTER, GUM_REG_RSI, GUM_ARG_REGISTER,
|
||||
GUM_REG_RDX);
|
||||
GUM_ADDRESS(®s->ctx), GUM_ARG_REGISTER, GUM_X86_RSI, GUM_ARG_REGISTER,
|
||||
GUM_X86_RDX);
|
||||
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
(GUM_RED_ZONE_SIZE));
|
||||
|
||||
}
|
||||
@ -228,23 +228,23 @@ static void instrument_persitent_save_ret(GumX86Writer *cw) {
|
||||
|
||||
/* Stack usage by this function */
|
||||
gssize offset = GUM_RED_ZONE_SIZE + (3 * 8);
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
-(GUM_RED_ZONE_SIZE));
|
||||
|
||||
gum_x86_writer_put_pushfx(cw);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_RAX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_RAX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_RBX);
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, GUM_ADDRESS(&saved_ret));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP,
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, GUM_ADDRESS(&saved_ret));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_RBX, GUM_X86_RSP,
|
||||
offset);
|
||||
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_RAX, GUM_REG_RBX);
|
||||
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_X86_RAX, GUM_X86_RBX);
|
||||
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_X86_RBX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_X86_RAX);
|
||||
gum_x86_writer_put_popfx(cw);
|
||||
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP,
|
||||
(GUM_RED_ZONE_SIZE));
|
||||
|
||||
}
|
||||
@ -278,7 +278,7 @@ void persistent_prologue_arch(GumStalkerOutput *output) {
|
||||
FVERBOSE("Persistent loop reached");
|
||||
|
||||
/* Pop the return value */
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 8);
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP, 8);
|
||||
|
||||
instrument_persitent_save_regs(cw, &saved_regs);
|
||||
|
||||
@ -326,13 +326,13 @@ void persistent_epilogue_arch(GumStalkerOutput *output) {
|
||||
|
||||
/* The stack should be aligned when we re-enter our loop */
|
||||
gconstpointer zero = cw->code + 1;
|
||||
gum_x86_writer_put_test_reg_u32(cw, GUM_REG_RSP, 0xF);
|
||||
gum_x86_writer_put_test_reg_u32(cw, GUM_X86_RSP, 0xF);
|
||||
gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, zero, GUM_NO_HINT);
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, -8);
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_RSP, GUM_X86_RSP, -8);
|
||||
gum_x86_writer_put_label(cw, zero);
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, GUM_ADDRESS(&saved_ret));
|
||||
gum_x86_writer_put_jmp_reg_ptr(cw, GUM_REG_RAX);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_RAX, GUM_ADDRESS(&saved_ret));
|
||||
gum_x86_writer_put_jmp_reg_ptr(cw, GUM_X86_RAX);
|
||||
|
||||
}
|
||||
|
||||
|
@ -25,105 +25,105 @@ gboolean persistent_is_supported(void) {
|
||||
|
||||
}
|
||||
|
||||
static void instrument_persitent_save_regs(GumX86Writer * cw,
|
||||
static void instrument_persitent_save_regs(GumX86Writer *cw,
|
||||
persistent_ctx_t *regs) {
|
||||
|
||||
GumAddress regs_address = GUM_ADDRESS(regs);
|
||||
|
||||
/* Should be pushing FPU here, but meh */
|
||||
gum_x86_writer_put_pushfx(cw);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_EAX);
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX, regs_address);
|
||||
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(GumCpuContext, ebx), GUM_REG_EBX);
|
||||
cw, GUM_X86_EAX, offsetof(GumCpuContext, ebx), GUM_X86_EBX);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(GumCpuContext, ecx), GUM_REG_ECX);
|
||||
cw, GUM_X86_EAX, offsetof(GumCpuContext, ecx), GUM_X86_ECX);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(GumCpuContext, edx), GUM_REG_EDX);
|
||||
cw, GUM_X86_EAX, offsetof(GumCpuContext, edx), GUM_X86_EDX);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(GumCpuContext, edi), GUM_REG_EDI);
|
||||
cw, GUM_X86_EAX, offsetof(GumCpuContext, edi), GUM_X86_EDI);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(GumCpuContext, esi), GUM_REG_ESI);
|
||||
cw, GUM_X86_EAX, offsetof(GumCpuContext, esi), GUM_X86_ESI);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(GumCpuContext, ebp), GUM_REG_EBP);
|
||||
cw, GUM_X86_EAX, offsetof(GumCpuContext, ebp), GUM_X86_EBP);
|
||||
|
||||
/* Store RIP */
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EBX,
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EBX,
|
||||
GUM_ADDRESS(persistent_start));
|
||||
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(GumCpuContext, eip), GUM_REG_EBX);
|
||||
cw, GUM_X86_EAX, offsetof(GumCpuContext, eip), GUM_X86_EBX);
|
||||
|
||||
/* Store adjusted RSP */
|
||||
gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_EBX, GUM_REG_ESP);
|
||||
gum_x86_writer_put_mov_reg_reg(cw, GUM_X86_EBX, GUM_X86_ESP);
|
||||
|
||||
/* RED_ZONE + Saved flags, RAX */
|
||||
gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EBX, (0x4 * 2));
|
||||
gum_x86_writer_put_add_reg_imm(cw, GUM_X86_EBX, (0x4 * 2));
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(GumCpuContext, esp), GUM_REG_EBX);
|
||||
cw, GUM_X86_EAX, offsetof(GumCpuContext, esp), GUM_X86_EBX);
|
||||
|
||||
/* Save the flags */
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x4);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EBX, GUM_X86_ESP, 0x4);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(persistent_ctx_t, eflags), GUM_REG_EBX);
|
||||
cw, GUM_X86_EAX, offsetof(persistent_ctx_t, eflags), GUM_X86_EBX);
|
||||
|
||||
/* Save the RAX */
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x0);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EBX, GUM_X86_ESP, 0x0);
|
||||
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||
cw, GUM_REG_EAX, offsetof(GumCpuContext, eax), GUM_REG_EBX);
|
||||
cw, GUM_X86_EAX, offsetof(GumCpuContext, eax), GUM_X86_EBX);
|
||||
|
||||
/* Pop the saved values */
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 0x8);
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_ESP, GUM_X86_ESP, 0x8);
|
||||
|
||||
}
|
||||
|
||||
static void instrument_persitent_restore_regs(GumX86Writer * cw,
|
||||
static void instrument_persitent_restore_regs(GumX86Writer *cw,
|
||||
persistent_ctx_t *regs) {
|
||||
|
||||
GumAddress regs_address = GUM_ADDRESS(regs);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX, regs_address);
|
||||
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_EAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_ECX, GUM_X86_EAX,
|
||||
offsetof(GumCpuContext, ecx));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EDX, GUM_X86_EAX,
|
||||
offsetof(GumCpuContext, edx));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDI, GUM_REG_EAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EDI, GUM_X86_EAX,
|
||||
offsetof(GumCpuContext, edi));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESI, GUM_REG_EAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_ESI, GUM_X86_EAX,
|
||||
offsetof(GumCpuContext, esi));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EBP, GUM_X86_EAX,
|
||||
offsetof(GumCpuContext, ebp));
|
||||
|
||||
/* Don't restore RIP */
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESP, GUM_REG_EAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_ESP, GUM_X86_EAX,
|
||||
offsetof(GumCpuContext, esp));
|
||||
|
||||
/* Restore RBX, RAX & Flags */
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EBX, GUM_X86_EAX,
|
||||
offsetof(GumCpuContext, ebx));
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_EBX);
|
||||
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EBX, GUM_X86_EAX,
|
||||
offsetof(GumCpuContext, eax));
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_EBX);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EBX, GUM_X86_EAX,
|
||||
offsetof(persistent_ctx_t, eflags));
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_EBX);
|
||||
|
||||
gum_x86_writer_put_popfx(cw);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_X86_EAX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_X86_EBX);
|
||||
|
||||
}
|
||||
|
||||
static void instrument_exit(GumX86Writer *cw) {
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(_exit));
|
||||
gum_x86_writer_put_mov_reg_u32(cw, GUM_REG_EDI, 0);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_EDI);
|
||||
gum_x86_writer_put_call_reg(cw, GUM_REG_EAX);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX, GUM_ADDRESS(_exit));
|
||||
gum_x86_writer_put_mov_reg_u32(cw, GUM_X86_EDI, 0);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_EDI);
|
||||
gum_x86_writer_put_call_reg(cw, GUM_X86_EAX);
|
||||
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) {
|
||||
|
||||
gum_x86_writer_put_call_address_with_arguments(
|
||||
cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0);
|
||||
gum_x86_writer_put_test_reg_reg(cw, GUM_REG_EAX, GUM_REG_EAX);
|
||||
gum_x86_writer_put_test_reg_reg(cw, GUM_X86_EAX, GUM_X86_EAX);
|
||||
|
||||
}
|
||||
|
||||
@ -153,20 +153,20 @@ static void persistent_prologue_hook(GumX86Writer *cw, persistent_ctx_t *regs) {
|
||||
|
||||
if (persistent_hook == NULL) return;
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX,
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_ECX,
|
||||
GUM_ADDRESS(&__afl_fuzz_len));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_ECX, GUM_X86_ECX, 0);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_ECX, GUM_X86_ECX, 0);
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDX,
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EDX,
|
||||
GUM_ADDRESS(&__afl_fuzz_ptr));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EDX, 0);
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EDX, GUM_X86_EDX, 0);
|
||||
|
||||
/* Base address is 64-bits (hence two zero arguments) */
|
||||
gum_x86_writer_put_call_address_with_arguments(
|
||||
cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS,
|
||||
GUM_ADDRESS(®s->ctx), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER,
|
||||
GUM_REG_ECX);
|
||||
GUM_ADDRESS(®s->ctx), GUM_ARG_REGISTER, GUM_X86_EDX, GUM_ARG_REGISTER,
|
||||
GUM_X86_ECX);
|
||||
|
||||
}
|
||||
|
||||
@ -176,16 +176,16 @@ static void instrument_persitent_save_ret(GumX86Writer *cw) {
|
||||
gssize offset = (3 * 4);
|
||||
|
||||
gum_x86_writer_put_pushfx(cw);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_EAX);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_X86_EBX);
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(&saved_ret));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP,
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX, GUM_ADDRESS(&saved_ret));
|
||||
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_X86_EBX, GUM_X86_ESP,
|
||||
offset);
|
||||
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_EAX, GUM_REG_EBX);
|
||||
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_X86_EAX, GUM_X86_EBX);
|
||||
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_X86_EBX);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_X86_EAX);
|
||||
gum_x86_writer_put_popfx(cw);
|
||||
|
||||
}
|
||||
@ -219,7 +219,7 @@ void persistent_prologue_arch(GumStalkerOutput *output) {
|
||||
FVERBOSE("Persistent loop reached");
|
||||
|
||||
/* Pop the return value */
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 4);
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_X86_ESP, GUM_X86_ESP, 4);
|
||||
|
||||
instrument_persitent_save_regs(cw, &saved_regs);
|
||||
|
||||
@ -263,8 +263,8 @@ void persistent_epilogue_arch(GumStalkerOutput *output) {
|
||||
|
||||
if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
|
||||
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(&saved_ret));
|
||||
gum_x86_writer_put_jmp_reg_ptr(cw, GUM_REG_EAX);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_X86_EAX, GUM_ADDRESS(&saved_ret));
|
||||
gum_x86_writer_put_jmp_reg_ptr(cw, GUM_X86_EAX);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,11 @@
|
||||
#include <errno.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
#include "entry.h"
|
||||
#include "intercept.h"
|
||||
#include "prefetch.h"
|
||||
#include "shm.h"
|
||||
#include "stalker.h"
|
||||
#include "util.h"
|
||||
|
||||
@ -19,7 +18,7 @@
|
||||
typedef struct {
|
||||
|
||||
size_t count;
|
||||
void * entry[PREFETCH_ENTRIES];
|
||||
void *entry[PREFETCH_ENTRIES];
|
||||
|
||||
guint8 backpatch_data[BP_SIZE];
|
||||
gsize backpatch_size;
|
||||
@ -32,6 +31,8 @@ gboolean prefetch_backpatch = TRUE;
|
||||
static prefetch_data_t *prefetch_data = NULL;
|
||||
static int prefetch_shm_id = -1;
|
||||
|
||||
static GHashTable *cant_prefetch = NULL;
|
||||
|
||||
static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self,
|
||||
const GumBackpatch *backpatch,
|
||||
gsize size) {
|
||||
@ -40,6 +41,18 @@ static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self,
|
||||
if (!entry_run) { return; }
|
||||
gsize remaining =
|
||||
sizeof(prefetch_data->backpatch_data) - prefetch_data->backpatch_size;
|
||||
|
||||
gpointer from = gum_stalker_backpatch_get_from(backpatch);
|
||||
gpointer to = gum_stalker_backpatch_get_to(backpatch);
|
||||
|
||||
/* Stop reporting patches which can't be prefetched */
|
||||
if (g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(from)) ||
|
||||
g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(to))) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (sizeof(gsize) + size > remaining) { return; }
|
||||
|
||||
gsize *dst_backpatch_size =
|
||||
@ -68,6 +81,9 @@ void prefetch_write(void *addr) {
|
||||
/* Bail if we aren't initialized */
|
||||
if (prefetch_data == NULL) return;
|
||||
|
||||
/* Stop reporting blocks which can't be prefetched */
|
||||
if (g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(addr))) { return; }
|
||||
|
||||
/*
|
||||
* Our shared memory IPC is large enough for about 1000 entries, we can fine
|
||||
* tune this if we need to. But if we have more new blocks that this in a
|
||||
@ -84,6 +100,38 @@ void prefetch_write(void *addr) {
|
||||
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
||||
GumAddress address;
|
||||
gboolean executable;
|
||||
|
||||
} check_executable_t;
|
||||
|
||||
static gboolean prefetch_find_executable(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
check_executable_t *ctx = (check_executable_t *)user_data;
|
||||
if (GUM_MEMORY_RANGE_INCLUDES(details->range, ctx->address)) {
|
||||
|
||||
ctx->executable = TRUE;
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static gboolean prefetch_is_executable(void *address) {
|
||||
|
||||
check_executable_t ctx = {.address = GUM_ADDRESS(address),
|
||||
.executable = FALSE};
|
||||
gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, prefetch_find_executable,
|
||||
&ctx);
|
||||
return ctx.executable;
|
||||
|
||||
}
|
||||
|
||||
static void prefetch_read_blocks(void) {
|
||||
|
||||
GumStalker *stalker = stalker_get();
|
||||
@ -92,7 +140,24 @@ static void prefetch_read_blocks(void) {
|
||||
for (size_t i = 0; i < prefetch_data->count; i++) {
|
||||
|
||||
void *addr = prefetch_data->entry[i];
|
||||
gum_stalker_prefetch(stalker, addr, 1);
|
||||
|
||||
if (prefetch_is_executable(addr)) {
|
||||
|
||||
gum_stalker_prefetch(stalker, addr, 1);
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
* If our child process creates a new executable mapping, e.g. by
|
||||
* dynamically loading a new DSO, then this won't appear in our parent
|
||||
* process' memory map and hence we can't prefetch it. Add it to a
|
||||
* hashtable which the child will inherit on the next fork to prevent the
|
||||
* child from keep reporting it and exhausting the shared memory buffers
|
||||
* used to pass new blocks from the child back to the parent.
|
||||
*/
|
||||
g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(addr));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -107,7 +172,7 @@ static void prefetch_read_blocks(void) {
|
||||
static void prefetch_read_patches(void) {
|
||||
|
||||
gsize offset = 0;
|
||||
GumStalker * stalker = stalker_get();
|
||||
GumStalker *stalker = stalker_get();
|
||||
GumBackpatch *backpatch = NULL;
|
||||
|
||||
for (gsize remaining = prefetch_data->backpatch_size - offset;
|
||||
@ -125,7 +190,36 @@ static void prefetch_read_patches(void) {
|
||||
}
|
||||
|
||||
backpatch = (GumBackpatch *)&prefetch_data->backpatch_data[offset];
|
||||
gum_stalker_prefetch_backpatch(stalker, backpatch);
|
||||
|
||||
gpointer from = gum_stalker_backpatch_get_from(backpatch);
|
||||
gpointer to = gum_stalker_backpatch_get_to(backpatch);
|
||||
|
||||
/*
|
||||
* If our child process creates a new executable mapping, e.g. by
|
||||
* dynamically loading a new DSO, then this won't appear in our parent
|
||||
* process' memory map and hence we can't prefetch it. Add it to a
|
||||
* hashtable which the child will inherit on the next fork to prevent the
|
||||
* child from keep reporting it and exhausting the shared memory buffers
|
||||
* used to pass new blocks from the child back to the parent.
|
||||
*/
|
||||
if (!prefetch_is_executable(from)) {
|
||||
|
||||
g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(from));
|
||||
|
||||
}
|
||||
|
||||
if (!prefetch_is_executable(to)) {
|
||||
|
||||
g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(to));
|
||||
|
||||
}
|
||||
|
||||
if (prefetch_is_executable(from) && prefetch_is_executable(to)) {
|
||||
|
||||
gum_stalker_prefetch_backpatch(stalker, backpatch);
|
||||
|
||||
}
|
||||
|
||||
offset += size;
|
||||
|
||||
}
|
||||
@ -190,34 +284,20 @@ void prefetch_init(void) {
|
||||
* with the coverage bitmap region and fork will take care of ensuring both
|
||||
* the parent and child see the same consistent memory region.
|
||||
*/
|
||||
prefetch_shm_id =
|
||||
shmget(IPC_PRIVATE, sizeof(prefetch_data_t), IPC_CREAT | IPC_EXCL | 0600);
|
||||
if (prefetch_shm_id < 0) {
|
||||
|
||||
FFATAL("prefetch_shm_id < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
prefetch_data = shmat(prefetch_shm_id, NULL, 0);
|
||||
g_assert(prefetch_data != MAP_FAILED);
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process dies.
|
||||
*/
|
||||
if (shmctl(prefetch_shm_id, IPC_RMID, NULL) < 0) {
|
||||
|
||||
FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(prefetch_data, '\0', sizeof(prefetch_data_t));
|
||||
prefetch_data = shm_create(sizeof(prefetch_data_t));
|
||||
|
||||
prefetch_hook_fork();
|
||||
|
||||
cant_prefetch = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
if (cant_prefetch == NULL) {
|
||||
|
||||
FFATAL("Failed to g_hash_table_new, errno: %d", errno);
|
||||
|
||||
}
|
||||
|
||||
if (!prefetch_backpatch) { return; }
|
||||
|
||||
GumStalkerObserver * observer = stalker_get_observer();
|
||||
GumStalkerObserver *observer = stalker_get_observer();
|
||||
GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer);
|
||||
iface->notify_backpatch = gum_afl_stalker_backpatcher_notify;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
typedef struct {
|
||||
|
||||
gchar * suffix;
|
||||
gchar *suffix;
|
||||
GumMemoryRange *range;
|
||||
gboolean done;
|
||||
|
||||
@ -135,7 +135,7 @@ static gboolean convert_name_token_for_module(const GumModuleDetails *details,
|
||||
|
||||
static void convert_name_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
gchar * suffix = g_strconcat("/", token, NULL);
|
||||
gchar *suffix = g_strconcat("/", token, NULL);
|
||||
convert_name_ctx_t ctx = {.suffix = suffix, .range = range, .done = false};
|
||||
|
||||
gum_process_enumerate_modules(convert_name_token_for_module, &ctx);
|
||||
@ -235,7 +235,7 @@ static void print_ranges(char *key, GArray *ranges) {
|
||||
static gboolean collect_module_ranges_callback(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
GArray * ranges = (GArray *)user_data;
|
||||
GArray *ranges = (GArray *)user_data;
|
||||
GumMemoryRange range = *details->range;
|
||||
g_array_append_val(ranges, range);
|
||||
return TRUE;
|
||||
@ -292,12 +292,12 @@ void ranges_add_exclude(GumMemoryRange *range) {
|
||||
|
||||
static GArray *collect_ranges(char *env_key) {
|
||||
|
||||
char * env_val;
|
||||
gchar ** tokens;
|
||||
char *env_val;
|
||||
gchar **tokens;
|
||||
int token_count;
|
||||
GumMemoryRange range;
|
||||
int i;
|
||||
GArray * result;
|
||||
GArray *result;
|
||||
|
||||
result = g_array_new(false, false, sizeof(GumMemoryRange));
|
||||
|
||||
@ -330,7 +330,7 @@ static GArray *collect_ranges(char *env_key) {
|
||||
|
||||
static GArray *collect_libs_ranges(void) {
|
||||
|
||||
GArray * result;
|
||||
GArray *result;
|
||||
GumMemoryRange range;
|
||||
result = g_array_new(false, false, sizeof(GumMemoryRange));
|
||||
|
||||
@ -422,7 +422,7 @@ static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra,
|
||||
|
||||
static GArray *intersect_ranges(GArray *a, GArray *b) {
|
||||
|
||||
GArray * result;
|
||||
GArray *result;
|
||||
GumMemoryRange *ra;
|
||||
GumMemoryRange *rb;
|
||||
GumMemoryRange ri;
|
||||
@ -452,7 +452,7 @@ static GArray *intersect_ranges(GArray *a, GArray *b) {
|
||||
|
||||
static GArray *subtract_ranges(GArray *a, GArray *b) {
|
||||
|
||||
GArray * result;
|
||||
GArray *result;
|
||||
GumMemoryRange *ra;
|
||||
GumAddress ral;
|
||||
GumMemoryRange *rb;
|
||||
@ -528,7 +528,7 @@ static GArray *subtract_ranges(GArray *a, GArray *b) {
|
||||
|
||||
static GArray *merge_ranges(GArray *a) {
|
||||
|
||||
GArray * result;
|
||||
GArray *result;
|
||||
GumMemoryRange rp;
|
||||
GumMemoryRange *r;
|
||||
|
||||
@ -585,18 +585,16 @@ void ranges_config(void) {
|
||||
void ranges_init(void) {
|
||||
|
||||
GumMemoryRange ri;
|
||||
GArray * step1;
|
||||
GArray * step2;
|
||||
GArray * step3;
|
||||
GArray * step4;
|
||||
GArray * step5;
|
||||
GArray *step1;
|
||||
GArray *step2;
|
||||
GArray *step3;
|
||||
GArray *step4;
|
||||
GArray *step5;
|
||||
|
||||
FOKF(cBLU "Ranges" cRST " - " cGRN "instrument jit:" cYEL " [%c]",
|
||||
ranges_inst_jit ? 'X' : ' ');
|
||||
FOKF(cBLU "Ranges" cRST " - " cGRN "instrument libraries:" cYEL " [%c]",
|
||||
ranges_inst_libs ? 'X' : ' ');
|
||||
FOKF(cBLU "Ranges" cRST " - " cGRN "instrument libraries:" cYEL " [%c]",
|
||||
ranges_inst_libs ? 'X' : ' ');
|
||||
|
||||
print_ranges("include", include_ranges);
|
||||
print_ranges("exclude", exclude_ranges);
|
||||
@ -671,7 +669,7 @@ gboolean range_is_excluded(GumAddress address) {
|
||||
void ranges_exclude() {
|
||||
|
||||
GumMemoryRange *r;
|
||||
GumStalker * stalker = stalker_get();
|
||||
GumStalker *stalker = stalker_get();
|
||||
|
||||
FVERBOSE("Excluding ranges");
|
||||
|
||||
|
@ -11,6 +11,8 @@ void seccomp_on_fork(void) {
|
||||
|
||||
#ifdef __APPLE__
|
||||
FFATAL("Seccomp not supported on OSX");
|
||||
#elif defined(__ANDROID__)
|
||||
FFATAL("Seccomp not supported on Android");
|
||||
#else
|
||||
seccomp_callback_parent();
|
||||
#endif
|
||||
@ -32,6 +34,8 @@ void seccomp_init(void) {
|
||||
|
||||
#ifdef __APPLE__
|
||||
FFATAL("Seccomp not supported on OSX");
|
||||
#elif defined(__ANDROID__)
|
||||
FFATAL("Seccomp not supported on Android");
|
||||
#else
|
||||
seccomp_callback_initialize();
|
||||
#endif
|
||||
|
@ -8,9 +8,9 @@
|
||||
#include "seccomp.h"
|
||||
#include "util.h"
|
||||
|
||||
static void seccomp_callback_filter(struct seccomp_notif * req,
|
||||
static void seccomp_callback_filter(struct seccomp_notif *req,
|
||||
struct seccomp_notif_resp *resp,
|
||||
GumReturnAddressArray * frames) {
|
||||
GumReturnAddressArray *frames) {
|
||||
|
||||
GumDebugSymbolDetails details = {0};
|
||||
if (req->data.nr == SYS_OPENAT) {
|
||||
@ -54,7 +54,7 @@ static void seccomp_callback_filter(struct seccomp_notif * req,
|
||||
free(syms);
|
||||
#else
|
||||
void **syms = (void **)__builtin_frame_address(0);
|
||||
void * framep = __builtin_frame_address(1);
|
||||
void *framep = __builtin_frame_address(1);
|
||||
int i = 0;
|
||||
|
||||
syms = framep;
|
||||
|
@ -21,7 +21,7 @@ typedef struct {
|
||||
|
||||
seccomp_child_func_t func;
|
||||
int event_fd;
|
||||
void * ctx;
|
||||
void *ctx;
|
||||
|
||||
} seccomp_child_func_ctx_t;
|
||||
|
||||
|
@ -129,7 +129,7 @@ static volatile bool seccomp_filter_child_done = false;
|
||||
static pid_t seccomp_filter_child = -1;
|
||||
static GumCpuContext seccomp_filter_cpu_context = {0};
|
||||
static GumReturnAddressArray seccomp_filter_frames = {.len = 0, .items = {0}};
|
||||
static GumBacktracer * seccomp_filter_backtracer = NULL;
|
||||
static GumBacktracer *seccomp_filter_backtracer = NULL;
|
||||
|
||||
static void seccomp_filter_child_handler(int sig, siginfo_t *info,
|
||||
void *ucontext) {
|
||||
@ -209,7 +209,7 @@ int seccomp_filter_install(pid_t child) {
|
||||
|
||||
void seccomp_filter_run(int fd, seccomp_filter_callback_t callback) {
|
||||
|
||||
struct seccomp_notif * req = NULL;
|
||||
struct seccomp_notif *req = NULL;
|
||||
struct seccomp_notif_resp *resp = NULL;
|
||||
struct seccomp_notif_sizes sizes;
|
||||
|
||||
|
@ -59,9 +59,9 @@ void seccomp_socket_send(int sockfd, int fd) {
|
||||
struct iovec iov = {.iov_base = &data, .iov_len = sizeof(data)};
|
||||
union cmsg control_msg = {.hdr = {
|
||||
|
||||
.cmsg_len = CMSG_LEN(sizeof(int)),
|
||||
.cmsg_level = SOL_SOCKET,
|
||||
.cmsg_type = SCM_RIGHTS,
|
||||
.cmsg_len = CMSG_LEN(sizeof(int)),
|
||||
.cmsg_level = SOL_SOCKET,
|
||||
.cmsg_type = SCM_RIGHTS,
|
||||
|
||||
}};
|
||||
|
||||
|
87
frida_mode/src/shm.c
Normal file
87
frida_mode/src/shm.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include "shm.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#ifdef __ANDROID__
|
||||
#include <linux/ashmem.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define ASHMEM_DEVICE "/dev/ashmem"
|
||||
|
||||
void *shm_create(size_t size) {
|
||||
|
||||
int fd = -1;
|
||||
char ourkey[11] = {0};
|
||||
void *addr = MAP_FAILED;
|
||||
struct ashmem_pin pin = {0, size};
|
||||
|
||||
fd = open(ASHMEM_DEVICE, O_RDWR);
|
||||
if (fd < 0) { FFATAL("Failed open /dev/ashmem: %d", errno); }
|
||||
|
||||
if (snprintf(ourkey, sizeof(ourkey) - 1, "%d", IPC_PRIVATE) < 0) {
|
||||
|
||||
FFATAL("Failed to generate key: %d", errno);
|
||||
|
||||
}
|
||||
|
||||
if (ioctl(fd, ASHMEM_SET_NAME, ourkey) < 0) {
|
||||
|
||||
FFATAL("ioctl(ASHMEM_SET_NAME) errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
if (ioctl(fd, ASHMEM_SET_SIZE, size) < 0) {
|
||||
|
||||
FFATAL("ioctl(ASHMEM_SET_SIZE) errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (addr == MAP_FAILED) { FFATAL("mmap failed: %d\n", errno); }
|
||||
|
||||
/* Shared memory pinning has been deprecated. So if the ioctl fails, then
|
||||
just assume we are running on a version where it has been. Worst case, we
|
||||
will leak the shared memory region.*/
|
||||
ioctl(fd, ASHMEM_UNPIN, &pin);
|
||||
close(fd);
|
||||
|
||||
return addr;
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
void *shm_create(size_t size) {
|
||||
|
||||
int shm_id =
|
||||
shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
|
||||
if (shm_id < 0) { FFATAL("shm_id < 0 - errno: %d\n", errno); }
|
||||
|
||||
void *addr = shmat(shm_id, NULL, 0);
|
||||
if (addr == MAP_FAILED) { FFATAL("addr == MAP_FAILED - errno: %d\n", errno); }
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process
|
||||
* dies.
|
||||
*/
|
||||
if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
|
||||
|
||||
FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(addr, '\0', size);
|
||||
|
||||
return addr;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -74,7 +74,7 @@ static gboolean stalker_exclude_self(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(user_data);
|
||||
gchar * name;
|
||||
gchar *name;
|
||||
gboolean found;
|
||||
GumStalker *stalker;
|
||||
if (details->file == NULL) { return TRUE; }
|
||||
@ -100,7 +100,7 @@ void stalker_init(void) {
|
||||
FOKF(cBLU "Stalker" cRST " - " cGRN "adjacent_blocks:" cYEL " [%u]",
|
||||
stalker_adjacent_blocks);
|
||||
|
||||
#if !(defined(__x86_64__) || defined(__i386__))
|
||||
#if !(defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))
|
||||
if (getenv("AFL_FRIDA_STALKER_IC_ENTRIES") != NULL) {
|
||||
|
||||
FFATAL("AFL_FRIDA_STALKER_IC_ENTRIES not supported");
|
||||
@ -131,9 +131,14 @@ void stalker_init(void) {
|
||||
|
||||
}
|
||||
|
||||
gum_stalker_activate_experimental_unwind_support();
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
stalker = g_object_new(GUM_TYPE_STALKER, "ic-entries", stalker_ic_entries,
|
||||
"adjacent-blocks", stalker_adjacent_blocks, NULL);
|
||||
#elif defined(__aarch64__)
|
||||
stalker =
|
||||
g_object_new(GUM_TYPE_STALKER, "ic-entries", stalker_ic_entries, NULL);
|
||||
#else
|
||||
stalker = gum_stalker_new();
|
||||
#endif
|
||||
|
@ -2,21 +2,20 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "entry.h"
|
||||
#include "shm.h"
|
||||
#include "stalker.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MICRO_TO_SEC 1000000
|
||||
|
||||
char * stats_filename = NULL;
|
||||
char *stats_filename = NULL;
|
||||
guint64 stats_interval = 0;
|
||||
static guint64 stats_interval_us = 0;
|
||||
static int stats_fd = -1;
|
||||
@ -41,8 +40,8 @@ void stats_write(void) {
|
||||
stats_data->curr.stats_time = current_time;
|
||||
|
||||
GDateTime *date_time = g_date_time_new_now_local();
|
||||
char * date_string = g_date_time_format(date_time, "%Y-%m-%d");
|
||||
char * time_string = g_date_time_format(date_time, "%H:%M:%S");
|
||||
char *date_string = g_date_time_format(date_time, "%Y-%m-%d");
|
||||
char *time_string = g_date_time_format(date_time, "%H:%M:%S");
|
||||
guint elapsed = (stats_data->curr.stats_time - stats_data->prev.stats_time) /
|
||||
MICRO_TO_SEC;
|
||||
|
||||
@ -360,27 +359,10 @@ void stats_init(void) {
|
||||
|
||||
g_free(path);
|
||||
|
||||
int shm_id =
|
||||
shmget(IPC_PRIVATE, sizeof(stats_data_t), IPC_CREAT | IPC_EXCL | 0600);
|
||||
if (shm_id < 0) { FFATAL("shm_id < 0 - errno: %d\n", errno); }
|
||||
|
||||
stats_data = shmat(shm_id, NULL, 0);
|
||||
g_assert(stats_data != MAP_FAILED);
|
||||
|
||||
GumStalkerObserver *observer = stalker_get_observer();
|
||||
stats_observer_init(observer);
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process dies.
|
||||
*/
|
||||
if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
|
||||
|
||||
FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(stats_data, '\0', sizeof(stats_data_t));
|
||||
stats_data = shm_create(sizeof(stats_data_t));
|
||||
|
||||
starts_arch_init();
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
#include "ranges.h"
|
||||
#include "shm.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
|
||||
@ -44,24 +44,7 @@ static stats_data_arch_t *stats_data_arch = NULL;
|
||||
|
||||
void starts_arch_init(void) {
|
||||
|
||||
int shm_id = shmget(IPC_PRIVATE, sizeof(stats_data_arch_t),
|
||||
IPC_CREAT | IPC_EXCL | 0600);
|
||||
if (shm_id < 0) { FFATAL("shm_id < 0 - errno: %d\n", errno); }
|
||||
|
||||
stats_data_arch = shmat(shm_id, NULL, 0);
|
||||
g_assert(stats_data_arch != MAP_FAILED);
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process dies.
|
||||
*/
|
||||
if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
|
||||
|
||||
FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(stats_data_arch, '\0', sizeof(stats_data_arch_t));
|
||||
stats_data_arch = shm_create(sizeof(stats_data_arch_t));
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
#include "ranges.h"
|
||||
#include "shm.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
|
||||
@ -46,24 +46,7 @@ static stats_data_arch_t *stats_data_arch = NULL;
|
||||
|
||||
void starts_arch_init(void) {
|
||||
|
||||
int shm_id = shmget(IPC_PRIVATE, sizeof(stats_data_arch_t),
|
||||
IPC_CREAT | IPC_EXCL | 0600);
|
||||
if (shm_id < 0) { FFATAL("shm_id < 0 - errno: %d\n", errno); }
|
||||
|
||||
stats_data_arch = shmat(shm_id, NULL, 0);
|
||||
g_assert(stats_data_arch != MAP_FAILED);
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process dies.
|
||||
*/
|
||||
if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
|
||||
|
||||
FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(stats_data_arch, '\0', sizeof(stats_data_arch_t));
|
||||
stats_data_arch = shm_create(sizeof(stats_data_arch_t));
|
||||
|
||||
}
|
||||
|
||||
@ -248,7 +231,7 @@ void stats_write_arch(stats_data_t *data) {
|
||||
|
||||
static x86_op_type stats_get_operand_type(const cs_insn *instr) {
|
||||
|
||||
cs_x86 * x86 = &instr->detail->x86;
|
||||
cs_x86 *x86 = &instr->detail->x86;
|
||||
cs_x86_op *operand;
|
||||
|
||||
if (x86->op_count != 1) {
|
||||
@ -266,7 +249,7 @@ static x86_op_type stats_get_operand_type(const cs_insn *instr) {
|
||||
|
||||
static void stats_collect_call_imm_excluded_arch(const cs_insn *instr) {
|
||||
|
||||
cs_x86 * x86 = &instr->detail->x86;
|
||||
cs_x86 *x86 = &instr->detail->x86;
|
||||
cs_x86_op *operand = &x86->operands[0];
|
||||
|
||||
if (range_is_excluded(GUM_ADDRESS(operand->imm))) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user