diff options
author | hexcoder <hexcoder-@users.noreply.github.com> | 2021-05-31 19:18:24 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-31 19:18:24 +0200 |
commit | 97a1f89881878db9bd6b4cd666b3447a63818dcf (patch) | |
tree | 46e844356f7cf88c08f9f9907caa11656a24f416 | |
parent | b246de789105750558f3d6f884ba61e54cb98441 (diff) | |
parent | 1a2da67ed0505c9ac0aa1048ba3d607f3c1aa639 (diff) | |
download | afl++-97a1f89881878db9bd6b4cd666b3447a63818dcf.tar.gz |
Merge branch 'dev' into going_atomic
188 files changed, 12971 insertions, 1329 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..102722a4 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: AFLplusplusEU +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5f3429e..35051a20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: - name: update run: sudo apt-get update && sudo apt-get upgrade -y - name: install packages - run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools + run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build - name: compiler installed run: gcc -v ; echo ; clang -v - name: install gcc plugin diff --git a/.gitignore b/.gitignore index c8d29e50..8c420b5e 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,4 @@ gmon.out afl-frida-trace.so utils/afl_network_proxy/afl-network-client utils/afl_network_proxy/afl-network-server +*.o.tmp diff --git a/Dockerfile b/Dockerfile index 8f89b9aa..18fb6367 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,6 +50,7 @@ RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0 ENV LLVM_CONFIG=llvm-config-12 ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_TRY_AFFINITY=1 ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov @@ -61,8 +62,10 @@ WORKDIR /AFLplusplus RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \ make distrib && make install && make clean -RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc -RUN echo 'export PS1="[afl++]$PS1"' >> ~/.bashrc +RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc' +RUN echo '. /etc/bash_completion' >> ~/.bashrc +RUN echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc +RUN echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc ENV IS_DOCKER="1" # Disabled until we have the container ready diff --git a/GNUmakefile b/GNUmakefile index 9d98aa00..270746b4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -503,21 +503,21 @@ code-format: ./.custom-format.py -i instrumentation/*.h ./.custom-format.py -i instrumentation/*.cc ./.custom-format.py -i instrumentation/*.c + ./.custom-format.py -i *.h + ./.custom-format.py -i *.c @#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-( @#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-( ./.custom-format.py -i utils/*/*.c* ./.custom-format.py -i utils/*/*.h ./.custom-format.py -i test/*.c + ./.custom-format.py -i frida_mode/src/*.c + ./.custom-format.py -i frida_mode/include/*.h + -./.custom-format.py -i frida_mode/src/*/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.cc ./.custom-format.py -i qemu_mode/libcompcov/*.h ./.custom-format.py -i qemu_mode/libqasan/*.c ./.custom-format.py -i qemu_mode/libqasan/*.h - ./.custom-format.py -i frida_mode/src/*.c - ./.custom-format.py -i frida_mode/include/*.h - -./.custom-format.py -i frida_mode/src/*/*.c - ./.custom-format.py -i *.h - ./.custom-format.py -i *.c .PHONY: test_build diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 61c17e92..2d50badc 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -36,7 +36,7 @@ ifeq "$(SYS)" "OpenBSD" LLVM_CONFIG ?= $(BIN_PATH)/llvm-config HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) ifeq "$(HAS_OPT)" "1" - $(warning llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9") + $(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 12) -> e.g. "pkg_add llvm-7.0.1p9") endif else LLVM_CONFIG ?= llvm-config @@ -45,7 +45,7 @@ endif LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' ) LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' ) LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' ) -LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^[0-2]\.' && echo 1 || echo 0 ) +LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-5]\.' && echo 1 || echo 0 ) LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[3-9]' && echo 1 || echo 0 ) LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 ) LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 ) @@ -61,7 +61,7 @@ ifeq "$(LLVMVER)" "" endif ifeq "$(LLVM_UNSUPPORTED)" "1" - $(error llvm_mode only supports llvm from version 3.4 onwards) + $(error llvm_mode only supports llvm from version 6.0 onwards) endif ifeq "$(LLVM_TOO_NEW)" "1" @@ -346,7 +346,7 @@ no_build: test_deps: @echo "[*] Checking for working 'llvm-config'..." ifneq "$(LLVM_APPLE_XCODE)" "1" - @type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 ) + @type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-11 or something like that.)"; exit 1 ) endif @echo "[*] Checking for working '$(CC)'..." @type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 ) diff --git a/README.md b/README.md index 583db85f..69e2d14a 100644 --- a/README.md +++ b/README.md @@ -84,22 +84,23 @@ behaviours and defaults: ## Important features of afl++ - afl++ supports llvm up to version 12, very fast binary fuzzing with QEMU 5.1 + afl++ supports llvm from 6.0 up to version 12, very fast binary fuzzing with QEMU 5.1 with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, Mac OS, Solaris and Android support and much, much, much more. | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| - | NeverZero | x86[_64]| x(1) | x | | x | x | - | Persistent Mode | | x | x | | x86[_64]/arm[64] | x | + | NeverZero | x86[_64]| x(1) | x | x | x | x | + | Persistent Mode | | x | x | x86[_64] | x86[_64]/arm[64] | x | | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | - | CmpLog | | x | | | x86[_64]/arm[64] | | + | CmpLog | | x | | x86[_64] | x86[_64]/arm[64] | | | Selective Instrumentation| | x | x | x | x | | | Non-Colliding Coverage | | x(4) | | | (x)(5) | | | Ngram prev_loc Coverage | | x(6) | | | | | | Context Coverage | | x(6) | | | | | | Auto Dictionary | | x(7) | | | | | | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | + | Shared Memory Testcases | | x | x | x | x | x | 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin @@ -254,6 +255,7 @@ Here are some good writeups to show how to effectively use AFL++: If you are interested in fuzzing structured data (where you define what the structure is), these links have you covered: * Superion for afl++: [https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator) + * libprotobuf for afl++: [https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator) * libprotobuf raw: [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator) * libprotobuf for old afl++ API: [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator) @@ -293,7 +295,7 @@ anything below 9 is not recommended. | v +---------------------------------+ -| clang/clang++ 3.3+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +| clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +---------------------------------+ see [instrumentation/README.llvm.md](instrumentation/README.llvm.md) | | if not, or if the target fails with LLVM afl-clang-fast/++ @@ -435,7 +437,7 @@ described in [instrumentation/README.lto.md](instrumentation/README.lto.md). ##### cmake For `cmake` build systems this is usually done by: -`mkdir build; cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..` +`mkdir build; cd build; cmake -DCMAKE_C_COMPILER=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..` Note that if you are using the (better) afl-clang-lto compiler you also have to set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is @@ -677,8 +679,8 @@ If you see that an important area or a feature has not been covered so far then try to find an input that is able to reach that and start a new secondary in that fuzzing campaign with that seed as input, let it run for a few minutes, then terminate it. The main node will pick it up and make it available to the -other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no -free core. +other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` or +`export AFL_TRY_AFFINITY=1` if you have no free core. Note that you in nearly all cases can never reach full coverage. A lot of functionality is usually behind options that were not activated or fuzz e.g. @@ -789,16 +791,19 @@ How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz]( When source code is *NOT* available, afl++ offers various support for fast, on-the-fly instrumentation of black-box binaries. -If you do not have to use Unicorn the following setup is recommended: +If you do not have to use Unicorn the following setup is recommended to use +qemu_mode: * run 1 afl-fuzz -Q instance with CMPLOG (`-c 0` + `AFL_COMPCOV_LEVEL=2`) * run 1 afl-fuzz -Q instance with QASAN (`AFL_USE_QASAN=1`) * run 1 afl-fuzz -Q instance with LAF (``AFL_PRELOAD=libcmpcov.so` + `AFL_COMPCOV_LEVEL=2`) +Alternatively you can use frida_mode, just switch `-Q` with `-O` and remove the +LAF instance. Then run as many instances as you have cores left with either -Q mode or - better - -use a binary rewriter like afl-dyninst, retrowrite, zipr, fibre, etc. +use a binary rewriter like afl-dyninst, retrowrite, zaflr, etc. -For Qemu mode, check out the persistent mode and snapshot features, they give -a huge speed improvement! +For Qemu and Frida mode, check out the persistent mode, it gives a huge speed +improvement if it is possible to use. ### QEMU @@ -810,18 +815,31 @@ feature by doing: cd qemu_mode ./build_qemu_support.sh ``` -For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md) - -check out the snapshot feature! :-) +For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md). If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md). The mode is approximately 2-5x slower than compile-time instrumentation, and is less conducive to parallelization. If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for your binary, then you can use afl-fuzz normally and it will have twice -the speed compared to qemu_mode (but slower than persistent mode). +the speed compared to qemu_mode (but slower than qemu persistent mode). Note that several other binary rewriters exist, all with their advantages and caveats. +### Frida + +Frida mode is sometimes faster and sometimes slower than Qemu mode. +It is also newer, lacks COMPCOV, but supports MacOS. + +```shell +cd frida_mode +make +``` +For additional instructions and caveats, see [frida_mode/README.md](frida_mode/README.md). +If possible you should use the persistent mode, see [qemu_frida/README.persistent.md](qemu_frida/README.persistent.md). +The mode is approximately 2-5x slower than compile-time instrumentation, and is +less conducive to parallelization. + ### Unicorn For non-Linux binaries you can use afl++'s unicorn mode which can emulate diff --git a/TODO.md b/TODO.md index 5a5e7c4e..398f3d11 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,7 @@ - align map to 64 bytes but keep real IDs - Update afl->pending_not_fuzzed for MOpt - - CPU affinity for many cores? There seems to be an issue > 96 cores + - put fuzz target in top line of UI - afl-plot to support multiple plot_data - afl_custom_fuzz_splice_optin() - afl_custom_splice() diff --git a/afl-cmin b/afl-cmin index 3f3a7517..9fa63ec6 100755 --- a/afl-cmin +++ b/afl-cmin @@ -119,11 +119,13 @@ function usage() { "Environment variables used:\n" \ "AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \ "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \ -"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \ +"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \ "AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \ -"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" -"AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \ -"AFL_SKIP_BIN_CHECK: skip check for target binary\n" +"AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \ +"AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \ +"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ + "printed to stdout\n" \ +"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n" exit 1 } diff --git a/afl-plot b/afl-plot index ba100d3e..60a351ab 100755 --- a/afl-plot +++ b/afl-plot @@ -111,9 +111,9 @@ set terminal png truecolor enhanced size 1000,300 butt set output '$outputdir/high_freq.png' -set xdata time -set timefmt '%s' -set format x "%b %d\n%H:%M" +#set xdata time +#set timefmt '%s' +#set format x "%b %d\n%H:%M" set tics font 'small' unset mxtics unset mytics @@ -127,9 +127,8 @@ set key outside set autoscale xfixmin set autoscale xfixmax -set xlabel "all times in UTC" font "small" +#set xlabel "all times in UTC" font "small" -set ytics auto plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\ '' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\ '' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\ @@ -139,7 +138,6 @@ plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' lin set terminal png truecolor enhanced size 1000,200 butt set output '$outputdir/low_freq.png' -set ytics 1 plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\ '' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\ '' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\ @@ -148,14 +146,12 @@ plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb set terminal png truecolor enhanced size 1000,200 butt set output '$outputdir/exec_speed.png' -set ytics auto plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\ '$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier; set terminal png truecolor enhanced size 1000,300 butt set output '$outputdir/edges.png' -set ytics auto plot '$inputdir/plot_data' using 1:13 with lines title ' edges' linecolor rgb '#0090ff' linewidth 3 _EOF_ diff --git a/afl-system-config b/afl-system-config index 5ad9d937..e149e4cd 100755 --- a/afl-system-config +++ b/afl-system-config @@ -7,7 +7,7 @@ test "$1" = "-h" -o "$1" = "-hh" && { echo afl-system-config has no command line options echo echo afl-system reconfigures the system to a high performance fuzzing state - echo WARNING: this reduces the security of the system + echo "WARNING: this reduces the security of the system!" echo exit 1 } @@ -15,14 +15,20 @@ test "$1" = "-h" -o "$1" = "-hh" && { DONE= PLATFORM=`uname -s` echo This reconfigures the system to have a better fuzzing performance. +echo "WARNING: this reduces the security of the system!" +echo if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then echo "Warning: you need to be root to run this!" # we do not exit as other mechanisms exist that allows to do this than # being root. let the errors speak for themselves. fi +sleep 1 if [ "$PLATFORM" = "Linux" ] ; then { - sysctl -w kernel.core_pattern=core + sysctl -w kernel.core_uses_pid=0 + # Arch Linux requires core_pattern to be empty :( + test -e /etc/arch-release && sysctl -w kernel.core_pattern= + test -e /etc/arch-release || sysctl -w kernel.core_pattern=core sysctl -w kernel.randomize_va_space=0 sysctl -w kernel.sched_child_runs_first=1 sysctl -w kernel.sched_autogroup_enabled=1 @@ -35,12 +41,17 @@ if [ "$PLATFORM" = "Linux" ] ; then test -e /sys/devices/system/cpu/intel_pstate/no_turbo && echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cpu/cpufreq/boost test -e /sys/devices/system/cpu/intel_pstate/max_perf_pct && echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct + test -n "$(which auditctl)" && auditctl -a never,task >/dev/null 2>&1 } > /dev/null echo Settings applied. + echo dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || { echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this: echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"' + echo } + echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed + echo DONE=1 fi if [ "$PLATFORM" = "FreeBSD" ] ; then @@ -49,6 +60,7 @@ if [ "$PLATFORM" = "FreeBSD" ] ; then sysctl kern.elf64.aslr.enable=0 } > /dev/null echo Settings applied. + echo cat <<EOF In order to suppress core file generation during fuzzing it is recommended to set me:\\ @@ -58,11 +70,12 @@ EOF echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this: echo ' sysctl hw.ibrs_disable=1' echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.' + echo DONE=1 fi if [ "$PLATFORM" = "OpenBSD" ] ; then - echo echo 'System security features cannot be disabled on OpenBSD.' + echo DONE=1 fi if [ "$PLATFORM" = "DragonFly" ] ; then @@ -74,27 +87,33 @@ me:\\ :coredumpsize=0: in the ~/.login_conf file for the user used for fuzzing. EOF + echo DONE=1 fi if [ "$PLATFORM" = "NetBSD" ] ; then { - #echo It is recommended to enable unprivileged users to set cpu affinity - #echo to be able to use afl-gotcpu meaningfully. /sbin/sysctl -w security.models.extensions.user_set_cpu_affinity=1 } > /dev/null echo Settings applied. + echo DONE=1 fi if [ "$PLATFORM" = "Darwin" ] ; then + sysctl kern.sysv.shmmax=8388608 + sysctl kern.sysv.shmseg=48 + sysctl kern.sysv.shmall=98304 + echo Settings applied. + echo if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then - echo We unload the default crash reporter here + echo + echo Unloading the default crash reporter SL=/System/Library; PL=com.apple.ReportCrash - launchctl unload -w ${SL}/LaunchAgents/${PL}.plist - sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist - echo Settings applied. - else - echo Nothing to do. + launchctl unload -w ${SL}/LaunchAgents/${PL}.plist >/dev/null 2>&1 + sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist >/dev/null 2>&1 + echo fi + echo It is recommended to disable System Integration Protection for increased performance. + echo DONE=1 fi if [ "$PLATFORM" = "Haiku" ] ; then @@ -104,7 +123,7 @@ if [ "$PLATFORM" = "Haiku" ] ; then [ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \ echo We change the debug_server default_action from user to silently kill; \ [ ! -r ${SETTINGS} ] && echo "default_action kill" >${SETTINGS} || { mv ${SETTINGS} s.tmp; sed -e "s/default_action\s\s*user/default_action kill/" s.tmp > ${SETTINGS}; rm s.tmp; }; \ - echo Settings applied.; \ + echo Settings applied.; echo; \ } DONE=1 fi diff --git a/afl-whatsup b/afl-whatsup index be259829..9c2564c6 100755 --- a/afl-whatsup +++ b/afl-whatsup @@ -21,11 +21,11 @@ echo "$0 status check tool for afl-fuzz by Michal Zalewski" echo test "$1" = "-h" -o "$1" = "-hh" && { - echo "$0 [-s] [-d] output_directory" + echo "Usage: $0 [-s] [-d] afl_output_directory" echo echo Options: - echo -s - skip details and output summary results only - echo -d - include dead fuzzer stats + echo " -s - skip details and output summary results only" + echo " -d - include dead fuzzer stats" echo exit 1 } @@ -51,10 +51,11 @@ DIR="$1" if [ "$DIR" = "" ]; then - echo "Usage: $0 [-s] [-d] afl_sync_dir" 1>&2 + echo "Usage: $0 [-s] [-d] afl_output_directory" 1>&2 echo 1>&2 - echo "The -s option causes the tool to skip all the per-fuzzer trivia and show" 1>&2 - echo "just the summary results. See docs/parallel_fuzzing.md for additional tips." 1>&2 + echo Options: 1>&2 + echo " -s - skip details and output summary results only" 1>&2 + echo " -d - include dead fuzzer stats" 1>&2 echo 1>&2 exit 1 diff --git a/custom_mutators/README.md b/custom_mutators/README.md index b0444c85..13172cdc 100644 --- a/custom_mutators/README.md +++ b/custom_mutators/README.md @@ -3,6 +3,14 @@ Custom mutators enhance and alter the mutation strategies of afl++. For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md). +## Examples + +The `./examples` folder contains examples for custom mutators in python and C. + +## Rust + +In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`. + ## The afl++ Grammar Mutator If you use git to clone afl++, then the following will incorporate our @@ -46,3 +54,6 @@ https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4 has a transform function you need to fill for your protobuf format, however needs to be ported to the updated afl++ custom mutator API (not much work): https://github.com/thebabush/afl-libprotobuf-mutator + +same as above but is for current afl++: +https://github.com/P1umer/AFLplusplus-protobuf-mutator diff --git a/utils/custom_mutators/Makefile b/custom_mutators/examples/Makefile index 9849f3f4..9849f3f4 100644 --- a/utils/custom_mutators/Makefile +++ b/custom_mutators/examples/Makefile diff --git a/utils/custom_mutators/README.md b/custom_mutators/examples/README.md index 655f7a5e..655f7a5e 100644 --- a/utils/custom_mutators/README.md +++ b/custom_mutators/examples/README.md diff --git a/utils/custom_mutators/XmlMutatorMin.py b/custom_mutators/examples/XmlMutatorMin.py index 3e6cd0ff..3e6cd0ff 100644 --- a/utils/custom_mutators/XmlMutatorMin.py +++ b/custom_mutators/examples/XmlMutatorMin.py diff --git a/utils/custom_mutators/common.py b/custom_mutators/examples/common.py index 44a5056a..44a5056a 100644 --- a/utils/custom_mutators/common.py +++ b/custom_mutators/examples/common.py diff --git a/utils/custom_mutators/custom_mutator_helpers.h b/custom_mutators/examples/custom_mutator_helpers.h index 62e6efba..62e6efba 100644 --- a/utils/custom_mutators/custom_mutator_helpers.h +++ b/custom_mutators/examples/custom_mutator_helpers.h diff --git a/utils/custom_mutators/example.c b/custom_mutators/examples/example.c index 23add128..23add128 100644 --- a/utils/custom_mutators/example.c +++ b/custom_mutators/examples/example.c diff --git a/utils/custom_mutators/example.py b/custom_mutators/examples/example.py index 3a6d22e4..3a6d22e4 100644 --- a/utils/custom_mutators/example.py +++ b/custom_mutators/examples/example.py diff --git a/utils/custom_mutators/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c index ac10f409..ac10f409 100644 --- a/utils/custom_mutators/post_library_gif.so.c +++ b/custom_mutators/examples/post_library_gif.so.c diff --git a/utils/custom_mutators/post_library_png.so.c b/custom_mutators/examples/post_library_png.so.c index 941f7e55..941f7e55 100644 --- a/utils/custom_mutators/post_library_png.so.c +++ b/custom_mutators/examples/post_library_png.so.c diff --git a/utils/custom_mutators/simple-chunk-replace.py b/custom_mutators/examples/simple-chunk-replace.py index c57218dd..c57218dd 100644 --- a/utils/custom_mutators/simple-chunk-replace.py +++ b/custom_mutators/examples/simple-chunk-replace.py diff --git a/utils/custom_mutators/simple_example.c b/custom_mutators/examples/simple_example.c index d888ec1f..d888ec1f 100644 --- a/utils/custom_mutators/simple_example.c +++ b/custom_mutators/examples/simple_example.c diff --git a/utils/custom_mutators/wrapper_afl_min.py b/custom_mutators/examples/wrapper_afl_min.py index 5cd60031..5cd60031 100644 --- a/utils/custom_mutators/wrapper_afl_min.py +++ b/custom_mutators/examples/wrapper_afl_min.py diff --git a/custom_mutators/grammar_mutator/GRAMMAR_VERSION b/custom_mutators/grammar_mutator/GRAMMAR_VERSION index c7c1948d..3df8150e 100644 --- a/custom_mutators/grammar_mutator/GRAMMAR_VERSION +++ b/custom_mutators/grammar_mutator/GRAMMAR_VERSION @@ -1 +1 @@ -a2d4e4a +b79d51a diff --git a/custom_mutators/grammar_mutator/grammar_mutator b/custom_mutators/grammar_mutator/grammar_mutator -Subproject a2d4e4ab966f0581219fbb282f5ac8c89e85ead +Subproject b79d51a8daccbd7a693f9b6765c81ead14f28e2 diff --git a/docs/Changelog.md b/docs/Changelog.md index d8e96bf3..d8ffe498 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,7 +9,9 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to <afl-users+subscribe@googlegroups.com>. ### Version ++3.13a (development) + - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, + it currently supports persistent mode and cmplog. thanks to @WorksButNotTested! - create a fuzzing dictionary with the help of CodeQL thanks to @microsvuln! see utils/autodict_ql @@ -19,6 +21,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. - add recording of previous fuzz attempts for persistent mode to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h + - fixed a bug when trimming for stdin targets - default cmplog level (-l) is now 2, better efficiency. - cmplog level 3 (-l 3) now performs redqueen on everything. use with care. @@ -26,16 +29,39 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - on a crashing seed potentially the wrong input was disabled - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. + - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing + after no new paths have been found for n seconds + - when AFL_FAST_CAL is set a variable path will now be calibrated + 8 times instead of originally 40. Long calibration is now 20. + - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if + it fails - afl-cc: + - We do not support llvm versions prior 6.0 anymore + - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode + - Fixed a crash in llvm dict2file when a strncmp length was -1 + - added --afl-noopt support + - utils/aflpp_driver: + - aflpp_qemu_driver_hook fixed to work with qemu_mode + - aflpp_driver now compiled with -fPIC + - unicornafl: + - fix MIPS delay slot caching, thanks @JackGrence + - fixed aarch64 exit address + - execution no longer stops at address 0x0 + - updated afl-system-config to support Arch Linux weirdness and increase + MacOS shared memory + - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup - add thread safe counters for LLVM CLASSIC (set AFL_LLVM_THREADSAFE_INST) + - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the + current filename + - afl-showmap/cmin will now process queue items in alphabetical order ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/INSTALL.md b/docs/INSTALL.md index e3c06c9d..80d452f7 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -103,6 +103,41 @@ The llvm instrumentation requires a fully-operational installation of clang. The comes with Xcode is missing some of the essential headers and helper tools. See README.llvm.md for advice on how to build the compiler from scratch. +MacOS X supports SYSV shared memory used by AFL's instrumentation, but the +default settings aren't usable with AFL++. The default settings on 10.14 seem +to be: + +```bash +$ ipcs -M +IPC status from <running system> as of XXX +shminfo: + shmmax: 4194304 (max shared memory segment size) + shmmin: 1 (min shared memory segment size) + shmmni: 32 (max number of shared memory identifiers) + shmseg: 8 (max shared memory segments per process) + shmall: 1024 (max amount of shared memory in pages) +``` + +To temporarily change your settings to something minimally usable with AFL++, +run these commands as root: + +```bash +sysctl kern.sysv.shmmax=8388608 +sysctl kern.sysv.shmall=4096 +``` + +If you're running more than one instance of AFL you likely want to make `shmall` +bigger and increase `shmseg` as well: + +```bash +sysctl kern.sysv.shmmax=8388608 +sysctl kern.sysv.shmseg=48 +sysctl kern.sysv.shmall=98304 +``` + +See http://www.spy-hill.com/help/apple/SharedMemory.html for documentation for +these settings and how to make them permanent. + ## 4. Linux or *BSD on non-x86 systems Standard build will fail on non-x86 systems, but you should be able to diff --git a/docs/QuickStartGuide.md b/docs/QuickStartGuide.md index 10be409a..d1966170 100644 --- a/docs/QuickStartGuide.md +++ b/docs/QuickStartGuide.md @@ -1,6 +1,6 @@ # AFL quick start guide -You should read [README.md](README.md) - it's pretty short. If you really can't, here's +You should read [README.md](../README.md) - it's pretty short. If you really can't, here's how to hit the ground running: 1) Compile AFL with 'make'. If build fails, see [INSTALL.md](INSTALL.md) for tips. diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md index 787d970d..11e1dbeb 100644 --- a/docs/binaryonly_fuzzing.md +++ b/docs/binaryonly_fuzzing.md @@ -41,6 +41,33 @@ As it is included in afl++ this needs no URL. + If you like to code a customized fuzzer without much work, we highly + recommend to check out our sister project libafl which will support QEMU + too: + [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL) + + +## AFL FRIDA + + In frida_mode you can fuzz binary-only targets easily like with QEMU, + with the advantage that frida_mode also works on MacOS (both intel and M1). + + If you want to fuzz a binary-only library then you can fuzz it with + frida-gum via utils/afl_frida/, you will have to write a harness to + call the target function in the library, use afl-frida.c as a template. + + Both come with afl++ so this needs no URL. + + You can also perform remote fuzzing with frida, e.g. if you want to fuzz + on iPhone or Android devices, for this you can use + [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) + as an intermediate that uses afl++ for fuzzing. + + If you like to code a customized fuzzer without much work, we highly + recommend to check out our sister project libafl which supports Frida too: + [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL) + Working examples already exist :-) + ## WINE+QEMU @@ -62,13 +89,6 @@ As it is included in afl++ this needs no URL. -## AFL FRIDA - - If you want to fuzz a binary-only shared library then you can fuzz it with - frida-gum via utils/afl_frida/, you will have to write a harness to - call the target function in the library, use afl-frida.c as a template. - - ## AFL UNTRACER If you want to fuzz a binary-only shared library then you can fuzz it with @@ -157,19 +177,6 @@ If anyone finds any coresight implementation for afl please ping me: vh@thc.org -## FRIDA - - Frida is a dynamic instrumentation engine like Pintool, Dyninst and Dynamorio. - What is special is that it is written Python, and scripted with Javascript. - It is mostly used to reverse binaries on mobile phones however can be used - everywhere. - - There is a WIP fuzzer available at [https://github.com/andreafioraldi/frida-fuzzer](https://github.com/andreafioraldi/frida-fuzzer) - - There is also an early implementation in an AFL++ test branch: - [https://github.com/AFLplusplus/AFLplusplus/tree/frida](https://github.com/AFLplusplus/AFLplusplus/tree/frida) - - ## PIN & DYNAMORIO Pintool and Dynamorio are dynamic instrumentation engines, and they can be @@ -205,7 +212,8 @@ * QSYM: [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym) * Manticore: [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore) * S2E: [https://github.com/S2E](https://github.com/S2E) - * Tinyinst [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only) + * Tinyinst: [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only) + * Jackalope: [https://github.com/googleprojectzero/Jackalope](https://github.com/googleprojectzero/Jackalope) * ... please send me any missing that are good diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 62e01f83..3e3ae01d 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -92,6 +92,9 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): def introspection(): return string + +def deinit(): # optional for Python + pass ``` ### Custom Mutation @@ -285,8 +288,8 @@ afl-fuzz /path/to/program ## 4) Example -Please see [example.c](../utils/custom_mutators/example.c) and -[example.py](../utils/custom_mutators/example.py) +Please see [example.c](../custom_mutators/examples/example.c) and +[example.py](../custom_mutators/examples/example.py) ## 5) Other Resources diff --git a/docs/env_variables.md b/docs/env_variables.md index d9a774aa..b4b866ab 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -289,6 +289,10 @@ checks or alter some of the more exotic semantics of the tool: normally indicated by the cycle counter in the UI turning green. May be convenient for some types of automated jobs. + - `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were + found within a specified period of time (in seconds). May be convenient + for some types of automated jobs. + - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour which does not allow crashes or timeout seeds in the initial -i corpus. @@ -313,14 +317,12 @@ checks or alter some of the more exotic semantics of the tool: on Linux systems. This slows things down, but lets you run more instances of afl-fuzz than would be prudent (if you really want to). + - Setting `AFL_TRY_AFFINITY` tries to attempt binding to a specific CPU core + on Linux systems, but will not terminate if that fails. + - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary that is compiled into the target. - - `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input - queue. This can help with rare situations where a program crashes only - intermittently, but it's not really recommended under normal operating - conditions. - - Setting `AFL_HANG_TMOUT` allows you to specify a different timeout for deciding if a particular test case is a "hang". The default is 1 second or the value of the `-t` parameter, whichever is larger. Dialing the value @@ -356,6 +358,7 @@ checks or alter some of the more exotic semantics of the tool: and shell scripts; and `AFL_DUMB_FORKSRV` in conjunction with the `-n` setting to instruct afl-fuzz to still follow the fork server protocol without expecting any instrumentation data in return. + Note that this also turns off auto map size detection. - When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the fuzzer to import test cases from other instances before doing anything @@ -568,6 +571,9 @@ The corpus minimization script offers very little customization: a modest security risk on multi-user systems with rogue users, but should be safe on dedicated fuzzing boxes. + - `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed. + This can help when embedding `afl-cmin` or `afl-showmap` in other scripts scripting. + ## 7) Settings for afl-tmin Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be diff --git a/docs/life_pro_tips.md b/docs/life_pro_tips.md index 50ad75d4..13ffcea0 100644 --- a/docs/life_pro_tips.md +++ b/docs/life_pro_tips.md @@ -83,5 +83,5 @@ You can find a simple solution in utils/argv_fuzzing. ## Attacking a format that uses checksums? Remove the checksum-checking code or use a postprocessor! -See utils/custom_mutators/ for more. +See `afl_custom_post_process` in custom_mutators/examples/example.c for more. diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile new file mode 100644 index 00000000..a0387cac --- /dev/null +++ b/frida_mode/GNUmakefile @@ -0,0 +1,188 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)..)/ +INC_DIR:=$(PWD)include/ +SRC_DIR:=$(PWD)src/ +INCLUDES:=$(wildcard $(INC_DIR)*.h) +BUILD_DIR:=$(PWD)build/ +OBJ_DIR:=$(BUILD_DIR)obj/ + +SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c) +OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src)))) +CFLAGS+=-fPIC \ + -D_GNU_SOURCE \ + -D_FORTIFY_SOURCE=2 \ + -g \ + -O3 \ + -funroll-loops \ + +RT_CFLAGS:=-Wno-unused-parameter \ + -Wno-sign-compare \ + -Wno-unused-function \ + -Wno-unused-result \ + -Wno-int-to-pointer-cast \ + +LDFLAGS+=-shared \ + -lpthread \ + -lresolv \ + -ldl \ + -z noexecstack \ + +ifdef DEBUG +CFLAGS+=-Werror \ + -Wall \ + -Wextra \ + -Wpointer-arith +else +CFLAGS+=-Wno-pointer-arith +endif + +FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ +FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so +FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ifeq "$(shell uname)" "Darwin" + OS:=macos + RT_CFLAGS:=$(RT_CFLAGS) -Wno-deprecated-declarations +else +ifdef DEBUG + RT_CFLAGS:=$(RT_CFLAGS) -Wno-prio-ctor-dtor +endif +endif + +ifeq "$(shell uname)" "Linux" + OS:=linux +endif + +ifndef OS + $(error "Operating system unsupported") +endif + +GUM_DEVKIT_VERSION=14.2.18 +GUM_DEVKIT_FILENAME=frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz +GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)" + +GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME) +GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a +GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h + +FRIDA_DIR:=$(PWD)build/frida-source/ +FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile +FRIDA_GUM:=$(FRIDA_DIR)build/frida-linux-x86_64/lib/libfrida-gum-1.0.a +FRIDA_GUM_DEVKIT_DIR:=$(FRIDA_DIR)build/gum-devkit/ +FRIDA_GUM_DEVKIT_HEADER:=$(FRIDA_GUM_DEVKIT_DIR)frida-gum.h +FRIDA_GUM_DEVKIT_TARBALL:=$(FRIDA_DIR)build/frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar +FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL:=$(FRIDA_DIR)build/$(GUM_DEVKIT_FILENAME) + +AFL_COMPILER_RT_SRC:=$(ROOT)instrumentation/afl-compiler-rt.o.c +AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o + +.PHONY: all 32 clean format $(FRIDA_GUM) + +############################## ALL ############################################# + +all: $(FRIDA_TRACE) + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +$(OBJ_DIR): | $(BUILD_DIR) + mkdir -p $@ + +############################# FRIDA ############################################ + +$(FRIDA_MAKEFILE): | $(BUILD_DIR) + git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR) + +$(FRIDA_GUM): $(FRIDA_MAKEFILE) + cd $(FRIDA_DIR) && make gum-linux-$(ARCH) + +$(FRIDA_GUM_DEVKIT_HEADER): $(FRIDA_GUM) + $(FRIDA_DIR)releng/devkit.py frida-gum linux-$(ARCH) $(FRIDA_DIR)build/gum-devkit/ + +$(FRIDA_GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_HEADER) + cd $(FRIDA_GUM_DEVKIT_DIR) && tar cvf $(FRIDA_GUM_DEVKIT_TARBALL) . + +$(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL): $(FRIDA_GUM_DEVKIT_TARBALL) + xz -k -f -0 $(FRIDA_GUM_DEVKIT_TARBALL) + +############################# DEVKIT ########################################### + +$(FRIDA_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +ifdef FRIDA_SOURCE +$(GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL)| $(FRIDA_BUILD_DIR) + cp -v $< $@ +else +$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR) + wget -O $@ $(GUM_DEVKIT_URL) +endif + +$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL) + tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) + +$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL) + tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) + +############################## AFL ############################################# +$(AFL_COMPILER_RT_OBJ): $(AFL_COMPILER_RT_SRC) + $(CC) \ + $(CFLAGS) \ + $(RT_CFLAGS) \ + -I $(ROOT) \ + -I $(ROOT)include \ + -o $@ \ + -c $< + +############################# SOURCE ########################################### + +define BUILD_SOURCE +$(2): $(1) $(INCLUDES) GNUmakefile | $(OBJ_DIR) + $(CC) \ + $(CFLAGS) \ + -I $(ROOT)include \ + -I $(FRIDA_BUILD_DIR) \ + -I $(INC_DIR) \ + -c $1 \ + -o $2 +endef + +$(foreach src,$(SOURCES),$(eval $(call BUILD_SOURCE,$(src),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src)))))) + +######################## AFL-FRIDA-TRACE ####################################### + +$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR) + $(CC) \ + $(OBJS) \ + $(GUM_DEVIT_LIBRARY) \ + $(AFL_COMPILER_RT_OBJ) \ + $(LDFLAGS) \ + -o $@ \ + + cp -v $(FRIDA_TRACE) $(ROOT) + +############################# CLEAN ############################################ +clean: + rm -rf $(BUILD_DIR) + +############################# FORMAT ########################################### +format: + cd $(ROOT) && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i + cd $(ROOT) && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i + +############################# RUN ############################################# diff --git a/frida_mode/Makefile b/frida_mode/Makefile index 822f1c6a..6cd1a64e 100644 --- a/frida_mode/Makefile +++ b/frida_mode/Makefile @@ -1,348 +1,13 @@ -PWD:=$(shell pwd)/ -INC_DIR:=$(PWD)include/ -SRC_DIR:=$(PWD)src/ -INCLUDES:=$(wildcard $(INC_DIR)*.h) -SOURCES:=$(wildcard $(SRC_DIR)*.c) -BUILD_DIR:=$(PWD)build/ -CFLAGS+=-fPIC -D_GNU_SOURCE +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake -FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ -FRIDA_TRACE:=$(FRIDA_BUILD_DIR)afl-frida-trace.so +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake -ARCH=$(shell uname -m) -ifeq "$(ARCH)" "aarch64" - ARCH:=arm64 - TESTINSTR_BASE:=0x0000aaaaaaaaa000 -endif - -ifeq "$(ARCH)" "x86_64" - TESTINSTR_BASE:=0x0000555555554000 -endif - -ifeq "$(shell uname)" "Darwin" - OS:=macos - AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF - CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations - TEST_LDFLAGS:=-undefined dynamic_lookup -endif -ifeq "$(shell uname)" "Linux" - OS:=linux - AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) - CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor - TEST_LDFLAGS:= -endif - -ifndef OS - $(error "Operating system unsupported") -endif - -VERSION=14.2.13 -GUM_DEVKIT_FILENAME=frida-gum-devkit-$(VERSION)-$(OS)-$(ARCH).tar.xz -GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(VERSION)/$(GUM_DEVKIT_FILENAME)" -GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME) -GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a -GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h - -TEST_BUILD_DIR:=$(BUILD_DIR)test/ - -LIBPNG_FILE:=$(TEST_BUILD_DIR)libpng-1.2.56.tar.gz -LIBPNG_URL:=https://downloads.sourceforge.net/project/libpng/libpng12/older-releases/1.2.56/libpng-1.2.56.tar.gz -LIBPNG_DIR:=$(TEST_BUILD_DIR)libpng-1.2.56/ -LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile -LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a - -HARNESS_FILE:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.c -HARNESS_OBJ:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.o -HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" - -PNGTEST_FILE:=$(TEST_BUILD_DIR)target.cc -PNGTEST_OBJ:=$(TEST_BUILD_DIR)target.o -PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc" - -TEST_BIN:=$(TEST_BUILD_DIR)pngtest - -TESTINSTBIN:=$(BUILD_DIR)testinstr -TESTINSTSRC:=$(PWD)test/testinstr.c - -TEST_DATA_DIR:=$(PWD)build/test/libpng-1.2.56/contrib/pngsuite/ - -TESTINSTR_DATA_DIR:=$(BUILD_DIR)testinstr_in/ -TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)test.dat -FRIDA_OUT:=$(PWD)frida_out -QEMU_OUT:=$(PWD)qemu_out - -.PHONY: all frida test clean format test_frida test_qemu compare testinstr test_testinstr standalone - -all: $(FRIDA_TRACE) - -frida: $(FRIDA_TRACE) - -$(BUILD_DIR): - mkdir -p $(BUILD_DIR) - -############################# FRIDA ############################################ -$(FRIDA_BUILD_DIR): | $(BUILD_DIR) - mkdir -p $@ - -$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR) - wget -O $@ $(GUM_DEVKIT_URL) - -$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL) - tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) - -$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL) - tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) - -$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(SOURCES) Makefile | $(FRIDA_BUILD_DIR) - $(CC) -shared \ - $(CFLAGS) \ - -o $@ $(SOURCES) \ - $(GUM_DEVIT_LIBRARY) \ - -I $(FRIDA_BUILD_DIR) \ - -I .. \ - -I ../include \ - -I $(INC_DIR) \ - ../instrumentation/afl-compiler-rt.o.c \ - -lpthread -ldl -lresolv - - cp -v $(FRIDA_TRACE) ../ - -############################# TEST ############################################# - -test: $(TEST_BIN) - -$(TEST_BUILD_DIR): $(BUILD_DIR) - mkdir -p $@ - -$(HARNESS_FILE): | $(TEST_BUILD_DIR) - wget -O $@ $(HARNESS_URL) - -$(HARNESS_OBJ): $(HARNESS_FILE) - $(CC) -o $@ -c $< - -$(PNGTEST_FILE): | $(TEST_BUILD_DIR) - wget -O $@ $(PNGTEST_URL) - -$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR) - $(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $< - -$(LIBPNG_FILE): | $(TEST_BUILD_DIR) - wget -O $@ $(LIBPNG_URL) - -$(LIBPNG_DIR): $(LIBPNG_FILE) - tar zxvf $(LIBPNG_FILE) -C $(TEST_BUILD_DIR) - -$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR) - cd $(LIBPNG_DIR) && ./configure - -$(LIBPNG_LIB): $(LIBPNG_MAKEFILE) - make -C $(LIBPNG_DIR) - -$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) - $(CXX) \ - -o $@ \ - $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \ - -lz \ - $(TEST_LDFLAGS) - -############################# TESTINSR ######################################### -$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) - mkdir -p $@ - -$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) - echo -n "000" > $@ - -$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) - $(CC) -o $@ $< - -testinstr: $(TESTINSTBIN) - -############################# CLEAN ############################################ clean: - rm -rf $(BUILD_DIR) + @gmake clean -############################# FORMAT ########################################### format: - cd .. && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i - cd .. && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i - cd .. && ./.custom-format.py -i $(TESTINSTSRC) - -############################# RUN ############################################# - -# Add the environment variable AFL_DEBUG_CHILD=1 to show printf's from the target - -png_frida: $(FRIDA_TRACE) $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-fuzz \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ - -png_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-fuzz \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - -compare: $(FRIDA_TRACE) $(TEST_BIN) - cd .. && \ - ./afl-fuzz \ - -V30 \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ - cd .. && \ - ./afl-fuzz \ - -V30 \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - cat frida_out/default/fuzzer_stats - cat qemu_out/default/fuzzer_stats - -testinstr_qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) - make -C .. - cd .. && \ - AFL_QEMU_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ - ./afl-fuzz \ - -Q \ - -i $(TESTINSTR_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TESTINSTBIN) @@ - -testinstr_frida: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) - make -C .. - cd .. && \ - AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ - AFL_FRIDA_INST_NO_OPTIMIZE=1 \ - AFL_FRIDA_INST_NO_PREFETCH=1 \ - AFL_FRIDA_INST_STRICT=1 \ - ./afl-fuzz \ - -O \ - -i $(TESTINSTR_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TESTINSTBIN) @@ - -standalone: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) - cd .. && \ - AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ - AFL_DEBUG_CHILD=1 \ - AFL_FRIDA_DEBUG_MAPS=1 \ - AFL_FRIDA_INST_NO_OPTIMIZE=1 \ - AFL_FRIDA_INST_NO_PREFETCH=1 \ - AFL_FRIDA_INST_TRACE=1 \ - AFL_FRIDA_INST_STRICT=1 \ - LD_PRELOAD=$(FRIDA_TRACE) \ - DYLD_INSERT_LIBRARIES=$(FRIDA_TRACE) \ - $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) - -tmin_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-tmin \ - -Q \ - -i $(TEST_DATA_DIR)basn0g01.png \ - -o $(QEMU_OUT)/qemu-min-basn0g01.png \ - -- \ - $(TEST_BIN) @@ - -tmin_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-tmin \ - -O \ - -i $(TEST_DATA_DIR)basn0g01.png \ - -o $(FRIDA_OUT)/qemu-min-basn0g01.png \ - -- \ - $(TEST_BIN) - -showmap_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-showmap \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - -showmap_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-showmap \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ - -analyze_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-analyze \ - -Q \ - -i $(TEST_DATA_DIR)basn0g01.png \ - -- \ - $(TEST_BIN) @@ - -analyze_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-analyze \ - -O \ - -i $(TEST_DATA_DIR)basn0g01.png \ - -- \ - $(TEST_BIN) @@ - -cmin_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-cmin \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - -cmin_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-cmin \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ - -cmin_bash_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-cmin.bash \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - -cmin_bash_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-cmin.bash \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ + @gmake format diff --git a/frida_mode/README.md b/frida_mode/README.md index 8abee0dd..0103a395 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -1,34 +1,38 @@ # FRIDA MODE -The purpose of FRIDA mode is to provide an alternative binary only fuzzer for AFL -just like that provided by QEMU mode. The intention is to provide a very similar -user experience, right down to the options provided through environment variables. + +The purpose of FRIDA mode is to provide an alternative binary only fuzzer for +AFL just like that provided by QEMU mode. The intention is to provide a very +similar user experience, right down to the options provided through environment +variables. Whilst AFLplusplus already has some support for running on FRIDA [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida) this requires the code to be fuzzed to be provided as a shared library, it cannot be used to fuzz executables. Additionally, it requires the user to write -a small harness around their target code of interest, FRIDA mode instead takes a -different approach to avoid these limitations. - -# Current Progress -As FRIDA mode is new, it is missing a lot of features. Most importantly, -persistent mode. The design is such that it should be possible to add these -features in a similar manner to QEMU mode and perhaps leverage some of its -design and implementation. - - | Feature/Instrumentation | frida-mode | - | -------------------------|:----------:| - | NeverZero | | - | Persistent Mode | | - | LAF-Intel / CompCov | | - | CmpLog | | - | Selective Instrumentation| x | - | Non-Colliding Coverage | | - | Ngram prev_loc Coverage | | - | Context Coverage | | - | Auto Dictionary | | - | Snapshot LKM Support | | - -# Compatibility +a small harness around their target code of interest. +FRIDA mode instead takes a different approach to avoid these limitations. +In Frida mode binary programs are instrumented, similarly to QEMU mode. + +## Current Progress + +As FRIDA mode is new, it is missing a lot of features. The design is such that it +should be possible to add these features in a similar manner to QEMU mode and +perhaps leverage some of its design and implementation. + + | Feature/Instrumentation | frida-mode | Notes | + | -------------------------|:----------:|:--------------------------------------------:| + | NeverZero | x | | + | Persistent Mode | x | (x86/x64 only)(Only on function boundaries) | + | LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) | + | CMPLOG | x | (x86/x64 only) | + | Selective Instrumentation| x | | + | Non-Colliding Coverage | - | (Not possible in binary-only instrumentation | + | Ngram prev_loc Coverage | - | | + | Context Coverage | - | | + | Auto Dictionary | - | | + | Snapshot LKM Support | - | | + | In-Memory Test Cases | x | (x86/x64 only) | + +## Compatibility Currently FRIDA mode supports Linux and macOS targets on both x86/x64 architecture and aarch64. Later releases may add support for aarch32 and Windows targets as well as embedded linux environments. @@ -38,54 +42,61 @@ runtime libraries, so porting should be possible. However, the current build system does not support cross compilation. ## Getting Started -To build everything run `make`. -To run the benchmark sample with qemu run `make png_qemu`. -To run the benchmark sample with frida run `make png_frida`. +To build everything run `make`. To build for x86 run `make 32`. Note that in +x86 bit mode, it is not necessary for afl-fuzz to be built for 32-bit. However, +the shared library for frida_mode must be since it is injected into the target +process. + +Various tests can be found in subfolders within the `test/` directory. To use +these, first run `make` to build any dependencies. Then run `make qemu` or +`make frida` to run on either QEMU of FRIDA mode respectively. To run frida +tests in 32-bit mode, run `make ARCH=x86 frida`. When switching between +architectures it may be necessary to run `make clean` first for a given build +target to remove previously generated binaries for a different architecture. ## Usage -FRIDA mode requires some small modifications to `afl-fuzz` and similar tools -in AFLplusplus. The intention is that it behaves identically to QEMU, but uses + +FRIDA mode added some small modifications to `afl-fuzz` and similar tools +in AFLplusplus. The intention was that it behaves identically to QEMU, but it uses the 'O' switch rather than 'Q'. Whilst the options 'f', 'F', 's' or 'S' may have made more sense for a mode powered by FRIDA Stalker, they were all taken, so instead we use 'O' in hommage to the [author](https://github.com/oleavr) of FRIDA. Similarly, the intention is to mimic the use of environment variables used by -QEMU where possible (although replacing `s/QEMU/FRIDA/g`). Accodingly, the -following options are currently supported. +QEMU where possible (by replacing `s/QEMU/FRIDA/g`). Accordingly, the +following options are currently supported: * `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS` * `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES` * `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES` +* `AFL_FRIDA_PERSISTENT_ADDR` - See `AFL_QEMU_PERSISTENT_ADDR` +* `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT` +* `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK` +* `AFL_FRIDA_PERSISTENT_RET` - See `AFL_QEMU_PERSISTENT_RET` +* `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` - See `AFL_QEMU_PERSISTENT_RETADDR_OFFSET` + +To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`. -# Performance +## Performance Additionally, the intention is to be able to make a direct performance -comparison between the two approaches. Accordingly, FRIDA mode includes a test -target based on the [libpng](https://libpng.sourceforge.io/) benchmark used by -[fuzzbench](https://google.github.io/fuzzbench/) and integrated with the +comparison between the two approaches. Accordingly, FRIDA mode includes various +test targets based on the [libpng](https://libpng.sourceforge.io/) benchmark +used by [fuzzbench](https://google.github.io/fuzzbench/) and integrated with the [StandaloneFuzzTargetMain](https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c) -from the llvm project. This is built and linked without any special -modifications to suit FRIDA or QEMU. We use the test data provided with libpng -as our corpus. - -Whilst not much performance tuning has been completed to date, performance is -around 30-50% of that of QEMU mode, however, this gap may reduce with the -introduction of persistent mode. Performance can be tested by running -`make compare`, albeit a longer time measurement may be required for more -accurate results. - -Whilst [afl_frida](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida) -claims a 5-10x performance increase over QEMU, it has not been possible to -reproduce these claims. However, the number of executions per second can vary -dramatically as a result of the randomization of the fuzzer input. Some inputs -may traverse relatively few paths before being rejected as invalid whilst others -may be valid inputs or be subject to much more processing before rejection. -Accordingly, it is recommended that testing be carried out over prolongued -periods to gather timings which are more than indicative. - -# Design +from the llvm project. These tests include basic fork-server support, persistent +mode and persistent mode with in-memory test-cases. These are built and linked +without any special modifications to suit FRIDA or QEMU. The test data provided +with libpng is used as the corpus. + +The intention is to add support for FRIDA mode to the FuzzBench project and +perform a like-for-like comparison with QEMU mode to get an accurate +appreciation of its performance. + +## Design + FRIDA mode is supported by using `LD_PRELOAD` (`DYLD_INSERT_LIBRARIES` on macOS) to inject a shared library (`afl-frida-trace.so`) into the target. This shared library is built using the [frida-gum](https://github.com/frida/frida-gum) @@ -102,34 +113,182 @@ this coverage information to AFL++ and also provide a fork server. It also makes use of the FRIDA [prefetch](https://github.com/frida/frida-gum/blob/56dd9ba3ee9a5511b4b0c629394bf122775f1ab7/gum/gumstalker.h#L115) support to feedback instrumented blocks from the child to the parent using a shared memory region to avoid the need to regenerate instrumented blocks on each -fork. +fork. Whilst FRIDA allows for a normal C function to be used to augment instrumented -code, to minimize the costs of storing and restoring all of the registers, FRIDA -mode instead makes use of optimized assembly instead on AARCH64 and x86/64 -targets. +code, FRIDA mode instead makes use of optimized assembly instead on AARCH64 and +x86/64 targets. By injecting these small snippets of assembly, we avoid having +to push and pop the full register context. Note that since this instrumentation +is used on every basic block to generate coverage, it has a large impact on +performance. + +CMPLOG support also adds code to the assembly, however, at present this code +makes use of a basic C function and is yet to be optimized. Since not all +instances run CMPLOG mode and instrumentation of the binary is less frequent +(only on CMP, SUB and CALL instructions) performance is not quite so critical. + +## Advanced configuration options + +* `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks +and their instrumented counterparts during block compilation. +``` +*** + +Creating block for 0x7ffff7953313: + 0x7ffff7953313 mov qword ptr [rax], 0 + 0x7ffff795331a add rsp, 8 + 0x7ffff795331e ret -# Advanced configuration options +Generated block 0x7ffff75e98e2 + 0x7ffff75e98e2 mov qword ptr [rax], 0 + 0x7ffff75e98e9 add rsp, 8 + 0x7ffff75e98ed lea rsp, [rsp - 0x80] + 0x7ffff75e98f5 push rcx + 0x7ffff75e98f6 movabs rcx, 0x7ffff795331e + 0x7ffff75e9900 jmp 0x7ffff75e9384 + + +*** +``` * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage instrumentation (the default where available). Required to use `AFL_FRIDA_INST_TRACE`. * `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default the child will report instrumented blocks back to the parent so that it can also instrument them and they be inherited by the next child on fork. -* `AFL_FRIDA_INST_STRICT` - Under certain conditions, Stalker may encroach into -excluded regions and generate both instrumented blocks and coverage data (e.g. -indirect calls on x86). The excluded block is generally honoured as soon as -another function is called within the excluded region and so such encroachment -is usually of little consequence. This detail may however, hinder you when -checking that the correct number of paths are found for testing purposes or -similar. There is a performance penatly for this option during block compilation -where we check the block isn't in a list of excluded ranges. -* `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code. -Requires `AFL_FRIDA_INST_NO_OPTIMIZE`. - -# TODO -As can be seen from the progress section above, there are a number of features -which are missing in its currently form. Chief amongst which is persistent mode. -The intention is to achieve feature parity with QEMU mode in due course. -Contributions are welcome, but please get in touch to ensure that efforts are -deconflicted. +* `AFL_FRIDA_INST_TRACE` - Log to stdout the address of executed blocks +`AFL_FRIDA_INST_NO_OPTIMIZE`. +* `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target +application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) +* `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target +application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) +* `AFL_FRIDA_PERSISTENT_DEBUG` - Insert a Breakpoint into the instrumented code +at `AFL_FRIDA_PERSISTENT_HOOK` and `AFL_FRIDA_PERSISTENT_RET` to allow the user +to determine the value of `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` using a +debugger. + +``` + +gdb \ + --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=XXXXXXXXXX' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_RET=XXXXXXXXXX' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \ + --ex 'set environment AFL_DEBUG_CHILD=1' \ + --ex 'set environment LD_PRELOAD=afl-frida-trace.so' \ + --args <my-executable> [my arguments] + +``` +* `AFL_FRIDA_STATS_FILE` - Write statistics information about the code being +instrumented to the given file name. The statistics are written only for the +child process when new block is instrumented (when the +`AFL_FRIDA_STATS_INTERVAL` has expired). Note that simply because a new path is +found does not mean a new block needs to be compiled. It could simply be that +the existing blocks instrumented have been executed in a different order. +``` +stats +----- +Index: 2 +Pid: 1815944 +Time: 2021-05-28 15:26:41 +Blocks: 1985 +Instructions: 9192 +Avg Instructions / Block: 4 + +Call Immediates: 391 (4.25%) +Call Immediates Excluded: 65 (0.71%) +Call Register: 0 (0.00%) +Call Memory: 0 (0.00%) + +Jump Immediates: 202 (2.20%) +Jump Register: 10 (0.11%) +Jump Memory: 12 (0.13%) + +Conditional Jump Immediates: 1210 (13.16%) +Conditional Jump CX Immediate: 0 (0.00%) +Conditional Jump Register: 0 (0.00%) +Conditional Jump Memory: 0 (0.00%) + +Returns: 159 (0.00%) + +Rip Relative: 247 (0.00%) + +``` +* `AFL_FRIDA_STATS_INTERVAL` - The maximum frequency to output statistics +information. Stats will be written whenever they are updated if the given +interval has elapsed since last time they were written. +* `AFL_FRIDA_STATS_TRANSITIONS` - Also dump the internal stalker counters to +stderr when the regular stats are written. Note that these stats are reset in +the child each time a new fork occurs since they are not stored in shared +memory. Unfortunately, these stats are internal to stalker, so this is the best +we can do for now. +``` +stats +----- +Index: 2 +Pid: 1816794 +Time: 2021-05-28 15:26:41 + + +total_transitions: 786 + call_imms: 97 + call_regs: 0 + call_mems: 0 + post_call_invokes: 86 + excluded_call_imms: 29 + ret_slow_paths: 23 + + jmp_imms: 58 + jmp_mems: 7 + jmp_regs: 26 + + jmp_cond_imms: 460 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +``` +## FASAN - Frida Address Sanitizer Mode +Frida mode also supports FASAN. The design of this is actually quite simple and +very similar to that used when instrumenting applications compiled from source. + +### Address Sanitizer Basics + +When Address Sanitizer is used to instrument programs built from source, the +compiler first adds a dependency (`DT_NEEDED` entry) for the Address Sanitizer +dynamic shared object (DSO). This shared object contains the main logic for Address +Sanitizer, including setting and managing up the shadow memory. It also provides +replacement implementations for a number of functions in standard libraries. + +These replacements include things like `malloc` and `free` which allows for those +allocations to be marked in the shadow memory, but also a number of other fuctions. +Consider `memcpy` for example, this is instrumented to validate the paramters +(test the source and destination buffers against the shadow memory. This is much +easier than instrumenting those standard libraries since, first it would require +you to re-compile them and secondly it would mean that the instrumentation would +be applied at a more expensive granular level. Lastly, load-widening (typically +found in highy optimized code) can also make this instrumentation more difficult. + +Since the DSO is loaded before all of the standard libraries (in fact it insists +on being first), the dynamic loader will use it to resolve imports from other +modules which depend on it. + +### FASAN Implementation + +FASAN takes a similar approach. It requires the user to add the Address Sanitizer +DSO to the `AFL_PRELOAD` environment variable such that it is loaded into the target. +Again, it must be first in the list. This means that it is not necessary to +instrument the standard libraries to detect when an application has provided an +incorrect argument to `memcpy` for example. This avoids issues with load-widening +and should also mean a huge improvement in performance. + +FASAN then adds instrumentation for any instrucutions which use memory operands and +then calls into the `__asan_loadN` and `__asan_storeN` functions provided by the DSO +to validate memory accesses against the shadow memory. + +## TODO + +The next features to be added are Aarch64 and Aarch32 support as well as looking at +potential performance improvements. The intention is to achieve feature parity with +QEMU mode in due course. Contributions are welcome, but please get in touch to +ensure that efforts are deconflicted. diff --git a/frida_mode/include/asan.h b/frida_mode/include/asan.h new file mode 100644 index 00000000..7a8726e0 --- /dev/null +++ b/frida_mode/include/asan.h @@ -0,0 +1,13 @@ +#ifndef _ASAN_H +#define _ASAN_H + +#include "frida-gum.h" + +extern gboolean asan_initialized; + +void asan_init(void); +void asan_arch_init(void); +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator); + +#endif + diff --git a/frida_mode/include/ctx.h b/frida_mode/include/ctx.h new file mode 100644 index 00000000..cbcc892a --- /dev/null +++ b/frida_mode/include/ctx.h @@ -0,0 +1,11 @@ +#ifndef _CTX_H +#define _CTX_H + +#include "frida-gum.h" + +#if defined(__x86_64__) || defined(__i386__) +gsize ctx_read_reg(GumCpuContext *ctx, x86_reg reg); +#endif + +#endif + diff --git a/frida_mode/include/entry.h b/frida_mode/include/entry.h new file mode 100644 index 00000000..967831af --- /dev/null +++ b/frida_mode/include/entry.h @@ -0,0 +1,15 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#include "frida-gum.h" + +extern guint64 entry_start; + +void entry_init(void); + +void entry_run(void); + +void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output); + +#endif + diff --git a/frida_mode/include/frida_cmplog.h b/frida_mode/include/frida_cmplog.h new file mode 100644 index 00000000..b620a472 --- /dev/null +++ b/frida_mode/include/frida_cmplog.h @@ -0,0 +1,14 @@ +#ifndef _CMPLOG_H +#define _CMPLOG_H + +extern struct cmp_map *__afl_cmp_map; + +void cmplog_init(void); + +/* Functions to be implemented by the different architectures */ +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator); + +gboolean cmplog_is_readable(guint64 addr, size_t size); + +#endif + diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index ff71bed4..ed92c25a 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -1,7 +1,27 @@ +#ifndef _INSTRUMENT_H +#define _INSTRUMENT_H + #include "frida-gum.h" -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); +#include "config.h" + +extern __thread uint64_t previous_pc; +extern uint8_t * __afl_area_ptr; +extern uint32_t __afl_map_size; + +void instrument_init(void); + +GumStalkerTransformer *instrument_get_transformer(void); + +/* Functions to be implemented by the different architectures */ +gboolean instrument_is_coverage_optimize_supported(void); + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output); -void instrument_init(); +void instrument_debug_init(void); +void instrument_debug_start(uint64_t address, GumStalkerOutput *output); +void instrument_debug_instruction(uint64_t address, uint16_t size); +void instrument_debug_end(GumStalkerOutput *output); +#endif diff --git a/frida_mode/include/interceptor.h b/frida_mode/include/interceptor.h index 5ed3cf49..0ff754a4 100644 --- a/frida_mode/include/interceptor.h +++ b/frida_mode/include/interceptor.h @@ -1,4 +1,11 @@ +#ifndef _INTERCEPTOR_H +#define _INTERCEPTOR_H + #include "frida-gum.h" void intercept(void *address, gpointer replacement, gpointer user_data); +void unintercept(void *address); +void unintercept_self(void); + +#endif diff --git a/frida_mode/include/lib.h b/frida_mode/include/lib.h new file mode 100644 index 00000000..237aecb0 --- /dev/null +++ b/frida_mode/include/lib.h @@ -0,0 +1,13 @@ +#ifndef _LIB_H +#define _LIB_H + +#include "frida-gum.h" + +void lib_init(void); + +guint64 lib_get_text_base(void); + +guint64 lib_get_text_limit(void); + +#endif + diff --git a/frida_mode/include/output.h b/frida_mode/include/output.h new file mode 100644 index 00000000..53a9fdd3 --- /dev/null +++ b/frida_mode/include/output.h @@ -0,0 +1,9 @@ +#ifndef _OUTPUT_H +#define _OUTPUT_H + +#include "frida-gum.h" + +void output_init(void); + +#endif + diff --git a/frida_mode/include/persistent.h b/frida_mode/include/persistent.h new file mode 100644 index 00000000..25b44ab0 --- /dev/null +++ b/frida_mode/include/persistent.h @@ -0,0 +1,35 @@ + +#ifndef _PERSISTENT_H +#define _PERSISTENT_H + +#include "frida-gum.h" +#include "config.h" + +typedef struct arch_api_regs api_regs; + +typedef void (*afl_persistent_hook_fn)(api_regs *regs, uint64_t guest_base, + uint8_t *input_buf, + uint32_t input_buf_len); + +extern int __afl_persistent_loop(unsigned int max_cnt); + +extern unsigned int * __afl_fuzz_len; +extern unsigned char *__afl_fuzz_ptr; + +extern guint64 persistent_start; +extern guint64 persistent_count; +extern guint64 persistent_ret; +extern guint64 persistent_ret_offset; +extern gboolean persistent_debug; +extern afl_persistent_hook_fn hook; + +void persistent_init(void); + +/* Functions to be implemented by the different architectures */ +gboolean persistent_is_supported(void); + +void persistent_prologue(GumStalkerOutput *output); +void persistent_epilogue(GumStalkerOutput *output); + +#endif + diff --git a/frida_mode/include/prefetch.h b/frida_mode/include/prefetch.h index b7f25a97..8f0cee68 100644 --- a/frida_mode/include/prefetch.h +++ b/frida_mode/include/prefetch.h @@ -1,5 +1,11 @@ -void prefetch_init(); -void prefetch_start(GumStalker *stalker); +#ifndef _PREFETCH_H +#define _PREFETCH_H + +#include "frida-gum.h" + +void prefetch_init(void); void prefetch_write(void *addr); -void prefetch_read(GumStalker *stalker); +void prefetch_read(void); + +#endif diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h index b9394dbc..c623f473 100644 --- a/frida_mode/include/ranges.h +++ b/frida_mode/include/ranges.h @@ -1,6 +1,13 @@ +#ifndef _RANGES_H +#define _RANGES_H + #include "frida-gum.h" -void ranges_init(GumStalker *stalker); +void ranges_init(void); gboolean range_is_excluded(gpointer address); +void ranges_exclude(); + +#endif + diff --git a/frida_mode/include/stalker.h b/frida_mode/include/stalker.h new file mode 100644 index 00000000..186ead11 --- /dev/null +++ b/frida_mode/include/stalker.h @@ -0,0 +1,11 @@ +#ifndef _STALKER_H +#define _STALKER_H + +#include "frida-gum.h" + +void stalker_init(void); +GumStalker *stalker_get(void); +void stalker_start(void); + +#endif + diff --git a/frida_mode/include/stats.h b/frida_mode/include/stats.h new file mode 100644 index 00000000..4271132a --- /dev/null +++ b/frida_mode/include/stats.h @@ -0,0 +1,28 @@ +#ifndef _STATS_H +#define _STATS_H + +#include "frida-gum.h" + +typedef struct { + + guint64 num_blocks; + guint64 num_instructions; + guint64 stats_last_time; + guint64 stats_idx; + guint64 transitions_idx; + +} stats_data_header_t; + +extern stats_data_header_t *stats_data; + +void stats_init(void); +void stats_collect(const cs_insn *instr, gboolean begin); +void stats_print(char *format, ...); + +gboolean stats_is_supported_arch(void); +size_t stats_data_size_arch(void); +void stats_collect_arch(const cs_insn *instr); +void stats_write_arch(void); + +#endif + diff --git a/frida_mode/include/util.h b/frida_mode/include/util.h new file mode 100644 index 00000000..7b443b5e --- /dev/null +++ b/frida_mode/include/util.h @@ -0,0 +1,14 @@ +#ifndef _UTIL_H +#define _UTIL_H + +#include "frida-gum.h" + +#define UNUSED_PARAMETER(x) (void)(x) +#define IGNORED_RETURN(x) (void)!(x) + +guint64 util_read_address(char *key); + +guint64 util_read_num(char *key); + +#endif + diff --git a/frida_mode/src/asan/asan.c b/frida_mode/src/asan/asan.c new file mode 100644 index 00000000..f78f690c --- /dev/null +++ b/frida_mode/src/asan/asan.c @@ -0,0 +1,24 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" + +gboolean asan_initialized = FALSE; + +void asan_init(void) { + + if (getenv("AFL_USE_FASAN") != NULL) { + + OKF("Frida ASAN mode enabled"); + asan_arch_init(); + asan_initialized = TRUE; + + } else { + + OKF("Frida ASAN mode disabled"); + + } + +} + diff --git a/frida_mode/src/asan/asan_arm.c b/frida_mode/src/asan/asan_arm.c new file mode 100644 index 00000000..79475ced --- /dev/null +++ b/frida_mode/src/asan/asan_arm.c @@ -0,0 +1,28 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__arm__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +void asan_arch_init(void) { + + FATAL("ASAN mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/asan/asan_arm64.c b/frida_mode/src/asan/asan_arm64.c new file mode 100644 index 00000000..6262ee18 --- /dev/null +++ b/frida_mode/src/asan/asan_arm64.c @@ -0,0 +1,28 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__aarch64__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +void asan_arch_init(void) { + + FATAL("ASAN mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/asan/asan_x64.c b/frida_mode/src/asan/asan_x64.c new file mode 100644 index 00000000..a2eabe3c --- /dev/null +++ b/frida_mode/src/asan/asan_x64.c @@ -0,0 +1,93 @@ +#include <dlfcn.h> +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "ctx.h" +#include "util.h" + +#if defined(__x86_64__) + +typedef void (*asan_loadN_t)(uint64_t address, uint8_t size); +typedef void (*asan_storeN_t)(uint64_t address, uint8_t size); + +asan_loadN_t asan_loadN = NULL; +asan_storeN_t asan_storeN = NULL; + +static void asan_callout(GumCpuContext *ctx, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + cs_x86_op * operand = (cs_x86_op *)user_data; + x86_op_mem *mem = &operand->mem; + gsize base = 0; + gsize index = 0; + gsize address; + uint8_t size; + + if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); } + + if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); } + + address = base + (mem->scale * index) + mem->disp; + size = operand->size; + + if (operand->access == CS_AC_READ) { + + asan_loadN(address, size); + + } else if (operand->access == CS_AC_WRITE) { + + asan_storeN(address, size); + + } + +} + +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(iterator); + + cs_x86 x86 = instr->detail->x86; + cs_x86_op * operand; + x86_op_mem *mem; + cs_x86_op * ctx; + + if (!asan_initialized) return; + + if (instr->id == X86_INS_LEA) return; + + if (instr->id == X86_INS_NOP) return; + + for (uint8_t i = 0; i < x86.op_count; i++) { + + operand = &x86.operands[i]; + + if (operand->type != X86_OP_MEM) { continue; } + + mem = &operand->mem; + if (mem->segment != X86_REG_INVALID) { continue; } + + ctx = g_malloc0(sizeof(cs_x86_op)); + memcpy(ctx, operand, sizeof(cs_x86_op)); + gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free); + + } + +} + +void asan_arch_init(void) { + + asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN"); + asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN"); + if (asan_loadN == NULL || asan_storeN == NULL) { + + FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'"); + + } + +} + +#endif + diff --git a/frida_mode/src/asan/asan_x86.c b/frida_mode/src/asan/asan_x86.c new file mode 100644 index 00000000..8490b490 --- /dev/null +++ b/frida_mode/src/asan/asan_x86.c @@ -0,0 +1,93 @@ +#include <dlfcn.h> +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "ctx.h" +#include "util.h" + +#if defined(__i386__) + +typedef void (*asan_loadN_t)(gsize address, uint8_t size); +typedef void (*asan_storeN_t)(gsize address, uint8_t size); + +asan_loadN_t asan_loadN = NULL; +asan_storeN_t asan_storeN = NULL; + +static void asan_callout(GumCpuContext *ctx, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + cs_x86_op * operand = (cs_x86_op *)user_data; + x86_op_mem *mem = &operand->mem; + gsize base = 0; + gsize index = 0; + gsize address; + uint8_t size; + + if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); } + + if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); } + + address = base + (mem->scale * index) + mem->disp; + size = operand->size; + + if (operand->access == CS_AC_READ) { + + asan_loadN(address, size); + + } else if (operand->access == CS_AC_WRITE) { + + asan_storeN(address, size); + + } + +} + +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(iterator); + + cs_x86 x86 = instr->detail->x86; + cs_x86_op * operand; + x86_op_mem *mem; + cs_x86_op * ctx; + + if (!asan_initialized) return; + + if (instr->id == X86_INS_LEA) return; + + if (instr->id == X86_INS_NOP) return; + + for (uint8_t i = 0; i < x86.op_count; i++) { + + operand = &x86.operands[i]; + + if (operand->type != X86_OP_MEM) { continue; } + + mem = &operand->mem; + if (mem->segment != X86_REG_INVALID) { continue; } + + ctx = g_malloc0(sizeof(cs_x86_op)); + memcpy(ctx, operand, sizeof(cs_x86_op)); + gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free); + + } + +} + +void asan_arch_init(void) { + + asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN"); + asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN"); + if (asan_loadN == NULL || asan_storeN == NULL) { + + FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'"); + + } + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c new file mode 100644 index 00000000..7b11c350 --- /dev/null +++ b/frida_mode/src/cmplog/cmplog.c @@ -0,0 +1,87 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "util.h" + +#define DEFAULT_MMAP_MIN_ADDR (32UL << 10) + +extern struct cmp_map *__afl_cmp_map; + +static GArray *cmplog_ranges = NULL; + +static gboolean cmplog_range(const GumRangeDetails *details, + gpointer user_data) { + + UNUSED_PARAMETER(user_data); + GumMemoryRange range = *details->range; + g_array_append_val(cmplog_ranges, range); + return TRUE; + +} + +static gint cmplog_sort(gconstpointer a, gconstpointer b) { + + return ((GumMemoryRange *)b)->base_address - + ((GumMemoryRange *)a)->base_address; + +} + +void cmplog_init(void) { + + if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); } + + cmplog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100); + gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, NULL); + g_array_sort(cmplog_ranges, cmplog_sort); + + for (guint i = 0; i < cmplog_ranges->len; i++) { + + GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); + OKF("CMPLOG Range - 0x%016" G_GINT64_MODIFIER "X - 0x%016" G_GINT64_MODIFIER + "X", + range->base_address, range->base_address + range->size); + + } + +} + +static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit, + GumAddress outer_base, GumAddress outer_limit) { + + return (inner_base >= outer_base && inner_limit <= outer_limit); + +} + +gboolean cmplog_is_readable(guint64 addr, size_t size) { + + if (cmplog_ranges == NULL) FATAL("CMPLOG not initialized"); + + /* + * The Linux kernel prevents mmap from allocating from the very bottom of the + * address space to mitigate NULL pointer dereference attacks. The exact size + * is set by sysctl by setting mmap_min_addr and 64k is suggested on most + * platforms with 32k on ARM systems. We therefore fail fast if the address + * is lower than this. This should avoid some overhead when functions are + * called where one of the parameters is a size, or a some other small value. + */ + if (addr < DEFAULT_MMAP_MIN_ADDR) { return false; } + + GumAddress inner_base = addr; + GumAddress inner_limit = inner_base + size; + + for (guint i = 0; i < cmplog_ranges->len; i++) { + + GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); + GumAddress outer_base = range->base_address; + GumAddress outer_limit = outer_base + range->size; + + if (cmplog_contains(inner_base, inner_limit, outer_base, outer_limit)) + return true; + + } + + return false; + +} + diff --git a/frida_mode/src/cmplog/cmplog_arm.c b/frida_mode/src/cmplog/cmplog_arm.c new file mode 100644 index 00000000..5af28f3f --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_arm.c @@ -0,0 +1,19 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "frida_cmplog.h" +#include "util.h" + +#if defined(__arm__) +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (__afl_cmp_map == NULL) { return; } + FATAL("CMPLOG mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog_arm64.c b/frida_mode/src/cmplog/cmplog_arm64.c new file mode 100644 index 00000000..187d0162 --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_arm64.c @@ -0,0 +1,19 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "frida_cmplog.h" +#include "util.h" + +#if defined(__aarch64__) +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (__afl_cmp_map == NULL) { return; } + FATAL("CMPLOG mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog_x64.c b/frida_mode/src/cmplog/cmplog_x64.c new file mode 100644 index 00000000..9f56c32a --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_x64.c @@ -0,0 +1,272 @@ +#include "frida-gum.h" + +#include "debug.h" +#include "cmplog.h" + +#include "ctx.h" +#include "frida_cmplog.h" +#include "util.h" + +#if defined(__x86_64__) + +typedef struct { + + x86_op_type type; + uint8_t size; + + union { + + x86_op_mem mem; + x86_reg reg; + int64_t imm; + + }; + +} cmplog_ctx_t; + +typedef struct { + + cmplog_ctx_t operand1; + cmplog_ctx_t operand2; + +} cmplog_pair_ctx_t; + +static gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size, + x86_op_mem *mem, gsize *val) { + + gsize base = 0; + gsize index = 0; + gsize address; + + if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base); + + if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index); + + address = base + (index * mem->scale) + mem->disp; + + if (!cmplog_is_readable(address, size)) { return FALSE; } + + switch (size) { + + case 1: + *val = *((guint8 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 2: + *val = *((guint16 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 4: + *val = *((guint32 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 8: + *val = *((guint64 *)GSIZE_TO_POINTER(address)); + return TRUE; + default: + FATAL("Invalid operand size: %d\n", size); + + } + + return FALSE; + +} + +static gboolean cmplog_get_operand_value(GumCpuContext *context, + cmplog_ctx_t *ctx, gsize *val) { + + switch (ctx->type) { + + case X86_OP_REG: + *val = ctx_read_reg(context, ctx->reg); + return TRUE; + case X86_OP_IMM: + *val = ctx->imm; + return TRUE; + case X86_OP_MEM: + return cmplog_read_mem(context, ctx->size, &ctx->mem, val); + default: + FATAL("Invalid operand type: %d\n", ctx->type); + + } + + return FALSE; + +} + +static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + gsize address = ctx_read_reg(context, X86_REG_RIP); + gsize rdi = ctx_read_reg(context, X86_REG_RDI); + gsize rsi = ctx_read_reg(context, X86_REG_RSI); + + if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return; + + if (!cmplog_is_readable(rdi, 32) || !cmplog_is_readable(rsi, 32)) return; + + void *ptr1 = GSIZE_TO_POINTER(rdi); + void *ptr2 = GSIZE_TO_POINTER(rsi); + + uintptr_t k = address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_RTN; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = 31; + + hits &= CMP_MAP_RTN_H - 1; + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, ptr1, + 32); + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, ptr2, + 32); + +} + +static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx, + cs_x86_op * operand) { + + ctx->type = operand->type; + ctx->size = operand->size; + switch (operand->type) { + + case X86_OP_REG: + gum_memcpy(&ctx->reg, &operand->reg, sizeof(x86_reg)); + break; + case X86_OP_IMM: + gum_memcpy(&ctx->imm, &operand->imm, sizeof(int64_t)); + break; + case X86_OP_MEM: + gum_memcpy(&ctx->mem, &operand->mem, sizeof(x86_op_mem)); + break; + default: + FATAL("Invalid operand type: %d\n", operand->type); + + } + +} + +static void cmplog_instrument_call(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand; + + if (instr->id != X86_INS_CALL) return; + + if (x86.op_count != 1) return; + + operand = &x86.operands[0]; + + if (operand->type == X86_OP_INVALID) return; + if (operand->type == X86_OP_MEM && operand->mem.segment != X86_REG_INVALID) + return; + + gum_stalker_iterator_put_callout(iterator, cmplog_call_callout, NULL, NULL); + +} + +static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1, + gsize operand2, uint8_t size) { + + gsize address = ctx_read_reg(context, X86_REG_RIP); + + register uintptr_t k = (uintptr_t)address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = (size - 1); + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = operand1; + __afl_cmp_map->log[k][hits].v1 = operand2; + +} + +static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) { + + cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data; + gsize operand1; + gsize operand2; + + if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch"); + + if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; } + if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; } + + cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size); + +} + +static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator, + cs_x86_op * operand1, + cs_x86_op *operand2) { + + cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t)); + if (ctx == NULL) return; + + cmplog_instrument_put_operand(&ctx->operand1, operand1); + cmplog_instrument_put_operand(&ctx->operand2, operand2); + + gum_stalker_iterator_put_callout(iterator, cmplog_cmp_sub_callout, ctx, + g_free); + +} + +static void cmplog_instrument_cmp_sub(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand1; + cs_x86_op *operand2; + + switch (instr->id) { + + case X86_INS_CMP: + case X86_INS_SUB: + break; + default: + return; + + } + + if (x86.op_count != 2) return; + + operand1 = &x86.operands[0]; + operand2 = &x86.operands[1]; + + if (operand1->type == X86_OP_INVALID) return; + if (operand2->type == X86_OP_INVALID) return; + + if ((operand1->type == X86_OP_MEM) && + (operand1->mem.segment != X86_REG_INVALID)) + return; + + if ((operand2->type == X86_OP_MEM) && + (operand2->mem.segment != X86_REG_INVALID)) + return; + + cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2); + +} + +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + if (__afl_cmp_map == NULL) return; + + cmplog_instrument_call(instr, iterator); + cmplog_instrument_cmp_sub(instr, iterator); + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog_x86.c b/frida_mode/src/cmplog/cmplog_x86.c new file mode 100644 index 00000000..a27df0af --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_x86.c @@ -0,0 +1,277 @@ +#include "frida-gum.h" + +#include "debug.h" +#include "cmplog.h" + +#include "ctx.h" +#include "frida_cmplog.h" +#include "util.h" + +#if defined(__i386__) + +typedef struct { + + x86_op_type type; + uint8_t size; + + union { + + x86_op_mem mem; + x86_reg reg; + int64_t imm; + + }; + +} cmplog_ctx_t; + +typedef struct { + + cmplog_ctx_t operand1; + cmplog_ctx_t operand2; + +} cmplog_pair_ctx_t; + +static gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size, + x86_op_mem *mem, gsize *val) { + + gsize base = 0; + gsize index = 0; + gsize address; + + if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base); + + if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index); + + address = base + (index * mem->scale) + mem->disp; + + if (!cmplog_is_readable(address, size)) { return FALSE; } + + switch (size) { + + case 1: + *val = *((guint8 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 2: + *val = *((guint16 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 4: + *val = *((guint32 *)GSIZE_TO_POINTER(address)); + return TRUE; + default: + FATAL("Invalid operand size: %d\n", size); + + } + + return FALSE; + +} + +static gboolean cmplog_get_operand_value(GumCpuContext *context, + cmplog_ctx_t *ctx, gsize *val) { + + switch (ctx->type) { + + case X86_OP_REG: + *val = ctx_read_reg(context, ctx->reg); + return TRUE; + case X86_OP_IMM: + *val = ctx->imm; + return TRUE; + case X86_OP_MEM: + return cmplog_read_mem(context, ctx->size, &ctx->mem, val); + default: + FATAL("Invalid operand type: %d\n", ctx->type); + + } + + return FALSE; + +} + +static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + gsize address = ctx_read_reg(context, X86_REG_EIP); + gsize *esp = (gsize *)ctx_read_reg(context, X86_REG_ESP); + + if (!cmplog_is_readable(GPOINTER_TO_SIZE(esp), 12)) return; + + /* + * This callout is place immediately before the call instruction, and hence + * the return address is not yet pushed on the top of the stack. + */ + gsize arg1 = esp[0]; + gsize arg2 = esp[1]; + + if (((G_MAXULONG - arg1) < 32) || ((G_MAXULONG - arg2) < 32)) return; + + if (!cmplog_is_readable(arg1, 32) || !cmplog_is_readable(arg2, 32)) return; + + void *ptr1 = GSIZE_TO_POINTER(arg1); + void *ptr2 = GSIZE_TO_POINTER(arg2); + + uintptr_t k = address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_RTN; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = 31; + + hits &= CMP_MAP_RTN_H - 1; + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, ptr1, + 32); + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, ptr2, + 32); + +} + +static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx, + cs_x86_op * operand) { + + ctx->type = operand->type; + ctx->size = operand->size; + switch (operand->type) { + + case X86_OP_REG: + gum_memcpy(&ctx->reg, &operand->reg, sizeof(x86_reg)); + break; + case X86_OP_IMM: + gum_memcpy(&ctx->imm, &operand->imm, sizeof(int64_t)); + break; + case X86_OP_MEM: + gum_memcpy(&ctx->mem, &operand->mem, sizeof(x86_op_mem)); + break; + default: + FATAL("Invalid operand type: %d\n", operand->type); + + } + +} + +static void cmplog_instrument_call(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand; + + if (instr->id != X86_INS_CALL) return; + + if (x86.op_count != 1) return; + + operand = &x86.operands[0]; + + if (operand->type == X86_OP_INVALID) return; + if (operand->type == X86_OP_MEM && operand->mem.segment != X86_REG_INVALID) + return; + + gum_stalker_iterator_put_callout(iterator, cmplog_call_callout, NULL, NULL); + +} + +static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1, + gsize operand2, uint8_t size) { + + gsize address = ctx_read_reg(context, X86_REG_EIP); + + register uintptr_t k = (uintptr_t)address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = (size - 1); + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = operand1; + __afl_cmp_map->log[k][hits].v1 = operand2; + +} + +static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) { + + cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data; + gsize operand1; + gsize operand2; + + if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch"); + + if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; } + if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; } + + cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size); + +} + +static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator, + cs_x86_op * operand1, + cs_x86_op *operand2) { + + cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t)); + if (ctx == NULL) return; + + cmplog_instrument_put_operand(&ctx->operand1, operand1); + cmplog_instrument_put_operand(&ctx->operand2, operand2); + + gum_stalker_iterator_put_callout(iterator, cmplog_cmp_sub_callout, ctx, + g_free); + +} + +static void cmplog_instrument_cmp_sub(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand1; + cs_x86_op *operand2; + + switch (instr->id) { + + case X86_INS_CMP: + case X86_INS_SUB: + break; + default: + return; + + } + + if (x86.op_count != 2) return; + + operand1 = &x86.operands[0]; + operand2 = &x86.operands[1]; + + if (operand1->type == X86_OP_INVALID) return; + if (operand2->type == X86_OP_INVALID) return; + + if ((operand1->type == X86_OP_MEM) && + (operand1->mem.segment != X86_REG_INVALID)) + return; + + if ((operand2->type == X86_OP_MEM) && + (operand2->mem.segment != X86_REG_INVALID)) + return; + + cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2); + +} + +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + if (__afl_cmp_map == NULL) return; + + cmplog_instrument_call(instr, iterator); + cmplog_instrument_cmp_sub(instr, iterator); + +} + +#endif + diff --git a/frida_mode/src/ctx/ctx_x64.c b/frida_mode/src/ctx/ctx_x64.c new file mode 100644 index 00000000..c5900533 --- /dev/null +++ b/frida_mode/src/ctx/ctx_x64.c @@ -0,0 +1,114 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__x86_64__) + + #define X86_REG_8L(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define X86_REG_8H(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK) >> 8; \ + \ + } + + #define X86_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define X86_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + + #define X86_REG_64(LABEL, REG) \ + case LABEL: { \ + \ + return (REG); \ + \ + } + +gsize ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg) { + + switch (reg) { + + X86_REG_8L(X86_REG_AL, ctx->rax) + X86_REG_8L(X86_REG_BL, ctx->rbx) + X86_REG_8L(X86_REG_CL, ctx->rcx) + X86_REG_8L(X86_REG_DL, ctx->rdx) + X86_REG_8L(X86_REG_BPL, ctx->rbp) + X86_REG_8L(X86_REG_SIL, ctx->rsi) + X86_REG_8L(X86_REG_DIL, ctx->rdi) + + X86_REG_8H(X86_REG_AH, ctx->rax) + X86_REG_8H(X86_REG_BH, ctx->rbx) + X86_REG_8H(X86_REG_CH, ctx->rcx) + X86_REG_8H(X86_REG_DH, ctx->rdx) + + X86_REG_16(X86_REG_AX, ctx->rax) + X86_REG_16(X86_REG_BX, ctx->rbx) + X86_REG_16(X86_REG_CX, ctx->rcx) + X86_REG_16(X86_REG_DX, ctx->rdx) + X86_REG_16(X86_REG_DI, ctx->rdi) + X86_REG_16(X86_REG_SI, ctx->rsi) + X86_REG_16(X86_REG_BP, ctx->rbp) + + X86_REG_32(X86_REG_EAX, ctx->rax) + X86_REG_32(X86_REG_ECX, ctx->rcx) + X86_REG_32(X86_REG_EDX, ctx->rdx) + X86_REG_32(X86_REG_EBX, ctx->rbx) + X86_REG_32(X86_REG_ESP, ctx->rsp) + X86_REG_32(X86_REG_EBP, ctx->rbp) + X86_REG_32(X86_REG_ESI, ctx->rsi) + X86_REG_32(X86_REG_EDI, ctx->rdi) + X86_REG_32(X86_REG_R8D, ctx->r8) + X86_REG_32(X86_REG_R9D, ctx->r9) + X86_REG_32(X86_REG_R10D, ctx->r10) + X86_REG_32(X86_REG_R11D, ctx->r11) + X86_REG_32(X86_REG_R12D, ctx->r12) + X86_REG_32(X86_REG_R13D, ctx->r13) + X86_REG_32(X86_REG_R14D, ctx->r14) + X86_REG_32(X86_REG_R15D, ctx->r15) + X86_REG_32(X86_REG_EIP, ctx->rip) + + X86_REG_64(X86_REG_RAX, ctx->rax) + X86_REG_64(X86_REG_RCX, ctx->rcx) + X86_REG_64(X86_REG_RDX, ctx->rdx) + X86_REG_64(X86_REG_RBX, ctx->rbx) + X86_REG_64(X86_REG_RSP, ctx->rsp) + X86_REG_64(X86_REG_RBP, ctx->rbp) + X86_REG_64(X86_REG_RSI, ctx->rsi) + X86_REG_64(X86_REG_RDI, ctx->rdi) + X86_REG_64(X86_REG_R8, ctx->r8) + X86_REG_64(X86_REG_R9, ctx->r9) + X86_REG_64(X86_REG_R10, ctx->r10) + X86_REG_64(X86_REG_R11, ctx->r11) + X86_REG_64(X86_REG_R12, ctx->r12) + X86_REG_64(X86_REG_R13, ctx->r13) + X86_REG_64(X86_REG_R14, ctx->r14) + X86_REG_64(X86_REG_R15, ctx->r15) + X86_REG_64(X86_REG_RIP, ctx->rip) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +#endif + diff --git a/frida_mode/src/ctx/ctx_x86.c b/frida_mode/src/ctx/ctx_x86.c new file mode 100644 index 00000000..45308272 --- /dev/null +++ b/frida_mode/src/ctx/ctx_x86.c @@ -0,0 +1,81 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__i386__) + + #define X86_REG_8L(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define X86_REG_8H(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK) >> 8; \ + \ + } + + #define X86_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define X86_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + +gsize ctx_read_reg(GumIA32CpuContext *ctx, x86_reg reg) { + + switch (reg) { + + X86_REG_8L(X86_REG_AL, ctx->eax) + X86_REG_8L(X86_REG_BL, ctx->ebx) + X86_REG_8L(X86_REG_CL, ctx->ecx) + X86_REG_8L(X86_REG_DL, ctx->edx) + X86_REG_8L(X86_REG_BPL, ctx->ebp) + X86_REG_8L(X86_REG_SIL, ctx->esi) + X86_REG_8L(X86_REG_DIL, ctx->edi) + + X86_REG_8H(X86_REG_AH, ctx->eax) + X86_REG_8H(X86_REG_BH, ctx->ebx) + X86_REG_8H(X86_REG_CH, ctx->ecx) + X86_REG_8H(X86_REG_DH, ctx->edx) + + X86_REG_16(X86_REG_AX, ctx->eax) + X86_REG_16(X86_REG_BX, ctx->ebx) + X86_REG_16(X86_REG_CX, ctx->ecx) + X86_REG_16(X86_REG_DX, ctx->edx) + X86_REG_16(X86_REG_DI, ctx->edi) + X86_REG_16(X86_REG_SI, ctx->esi) + X86_REG_16(X86_REG_BP, ctx->ebp) + + X86_REG_32(X86_REG_EAX, ctx->eax) + X86_REG_32(X86_REG_ECX, ctx->ecx) + X86_REG_32(X86_REG_EDX, ctx->edx) + X86_REG_32(X86_REG_EBX, ctx->ebx) + X86_REG_32(X86_REG_ESP, ctx->esp) + X86_REG_32(X86_REG_EBP, ctx->ebp) + X86_REG_32(X86_REG_ESI, ctx->esi) + X86_REG_32(X86_REG_EDI, ctx->edi) + X86_REG_32(X86_REG_EIP, ctx->eip) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +#endif + diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c new file mode 100644 index 00000000..e71386a0 --- /dev/null +++ b/frida_mode/src/entry.c @@ -0,0 +1,50 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "entry.h" +#include "instrument.h" +#include "stalker.h" +#include "util.h" + +extern void __afl_manual_init(); + +guint64 entry_start = 0; + +static void entry_launch(void) { + + __afl_manual_init(); + + /* Child here */ + previous_pc = 0; + +} + +void entry_init(void) { + + entry_start = util_read_address("AFL_ENTRYPOINT"); + OKF("entry_point: 0x%016" G_GINT64_MODIFIER "X", entry_start); + +} + +void entry_run(void) { + + if (entry_start == 0) { entry_launch(); } + +} + +static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) { + + UNUSED_PARAMETER(cpu_context); + UNUSED_PARAMETER(user_data); + entry_launch(); + +} + +void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + gum_stalker_iterator_put_callout(iterator, entry_callout, NULL, NULL); + +} + diff --git a/frida_mode/src/instrument.c b/frida_mode/src/instrument.c deleted file mode 100644 index 22910062..00000000 --- a/frida_mode/src/instrument.c +++ /dev/null @@ -1,271 +0,0 @@ -#include "frida-gum.h" -#include "config.h" -#include "debug.h" -#include "prefetch.h" -#include "ranges.h" -#include "unistd.h" - -extern uint8_t *__afl_area_ptr; -extern u32 __afl_map_size; - -uint64_t __thread previous_pc = 0; -GumAddress current_log_impl = GUM_ADDRESS(0); - -static gboolean tracing = false; -static gboolean optimize = false; -static gboolean strict = false; - -#if defined(__x86_64__) -static const guint8 afl_log_code[] = { - - 0x9c, /* pushfq */ - 0x50, /* push rax */ - 0x51, /* push rcx */ - 0x52, /* push rdx */ - - 0x48, 0x8d, 0x05, 0x27, - 0x00, 0x00, 0x00, /* lea rax, sym._afl_area_ptr_ptr */ - 0x48, 0x8b, 0x00, /* mov rax, qword [rax] */ - 0x48, 0x8b, 0x00, /* mov rax, qword [rax] */ - 0x48, 0x8d, 0x0d, 0x22, - 0x00, 0x00, 0x00, /* lea rcx, sym.previous_pc */ - 0x48, 0x8b, 0x11, /* mov rdx, qword [rcx] */ - 0x48, 0x8b, 0x12, /* mov rdx, qword [rdx] */ - 0x48, 0x31, 0xfa, /* xor rdx, rdi */ - 0xfe, 0x04, 0x10, /* inc byte [rax + rdx] */ - 0x48, 0xd1, 0xef, /* shr rdi, 1 */ - 0x48, 0x8b, 0x01, /* mov rax, qword [rcx] */ - 0x48, 0x89, 0x38, /* mov qword [rax], rdi */ - - 0x5a, /* pop rdx */ - 0x59, /* pop rcx */ - 0x58, /* pop rax */ - 0x9d, /* popfq */ - - 0xc3, /* ret */ - - /* Read-only data goes here: */ - /* uint8_t** afl_area_ptr_ptr */ - /* uint64_t* afl_prev_loc_ptr */ - -}; - -void instrument_coverage_optimize(const cs_insn * instr, - GumStalkerOutput *output) { - - guint64 current_pc = instr->address; - guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); - area_offset &= MAP_SIZE - 1; - GumX86Writer *cw = output->writer.x86; - - if (current_log_impl == 0 || - !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || - !gum_x86_writer_can_branch_directly_between(cw->pc + 128, - current_log_impl)) { - - gconstpointer after_log_impl = cw->code + 1; - - gum_x86_writer_put_jmp_near_label(cw, after_log_impl); - - current_log_impl = cw->pc; - gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); - - uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; - uint64_t *afl_prev_loc_ptr = &previous_pc; - gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, - sizeof(afl_area_ptr_ptr)); - gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, - sizeof(afl_prev_loc_ptr)); - - gum_x86_writer_put_label(cw, after_log_impl); - - } - - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - -GUM_RED_ZONE_SIZE); - gum_x86_writer_put_push_reg(cw, GUM_REG_RDI); - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset); - gum_x86_writer_put_call_address(cw, current_log_impl); - gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI); - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - GUM_RED_ZONE_SIZE); - -} - -#elif defined(__aarch64__) -static const guint8 afl_log_code[] = { - - // __afl_area_ptr[current_pc ^ previous_pc]++; - // previous_pc = current_pc >> 1; - 0xE1, 0x0B, 0xBF, 0xA9, // stp x1, x2, [sp, -0x10]! - 0xE3, 0x13, 0xBF, 0xA9, // stp x3, x4, [sp, -0x10]! - - // x0 = current_pc - 0xc1, 0x01, 0x00, 0x58, // ldr x1, #0x38, =&__afl_area_ptr - 0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr) - - 0xc2, 0x01, 0x00, 0x58, // ldr x2, #0x38, =&previous_pc - 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2] (=previous_pc) - - // __afl_area_ptr[current_pc ^ previous_pc]++; - 0x42, 0x00, 0x00, 0xca, // eor x2, x2, x0 - 0x23, 0x68, 0x62, 0xf8, // ldr x3, [x1, x2] - 0x63, 0x04, 0x00, 0x91, // add x3, x3, #1 - 0x23, 0x68, 0x22, 0xf8, // str x3, [x1, x2] - - // previous_pc = current_pc >> 1; - 0xe0, 0x07, 0x40, 0x8b, // add x0, xzr, x0, LSR #1 - 0xe2, 0x00, 0x00, 0x58, // ldr x2, #0x1c, =&previous_pc - 0x40, 0x00, 0x00, 0xf9, // str x0, [x2] - - 0xE3, 0x13, 0xc1, 0xA8, // ldp x3, x4, [sp], #0x10 - 0xE1, 0x0B, 0xc1, 0xA8, // ldp x1, x2, [sp], #0x10 - 0xC0, 0x03, 0x5F, 0xD6, // ret - - // &afl_area_ptr_ptr - // &afl_prev_loc_ptr - -}; - -void instrument_coverage_optimize(const cs_insn * instr, - GumStalkerOutput *output) { - - guint64 current_pc = instr->address; - guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); - area_offset &= MAP_SIZE - 1; - GumArm64Writer *cw = output->writer.arm64; - - if (current_log_impl == 0 || - !gum_arm64_writer_can_branch_directly_between(cw, cw->pc, - current_log_impl) || - !gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128, - current_log_impl)) { - - gconstpointer after_log_impl = cw->code + 1; - - gum_arm64_writer_put_b_label(cw, after_log_impl); - - current_log_impl = cw->pc; - gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); - - uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; - uint64_t *afl_prev_loc_ptr = &previous_pc; - gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, - sizeof(afl_area_ptr_ptr)); - gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, - sizeof(afl_prev_loc_ptr)); - - gum_arm64_writer_put_label(cw, after_log_impl); - - } - - gum_arm64_writer_put_stp_reg_reg_reg_offset( - cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE), - GUM_INDEX_PRE_ADJUST); - gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset); - gum_arm64_writer_put_bl_imm(cw, current_log_impl); - gum_arm64_writer_put_ldp_reg_reg_reg_offset( - cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE, - GUM_INDEX_POST_ADJUST); - -} - -#endif - -static void on_basic_block(GumCpuContext *context, gpointer user_data) { - - /* - * This function is performance critical as it is called to instrument every - * basic block. By moving our print buffer to a global, we avoid it affecting - * the critical path with additional stack adjustments if tracing is not - * enabled. If tracing is enabled, then we're printing a load of diagnostic - * information so this overhead is unlikely to be noticeable. - */ - static char buffer[200]; - int len; - guint64 current_pc = (guint64)user_data; - if (tracing) { - - /* Avoid any functions which may cause an allocation since the target app - * may already be running inside malloc and it isn't designed to be - * re-entrant on a single thread */ - len = snprintf(buffer, sizeof(buffer), - "current_pc: 0x%016" G_GINT64_MODIFIER - "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n", - current_pc, previous_pc); - - write(STDOUT_FILENO, buffer, len + 1); - - } - - current_pc = (current_pc >> 4) ^ (current_pc << 8); - current_pc &= MAP_SIZE - 1; - - __afl_area_ptr[current_pc ^ previous_pc]++; - previous_pc = current_pc >> 1; - -} - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data) { - - const cs_insn *instr; - gboolean begin = TRUE; - while (gum_stalker_iterator_next(iterator, &instr)) { - - if (begin) { - - prefetch_write((void *)instr->address); - if (!strict || !range_is_excluded((void *)instr->address)) { - - if (optimize) { - - instrument_coverage_optimize(instr, output); - - } else { - - gum_stalker_iterator_put_callout(iterator, on_basic_block, - (gpointer)instr->address, NULL); - - } - - } - - begin = FALSE; - - } - - gum_stalker_iterator_keep(iterator); - - } - -} - -void instrument_init() { - - optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL); - tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); - strict = (getenv("AFL_FRIDA_INST_STRICT") != NULL); - -#if !defined(__x86_64__) && !defined(__aarch64__) - optimize = false; -#endif - - OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' '); - OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' '); - OKF("Instrumentation - strict [%c]", strict ? 'X' : ' '); - - if (tracing && optimize) { - - FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible"); - - } - - if (__afl_map_size != 0x10000) { - - FATAL("Bad map size: 0x%08x", __afl_map_size); - - } - -} - diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c new file mode 100644 index 00000000..cd1ac0be --- /dev/null +++ b/frida_mode/src/instrument/instrument.c @@ -0,0 +1,199 @@ +#include <unistd.h> + +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "asan.h" +#include "entry.h" +#include "frida_cmplog.h" +#include "instrument.h" +#include "persistent.h" +#include "prefetch.h" +#include "ranges.h" +#include "stalker.h" +#include "stats.h" +#include "util.h" + +static gboolean tracing = false; +static gboolean optimize = false; +static GumStalkerTransformer *transformer = NULL; + +__thread uint64_t previous_pc = 0; + +__attribute__((hot)) static void on_basic_block(GumCpuContext *context, + gpointer user_data) { + + UNUSED_PARAMETER(context); + /* + * This function is performance critical as it is called to instrument every + * basic block. By moving our print buffer to a global, we avoid it affecting + * the critical path with additional stack adjustments if tracing is not + * enabled. If tracing is enabled, then we're printing a load of diagnostic + * information so this overhead is unlikely to be noticeable. + */ + static char buffer[200]; + int len; + GumAddress current_pc = GUM_ADDRESS(user_data); + uint8_t * cursor; + uint64_t value; + if (unlikely(tracing)) { + + /* Avoid any functions which may cause an allocation since the target app + * may already be running inside malloc and it isn't designed to be + * re-entrant on a single thread */ + len = snprintf(buffer, sizeof(buffer), + "current_pc: 0x%016" G_GINT64_MODIFIER + "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n", + current_pc, previous_pc); + + IGNORED_RETURN(write(STDOUT_FILENO, buffer, len + 1)); + + } + + current_pc = (current_pc >> 4) ^ (current_pc << 8); + current_pc &= MAP_SIZE - 1; + + cursor = &__afl_area_ptr[current_pc ^ previous_pc]; + value = *cursor; + + if (value == 0xff) { + + value = 1; + + } else { + + value++; + + } + + *cursor = value; + previous_pc = current_pc >> 1; + +} + +static void instr_basic_block(GumStalkerIterator *iterator, + GumStalkerOutput *output, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + const cs_insn *instr; + gboolean begin = TRUE; + gboolean excluded; + + while (gum_stalker_iterator_next(iterator, &instr)) { + + if (instr->address == entry_start) { entry_prologue(iterator, output); } + if (instr->address == persistent_start) { persistent_prologue(output); } + if (instr->address == persistent_ret) { persistent_epilogue(output); } + + /* + * Until we reach AFL_ENTRYPOINT (assumed to be main if not specified) or + * AFL_FRIDA_PERSISTENT_ADDR (if specified), we don't mark our ranges + * excluded as we wish to remain inside stalker at all times so that we can + * instrument our entry point and persistent loop (if present). This allows + * the user to exclude ranges which would be traversed between main and the + * AFL_ENTRYPOINT, but which they don't want included in their coverage + * information when fuzzing. + * + * Since we have no means to discard the instrumented copies of blocks + * (setting the trust threshold simply causes a new copy to be made on each + * execution), we instead ensure that we honour the additional + * instrumentation requested (e.g. coverage, asan and complog) when a block + * is compiled no matter where we are during initialization. We will end up + * re-using these blocks if the code under test calls a block which is also + * used during initialization. + * + * Coverage data generated during initialization isn't a problem since the + * map is zeroed each time the target is forked or each time the persistent + * loop is run. + * + * Lastly, we don't enable pre-fetching back to the parent until we reach + * our AFL_ENTRYPOINT, since it is not until then that we start the + * fork-server and thus start executing in the child. + */ + excluded = range_is_excluded(GSIZE_TO_POINTER(instr->address)); + + stats_collect(instr, begin); + + if (unlikely(begin)) { + + instrument_debug_start(instr->address, output); + + prefetch_write(GSIZE_TO_POINTER(instr->address)); + + if (likely(!excluded)) { + + if (likely(optimize)) { + + instrument_coverage_optimize(instr, output); + + } else { + + gum_stalker_iterator_put_callout( + iterator, on_basic_block, GSIZE_TO_POINTER(instr->address), NULL); + + } + + } + + begin = FALSE; + + } + + instrument_debug_instruction(instr->address, instr->size); + + if (likely(!excluded)) { + + asan_instrument(instr, iterator); + cmplog_instrument(instr, iterator); + + } + + gum_stalker_iterator_keep(iterator); + + } + + instrument_debug_end(output); + +} + +void instrument_init(void) { + + optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL); + tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); + + if (!instrument_is_coverage_optimize_supported()) optimize = false; + + OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' '); + OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' '); + + if (tracing && optimize) { + + FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible"); + + } + + if (__afl_map_size != 0x10000) { + + FATAL("Bad map size: 0x%08x", __afl_map_size); + + } + + transformer = + gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + + instrument_debug_init(); + asan_init(); + cmplog_init(); + +} + +GumStalkerTransformer *instrument_get_transformer(void) { + + if (transformer == NULL) { FATAL("Instrumentation not initialized"); } + return transformer; + +} + diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c new file mode 100644 index 00000000..1a3c40bb --- /dev/null +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -0,0 +1,26 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "instrument.h" +#include "util.h" + +#if defined(__arm__) + +gboolean instrument_is_coverage_optimize_supported(void) { + + return false; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(output); + FATAL("Optimized coverage not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c new file mode 100644 index 00000000..fa3afb48 --- /dev/null +++ b/frida_mode/src/instrument/instrument_arm64.c @@ -0,0 +1,97 @@ +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "instrument.h" + +#if defined(__aarch64__) + +static GumAddress current_log_impl = GUM_ADDRESS(0); + +static const guint8 afl_log_code[] = { + + // __afl_area_ptr[current_pc ^ previous_pc]++; + // previous_pc = current_pc >> 1; + 0xE1, 0x0B, 0xBF, 0xA9, // stp x1, x2, [sp, -0x10]! + 0xE3, 0x13, 0xBF, 0xA9, // stp x3, x4, [sp, -0x10]! + + // x0 = current_pc + 0xe1, 0x01, 0x00, 0x58, // ldr x1, #0x3c, =&__afl_area_ptr + 0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr) + + 0xe2, 0x01, 0x00, 0x58, // ldr x2, #0x3c, =&previous_pc + 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2] (=previous_pc) + + // __afl_area_ptr[current_pc ^ previous_pc]++; + 0x42, 0x00, 0x00, 0xca, // eor x2, x2, x0 + 0x23, 0x68, 0x62, 0xf8, // ldr x3, [x1, x2] + 0x63, 0x04, 0x00, 0x91, // add x3, x3, #1 + 0x63, 0x00, 0x1f, 0x9a, // adc x3, x3, xzr + 0x23, 0x68, 0x22, 0xf8, // str x3, [x1, x2] + + // previous_pc = current_pc >> 1; + 0xe0, 0x07, 0x40, 0x8b, // add x0, xzr, x0, LSR #1 + 0xe2, 0x00, 0x00, 0x58, // ldr x2, #0x1c, =&previous_pc + 0x40, 0x00, 0x00, 0xf9, // str x0, [x2] + + 0xE3, 0x13, 0xc1, 0xA8, // ldp x3, x4, [sp], #0x10 + 0xE1, 0x0B, 0xc1, 0xA8, // ldp x1, x2, [sp], #0x10 + 0xC0, 0x03, 0x5F, 0xD6, // ret + + // &afl_area_ptr_ptr + // &afl_prev_loc_ptr + +}; + +gboolean instrument_is_coverage_optimize_supported(void) { + + return true; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumArm64Writer *cw = output->writer.arm64; + + if (current_log_impl == 0 || + !gum_arm64_writer_can_branch_directly_between(cw, cw->pc, + current_log_impl) || + !gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_arm64_writer_put_b_label(cw, after_log_impl); + + current_log_impl = cw->pc; + gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); + + uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; + uint64_t *afl_prev_loc_ptr = &previous_pc; + gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, + sizeof(afl_area_ptr_ptr)); + gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, + sizeof(afl_prev_loc_ptr)); + + gum_arm64_writer_put_label(cw, after_log_impl); + + } + + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE), + GUM_INDEX_PRE_ADJUST); + gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset); + gum_arm64_writer_put_bl_imm(cw, current_log_impl); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE, + GUM_INDEX_POST_ADJUST); + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c new file mode 100644 index 00000000..be72ef89 --- /dev/null +++ b/frida_mode/src/instrument/instrument_debug.c @@ -0,0 +1,129 @@ +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <unistd.h> + +#include "frida-gum.h" + +#include "debug.h" + +#include "util.h" + +static int debugging_fd = -1; +static gpointer instrument_gen_start = NULL; + +static void instrument_debug(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(debugging_fd, buffer, len)); + +} + +static void instrument_disasm(guint8 *code, guint size) { + + csh capstone; + cs_err err; + cs_insn *insn; + size_t count, i; + + err = cs_open(GUM_DEFAULT_CS_ARCH, + GUM_DEFAULT_CS_MODE | GUM_DEFAULT_CS_ENDIAN, &capstone); + g_assert(err == CS_ERR_OK); + + count = cs_disasm(capstone, code, size, GPOINTER_TO_SIZE(code), 0, &insn); + g_assert(insn != NULL); + + for (i = 0; i != count; i++) { + + instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t%s %s\n", insn[i].address, + insn[i].mnemonic, insn[i].op_str); + + } + + cs_free(insn, count); + + cs_close(&capstone); + +} + +static gpointer instrument_cur(GumStalkerOutput *output) { + +#if defined(__i386__) || defined(__x86_64__) + return gum_x86_writer_cur(output->writer.x86); +#elif defined(__aarch64__) + return gum_arm64_writer_cur(output->writer.arm64); +#elif defined(__arm__) + return gum_arm_writer_cur(output->writer.arm); +#else + #error "Unsupported architecture" +#endif + +} + +void instrument_debug_init(void) { + + char *filename = getenv("AFL_FRIDA_INST_DEBUG_FILE"); + OKF("Instrumentation debugging - enabled [%c]", filename == NULL ? ' ' : 'X'); + + if (filename == NULL) { return; } + + OKF("Instrumentation debugging - file [%s]", filename); + + if (filename == NULL) { return; } + + char *path = g_canonicalize_filename(filename, g_get_current_dir()); + + OKF("Instrumentation debugging - path [%s]", path); + + debugging_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (debugging_fd < 0) { FATAL("Failed to open stats file '%s'", path); } + + g_free(path); + +} + +void instrument_debug_start(uint64_t address, GumStalkerOutput *output) { + + if (likely(debugging_fd < 0)) { return; } + + instrument_gen_start = instrument_cur(output); + + instrument_debug("\n\n***\n\nCreating block for 0x%" G_GINT64_MODIFIER "x:\n", + address); + +} + +void instrument_debug_instruction(uint64_t address, uint16_t size) { + + if (likely(debugging_fd < 0)) { return; } + uint8_t *start = (uint8_t *)GSIZE_TO_POINTER(address); + instrument_disasm(start, size); + +} + +void instrument_debug_end(GumStalkerOutput *output) { + + if (likely(debugging_fd < 0)) { return; } + gpointer instrument_gen_end = instrument_cur(output); + uint16_t size = GPOINTER_TO_SIZE(instrument_gen_end) - + GPOINTER_TO_SIZE(instrument_gen_start); + + instrument_debug("\nGenerated block %p\n", instrument_gen_start); + instrument_disasm(instrument_gen_start, size); + +} + diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c new file mode 100644 index 00000000..901f3bd0 --- /dev/null +++ b/frida_mode/src/instrument/instrument_x64.c @@ -0,0 +1,93 @@ +#include "frida-gum.h" + +#include "config.h" + +#include "instrument.h" + +#if defined(__x86_64__) + +static GumAddress current_log_impl = GUM_ADDRESS(0); + +static const guint8 afl_log_code[] = { + + // 0xcc, + + 0x9c, /* pushfq */ + 0x51, /* push rcx */ + 0x52, /* push rdx */ + + 0x48, 0x8b, 0x0d, 0x28, + 0x00, 0x00, 0x00, /* mov rcx, sym.&previous_pc */ + 0x48, 0x8b, 0x11, /* mov rdx, qword [rcx] */ + 0x48, 0x31, 0xfa, /* xor rdx, rdi */ + + 0x48, 0x03, 0x15, 0x13, + 0x00, 0x00, 0x00, /* add rdx, sym._afl_area_ptr_ptr */ + + 0x80, 0x02, 0x01, /* add byte ptr [rdx], 1 */ + 0x80, 0x12, 0x00, /* adc byte ptr [rdx], 0 */ + 0x48, 0xd1, 0xef, /* shr rdi, 1 */ + 0x48, 0x89, 0x39, /* mov qword [rcx], rdi */ + + 0x5a, /* pop rdx */ + 0x59, /* pop rcx */ + 0x9d, /* popfq */ + + 0xc3, /* ret */ + 0x90, 0x90, 0x90 /* nop pad */ + + /* Read-only data goes here: */ + /* uint8_t* __afl_area_ptr */ + /* uint64_t* &previous_pc */ + +}; + +gboolean instrument_is_coverage_optimize_supported(void) { + + return true; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumX86Writer *cw = output->writer.x86; + + if (current_log_impl == 0 || + !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || + !gum_x86_writer_can_branch_directly_between(cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_x86_writer_put_jmp_near_label(cw, after_log_impl); + + current_log_impl = cw->pc; + gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); + + uint64_t *afl_prev_loc_ptr = &previous_pc; + gum_x86_writer_put_bytes(cw, (const guint8 *)&__afl_area_ptr, + sizeof(__afl_area_ptr)); + gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, + sizeof(afl_prev_loc_ptr)); + + gum_x86_writer_put_label(cw, after_log_impl); + + } + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -GUM_RED_ZONE_SIZE); + gum_x86_writer_put_push_reg(cw, GUM_REG_RDI); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset); + gum_x86_writer_put_call_address(cw, current_log_impl); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + GUM_RED_ZONE_SIZE); + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c new file mode 100644 index 00000000..585bb5b8 --- /dev/null +++ b/frida_mode/src/instrument/instrument_x86.c @@ -0,0 +1,85 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "instrument.h" +#include "util.h" + +#if defined(__i386__) + +static GumAddress current_log_impl = GUM_ADDRESS(0); + +static void instrument_coverage_function(GumX86Writer *cw) { + + gum_x86_writer_put_pushfx(cw); + gum_x86_writer_put_push_reg(cw, GUM_REG_ECX); + gum_x86_writer_put_push_reg(cw, GUM_REG_EDX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX, + GUM_ADDRESS(&previous_pc)); + gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_EDX, GUM_REG_ECX); + gum_x86_writer_put_xor_reg_reg(cw, GUM_REG_EDX, GUM_REG_EDI); + + gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EDX, GUM_ADDRESS(__afl_area_ptr)); + + /* add byte ptr [edx], 1 */ + uint8_t add_byte_ptr_edx_1[] = {0x80, 0x02, 0x01}; + gum_x86_writer_put_bytes(cw, add_byte_ptr_edx_1, sizeof(add_byte_ptr_edx_1)); + + /* adc byte ptr [edx], 0 */ + uint8_t adc_byte_ptr_edx_0[] = {0x80, 0x12, 0x00}; + gum_x86_writer_put_bytes(cw, adc_byte_ptr_edx_0, sizeof(adc_byte_ptr_edx_0)); + + gum_x86_writer_put_shr_reg_u8(cw, GUM_REG_EDI, 1); + gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_ECX, GUM_REG_EDI); + + gum_x86_writer_put_pop_reg(cw, GUM_REG_EDX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_ECX); + gum_x86_writer_put_popfx(cw); + gum_x86_writer_put_ret(cw); + +} + +gboolean instrument_is_coverage_optimize_supported(void) { + + return true; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(output); + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumX86Writer *cw = output->writer.x86; + + if (current_log_impl == 0 || + !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || + !gum_x86_writer_can_branch_directly_between(cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_x86_writer_put_jmp_near_label(cw, after_log_impl); + + current_log_impl = cw->pc; + instrument_coverage_function(cw); + + gum_x86_writer_put_label(cw, after_log_impl); + + } + + // gum_x86_writer_put_breakpoint(cw); + gum_x86_writer_put_push_reg(cw, GUM_REG_EDI); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDI, area_offset); + gum_x86_writer_put_call_address(cw, current_log_impl); + gum_x86_writer_put_pop_reg(cw, GUM_REG_EDI); + +} + +#endif + diff --git a/frida_mode/src/interceptor.c b/frida_mode/src/interceptor.c index ba05a80a..d2802752 100644 --- a/frida_mode/src/interceptor.c +++ b/frida_mode/src/interceptor.c @@ -1,4 +1,5 @@ #include "frida-gum.h" + #include "debug.h" #include "interceptor.h" @@ -9,8 +10,26 @@ void intercept(void *address, gpointer replacement, gpointer user_data) { gum_interceptor_begin_transaction(interceptor); GumReplaceReturn ret = gum_interceptor_replace(interceptor, address, replacement, user_data); - if (ret != GUM_ATTACH_OK) { FATAL("gum_interceptor_attach: %d", ret); } + if (ret != GUM_REPLACE_OK) { FATAL("gum_interceptor_attach: %d", ret); } gum_interceptor_end_transaction(interceptor); } +void unintercept(void *address) { + + GumInterceptor *interceptor = gum_interceptor_obtain(); + + gum_interceptor_begin_transaction(interceptor); + gum_interceptor_revert(interceptor, address); + gum_interceptor_end_transaction(interceptor); + gum_interceptor_flush(interceptor); + +} + +void unintercept_self(void) { + + GumInvocationContext *ctx = gum_interceptor_get_current_invocation(); + unintercept(ctx->function); + +} + diff --git a/frida_mode/src/lib/lib.c b/frida_mode/src/lib/lib.c new file mode 100644 index 00000000..13a7d1e7 --- /dev/null +++ b/frida_mode/src/lib/lib.c @@ -0,0 +1,179 @@ +#ifndef __APPLE__ + #include <elf.h> + #include <fcntl.h> + #include <limits.h> + #include <stdio.h> + #include <sys/mman.h> + #include <unistd.h> + + #include "frida-gum.h" + + #include "debug.h" + + #include "lib.h" + + #if defined(__arm__) || defined(__i386__) + #define ELFCLASS ELFCLASS32 +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Addr Elf_Addr; + #elif defined(__aarch64__) || defined(__x86_64__) + #define ELFCLASS ELFCLASS64 +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Addr Elf_Addr; + #else + #error "Unsupported platform" + #endif + +typedef struct { + + gchar name[PATH_MAX + 1]; + gchar path[PATH_MAX + 1]; + GumAddress base_address; + gsize size; + +} lib_details_t; + +static guint64 text_base = 0; +static guint64 text_limit = 0; + +static gboolean lib_find_exe(const GumModuleDetails *details, + gpointer user_data) { + + lib_details_t *lib_details = (lib_details_t *)user_data; + + memcpy(lib_details->name, details->name, PATH_MAX); + memcpy(lib_details->path, details->path, PATH_MAX); + lib_details->base_address = details->range->base_address; + lib_details->size = details->range->size; + return FALSE; + +} + +static void lib_validate_hdr(Elf_Ehdr *hdr) { + + if (hdr->e_ident[0] != ELFMAG0) FATAL("Invalid e_ident[0]"); + if (hdr->e_ident[1] != ELFMAG1) FATAL("Invalid e_ident[1]"); + if (hdr->e_ident[2] != ELFMAG2) FATAL("Invalid e_ident[2]"); + if (hdr->e_ident[3] != ELFMAG3) FATAL("Invalid e_ident[3]"); + if (hdr->e_ident[4] != ELFCLASS) FATAL("Invalid class"); + +} + +static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) { + + Elf_Phdr *phdr; + gboolean found_preferred_base = FALSE; + Elf_Addr preferred_base; + Elf_Shdr *shdr; + Elf_Shdr *shstrtab; + char * shstr; + char * section_name; + Elf_Shdr *curr; + char text_name[] = ".text"; + + phdr = (Elf_Phdr *)((char *)hdr + hdr->e_phoff); + for (size_t i = 0; i < hdr->e_phnum; i++) { + + if (phdr[i].p_type == PT_LOAD) { + + preferred_base = phdr[i].p_vaddr; + found_preferred_base = TRUE; + break; + + } + + } + + if (!found_preferred_base) { FATAL("Failed to find preferred load address"); } + + OKF("Image preferred load address 0x%016" G_GSIZE_MODIFIER "x", + preferred_base); + + shdr = (Elf_Shdr *)((char *)hdr + hdr->e_shoff); + shstrtab = &shdr[hdr->e_shstrndx]; + shstr = (char *)hdr + shstrtab->sh_offset; + + OKF("shdr: %p", shdr); + OKF("shstrtab: %p", shstrtab); + OKF("shstr: %p", shstr); + + for (size_t i = 0; i < hdr->e_shnum; i++) { + + curr = &shdr[i]; + + if (curr->sh_name == 0) continue; + + section_name = &shstr[curr->sh_name]; + OKF("Section: %2" G_GSIZE_MODIFIER "u - base: 0x%016" G_GSIZE_MODIFIER + "X size: 0x%016" G_GSIZE_MODIFIER "X %s", + i, curr->sh_addr, curr->sh_size, section_name); + if (memcmp(section_name, text_name, sizeof(text_name)) == 0 && + text_base == 0) { + + text_base = lib_details->base_address + curr->sh_addr - preferred_base; + text_limit = text_base + curr->sh_size; + OKF("> text_addr: 0x%016" G_GINT64_MODIFIER "X", text_base); + OKF("> text_limit: 0x%016" G_GINT64_MODIFIER "X", text_limit); + + } + + } + +} + +static void lib_get_text_section(lib_details_t *details) { + + int fd = -1; + off_t len; + Elf_Ehdr *hdr; + + fd = open(details->path, O_RDONLY); + if (fd < 0) { FATAL("Failed to open %s", details->path); } + + len = lseek(fd, 0, SEEK_END); + + if (len == (off_t)-1) { FATAL("Failed to lseek %s", details->path); } + + OKF("len: %ld", len); + + hdr = (Elf_Ehdr *)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); + if (hdr == MAP_FAILED) { FATAL("Failed to map %s", details->path); } + + lib_validate_hdr(hdr); + lib_read_text_section(details, hdr); + + munmap(hdr, len); + close(fd); + +} + +void lib_init(void) { + + lib_details_t lib_details; + gum_process_enumerate_modules(lib_find_exe, &lib_details); + OKF("Executable: 0x%016" G_GINT64_MODIFIER "x - %s", lib_details.base_address, + lib_details.path); + lib_get_text_section(&lib_details); + +} + +guint64 lib_get_text_base(void) { + + if (text_base == 0) FATAL("Lib not initialized"); + return text_base; + +} + +guint64 lib_get_text_limit(void) { + + if (text_limit == 0) FATAL("Lib not initialized"); + return text_limit; + +} + +#endif + diff --git a/frida_mode/src/lib/lib_apple.c b/frida_mode/src/lib/lib_apple.c new file mode 100644 index 00000000..8f863861 --- /dev/null +++ b/frida_mode/src/lib/lib_apple.c @@ -0,0 +1,82 @@ +#ifdef __APPLE__ + #include "frida-gum.h" + + #include "debug.h" + + #include "lib.h" + #include "util.h" + +extern mach_port_t mach_task_self(); +extern void gum_darwin_enumerate_modules(mach_port_t task, + GumFoundModuleFunc func, + gpointer user_data); + +static guint64 text_base = 0; +static guint64 text_limit = 0; + +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); + + OKF("Found main module: %s", module->name); + + *ret = module; + + return FALSE; + +} + +gboolean lib_get_text_section(const GumDarwinSectionDetails *details, + gpointer user_data) { + + UNUSED_PARAMETER(user_data); + static size_t idx = 0; + char text_name[] = "__text"; + + OKF("Section: %2lu - base: 0x%016" G_GINT64_MODIFIER + "X size: 0x%016" G_GINT64_MODIFIER "X %s", + idx++, details->vm_address, details->vm_address + details->size, + details->section_name); + + if (memcmp(details->section_name, text_name, sizeof(text_name)) == 0 && + text_base == 0) { + + text_base = details->vm_address; + text_limit = details->vm_address + details->size; + OKF("> text_addr: 0x%016" G_GINT64_MODIFIER "X", text_base); + OKF("> text_limit: 0x%016" G_GINT64_MODIFIER "X", text_limit); + + } + + return TRUE; + +} + +void lib_init(void) { + + GumDarwinModule *module = NULL; + gum_darwin_enumerate_modules(mach_task_self(), lib_get_main_module, &module); + gum_darwin_module_enumerate_sections(module, lib_get_text_section, NULL); + +} + +guint64 lib_get_text_base(void) { + + if (text_base == 0) FATAL("Lib not initialized"); + return text_base; + +} + +guint64 lib_get_text_limit(void) { + + if (text_limit == 0) FATAL("Lib not initialized"); + return text_limit; + +} + +#endif + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 7505c2f9..1ab9993f 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -1,3 +1,4 @@ +#include <errno.h> #include <unistd.h> #include <sys/types.h> @@ -10,13 +11,21 @@ #endif #include "frida-gum.h" + #include "config.h" #include "debug.h" -#include "interceptor.h" +#include "entry.h" #include "instrument.h" +#include "interceptor.h" +#include "lib.h" +#include "output.h" +#include "persistent.h" #include "prefetch.h" #include "ranges.h" +#include "stalker.h" +#include "stats.h" +#include "util.h" #ifdef __APPLE__ extern mach_port_t mach_task_self(); @@ -30,16 +39,11 @@ extern int __libc_start_main(int *(main)(int, char **, char **), int argc, typedef int *(*main_fn_t)(int argc, char **argv, char **envp); -static main_fn_t main_fn = NULL; -static GumStalker * stalker = NULL; -static GumMemoryRange code_range = {0}; - -extern void __afl_manual_init(); -extern __thread uint64_t previous_pc; +static main_fn_t main_fn = NULL; -static int on_fork() { +static int on_fork(void) { - prefetch_read(stalker); + prefetch_read(); return fork(); } @@ -47,14 +51,20 @@ static int on_fork() { #ifdef __APPLE__ static void on_main_os(int argc, char **argv, char **envp) { + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + UNUSED_PARAMETER(envp); + } #else static void on_main_os(int argc, char **argv, char **envp) { + UNUSED_PARAMETER(argc); /* Personality doesn't affect the current process, it only takes effect on * evec */ int persona = personality(ADDR_NO_RANDOMIZE); + if (persona == -1) { WARNF("Failed to set ADDR_NO_RANDOMIZE: %d", errno); } if ((persona & ADDR_NO_RANDOMIZE) == 0) { execvpe(argv[0], argv, envp); } GumInterceptor *interceptor = gum_interceptor_obtain(); @@ -68,39 +78,64 @@ static void on_main_os(int argc, char **argv, char **envp) { #endif -static int *on_main(int argc, char **argv, char **envp) { +static void embedded_init() { - on_main_os(argc, argv, envp); + static gboolean initialized = false; + if (!initialized) { - stalker = gum_stalker_new(); - if (stalker == NULL) { FATAL("Failed to initialize stalker"); } + gum_init_embedded(); + initialized = true; - gum_stalker_set_trust_threshold(stalker, 0); + } + +} - GumStalkerTransformer *transformer = - gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); +void afl_frida_start() { + embedded_init(); + stalker_init(); + lib_init(); + entry_init(); instrument_init(); + output_init(); + persistent_init(); prefetch_init(); - ranges_init(stalker); + ranges_init(); + stats_init(); + + void *fork_addr = + GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork")); + intercept(fork_addr, on_fork, NULL); + + stalker_start(); + entry_run(); + +} - intercept(fork, on_fork, stalker); +static int *on_main(int argc, char **argv, char **envp) { + + on_main_os(argc, argv, envp); - gum_stalker_follow_me(stalker, transformer, NULL); - gum_stalker_deactivate(stalker); + unintercept_self(); - __afl_manual_init(); + afl_frida_start(); - /* Child here */ - previous_pc = 0; - prefetch_start(stalker); - main_fn(argc, argv, envp); - _exit(0); + return main_fn(argc, argv, envp); } -#ifdef __APPLE__ -static void intercept_main() { +#if defined(EMBEDDED) +extern int *main(int argc, char **argv, char **envp); + +static void intercept_main(void) { + + main_fn = main; + intercept(main, on_main, NULL); + +} + +#elif defined(__APPLE__) +static void intercept_main(void) { mach_port_t task = mach_task_self(); OKF("Task Id: %u", task); @@ -119,13 +154,14 @@ static int on_libc_start_main(int *(main)(int, char **, char **), int argc, void(*stack_end)) { main_fn = main; + unintercept_self(); intercept(main, on_main, NULL); return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end); } -static void intercept_main() { +static void intercept_main(void) { intercept(__libc_start_main, on_libc_start_main, NULL); @@ -133,15 +169,9 @@ static void intercept_main() { #endif -__attribute__((constructor)) static void init() { +__attribute__((constructor)) static void init(void) { - gum_init_embedded(); - if (!gum_stalker_is_supported()) { - - gum_deinit_embedded(); - FATAL("Failed to initialize embedded"); - - } + embedded_init(); intercept_main(); diff --git a/frida_mode/src/output.c b/frida_mode/src/output.c new file mode 100644 index 00000000..8a222b25 --- /dev/null +++ b/frida_mode/src/output.c @@ -0,0 +1,45 @@ +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include "frida-gum.h" + +#include "debug.h" + +#include "output.h" + +static int output_fd = -1; + +static void output_redirect(int fd, char *variable) { + + char *filename = getenv(variable); + char *path = NULL; + + if (filename == NULL) { return; } + + path = g_canonicalize_filename(filename, g_get_current_dir()); + + OKF("Redirect %d -> '%s'", fd, path); + + output_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + g_free(path); + + if (output_fd < 0) { FATAL("Failed to open fd(%d) error %d", fd, errno); } + + if (dup2(output_fd, fd) < 0) { + + FATAL("Failed to set fd(%d) error %d", fd, errno); + + } + +} + +void output_init(void) { + + output_redirect(STDOUT_FILENO, "AFL_FRIDA_OUTPUT_STDOUT"); + output_redirect(STDERR_FILENO, "AFL_FRIDA_OUTPUT_STDERR"); + +} + diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c new file mode 100644 index 00000000..2ec5b9cc --- /dev/null +++ b/frida_mode/src/persistent/persistent.c @@ -0,0 +1,97 @@ +#include <dlfcn.h> + +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "persistent.h" +#include "util.h" + +int __afl_sharedmem_fuzzing = 0; +afl_persistent_hook_fn hook = NULL; +guint64 persistent_start = 0; +guint64 persistent_count = 0; +guint64 persistent_ret = 0; +guint64 persistent_ret_offset = 0; +gboolean persistent_debug = FALSE; + +void persistent_init(void) { + + char *hook_name = getenv("AFL_FRIDA_PERSISTENT_HOOK"); + + persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR"); + persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT"); + persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET"); + persistent_ret_offset = + util_read_address("AFL_FRIDA_PERSISTENT_RETADDR_OFFSET"); + + if (getenv("AFL_FRIDA_PERSISTENT_DEBUG") != NULL) { persistent_debug = TRUE; } + + if (persistent_count != 0 && persistent_start == 0) { + + FATAL( + "AFL_FRIDA_PERSISTENT_ADDR must be specified if " + "AFL_FRIDA_PERSISTENT_CNT is"); + + } + + if (persistent_ret != 0 && persistent_start == 0) { + + FATAL( + "AFL_FRIDA_PERSISTENT_ADDR must be specified if " + "AFL_FRIDA_PERSISTENT_RET is"); + + } + + if (persistent_ret_offset != 0 && persistent_ret == 0) { + + FATAL( + "AFL_FRIDA_PERSISTENT_RET must be specified if " + "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET is"); + + } + + if (persistent_start != 0 && persistent_count == 0) persistent_count = 1000; + + if (persistent_count != 0 && persistent_count < 100) + WARNF("Persistent count out of recommended range (<100)"); + + if (persistent_start != 0 && !persistent_is_supported()) + FATAL("Persistent mode not supported on this architecture"); + + OKF("Instrumentation - persistent mode [%c] (0x%016" G_GINT64_MODIFIER "X)", + persistent_start == 0 ? ' ' : 'X', persistent_start); + OKF("Instrumentation - persistent count [%c] (%" G_GINT64_MODIFIER "d)", + persistent_start == 0 ? ' ' : 'X', persistent_count); + OKF("Instrumentation - hook [%s]", hook_name); + + OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)", + persistent_ret == 0 ? ' ' : 'X', persistent_ret); + OKF("Instrumentation - persistent ret offset [%c] (%" G_GINT64_MODIFIER "d)", + persistent_ret_offset == 0 ? ' ' : 'X', persistent_ret_offset); + + if (hook_name != NULL) { + + void *hook_obj = dlopen(hook_name, RTLD_NOW); + if (hook_obj == NULL) + FATAL("Failed to load AFL_FRIDA_PERSISTENT_HOOK (%s)", hook_name); + + int (*afl_persistent_hook_init_ptr)(void) = + dlsym(hook_obj, "afl_persistent_hook_init"); + if (afl_persistent_hook_init_ptr == NULL) + FATAL("Failed to find afl_persistent_hook_init in %s", hook_name); + + if (afl_persistent_hook_init_ptr() == 0) + FATAL("afl_persistent_hook_init returned a failure"); + + hook = (afl_persistent_hook_fn)dlsym(hook_obj, "afl_persistent_hook"); + if (hook == NULL) + FATAL("Failed to find afl_persistent_hook in %s", hook_name); + + __afl_sharedmem_fuzzing = 1; + + } + +} + diff --git a/frida_mode/src/persistent/persistent_arm32.c b/frida_mode/src/persistent/persistent_arm32.c new file mode 100644 index 00000000..6a3c06fa --- /dev/null +++ b/frida_mode/src/persistent/persistent_arm32.c @@ -0,0 +1,79 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "persistent.h" +#include "util.h" + +#if defined(__arm__) + +struct arm_regs { + + uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; + + union { + + uint32_t r11; + uint32_t fp; + + }; + + union { + + uint32_t r12; + uint32_t ip; + + }; + + 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; + +gboolean persistent_is_supported(void) { + + return false; + +} + +void persistent_prologue(GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + FATAL("Persistent mode not supported on this architecture"); + +} + +void persistent_epilogue(GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + FATAL("Persistent mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c new file mode 100644 index 00000000..1215d8da --- /dev/null +++ b/frida_mode/src/persistent/persistent_arm64.c @@ -0,0 +1,122 @@ +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "instrument.h" +#include "util.h" + +#if defined(__aarch64__) + +struct arm64_regs { + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10; + + union { + + uint64_t x11; + uint32_t fp_32; + + }; + + union { + + uint64_t x12; + uint32_t ip_32; + + }; + + union { + + uint64_t x13; + uint32_t sp_32; + + }; + + union { + + uint64_t x14; + uint32_t lr_32; + + }; + + union { + + uint64_t x15; + uint32_t pc_32; + + }; + + union { + + uint64_t x16; + uint64_t ip0; + + }; + + union { + + uint64_t x17; + uint64_t ip1; + + }; + + uint64_t x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28; + + union { + + uint64_t x29; + uint64_t fp; + + }; + + union { + + uint64_t x30; + uint64_t lr; + + }; + + union { + + uint64_t x31; + uint64_t sp; + + }; + + // the zero register is not saved here ofc + + uint64_t pc; + + uint32_t cpsr; + + uint8_t vfp_zregs[32][16 * 16]; + uint8_t vfp_pregs[17][32]; + uint32_t vfp_xregs[16]; + +}; + +typedef struct arm64_regs arch_api_regs; + +gboolean persistent_is_supported(void) { + + return false; + +} + +void persistent_prologue(GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + FATAL("Persistent mode not supported on this architecture"); + +} + +void persistent_epilogue(GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + FATAL("Persistent mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c new file mode 100644 index 00000000..4cb960fc --- /dev/null +++ b/frida_mode/src/persistent/persistent_x64.c @@ -0,0 +1,326 @@ +#include <unistd.h> +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "instrument.h" +#include "persistent.h" +#include "util.h" + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +typedef struct x86_64_regs arch_api_regs; + +static arch_api_regs saved_regs = {0}; + +gboolean persistent_is_supported(void) { + + return true; + +} + +static void instrument_persitent_save_regs(GumX86Writer * cw, + struct x86_64_regs *regs) { + + GumAddress regs_address = GUM_ADDRESS(regs); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_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_mov_reg_address(cw, GUM_REG_RAX, regs_address); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 1), + GUM_REG_RBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 2), + GUM_REG_RCX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 3), + GUM_REG_RDX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 4), + GUM_REG_RDI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 5), + GUM_REG_RSI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 6), + GUM_REG_RBP); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 7), + GUM_REG_R8); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 8), + GUM_REG_R9); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 9), + GUM_REG_R10); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 10), + GUM_REG_R11); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 11), + GUM_REG_R12); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 12), + GUM_REG_R13); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 13), + GUM_REG_R14); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 14), + GUM_REG_R15); + + /* Store RIP */ + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RBX, + GUM_ADDRESS(persistent_start)); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 15), + GUM_REG_RBX); + + /* Store adjusted RSP */ + gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_RBX, GUM_REG_RSP); + + /* RED_ZONE + Saved flags, RAX, alignment */ + gum_x86_writer_put_add_reg_imm(cw, GUM_REG_RBX, + GUM_RED_ZONE_SIZE + (0x8 * 3)); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 16), + GUM_REG_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_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 17), + GUM_REG_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_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 0), + GUM_REG_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_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void instrument_persitent_restore_regs(GumX86Writer * cw, + struct x86_64_regs *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_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RAX, + (0x8 * 2)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RAX, + (0x8 * 3)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDI, GUM_REG_RAX, + (0x8 * 4)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RAX, + (0x8 * 5)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBP, GUM_REG_RAX, + (0x8 * 6)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R8, GUM_REG_RAX, + (0x8 * 7)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R9, GUM_REG_RAX, + (0x8 * 8)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R10, GUM_REG_RAX, + (0x8 * 9)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R11, GUM_REG_RAX, + (0x8 * 10)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R12, GUM_REG_RAX, + (0x8 * 11)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R13, GUM_REG_RAX, + (0x8 * 12)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R14, GUM_REG_RAX, + (0x8 * 13)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R15, GUM_REG_RAX, + (0x8 * 14)); + + /* Don't restore RIP or RSP */ + + /* Restore RBX, RAX & Flags */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, + (0x8 * 1)); + 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, + (0x8 * 0)); + 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, + (0x8 * 17)); + gum_x86_writer_put_push_reg(cw, GUM_REG_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_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_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); + +} + +static int instrument_afl_persistent_loop_func(void) { + + int ret = __afl_persistent_loop(persistent_count); + previous_pc = 0; + return ret; + +} + +static void instrument_afl_persistent_loop(GumX86Writer *cw) { + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_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_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void persistent_prologue_hook(GumX86Writer * cw, + struct x86_64_regs *regs) { + + if (hook == NULL) return; + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RCX, + GUM_ADDRESS(&__afl_fuzz_len)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0); + gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_RDI, 0xffffffff); + gum_x86_writer_put_and_reg_reg(cw, GUM_REG_RCX, GUM_REG_RDI); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDX, + GUM_ADDRESS(&__afl_fuzz_ptr)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0); + + gum_x86_writer_put_call_address_with_arguments( + cw, GUM_CALL_CAPI, GUM_ADDRESS(hook), 4, GUM_ARG_ADDRESS, + GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_REGISTER, + GUM_REG_RDX, GUM_ARG_REGISTER, GUM_REG_RCX); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +void persistent_prologue(GumStalkerOutput *output) { + + /* + * 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 + */ + + GumX86Writer *cw = output->writer.x86; + + gconstpointer loop = cw->code + 1; + + /* Stack must be 16-byte aligned per ABI */ + instrument_persitent_save_regs(cw, &saved_regs); + + /* pop the return value */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, (8)); + + /* loop: */ + gum_x86_writer_put_label(cw, loop); + + /* call instrument_prologue_func */ + instrument_afl_persistent_loop(cw); + + /* jz done */ + gconstpointer done = cw->code + 1; + gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY); + + /* 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_x86_writer_put_call_near_label(cw, original); + + /* jmp loop */ + gum_x86_writer_put_jmp_near_label(cw, loop); + + /* done: */ + gum_x86_writer_put_label(cw, done); + + instrument_exit(cw); + + /* original: */ + gum_x86_writer_put_label(cw, original); + + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } + + gum_x86_writer_flush(cw); + +} + +void persistent_epilogue(GumStalkerOutput *output) { + + GumX86Writer *cw = output->writer.x86; + + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + persistent_ret_offset); + gum_x86_writer_put_ret(cw); + +} + +#endif + diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c new file mode 100644 index 00000000..b30dfadf --- /dev/null +++ b/frida_mode/src/persistent/persistent_x86.c @@ -0,0 +1,267 @@ +#include "frida-gum.h" + +#include "config.h" + +#include "instrument.h" +#include "persistent.h" + +#if defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +typedef struct x86_regs arch_api_regs; + +static arch_api_regs saved_regs = {0}; + +gboolean persistent_is_supported(void) { + + return true; + +} + +static void instrument_persitent_save_regs(GumX86Writer * cw, + struct x86_regs *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_mov_reg_address(cw, GUM_REG_EAX, regs_address); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 1), + GUM_REG_EBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 2), + GUM_REG_ECX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 3), + GUM_REG_EDX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 4), + GUM_REG_EDI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 5), + GUM_REG_ESI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 6), + GUM_REG_EBP); + + /* Store RIP */ + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EBX, + GUM_ADDRESS(persistent_start)); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 7), + GUM_REG_EBX); + + /* Store adjusted RSP */ + gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_EBX, GUM_REG_ESP); + + /* RED_ZONE + Saved flags, RAX */ + gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EBX, (0x4 * 2)); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 8), + GUM_REG_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_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 9), + GUM_REG_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_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 0), + GUM_REG_EBX); + + /* Pop the saved values */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 0x8); + +} + +static void instrument_persitent_restore_regs(GumX86Writer * cw, + struct x86_regs *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_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_EAX, + (0x4 * 2)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EAX, + (0x4 * 3)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDI, GUM_REG_EAX, + (0x4 * 4)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESI, GUM_REG_EAX, + (0x4 * 5)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX, + (0x4 * 6)); + + /* Don't restore RIP or RSP */ + + /* Restore RBX, RAX & Flags */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX, + (0x4 * 1)); + 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, + (0x4 * 0)); + 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, + (0x4 * 9)); + gum_x86_writer_put_push_reg(cw, GUM_REG_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); + +} + +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); + +} + +static int instrument_afl_persistent_loop_func(void) { + + int ret = __afl_persistent_loop(persistent_count); + previous_pc = 0; + return ret; + +} + +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); + +} + +static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) { + + if (hook == NULL) return; + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_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_address(cw, GUM_REG_EDX, + GUM_ADDRESS(&__afl_fuzz_ptr)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_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(hook), 5, GUM_ARG_ADDRESS, + GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_ADDRESS, + GUM_ADDRESS(0), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER, + GUM_REG_ECX); + +} + +void persistent_prologue(GumStalkerOutput *output) { + + /* + * 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 + */ + + GumX86Writer *cw = output->writer.x86; + + gconstpointer loop = cw->code + 1; + + /* Stack must be 16-byte aligned per ABI */ + instrument_persitent_save_regs(cw, &saved_regs); + + /* Pop the return value */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, (4)); + + /* loop: */ + gum_x86_writer_put_label(cw, loop); + + /* call instrument_prologue_func */ + instrument_afl_persistent_loop(cw); + + /* jz done */ + gconstpointer done = cw->code + 1; + gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY); + + /* 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_x86_writer_put_call_near_label(cw, original); + /* jmp loop */ + gum_x86_writer_put_jmp_near_label(cw, loop); + + /* done: */ + gum_x86_writer_put_label(cw, done); + + instrument_exit(cw); + + /* original: */ + gum_x86_writer_put_label(cw, original); + + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } + + gum_x86_writer_flush(cw); + +} + +void persistent_epilogue(GumStalkerOutput *output) { + + GumX86Writer *cw = output->writer.x86; + + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, + persistent_ret_offset); + + gum_x86_writer_put_ret(cw); + +} + +#endif + diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c index 64633c1c..65c09fba 100644 --- a/frida_mode/src/prefetch.c +++ b/frida_mode/src/prefetch.c @@ -3,9 +3,12 @@ #include <sys/mman.h> #include "frida-gum.h" -#include "prefetch.h" + #include "debug.h" +#include "prefetch.h" +#include "stalker.h" + #define TRUST 0 #define PREFETCH_SIZE 65536 #define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *)) @@ -49,8 +52,9 @@ void prefetch_write(void *addr) { /* * Read the IPC region one block at the time and prefetch it */ -void prefetch_read(GumStalker *stalker) { +void prefetch_read(void) { + GumStalker *stalker = stalker_get(); if (prefetch_data == NULL) return; for (size_t i = 0; i < prefetch_data->count; i++) { @@ -68,7 +72,7 @@ void prefetch_read(GumStalker *stalker) { } -void prefetch_init() { +void prefetch_init(void) { g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE); gboolean prefetch = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL); @@ -106,16 +110,3 @@ void prefetch_init() { } -__attribute__((noinline)) static void prefetch_activation() { - - asm volatile(""); - -} - -void prefetch_start(GumStalker *stalker) { - - gum_stalker_activate(stalker, prefetch_activation); - prefetch_activation(); - -} - diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index 49ef5a62..ef25b371 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -1,9 +1,12 @@ -// 0x123-0x321 -// module.so +#include "frida-gum.h" -#include "ranges.h" #include "debug.h" +#include "lib.h" +#include "ranges.h" +#include "stalker.h" +#include "util.h" + #define MAX_RANGES 20 typedef struct { @@ -14,15 +17,11 @@ typedef struct { } convert_name_ctx_t; -typedef struct { - - GumStalker *stalker; - GArray * array; - -} include_range_ctx_t; - -GArray * ranges = NULL; -gboolean exclude_ranges = false; +GArray *module_ranges = NULL; +GArray *libs_ranges = NULL; +GArray *include_ranges = NULL; +GArray *exclude_ranges = NULL; +GArray *ranges = NULL; static void convert_address_token(gchar *token, GumMemoryRange *range) { @@ -159,236 +158,454 @@ static void convert_token(gchar *token, GumMemoryRange *range) { } -static gboolean include_ranges(const GumRangeDetails *details, - gpointer user_data) { +gint range_sort(gconstpointer a, gconstpointer b) { - include_range_ctx_t *ctx = (include_range_ctx_t *)user_data; - GArray * array = (GArray *)ctx->array; - GumAddress base = details->range->base_address; - GumAddress limit = details->range->base_address + details->range->size; + return ((GumMemoryRange *)a)->base_address - + ((GumMemoryRange *)b)->base_address; - OKF("Range for inclusion 0x%016" G_GINT64_MODIFIER - "x-0x%016" G_GINT64_MODIFIER "x", - base, limit); +} - for (int i = 0; i < array->len; i++) { +static gboolean print_ranges_callback(const GumRangeDetails *details, + gpointer user_data) { - GumMemoryRange *range = &g_array_index(array, GumMemoryRange, i); - GumAddress range_base = range->base_address; - GumAddress range_limit = range->base_address + range->size; + UNUSED_PARAMETER(user_data); + if (details->file == NULL) { - /* Before the region */ - if (range_limit < base) { continue; } + OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X", + details->range->base_address, + details->range->base_address + details->range->size); - /* After the region */ - if (range_base > limit) { + } else { - GumMemoryRange exclude = {.base_address = base, .size = limit - base}; - OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER - "x", - base, limit); - gum_stalker_exclude(ctx->stalker, &exclude); - return true; + OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER + "X %s(0x%016" G_GINT64_MODIFIER "x)", + details->range->base_address, + details->range->base_address + details->range->size, + details->file->path, details->file->offset); - } + } - /* Overlap the start of the region */ - if (range_base < base) { + return true; - /* Range contains the region */ - if (range_limit > limit) { +} - return true; +static void print_ranges(char *key, GArray *ranges) { - } else { + OKF("Range: %s Length: %d", key, ranges->len); + for (guint i = 0; i < ranges->len; i++) { - base = range_limit; - continue; + GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); + GumAddress curr_limit = curr->base_address + curr->size; + OKF("Range: %s Idx: %3d - 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x", + key, i, curr->base_address, curr_limit); - } + } - /* Overlap the end of the region */ +} - } else { +static gboolean collect_module_ranges_callback(const GumRangeDetails *details, + gpointer user_data) { - GumMemoryRange exclude = {.base_address = base, - .size = range_base - base}; - OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER - "x", - base, range_base); - gum_stalker_exclude(ctx->stalker, &exclude); - /* Extend past the end of the region */ - if (range_limit >= limit) { + GArray * ranges = (GArray *)user_data; + GumMemoryRange range = *details->range; + g_array_append_val(ranges, range); + return TRUE; - return true; +} - /* Contained within the region */ +static GArray *collect_module_ranges(void) { - } else { + GArray *result; + result = g_array_new(false, false, sizeof(GumMemoryRange)); + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, + collect_module_ranges_callback, result); + print_ranges("Modules", result); + return result; - base = range_limit; - continue; +} - } +static GArray *collect_ranges(char *env_key) { - } + char * env_val; + gchar ** tokens; + int token_count; + GumMemoryRange range; + int i; + GArray * result; + + result = g_array_new(false, false, sizeof(GumMemoryRange)); + + env_val = getenv(env_key); + if (env_val == NULL) return result; + + tokens = g_strsplit(env_val, ",", MAX_RANGES); + + for (token_count = 0; tokens[token_count] != NULL; token_count++) + ; + + for (i = 0; i < token_count; i++) { + + convert_token(tokens[i], &range); + g_array_append_val(result, range); } - GumMemoryRange exclude = {.base_address = base, .size = limit - base}; - OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x", - base, limit); - gum_stalker_exclude(ctx->stalker, &exclude); - return true; + g_array_sort(result, range_sort); -} + /* Check for overlaps */ + for (i = 1; i < token_count; i++) { -gint range_sort(gconstpointer a, gconstpointer b) { + GumMemoryRange *prev = &g_array_index(result, GumMemoryRange, i - 1); + GumMemoryRange *curr = &g_array_index(result, GumMemoryRange, i); + GumAddress prev_limit = prev->base_address + prev->size; + GumAddress curr_limit = curr->base_address + curr->size; + if (prev_limit > curr->base_address) { - return ((GumMemoryRange *)a)->base_address - - ((GumMemoryRange *)b)->base_address; + FATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x", + prev->base_address, prev_limit, curr->base_address, curr_limit); + + } + + } + + print_ranges(env_key, result); + + g_strfreev(tokens); + + return result; } -static gboolean print_ranges(const GumRangeDetails *details, - gpointer user_data) { +static GArray *collect_libs_ranges(void) { - if (details->file == NULL) { + GArray * result; + GumMemoryRange range; + result = g_array_new(false, false, sizeof(GumMemoryRange)); - OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X", - details->range->base_address, - details->range->base_address + details->range->size); + if (getenv("AFL_INST_LIBS") == NULL) { + + range.base_address = lib_get_text_base(); + range.size = lib_get_text_limit() - lib_get_text_base(); } else { - OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER - "X %s(0x%016" G_GINT64_MODIFIER "x)", - details->range->base_address, - details->range->base_address + details->range->size, - details->file->path, details->file->offset); + range.base_address = 0; + range.size = G_MAXULONG; } + g_array_append_val(result, range); + + print_ranges("AFL_INST_LIBS", result); + + return result; + +} + +static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra, + GumMemoryRange *rb) { + + GumAddress rab = ra->base_address; + GumAddress ral = rab + ra->size; + + GumAddress rbb = rb->base_address; + GumAddress rbl = rbb + rb->size; + + GumAddress rrb = 0; + GumAddress rrl = 0; + + rr->base_address = 0; + rr->size = 0; + + /* ra is before rb */ + if (ral < rbb) { return false; } + + /* ra is after rb */ + if (rab > rbl) { return true; } + + /* The largest of the two base addresses */ + rrb = rab > rbb ? rab : rbb; + + /* The smallest of the two limits */ + rrl = ral < rbl ? ral : rbl; + + rr->base_address = rrb; + rr->size = rrl - rrb; return true; } -void ranges_init(GumStalker *stalker) { +static GArray *intersect_ranges(GArray *a, GArray *b) { - char * showmaps; - char * include; - char * exclude; - char * list; - gchar ** tokens; - int token_count; - GumMemoryRange range; + GArray * result; + GumMemoryRange *ra; + GumMemoryRange *rb; + GumMemoryRange ri; - int i; + result = g_array_new(false, false, sizeof(GumMemoryRange)); - showmaps = getenv("AFL_FRIDA_DEBUG_MAPS"); - include = getenv("AFL_FRIDA_INST_RANGES"); - exclude = getenv("AFL_FRIDA_EXCLUDE_RANGES"); + for (guint i = 0; i < a->len; i++) { - if (showmaps) { + ra = &g_array_index(a, GumMemoryRange, i); + for (guint j = 0; j < b->len; j++) { - gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges, NULL); + rb = &g_array_index(b, GumMemoryRange, j); - } + if (!intersect_range(&ri, ra, rb)) { break; } + + if (ri.size == 0) { continue; } - if (include != NULL && exclude != NULL) { + g_array_append_val(result, ri); - FATAL( - "Cannot specifify both AFL_FRIDA_INST_RANGES and " - "AFL_FRIDA_EXCLUDE_RANGES"); + } } - if (include == NULL && exclude == NULL) { return; } + return result; - list = include == NULL ? exclude : include; - exclude_ranges = include == NULL ? true : false; +} - tokens = g_strsplit(list, ",", MAX_RANGES); +static GArray *subtract_ranges(GArray *a, GArray *b) { - for (token_count = 0; tokens[token_count] != NULL; token_count++) - ; + GArray * result; + GumMemoryRange *ra; + GumAddress ral; + GumMemoryRange *rb; + GumMemoryRange ri; + GumMemoryRange rs; - ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), token_count); + result = g_array_new(false, false, sizeof(GumMemoryRange)); - for (i = 0; i < token_count; i++) { + for (guint i = 0; i < a->len; i++) { - convert_token(tokens[i], &range); - g_array_append_val(ranges, range); + ra = &g_array_index(a, GumMemoryRange, i); + ral = ra->base_address + ra->size; + for (guint j = 0; j < b->len; j++) { - } + rb = &g_array_index(b, GumMemoryRange, j); - g_array_sort(ranges, range_sort); + /* + * If rb is after ra, we have no more possible intersections and we can + * simply keep the remaining range + */ + if (!intersect_range(&ri, ra, rb)) { break; } - /* Check for overlaps */ - for (i = 1; i < token_count; i++) { + /* + * If there is no intersection, then rb must be before ra, so we must + * continue + */ + if (ri.size == 0) { continue; } - GumMemoryRange *prev = &g_array_index(ranges, GumMemoryRange, i - 1); - GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); - GumAddress prev_limit = prev->base_address + prev->size; - GumAddress curr_limit = curr->base_address + curr->size; - if (prev_limit > curr->base_address) { + /* + * If the intersection is part way through the range, then we keep the + * start of the range + */ + if (ra->base_address < ri.base_address) { - FATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER - "x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER - "x-0x%016" G_GINT64_MODIFIER "x", - prev->base_address, prev_limit, curr->base_address, curr_limit); + rs.base_address = ra->base_address; + rs.size = ri.base_address - ra->base_address; + g_array_append_val(result, rs); + + } + + /* + * If the intersection extends past the limit of the range, then we should + * continue with the next range + */ + if ((ri.base_address + ri.size) > ral) { + + ra->base_address = ral; + ra->size = 0; + break; + + } + + /* + * Otherwise we advance the base of the range to the end of the + * intersection and continue with the remainder of the range + */ + ra->base_address = ri.base_address + ri.size; + ra->size = ral - ra->base_address; } + /* + * When we have processed all the possible intersections, we add what is + * left + */ + if (ra->size != 0) g_array_append_val(result, *ra); + } - for (i = 0; i < token_count; i++) { + return result; - GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); - GumAddress curr_limit = curr->base_address + curr->size; - OKF("Range %3d - 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x", - i, curr->base_address, curr_limit); +} - } +static GArray *merge_ranges(GArray *a) { + + GArray * result; + GumMemoryRange rp; + GumMemoryRange *r; + + result = g_array_new(false, false, sizeof(GumMemoryRange)); + if (a->len == 0) return result; - if (include == NULL) { + rp = g_array_index(a, GumMemoryRange, 0); - for (i = 0; i < token_count; i++) { + for (guint i = 1; i < a->len; i++) { + + r = &g_array_index(a, GumMemoryRange, i); + + if (rp.base_address + rp.size == r->base_address) { + + rp.size += r->size; + + } else { - gum_stalker_exclude(stalker, &g_array_index(ranges, GumMemoryRange, i)); + g_array_append_val(result, rp); + rp.base_address = r->base_address; + rp.size = r->size; + continue; } - } else { + } + + g_array_append_val(result, rp); + + return result; + +} - include_range_ctx_t ctx = {.stalker = stalker, .array = ranges}; - gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, include_ranges, &ctx); +static gboolean exclude_ranges_callback(const GumRangeDetails *details, + gpointer user_data) { + + UNUSED_PARAMETER(user_data); + gchar * name; + gboolean found; + GumStalker *stalker; + if (details->file == NULL) { return TRUE; } + name = g_path_get_basename(details->file->path); + + found = (g_strcmp0(name, "afl-frida-trace.so") == 0); + g_free(name); + if (!found) { return TRUE; } + + stalker = stalker_get(); + gum_stalker_exclude(stalker, details->range); + + return FALSE; + +} + +static void ranges_exclude_self(void) { + + gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, exclude_ranges_callback, NULL); + +} + +void ranges_init(void) { + + GumMemoryRange ri; + GArray * step1; + GArray * step2; + GArray * step3; + GArray * step4; + + if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { + + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges_callback, + NULL); } - g_strfreev(tokens); + module_ranges = collect_module_ranges(); + libs_ranges = collect_libs_ranges(); + include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES"); + + /* If include ranges is empty, then assume everything is included */ + if (include_ranges->len == 0) { + + ri.base_address = 0; + ri.size = G_MAXULONG; + g_array_append_val(include_ranges, ri); + + } + + exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES"); + + /* Intersect with .text section of main executable unless AFL_INST_LIBS */ + step1 = intersect_ranges(module_ranges, libs_ranges); + print_ranges("step1", step1); + + /* Intersect with AFL_FRIDA_INST_RANGES */ + step2 = intersect_ranges(step1, include_ranges); + print_ranges("step2", step2); + + /* Subtract AFL_FRIDA_EXCLUDE_RANGES */ + step3 = subtract_ranges(step2, exclude_ranges); + print_ranges("step3", step3); + + /* + * After step3, we have the total ranges to be instrumented, we now subtract + * that from the original ranges of the modules to configure stalker. + */ + + step4 = subtract_ranges(module_ranges, step3); + print_ranges("step4", step4); + + ranges = merge_ranges(step4); + print_ranges("final", ranges); + + g_array_free(step4, TRUE); + g_array_free(step3, TRUE); + g_array_free(step2, TRUE); + g_array_free(step1, TRUE); + + /* *NEVER* stalk the stalker, only bad things will ever come of this! */ + ranges_exclude_self(); + + ranges_exclude(); } gboolean range_is_excluded(gpointer address) { - int i; GumAddress test = GUM_ADDRESS(address); if (ranges == NULL) { return false; } - for (i = 0; i < ranges->len; i++) { + for (guint i = 0; i < ranges->len; i++) { GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); GumAddress curr_limit = curr->base_address + curr->size; - if (test < curr->base_address) { return !exclude_ranges; } + if (test < curr->base_address) { return false; } - if (test < curr_limit) { return exclude_ranges; } + if (test < curr_limit) { return true; } } - return !exclude_ranges; + return false; + +} + +void ranges_exclude() { + + GumMemoryRange *r; + GumStalker * stalker = stalker_get(); + + OKF("Excluding ranges"); + + for (guint i = 0; i < ranges->len; i++) { + + r = &g_array_index(ranges, GumMemoryRange, i); + gum_stalker_exclude(stalker, r); + + } } diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c new file mode 100644 index 00000000..63f3c529 --- /dev/null +++ b/frida_mode/src/stalker.c @@ -0,0 +1,32 @@ +#include "debug.h" + +#include "instrument.h" +#include "stalker.h" + +static GumStalker *stalker = NULL; + +void stalker_init(void) { + + if (!gum_stalker_is_supported()) { FATAL("Failed to initialize embedded"); } + + stalker = gum_stalker_new(); + if (stalker == NULL) { FATAL("Failed to initialize stalker"); } + + gum_stalker_set_trust_threshold(stalker, 0); + +} + +GumStalker *stalker_get(void) { + + if (stalker == NULL) { FATAL("Stalker uninitialized"); } + return stalker; + +} + +void stalker_start(void) { + + GumStalkerTransformer *transformer = instrument_get_transformer(); + gum_stalker_follow_me(stalker, transformer, NULL); + +} + diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c new file mode 100644 index 00000000..890a8d6b --- /dev/null +++ b/frida_mode/src/stats/stats.c @@ -0,0 +1,208 @@ +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/shm.h> +#include <sys/mman.h> + +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" +#include "util.h" + +#include "stats.h" + +#define MICRO_TO_SEC 1000000 + +stats_data_header_t *stats_data = NULL; + +static int stats_parent_pid = -1; +static int stats_fd = -1; +static gboolean stats_transitions = FALSE; +static guint64 stats_interval = 0; + +void stats_init(void) { + + stats_parent_pid = getpid(); + char *filename = getenv("AFL_FRIDA_STATS_FILE"); + stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL"); + if (getenv("AFL_FRIDA_STATS_TRANSITIONS") != NULL) { + + stats_transitions = TRUE; + + } + + OKF("Stats - file [%s]", filename); + OKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval); + + if (stats_interval != 0 && filename == NULL) { + + FATAL( + "AFL_FRIDA_STATS_FILE must be specified if " + "AFL_FRIDA_STATS_INTERVAL is"); + + } + + if (stats_interval == 0) { stats_interval = 10; } + + if (filename == NULL) { return; } + + if (!stats_is_supported_arch()) { + + FATAL("Stats is not supported on this architecture"); + + } + + char *path = NULL; + + if (filename == NULL) { return; } + + if (stats_transitions) { gum_stalker_set_counters_enabled(TRUE); } + + path = g_canonicalize_filename(filename, g_get_current_dir()); + + OKF("Stats - path [%s]", path); + + stats_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (stats_fd < 0) { FATAL("Failed to open stats file '%s'", path); } + + g_free(path); + + size_t data_size = stats_data_size_arch(); + + int shm_id = shmget(IPC_PRIVATE, data_size, IPC_CREAT | IPC_EXCL | 0600); + if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } + + stats_data = shmat(shm_id, NULL, 0); + g_assert(stats_data != 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(stats_data, '\0', data_size); + +} + +void stats_vprint(int fd, char *format, va_list ap) { + + char buffer[4096] = {0}; + int ret; + int len; + + if(vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } + + len = strnlen(buffer, sizeof(buffer)); + IGNORED_RETURN(write(fd, buffer, len)); + +} + +void stats_print_fd(int fd, char *format, ...) { + + va_list ap; + va_start(ap, format); + stats_vprint(fd, format, ap); + va_end(ap); + +} + +void stats_print(char *format, ...) { + + va_list ap; + va_start(ap, format); + stats_vprint(stats_fd, format, ap); + va_end(ap); + +} + +void stats_write(void) { + + if (stats_parent_pid == getpid()) { return; } + + GDateTime *date_time = g_date_time_new_now_local(); + char *date_time_string = g_date_time_format(date_time, "%Y-%m-%e %H:%M:%S"); + + stats_print("stats\n"); + stats_print("-----\n"); + + stats_print("Index: %" G_GINT64_MODIFIER "u\n", + stats_data->stats_idx++); + stats_print("Pid: %d\n", getpid()); + stats_print("Time: %s\n", date_time_string); + stats_print("Blocks: %" G_GINT64_MODIFIER "u\n", + stats_data->num_blocks); + stats_print("Instructions: %" G_GINT64_MODIFIER "u\n", + stats_data->num_instructions); + stats_print("Avg Instructions / Block: %" G_GINT64_MODIFIER "u\n", + stats_data->num_instructions / stats_data->num_blocks); + + stats_print("\n"); + + g_free(date_time_string); + g_date_time_unref(date_time); + + stats_write_arch(); + + if (stats_transitions) { + + GDateTime *date_time = g_date_time_new_now_local(); + char *date_time_string = g_date_time_format(date_time, "%Y-%m-%e %H:%M:%S"); + + stats_print_fd(STDERR_FILENO, "stats\n"); + stats_print_fd(STDERR_FILENO, "-----\n"); + stats_print_fd(STDERR_FILENO, "Index: %" G_GINT64_MODIFIER "u\n", + stats_data->transitions_idx++); + stats_print_fd(STDERR_FILENO, "Pid: %d\n", getpid()); + stats_print_fd(STDERR_FILENO, "Time: %s\n", date_time_string); + + g_free(date_time_string); + g_date_time_unref(date_time); + gum_stalker_dump_counters(); + + } + +} + +static void stats_maybe_write(void) { + + guint64 current_time; + + if (stats_interval == 0) { return; } + + current_time = g_get_monotonic_time(); + + if ((current_time - stats_data->stats_last_time) > + (stats_interval * MICRO_TO_SEC)) { + + stats_write(); + stats_data->stats_last_time = current_time; + + } + +} + +void stats_collect(const cs_insn *instr, gboolean begin) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(begin); + + if (stats_fd < 0) { return; } + + if (begin) { stats_data->num_blocks++; } + stats_data->num_instructions++; + + stats_collect_arch(instr); + + stats_maybe_write(); + +} + diff --git a/frida_mode/src/stats/stats_arm.c b/frida_mode/src/stats/stats_arm.c new file mode 100644 index 00000000..7eea7f91 --- /dev/null +++ b/frida_mode/src/stats/stats_arm.c @@ -0,0 +1,36 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "stats.h" +#include "util.h" + +#if defined(__arm__) + +gboolean stats_is_supported_arch(void) { + + return FALSE; + +} + +size_t stats_data_size_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_write_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_collect_arch(const cs_insn *instr) { + + UNUSED_PARAMETER(instr); + FATAL("Stats not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/stats/stats_arm64.c b/frida_mode/src/stats/stats_arm64.c new file mode 100644 index 00000000..592af87a --- /dev/null +++ b/frida_mode/src/stats/stats_arm64.c @@ -0,0 +1,36 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "stats.h" +#include "util.h" + +#if defined(__aarch64__) + +gboolean stats_is_supported_arch(void) { + + return FALSE; + +} + +size_t stats_data_size_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_write_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_collect_arch(const cs_insn *instr) { + + UNUSED_PARAMETER(instr); + FATAL("Stats not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/stats/stats_x64.c b/frida_mode/src/stats/stats_x64.c new file mode 100644 index 00000000..c3e8742a --- /dev/null +++ b/frida_mode/src/stats/stats_x64.c @@ -0,0 +1,307 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ranges.h" +#include "stats.h" +#include "util.h" + +#if defined(__x86_64__) + +typedef struct { + + stats_data_header_t header; + + guint64 num_call_imm; + guint64 num_call_imm_excluded; + guint64 num_call_reg; + guint64 num_call_mem; + + guint64 num_jmp_imm; + guint64 num_jmp_reg; + guint64 num_jmp_mem; + + guint64 num_jmp_cond_imm; + guint64 num_jmp_cond_reg; + guint64 num_jmp_cond_mem; + + guint64 num_jmp_cond_jcxz; + + guint64 num_ret; + + guint64 num_rip_relative; + +} stats_data_arch_t; + +gboolean stats_is_supported_arch(void) { + + return TRUE; + +} + +size_t stats_data_size_arch(void) { + + return sizeof(stats_data_arch_t); + +} + +void stats_write_arch(void) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + guint64 num_instructions = stats_data_arch->header.num_instructions; + + stats_print( + "Call Immediates: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_call_imm, + ((float)(stats_data_arch->num_call_imm * 100) / num_instructions)); + stats_print("Call Immediates Excluded: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_call_imm_excluded, + ((float)(stats_data_arch->num_call_imm_excluded * 100) / + num_instructions)); + stats_print( + "Call Register: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_call_reg, + ((float)(stats_data_arch->num_call_reg * 100) / num_instructions)); + stats_print( + "Call Memory: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_call_mem, + ((float)(stats_data_arch->num_call_mem * 100) / num_instructions)); + + stats_print("\n"); + + stats_print("Jump Immediates: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_imm, + ((float)(stats_data_arch->num_jmp_imm * 100) / num_instructions)); + stats_print("Jump Register: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_reg, + ((float)(stats_data_arch->num_jmp_reg * 100) / num_instructions)); + stats_print("Jump Memory: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_mem, + ((float)(stats_data_arch->num_jmp_mem * 100) / num_instructions)); + + stats_print("\n"); + + stats_print( + "Conditional Jump Immediates: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_cond_imm, + ((float)(stats_data_arch->num_jmp_cond_imm * 100) / num_instructions)); + stats_print( + "Conditional Jump CX Immediate: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_cond_jcxz, + ((float)(stats_data_arch->num_jmp_cond_jcxz * 100) / num_instructions)); + stats_print( + "Conditional Jump Register: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_cond_reg, + ((float)(stats_data_arch->num_jmp_cond_reg * 100) / num_instructions)); + stats_print( + "Conditional Jump Memory: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_cond_mem, + ((float)(stats_data_arch->num_jmp_cond_mem * 100) / num_instructions)); + + stats_print("\n"); + + stats_print("Returns: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_ret, + (stats_data_arch->num_ret * 100 / num_instructions)); + + stats_print("\n"); + + stats_print("Rip Relative: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_rip_relative, + (stats_data_arch->num_rip_relative * 100 / num_instructions)); + + stats_print("\n"); + stats_print("\n"); + +} + +static x86_op_type stats_get_operand_type(const cs_insn *instr) { + + cs_x86 * x86 = &instr->detail->x86; + cs_x86_op *operand; + + if (x86->op_count != 1) { + + FATAL("Unexpected operand count (%d): %s %s\n", x86->op_count, + instr->mnemonic, instr->op_str); + + } + + operand = &x86->operands[0]; + + return operand->type; + +} + +static void stats_collect_call_imm_excluded_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + cs_x86 * x86 = &instr->detail->x86; + cs_x86_op * operand = &x86->operands[0]; + + if (range_is_excluded((gpointer)operand->imm)) { + + stats_data_arch->num_call_imm_excluded++; + + } + +} + +static void stats_collect_call_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + x86_op_type type = stats_get_operand_type(instr); + switch (type) { + + case X86_OP_IMM: + stats_data_arch->num_call_imm++; + stats_collect_call_imm_excluded_arch(instr); + break; + case X86_OP_REG: + stats_data_arch->num_call_reg++; + break; + case X86_OP_MEM: + stats_data_arch->num_call_mem++; + break; + default: + FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); + + } + +} + +static void stats_collect_jump_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + x86_op_type type = stats_get_operand_type(instr); + switch (type) { + + case X86_OP_IMM: + stats_data_arch->num_jmp_imm++; + break; + case X86_OP_REG: + stats_data_arch->num_jmp_reg++; + break; + case X86_OP_MEM: + stats_data_arch->num_jmp_mem++; + break; + default: + FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); + + } + +} + +static void stats_collect_jump_cond_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + x86_op_type type = stats_get_operand_type(instr); + switch (type) { + + case X86_OP_IMM: + stats_data_arch->num_jmp_cond_imm++; + break; + case X86_OP_REG: + stats_data_arch->num_jmp_cond_reg++; + break; + case X86_OP_MEM: + stats_data_arch->num_jmp_cond_mem++; + break; + default: + FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); + + } + +} + +static void stats_collect_rip_relative_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + cs_x86 * x86 = &instr->detail->x86; + guint mod; + guint rm; + + if (x86->encoding.modrm_offset == 0) { return; } + + mod = (x86->modrm & 0xc0) >> 6; + if (mod != 0) { return; } + + rm = (x86->modrm & 0x07) >> 0; + if (rm != 5) { return; } + + stats_data_arch->num_rip_relative++; + +} + +void stats_collect_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + switch (instr->id) { + + case X86_INS_CALL: + stats_collect_call_arch(instr); + break; + case X86_INS_JMP: + stats_collect_jump_arch(instr); + break; + case X86_INS_JA: + case X86_INS_JAE: + case X86_INS_JB: + case X86_INS_JBE: + case X86_INS_JE: + case X86_INS_JG: + case X86_INS_JGE: + case X86_INS_JL: + case X86_INS_JLE: + case X86_INS_JNE: + case X86_INS_JNO: + case X86_INS_JNP: + case X86_INS_JNS: + case X86_INS_JO: + case X86_INS_JP: + case X86_INS_JS: + stats_collect_jump_cond_arch(instr); + break; + case X86_INS_JECXZ: + case X86_INS_JRCXZ: + stats_data_arch->num_jmp_cond_jcxz++; + break; + case X86_INS_RET: + stats_data_arch->num_ret++; + break; + default: + stats_collect_rip_relative_arch(instr); + break; + + } + +} + +#endif + diff --git a/frida_mode/src/stats/stats_x86.c b/frida_mode/src/stats/stats_x86.c new file mode 100644 index 00000000..1906e809 --- /dev/null +++ b/frida_mode/src/stats/stats_x86.c @@ -0,0 +1,36 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "stats.h" +#include "util.h" + +#if defined(__i386__) + +gboolean stats_is_supported_arch(void) { + + return FALSE; + +} + +size_t stats_data_size_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_write_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_collect_arch(const cs_insn *instr) { + + UNUSED_PARAMETER(instr); + FATAL("Stats not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/util.c b/frida_mode/src/util.c new file mode 100644 index 00000000..09e8a58b --- /dev/null +++ b/frida_mode/src/util.c @@ -0,0 +1,68 @@ +#include "util.h" + +#include "debug.h" + +guint64 util_read_address(char *key) { + + char *value_str = getenv(key); + + if (value_str == NULL) { return 0; } + + if (!g_str_has_prefix(value_str, "0x")) { + + FATAL("Invalid address should have 0x prefix: %s=%s\n", key, value_str); + + } + + char *value_str2 = &value_str[2]; + + for (char *c = value_str2; *c != '\0'; c++) { + + if (!g_ascii_isxdigit(*c)) { + + FATAL("Invalid address not formed of hex digits: %s=%s ('%c')\n", key, + value_str, *c); + + } + + } + + guint64 value = g_ascii_strtoull(value_str2, NULL, 16); + if (value == 0) { + + FATAL("Invalid address failed hex conversion: %s=%s\n", key, value_str2); + + } + + return value; + +} + +guint64 util_read_num(char *key) { + + char *value_str = getenv(key); + + if (value_str == NULL) { return 0; } + + for (char *c = value_str; *c != '\0'; c++) { + + if (!g_ascii_isdigit(*c)) { + + FATAL("Invalid address not formed of decimal digits: %s=%s\n", key, + value_str); + + } + + } + + guint64 value = g_ascii_strtoull(value_str, NULL, 10); + if (value == 0) { + + FATAL("Invalid address failed numeric conversion: %s=%s\n", key, value_str); + + } + + return value; + +} + diff --git a/frida_mode/test/cmplog/GNUmakefile b/frida_mode/test/cmplog/GNUmakefile new file mode 100644 index 00000000..40de6a09 --- /dev/null +++ b/frida_mode/test/cmplog/GNUmakefile @@ -0,0 +1,69 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../../)/ +BUILD_DIR:=$(PWD)build/ + +TEST_CMPLOG_SRC=$(PWD)cmplog.c +TEST_CMPLOG_OBJ=$(BUILD_DIR)compcovtest + +TEST_BIN:=$(PWD)../../build/test + + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +CMP_LOG_INPUT:=$(TEST_DATA_DIR)in +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all 32 clean qemu frida format + +all: $(TEST_CMPLOG_OBJ) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(CMP_LOG_INPUT): | $(TEST_DATA_DIR) + echo -n "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" > $@ + +$(TEST_CMPLOG_OBJ): $(TEST_CMPLOG_SRC) | $(BUILD_DIR) + $(CXX) -std=c++11 -g $(CFLAGS) $(LDFLAGS) $< -o $@ + +qemu: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + $(ROOT)afl-fuzz \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -c 0 \ + -l 3AT \ + -Z \ + -- \ + $(TEST_CMPLOG_OBJ) @@ + +frida: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + $(ROOT)afl-fuzz \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -c 0 \ + -l 3AT \ + -Z \ + -- \ + $(TEST_CMPLOG_OBJ) @@ + +debug: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --ex 'r $(CMP_LOG_INPUT)' \ + --args $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + +clean: + rm -rf $(BUILD_DIR) + +format: + cd $(ROOT) && echo $(TEST_CMPLOG_SRC) | xargs -L1 ./.custom-format.py -i diff --git a/frida_mode/test/cmplog/Makefile b/frida_mode/test/cmplog/Makefile new file mode 100644 index 00000000..606b43a5 --- /dev/null +++ b/frida_mode/test/cmplog/Makefile @@ -0,0 +1,22 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida + +format: + @gmake format + +debug: + @gmake debug diff --git a/frida_mode/test/cmplog/cmplog.c b/frida_mode/test/cmplog/cmplog.c new file mode 100644 index 00000000..99010645 --- /dev/null +++ b/frida_mode/test/cmplog/cmplog.c @@ -0,0 +1,100 @@ +///////////////////////////////////////////////////////////////////////// +// +// Author: Mateusz Jurczyk (mjurczyk@google.com) +// +// Copyright 2019-2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// solution: echo -ne 'The quick brown fox jumps over the lazy +// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int main(int argc, char **argv) { + + char buffer[44] = {/* zero padding */}; + + FILE *file = stdin; + + if (argc > 1) { + + if ((file = fopen(argv[1], "r")) == NULL) { + + perror(argv[1]); + exit(-1); + + } + + } + + fread(buffer, 1, sizeof(buffer) - 1, file); + + if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 || + strncmp(&buffer[20], "jumps over ", 11) != 0 || + strcmp(&buffer[31], "the lazy dog") != 0) { + + if (argc > 1) { fclose(file); } + return 1; + + } + +#if defined(__x86_64__) + uint64_t x = 0; + fread(&x, sizeof(x), 1, file); + if (x != 0xCAFEBABECAFEBABE) { + + if (argc > 1) { fclose(file); } + return 2; + + } + +#endif + + uint32_t y = 0; + fread(&y, sizeof(y), 1, file); + + if (y != 0xDEADC0DE) { + + if (argc > 1) { fclose(file); } + return 3; + + } + + uint16_t z = 0; + fread(&z, sizeof(z), 1, file); + + switch (z) { + + case 0xBEEF: + break; + + default: + if (argc > 1) { fclose(file); } + return 4; + + } + + printf("Puzzle solved, congrats!\n"); + abort(); + + if (argc > 1) { fclose(file); } + + return 0; + +} + diff --git a/frida_mode/test/testinstr.py b/frida_mode/test/cmplog/get_section_addrs.py index f648808b..f648808b 100755 --- a/frida_mode/test/testinstr.py +++ b/frida_mode/test/cmplog/get_section_addrs.py diff --git a/frida_mode/test/deferred/GNUmakefile b/frida_mode/test/deferred/GNUmakefile new file mode 100644 index 00000000..c268ef66 --- /dev/null +++ b/frida_mode/test/deferred/GNUmakefile @@ -0,0 +1,71 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000) +endif + +.PHONY: all clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_ENTRYPOINT=$(AFL_ENTRYPOINT) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ diff --git a/frida_mode/test/deferred/Makefile b/frida_mode/test/deferred/Makefile new file mode 100644 index 00000000..07b139e9 --- /dev/null +++ b/frida_mode/test/deferred/Makefile @@ -0,0 +1,13 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida diff --git a/frida_mode/test/deferred/testinstr.c b/frida_mode/test/deferred/testinstr.c new file mode 100644 index 00000000..8b3688d7 --- /dev/null +++ b/frida_mode/test/deferred/testinstr.c @@ -0,0 +1,125 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +int run(char *file) { + + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + do { + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + +void slow() { + + usleep(100000); + +} + +TESTINSTR_SECTION int do_run(char * file) { + return run(file); +} + +int main(int argc, char **argv) { + + if (argc != 2) { return 1; } + slow(); + return do_run(argv[1]); + +} + diff --git a/frida_mode/test/entry_point/GNUmakefile b/frida_mode/test/entry_point/GNUmakefile new file mode 100644 index 00000000..c99bcecb --- /dev/null +++ b/frida_mode/test/entry_point/GNUmakefile @@ -0,0 +1,80 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000) +endif + +.PHONY: all clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida_entry: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_ENTRYPOINT=$(AFL_ENTRYPOINT) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ diff --git a/frida_mode/test/entry_point/Makefile b/frida_mode/test/entry_point/Makefile new file mode 100644 index 00000000..75c57e66 --- /dev/null +++ b/frida_mode/test/entry_point/Makefile @@ -0,0 +1,16 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida + +frida_entry: + @gmake frida diff --git a/frida_mode/test/entry_point/testinstr.c b/frida_mode/test/entry_point/testinstr.c new file mode 100644 index 00000000..bd605c52 --- /dev/null +++ b/frida_mode/test/entry_point/testinstr.c @@ -0,0 +1,121 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +int run(char *file) { + + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + do { + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + +void slow() { + + usleep(100000); + +} + +int main(int argc, char **argv) { + + if (argc != 2) { return 1; } + slow(); + return run(argv[1]); + +} + diff --git a/frida_mode/test/exe/GNUmakefile b/frida_mode/test/exe/GNUmakefile new file mode 100644 index 00000000..86e5a461 --- /dev/null +++ b/frida_mode/test/exe/GNUmakefile @@ -0,0 +1,53 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all 32 clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -no-pie + +clean: + rm -rf $(BUILD_DIR) + + +qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -Q \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ diff --git a/frida_mode/test/exe/Makefile b/frida_mode/test/exe/Makefile new file mode 100644 index 00000000..4bef1ccb --- /dev/null +++ b/frida_mode/test/exe/Makefile @@ -0,0 +1,16 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida diff --git a/frida_mode/test/testinstr.c b/frida_mode/test/exe/testinstr.c index 37d47f91..5e26fc46 100644 --- a/frida_mode/test/testinstr.c +++ b/frida_mode/test/exe/testinstr.c @@ -22,7 +22,7 @@ #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) #endif -TESTINSTR_SECTION void testinstr(char *buf, int len) { +void testinstr(char *buf, int len) { if (len < 1) return; buf[len] = 0; @@ -37,7 +37,7 @@ TESTINSTR_SECTION void testinstr(char *buf, int len) { } -int main(int argc, char **argv) { +TESTINSTR_SECTION int main(int argc, char **argv) { char * file; int fd = -1; diff --git a/frida_mode/test/fasan/GNUmakefile b/frida_mode/test/fasan/GNUmakefile new file mode 100644 index 00000000..08b271de --- /dev/null +++ b/frida_mode/test/fasan/GNUmakefile @@ -0,0 +1,159 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +TEST_DATA_FILE:=$(TEST_DATA_DIR)in +FRIDA_OUT:=$(BUILD_DIR)frida-out + +TEST_SRC:=$(PWD)/test.c +TEST_BIN:=$(BUILD_DIR)test + +CFLAGS+=-fPIC \ + -D_GNU_SOURCE \ + -g \ + -fno-omit-frame-pointer \ + -Wno-stringop-overflow \ + +LDFLAGS+=-ldl \ + +ifdef DEBUG +CFLAGS+=-Werror \ + -Wall \ + -Wextra \ + -Wpointer-arith +else +CFLAGS+=-Wno-pointer-arith +endif + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ifeq "$(ARCH)" "x86" +LIBASAN_FILE:=libclang_rt.asan-i386.so +endif + +ifeq "$(ARCH)" "x86_64" +LIBASAN_FILE:=libclang_rt.asan-x86_64.so +endif + +ifeq "$(ARCH)" "aarch64" +LIBASAN_FILE:=libclang_rt.asan-aarch64.so +endif + +# LIBASAN:=/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.so +# LIBASAN:=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0 + +LLVM_CONFIG ?= llvm-config +ifeq "$(shell test -e '$(shell which $(LLVM_CONFIG))' && echo 1)" "1" + $(info Found llvm-config: '$(shell which $(LLVM_CONFIG))') +else + $(warning Cannot find llvm-config) +endif + +LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)/ +$(info LLVM_BINDIR: $(LLVM_BINDIR)) + +CLANG ?= $(LLVM_BINDIR)clang +ifeq "$(shell test -e '$(CLANG)' && echo 1)" "1" + $(info Found clang: '$(CLANG)') +else + $(warning Cannot find clang) +endif + +CLANGVER = $(shell $(CLANG) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p') +$(info Clang version $(CLANGVER)) + +LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null) +$(info LLVM_LIBDIR: $(LLVM_LIBDIR)) + +LIBASAN:=$(LLVM_LIBDIR)/clang/$(CLANGVER)/lib/linux/$(LIBASAN_FILE) + +ifeq "$(shell test -e '$(LIBASAN)' && echo 1)" "1" + $(info Found Address Sanitizer DSO: '$(LIBASAN)') +else + $(error Error cannot find Address Sanitizer DSO) +endif + + +.PHONY: all 32 clean format frida-noasan frida debug run + +############################## ALL ############################################# + +all: $(TEST_BIN) + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(TEST_BIN): $(TEST_SRC) GNUmakefile | $(BUILD_DIR) + $(CC) \ + $(CFLAGS) \ + $(LDFLAGS) \ + -o $@ \ + $< + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +############################# TESTS ############################################ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TEST_DATA_FILE): | $(TEST_DATA_DIR) + echo -n "TUODATM" > $@ + +frida-noasan: $(TEST_BIN) $(TEST_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) + + +frida: $(TEST_BIN) $(TEST_DATA_FILE) + AFL_PRELOAD=$(LIBASAN) \ + AFL_USE_FASAN=1 \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) + +debug: $(TEST_BIN) $(TEST_DATA_FILE) + gdb \ + --ex 'set environment LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so' \ + --ex 'set environment ASAN_OPTIONS=detect_leaks=false,halt_on_error=0' \ + --ex 'set environment AFL_USE_FASAN=1' \ + --ex 'set disassembly-flavor intel' \ + --ex 'r < $(TEST_DATA_FILE)' \ + --args $(TEST_BIN) \ + +run: $(TEST_BIN) $(TEST_DATA_FILE) + LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so \ + ASAN_OPTIONS=detect_leaks=false \ + AFL_USE_FASAN=1 \ + $(TEST_BIN) < $(TEST_DATA_FILE) + +############################# CLEAN ############################################ +clean: + rm -rf $(BUILD_DIR) + +############################# FORMAT ########################################### +format: + cd $(ROOT) && echo $(TEST_SRC) | xargs -L1 ./.custom-format.py -i + +############################# RUN ############################################# diff --git a/frida_mode/test/fasan/Makefile b/frida_mode/test/fasan/Makefile new file mode 100644 index 00000000..3b4c71db --- /dev/null +++ b/frida_mode/test/fasan/Makefile @@ -0,0 +1,22 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida-noasan: + @gmake frida-noasan + +frida: + @gmake frida + +debug: + @gmake debug + +run: + @gmake run diff --git a/frida_mode/test/fasan/test.c b/frida_mode/test/fasan/test.c new file mode 100644 index 00000000..b9a119e6 --- /dev/null +++ b/frida_mode/test/fasan/test.c @@ -0,0 +1,90 @@ +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#define UNUSED_PARAMETER(x) (void)(x) + +#define LOG(x) \ + do { \ + \ + char buf[] = x; \ + write(STDOUT_FILENO, buf, sizeof(buf)); \ + \ + } while (false); + +void test(char data) { + + char *buf = malloc(10); + + if (buf == NULL) return; + + switch (data) { + + /* Underflow */ + case 'U': + LOG("Underflow\n"); + buf[-1] = '\0'; + free(buf); + break; + /* Overflow */ + case 'O': + LOG("Overflow\n"); + buf[10] = '\0'; + free(buf); + break; + /* Double free */ + case 'D': + LOG("Double free\n"); + free(buf); + free(buf); + break; + /* Use after free */ + case 'A': + LOG("Use after free\n"); + free(buf); + buf[0] = '\0'; + break; + /* Test Limits (OK) */ + case 'T': + LOG("Test-Limits - No Error\n"); + buf[0] = 'A'; + buf[9] = 'I'; + free(buf); + break; + case 'M': + LOG("Memset too many\n"); + memset(buf, '\0', 11); + free(buf); + break; + default: + LOG("Nop - No Error\n"); + break; + + } + +} + +int main(int argc, char **argv) { + + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + + char input = '\0'; + + if (read(STDIN_FILENO, &input, 1) < 0) { + + LOG("Failed to read stdin\n"); + return 1; + + } + + test(input); + + LOG("DONE\n"); + return 0; + +} + diff --git a/frida_mode/test/libpcap/GNUmakefile b/frida_mode/test/libpcap/GNUmakefile new file mode 100644 index 00000000..e30f2049 --- /dev/null +++ b/frida_mode/test/libpcap/GNUmakefile @@ -0,0 +1,188 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c +AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so + +LIBPCAP_BUILD_DIR:=$(BUILD_DIR)libpcap/ +HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ +PCAPTEST_BUILD_DIR:=$(BUILD_DIR)libpcaptest/ +TCPDUMP_BUILD_DIR:=$(BUILD_DIR)tcpdump/ + +LIBPCAP_PATCH_URL:=https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpcap_fuzz_both/patch.diff +LIBPCAP_PATCH_FILE:=$(LIBPCAP_BUILD_DIR)patch.diff +LIBPCAP_URL:=https://github.com/the-tcpdump-group/libpcap.git +LIBPCAP_DIR:=$(LIBPCAP_BUILD_DIR)libpcap/ +LIBPCAP_CMAKEFILE:=$(LIBPCAP_DIR)CMakeLists.txt +LIBPCAP_MAKEFILE:=$(LIBPCAP_DIR)Makefile +LIBPCAP_LIB:=$(LIBPCAP_DIR)libpcap.a + +HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" + +PCAPTEST_SRC_DIR:=$(LIBPCAP_DIR)testprogs/fuzz/ +PCAPTEST_FILE:=$(PCAPTEST_SRC_DIR)fuzz_both.c +PCAPTEST_OBJ:=$(PCAPTEST_BUILD_DIR)fuzz_both.o + +TCPDUMP_URL:=https://github.com/the-tcpdump-group/tcpdump.git +TCPDUMP_TESTS_DIR:=$(TCPDUMP_BUILD_DIR)tests/ + +CFLAGS += -fpermissive + +LDFLAGS += -lpthread + +TEST_BIN:=$(BUILD_DIR)test +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +endif + +AFLPP_DRIVER_DUMMY_INPUT:=$(TCPDUMP_TESTS_DIR)in + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) + +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) +endif + +.PHONY: all clean qemu frida hook + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +32: + CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +######### HARNESS ######## +$(HARNESS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(HARNESS_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $< + +######### PCAPTEST ######## + +$(PCAPTEST_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(PCAPTEST_FILE): | $(LIBPCAP_CMAKEFILE) + +$(PCAPTEST_OBJ): $(PCAPTEST_FILE) | $(PCAPTEST_BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -I $(LIBPCAP_DIR) -o $@ -c $< + +######### LIBPCAP ######## + +$(LIBPCAP_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(LIBPCAP_PATCH_FILE): | $(LIBPCAP_BUILD_DIR) + wget -O $@ $(LIBPCAP_PATCH_URL) + +$(LIBPCAP_CMAKEFILE): $(LIBPCAP_PATCH_FILE) | $(LIBPCAP_BUILD_DIR) + git clone --depth 1 $(LIBPCAP_URL) $(LIBPCAP_DIR) + git apply $(LIBPCAP_PATCH_FILE) + +$(LIBPCAP_MAKEFILE): $(LIBPCAP_CMAKEFILE) + cd $(LIBPCAP_DIR) && cmake . + +$(LIBPCAP_LIB): $(LIBPCAP_MAKEFILE) $(LIBPCAP_PATCH_FILE) + make -C $(LIBPCAP_DIR) + +######## TCPDUMP ###### + +$(TCPDUMP_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TCPDUMP_TESTS_DIR): | $(TCPDUMP_BUILD_DIR) + git clone --depth=1 $(TCPDUMP_URL) $(TCPDUMP_BUILD_DIR) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB) + $(CXX) \ + $(CFLAGS) \ + -o $@ \ + $(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB) \ + -lz \ + $(LDFLAGS) \ + $(TEST_BIN_LDFLAGS) \ + +########## HOOK ######## + +$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) + $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ + +########## DUMMY ####### + +$(AFLPP_DRIVER_DUMMY_INPUT): | $(TCPDUMP_TESTS_DIR) + truncate -s 1M $@ + +###### TEST DATA ####### + +hook: $(AFLPP_DRIVER_HOOK_OBJ) + +clean: + rm -rf $(BUILD_DIR) + +qemu: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) | $(TCPDUMP_TESTS_DIR) + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TCPDUMP_TESTS_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +frida: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) | $(TCPDUMP_TESTS_DIR) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TCPDUMP_TESTS_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +debug: + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) diff --git a/frida_mode/test/libpcap/Makefile b/frida_mode/test/libpcap/Makefile new file mode 100644 index 00000000..31cacb67 --- /dev/null +++ b/frida_mode/test/libpcap/Makefile @@ -0,0 +1,1143 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.16 + +# Default target executed when no arguments are given to make. +default_target: all + +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/jon/git/AFLplusplus/frida_mode/test/libpcap/build/libpcap/libpcap + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/jon/git/AFLplusplus/frida_mode/test/libpcap + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components + +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/jon/git/AFLplusplus/frida_mode/test/libpcap/CMakeFiles /home/jon/git/AFLplusplus/frida_mode/test/libpcap/CMakeFiles/progress.marks + $(MAKE) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /home/jon/git/AFLplusplus/frida_mode/test/libpcap/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named pcap + +# Build rule for target. +pcap: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 pcap +.PHONY : pcap + +# fast build rule for target. +pcap/fast: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/build +.PHONY : pcap/fast + +#============================================================================= +# Target rules for targets named uninstall + +# Build rule for target. +uninstall: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 uninstall +.PHONY : uninstall + +# fast build rule for target. +uninstall/fast: + $(MAKE) -f CMakeFiles/uninstall.dir/build.make CMakeFiles/uninstall.dir/build +.PHONY : uninstall/fast + +#============================================================================= +# Target rules for targets named pcap_static + +# Build rule for target. +pcap_static: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 pcap_static +.PHONY : pcap_static + +# fast build rule for target. +pcap_static/fast: + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/build +.PHONY : pcap_static/fast + +#============================================================================= +# Target rules for targets named SerializeTarget + +# Build rule for target. +SerializeTarget: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 SerializeTarget +.PHONY : SerializeTarget + +# fast build rule for target. +SerializeTarget/fast: + $(MAKE) -f CMakeFiles/SerializeTarget.dir/build.make CMakeFiles/SerializeTarget.dir/build +.PHONY : SerializeTarget/fast + +#============================================================================= +# Target rules for targets named testprogs + +# Build rule for target. +testprogs: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 testprogs +.PHONY : testprogs + +# fast build rule for target. +testprogs/fast: + $(MAKE) -f testprogs/CMakeFiles/testprogs.dir/build.make testprogs/CMakeFiles/testprogs.dir/build +.PHONY : testprogs/fast + +#============================================================================= +# Target rules for targets named capturetest + +# Build rule for target. +capturetest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 capturetest +.PHONY : capturetest + +# fast build rule for target. +capturetest/fast: + $(MAKE) -f testprogs/CMakeFiles/capturetest.dir/build.make testprogs/CMakeFiles/capturetest.dir/build +.PHONY : capturetest/fast + +#============================================================================= +# Target rules for targets named findalldevstest + +# Build rule for target. +findalldevstest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 findalldevstest +.PHONY : findalldevstest + +# fast build rule for target. +findalldevstest/fast: + $(MAKE) -f testprogs/CMakeFiles/findalldevstest.dir/build.make testprogs/CMakeFiles/findalldevstest.dir/build +.PHONY : findalldevstest/fast + +#============================================================================= +# Target rules for targets named filtertest + +# Build rule for target. +filtertest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 filtertest +.PHONY : filtertest + +# fast build rule for target. +filtertest/fast: + $(MAKE) -f testprogs/CMakeFiles/filtertest.dir/build.make testprogs/CMakeFiles/filtertest.dir/build +.PHONY : filtertest/fast + +#============================================================================= +# Target rules for targets named findalldevstest-perf + +# Build rule for target. +findalldevstest-perf: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 findalldevstest-perf +.PHONY : findalldevstest-perf + +# fast build rule for target. +findalldevstest-perf/fast: + $(MAKE) -f testprogs/CMakeFiles/findalldevstest-perf.dir/build.make testprogs/CMakeFiles/findalldevstest-perf.dir/build +.PHONY : findalldevstest-perf/fast + +#============================================================================= +# Target rules for targets named can_set_rfmon_test + +# Build rule for target. +can_set_rfmon_test: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 can_set_rfmon_test +.PHONY : can_set_rfmon_test + +# fast build rule for target. +can_set_rfmon_test/fast: + $(MAKE) -f testprogs/CMakeFiles/can_set_rfmon_test.dir/build.make testprogs/CMakeFiles/can_set_rfmon_test.dir/build +.PHONY : can_set_rfmon_test/fast + +#============================================================================= +# Target rules for targets named opentest + +# Build rule for target. +opentest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 opentest +.PHONY : opentest + +# fast build rule for target. +opentest/fast: + $(MAKE) -f testprogs/CMakeFiles/opentest.dir/build.make testprogs/CMakeFiles/opentest.dir/build +.PHONY : opentest/fast + +#============================================================================= +# Target rules for targets named reactivatetest + +# Build rule for target. +reactivatetest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 reactivatetest +.PHONY : reactivatetest + +# fast build rule for target. +reactivatetest/fast: + $(MAKE) -f testprogs/CMakeFiles/reactivatetest.dir/build.make testprogs/CMakeFiles/reactivatetest.dir/build +.PHONY : reactivatetest/fast + +#============================================================================= +# Target rules for targets named writecaptest + +# Build rule for target. +writecaptest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 writecaptest +.PHONY : writecaptest + +# fast build rule for target. +writecaptest/fast: + $(MAKE) -f testprogs/CMakeFiles/writecaptest.dir/build.make testprogs/CMakeFiles/writecaptest.dir/build +.PHONY : writecaptest/fast + +#============================================================================= +# Target rules for targets named selpolltest + +# Build rule for target. +selpolltest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 selpolltest +.PHONY : selpolltest + +# fast build rule for target. +selpolltest/fast: + $(MAKE) -f testprogs/CMakeFiles/selpolltest.dir/build.make testprogs/CMakeFiles/selpolltest.dir/build +.PHONY : selpolltest/fast + +#============================================================================= +# Target rules for targets named threadsignaltest + +# Build rule for target. +threadsignaltest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 threadsignaltest +.PHONY : threadsignaltest + +# fast build rule for target. +threadsignaltest/fast: + $(MAKE) -f testprogs/CMakeFiles/threadsignaltest.dir/build.make testprogs/CMakeFiles/threadsignaltest.dir/build +.PHONY : threadsignaltest/fast + +#============================================================================= +# Target rules for targets named valgrindtest + +# Build rule for target. +valgrindtest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 valgrindtest +.PHONY : valgrindtest + +# fast build rule for target. +valgrindtest/fast: + $(MAKE) -f testprogs/CMakeFiles/valgrindtest.dir/build.make testprogs/CMakeFiles/valgrindtest.dir/build +.PHONY : valgrindtest/fast + +#============================================================================= +# Target rules for targets named fuzz_both + +# Build rule for target. +fuzz_both: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 fuzz_both +.PHONY : fuzz_both + +# fast build rule for target. +fuzz_both/fast: + $(MAKE) -f testprogs/fuzz/CMakeFiles/fuzz_both.dir/build.make testprogs/fuzz/CMakeFiles/fuzz_both.dir/build +.PHONY : fuzz_both/fast + +#============================================================================= +# Target rules for targets named fuzz_filter + +# Build rule for target. +fuzz_filter: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 fuzz_filter +.PHONY : fuzz_filter + +# fast build rule for target. +fuzz_filter/fast: + $(MAKE) -f testprogs/fuzz/CMakeFiles/fuzz_filter.dir/build.make testprogs/fuzz/CMakeFiles/fuzz_filter.dir/build +.PHONY : fuzz_filter/fast + +#============================================================================= +# Target rules for targets named fuzz_pcap + +# Build rule for target. +fuzz_pcap: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 fuzz_pcap +.PHONY : fuzz_pcap + +# fast build rule for target. +fuzz_pcap/fast: + $(MAKE) -f testprogs/fuzz/CMakeFiles/fuzz_pcap.dir/build.make testprogs/fuzz/CMakeFiles/fuzz_pcap.dir/build +.PHONY : fuzz_pcap/fast + +bpf_dump.o: bpf_dump.c.o + +.PHONY : bpf_dump.o + +# target to build an object file +bpf_dump.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_dump.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_dump.c.o +.PHONY : bpf_dump.c.o + +bpf_dump.i: bpf_dump.c.i + +.PHONY : bpf_dump.i + +# target to preprocess a source file +bpf_dump.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_dump.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_dump.c.i +.PHONY : bpf_dump.c.i + +bpf_dump.s: bpf_dump.c.s + +.PHONY : bpf_dump.s + +# target to generate assembly for a file +bpf_dump.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_dump.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_dump.c.s +.PHONY : bpf_dump.c.s + +bpf_filter.o: bpf_filter.c.o + +.PHONY : bpf_filter.o + +# target to build an object file +bpf_filter.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_filter.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_filter.c.o +.PHONY : bpf_filter.c.o + +bpf_filter.i: bpf_filter.c.i + +.PHONY : bpf_filter.i + +# target to preprocess a source file +bpf_filter.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_filter.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_filter.c.i +.PHONY : bpf_filter.c.i + +bpf_filter.s: bpf_filter.c.s + +.PHONY : bpf_filter.s + +# target to generate assembly for a file +bpf_filter.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_filter.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_filter.c.s +.PHONY : bpf_filter.c.s + +bpf_image.o: bpf_image.c.o + +.PHONY : bpf_image.o + +# target to build an object file +bpf_image.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_image.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_image.c.o +.PHONY : bpf_image.c.o + +bpf_image.i: bpf_image.c.i + +.PHONY : bpf_image.i + +# target to preprocess a source file +bpf_image.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_image.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_image.c.i +.PHONY : bpf_image.c.i + +bpf_image.s: bpf_image.c.s + +.PHONY : bpf_image.s + +# target to generate assembly for a file +bpf_image.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_image.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_image.c.s +.PHONY : bpf_image.c.s + +etherent.o: etherent.c.o + +.PHONY : etherent.o + +# target to build an object file +etherent.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/etherent.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/etherent.c.o +.PHONY : etherent.c.o + +etherent.i: etherent.c.i + +.PHONY : etherent.i + +# target to preprocess a source file +etherent.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/etherent.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/etherent.c.i +.PHONY : etherent.c.i + +etherent.s: etherent.c.s + +.PHONY : etherent.s + +# target to generate assembly for a file +etherent.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/etherent.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/etherent.c.s +.PHONY : etherent.c.s + +fad-getad.o: fad-getad.c.o + +.PHONY : fad-getad.o + +# target to build an object file +fad-getad.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fad-getad.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fad-getad.c.o +.PHONY : fad-getad.c.o + +fad-getad.i: fad-getad.c.i + +.PHONY : fad-getad.i + +# target to preprocess a source file +fad-getad.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fad-getad.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fad-getad.c.i +.PHONY : fad-getad.c.i + +fad-getad.s: fad-getad.c.s + +.PHONY : fad-getad.s + +# target to generate assembly for a file +fad-getad.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fad-getad.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fad-getad.c.s +.PHONY : fad-getad.c.s + +fmtutils.o: fmtutils.c.o + +.PHONY : fmtutils.o + +# target to build an object file +fmtutils.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fmtutils.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fmtutils.c.o +.PHONY : fmtutils.c.o + +fmtutils.i: fmtutils.c.i + +.PHONY : fmtutils.i + +# target to preprocess a source file +fmtutils.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fmtutils.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fmtutils.c.i +.PHONY : fmtutils.c.i + +fmtutils.s: fmtutils.c.s + +.PHONY : fmtutils.s + +# target to generate assembly for a file +fmtutils.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fmtutils.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fmtutils.c.s +.PHONY : fmtutils.c.s + +gencode.o: gencode.c.o + +.PHONY : gencode.o + +# target to build an object file +gencode.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/gencode.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/gencode.c.o +.PHONY : gencode.c.o + +gencode.i: gencode.c.i + +.PHONY : gencode.i + +# target to preprocess a source file +gencode.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/gencode.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/gencode.c.i +.PHONY : gencode.c.i + +gencode.s: gencode.c.s + +.PHONY : gencode.s + +# target to generate assembly for a file +gencode.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/gencode.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/gencode.c.s +.PHONY : gencode.c.s + +grammar.o: grammar.c.o + +.PHONY : grammar.o + +# target to build an object file +grammar.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/grammar.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/grammar.c.o +.PHONY : grammar.c.o + +grammar.i: grammar.c.i + +.PHONY : grammar.i + +# target to preprocess a source file +grammar.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/grammar.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/grammar.c.i +.PHONY : grammar.c.i + +grammar.s: grammar.c.s + +.PHONY : grammar.s + +# target to generate assembly for a file +grammar.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/grammar.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/grammar.c.s +.PHONY : grammar.c.s + +missing/strlcat.o: missing/strlcat.c.o + +.PHONY : missing/strlcat.o + +# target to build an object file +missing/strlcat.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcat.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcat.c.o +.PHONY : missing/strlcat.c.o + +missing/strlcat.i: missing/strlcat.c.i + +.PHONY : missing/strlcat.i + +# target to preprocess a source file +missing/strlcat.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcat.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcat.c.i +.PHONY : missing/strlcat.c.i + +missing/strlcat.s: missing/strlcat.c.s + +.PHONY : missing/strlcat.s + +# target to generate assembly for a file +missing/strlcat.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcat.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcat.c.s +.PHONY : missing/strlcat.c.s + +missing/strlcpy.o: missing/strlcpy.c.o + +.PHONY : missing/strlcpy.o + +# target to build an object file +missing/strlcpy.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcpy.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcpy.c.o +.PHONY : missing/strlcpy.c.o + +missing/strlcpy.i: missing/strlcpy.c.i + +.PHONY : missing/strlcpy.i + +# target to preprocess a source file +missing/strlcpy.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcpy.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcpy.c.i +.PHONY : missing/strlcpy.c.i + +missing/strlcpy.s: missing/strlcpy.c.s + +.PHONY : missing/strlcpy.s + +# target to generate assembly for a file +missing/strlcpy.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcpy.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcpy.c.s +.PHONY : missing/strlcpy.c.s + +nametoaddr.o: nametoaddr.c.o + +.PHONY : nametoaddr.o + +# target to build an object file +nametoaddr.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/nametoaddr.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/nametoaddr.c.o +.PHONY : nametoaddr.c.o + +nametoaddr.i: nametoaddr.c.i + +.PHONY : nametoaddr.i + +# target to preprocess a source file +nametoaddr.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/nametoaddr.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/nametoaddr.c.i +.PHONY : nametoaddr.c.i + +nametoaddr.s: nametoaddr.c.s + +.PHONY : nametoaddr.s + +# target to generate assembly for a file +nametoaddr.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/nametoaddr.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/nametoaddr.c.s +.PHONY : nametoaddr.c.s + +optimize.o: optimize.c.o + +.PHONY : optimize.o + +# target to build an object file +optimize.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/optimize.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/optimize.c.o +.PHONY : optimize.c.o + +optimize.i: optimize.c.i + +.PHONY : optimize.i + +# target to preprocess a source file +optimize.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/optimize.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/optimize.c.i +.PHONY : optimize.c.i + +optimize.s: optimize.c.s + +.PHONY : optimize.s + +# target to generate assembly for a file +optimize.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/optimize.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/optimize.c.s +.PHONY : optimize.c.s + +pcap-common.o: pcap-common.c.o + +.PHONY : pcap-common.o + +# target to build an object file +pcap-common.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-common.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-common.c.o +.PHONY : pcap-common.c.o + +pcap-common.i: pcap-common.c.i + +.PHONY : pcap-common.i + +# target to preprocess a source file +pcap-common.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-common.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-common.c.i +.PHONY : pcap-common.c.i + +pcap-common.s: pcap-common.c.s + +.PHONY : pcap-common.s + +# target to generate assembly for a file +pcap-common.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-common.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-common.c.s +.PHONY : pcap-common.c.s + +pcap-linux.o: pcap-linux.c.o + +.PHONY : pcap-linux.o + +# target to build an object file +pcap-linux.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-linux.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-linux.c.o +.PHONY : pcap-linux.c.o + +pcap-linux.i: pcap-linux.c.i + +.PHONY : pcap-linux.i + +# target to preprocess a source file +pcap-linux.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-linux.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-linux.c.i +.PHONY : pcap-linux.c.i + +pcap-linux.s: pcap-linux.c.s + +.PHONY : pcap-linux.s + +# target to generate assembly for a file +pcap-linux.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-linux.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-linux.c.s +.PHONY : pcap-linux.c.s + +pcap-netfilter-linux.o: pcap-netfilter-linux.c.o + +.PHONY : pcap-netfilter-linux.o + +# target to build an object file +pcap-netfilter-linux.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-netfilter-linux.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-netfilter-linux.c.o +.PHONY : pcap-netfilter-linux.c.o + +pcap-netfilter-linux.i: pcap-netfilter-linux.c.i + +.PHONY : pcap-netfilter-linux.i + +# target to preprocess a source file +pcap-netfilter-linux.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-netfilter-linux.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-netfilter-linux.c.i +.PHONY : pcap-netfilter-linux.c.i + +pcap-netfilter-linux.s: pcap-netfilter-linux.c.s + +.PHONY : pcap-netfilter-linux.s + +# target to generate assembly for a file +pcap-netfilter-linux.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-netfilter-linux.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-netfilter-linux.c.s +.PHONY : pcap-netfilter-linux.c.s + +pcap-usb-linux.o: pcap-usb-linux.c.o + +.PHONY : pcap-usb-linux.o + +# target to build an object file +pcap-usb-linux.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-usb-linux.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-usb-linux.c.o +.PHONY : pcap-usb-linux.c.o + +pcap-usb-linux.i: pcap-usb-linux.c.i + +.PHONY : pcap-usb-linux.i + +# target to preprocess a source file +pcap-usb-linux.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-usb-linux.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-usb-linux.c.i +.PHONY : pcap-usb-linux.c.i + +pcap-usb-linux.s: pcap-usb-linux.c.s + +.PHONY : pcap-usb-linux.s + +# target to generate assembly for a file +pcap-usb-linux.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-usb-linux.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-usb-linux.c.s +.PHONY : pcap-usb-linux.c.s + +pcap.o: pcap.c.o + +.PHONY : pcap.o + +# target to build an object file +pcap.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap.c.o +.PHONY : pcap.c.o + +pcap.i: pcap.c.i + +.PHONY : pcap.i + +# target to preprocess a source file +pcap.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap.c.i +.PHONY : pcap.c.i + +pcap.s: pcap.c.s + +.PHONY : pcap.s + +# target to generate assembly for a file +pcap.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap.c.s +.PHONY : pcap.c.s + +savefile.o: savefile.c.o + +.PHONY : savefile.o + +# target to build an object file +savefile.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/savefile.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/savefile.c.o +.PHONY : savefile.c.o + +savefile.i: savefile.c.i + +.PHONY : savefile.i + +# target to preprocess a source file +savefile.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/savefile.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/savefile.c.i +.PHONY : savefile.c.i + +savefile.s: savefile.c.s + +.PHONY : savefile.s + +# target to generate assembly for a file +savefile.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/savefile.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/savefile.c.s +.PHONY : savefile.c.s + +scanner.o: scanner.c.o + +.PHONY : scanner.o + +# target to build an object file +scanner.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/scanner.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/scanner.c.o +.PHONY : scanner.c.o + +scanner.i: scanner.c.i + +.PHONY : scanner.i + +# target to preprocess a source file +scanner.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/scanner.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/scanner.c.i +.PHONY : scanner.c.i + +scanner.s: scanner.c.s + +.PHONY : scanner.s + +# target to generate assembly for a file +scanner.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/scanner.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/scanner.c.s +.PHONY : scanner.c.s + +sf-pcap.o: sf-pcap.c.o + +.PHONY : sf-pcap.o + +# target to build an object file +sf-pcap.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcap.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcap.c.o +.PHONY : sf-pcap.c.o + +sf-pcap.i: sf-pcap.c.i + +.PHONY : sf-pcap.i + +# target to preprocess a source file +sf-pcap.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcap.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcap.c.i +.PHONY : sf-pcap.c.i + +sf-pcap.s: sf-pcap.c.s + +.PHONY : sf-pcap.s + +# target to generate assembly for a file +sf-pcap.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcap.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcap.c.s +.PHONY : sf-pcap.c.s + +sf-pcapng.o: sf-pcapng.c.o + +.PHONY : sf-pcapng.o + +# target to build an object file +sf-pcapng.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcapng.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcapng.c.o +.PHONY : sf-pcapng.c.o + +sf-pcapng.i: sf-pcapng.c.i + +.PHONY : sf-pcapng.i + +# target to preprocess a source file +sf-pcapng.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcapng.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcapng.c.i +.PHONY : sf-pcapng.c.i + +sf-pcapng.s: sf-pcapng.c.s + +.PHONY : sf-pcapng.s + +# target to generate assembly for a file +sf-pcapng.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcapng.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcapng.c.s +.PHONY : sf-pcapng.c.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... install/strip" + @echo "... install/local" + @echo "... install" + @echo "... list_install_components" + @echo "... rebuild_cache" + @echo "... edit_cache" + @echo "... pcap" + @echo "... uninstall" + @echo "... pcap_static" + @echo "... SerializeTarget" + @echo "... testprogs" + @echo "... capturetest" + @echo "... findalldevstest" + @echo "... filtertest" + @echo "... findalldevstest-perf" + @echo "... can_set_rfmon_test" + @echo "... opentest" + @echo "... reactivatetest" + @echo "... writecaptest" + @echo "... selpolltest" + @echo "... threadsignaltest" + @echo "... valgrindtest" + @echo "... fuzz_both" + @echo "... fuzz_filter" + @echo "... fuzz_pcap" + @echo "... bpf_dump.o" + @echo "... bpf_dump.i" + @echo "... bpf_dump.s" + @echo "... bpf_filter.o" + @echo "... bpf_filter.i" + @echo "... bpf_filter.s" + @echo "... bpf_image.o" + @echo "... bpf_image.i" + @echo "... bpf_image.s" + @echo "... etherent.o" + @echo "... etherent.i" + @echo "... etherent.s" + @echo "... fad-getad.o" + @echo "... fad-getad.i" + @echo "... fad-getad.s" + @echo "... fmtutils.o" + @echo "... fmtutils.i" + @echo "... fmtutils.s" + @echo "... gencode.o" + @echo "... gencode.i" + @echo "... gencode.s" + @echo "... grammar.o" + @echo "... grammar.i" + @echo "... grammar.s" + @echo "... missing/strlcat.o" + @echo "... missing/strlcat.i" + @echo "... missing/strlcat.s" + @echo "... missing/strlcpy.o" + @echo "... missing/strlcpy.i" + @echo "... missing/strlcpy.s" + @echo "... nametoaddr.o" + @echo "... nametoaddr.i" + @echo "... nametoaddr.s" + @echo "... optimize.o" + @echo "... optimize.i" + @echo "... optimize.s" + @echo "... pcap-common.o" + @echo "... pcap-common.i" + @echo "... pcap-common.s" + @echo "... pcap-linux.o" + @echo "... pcap-linux.i" + @echo "... pcap-linux.s" + @echo "... pcap-netfilter-linux.o" + @echo "... pcap-netfilter-linux.i" + @echo "... pcap-netfilter-linux.s" + @echo "... pcap-usb-linux.o" + @echo "... pcap-usb-linux.i" + @echo "... pcap-usb-linux.s" + @echo "... pcap.o" + @echo "... pcap.i" + @echo "... pcap.s" + @echo "... savefile.o" + @echo "... savefile.i" + @echo "... savefile.s" + @echo "... scanner.o" + @echo "... scanner.i" + @echo "... scanner.s" + @echo "... sf-pcap.o" + @echo "... sf-pcap.i" + @echo "... sf-pcap.s" + @echo "... sf-pcapng.o" + @echo "... sf-pcapng.i" + @echo "... sf-pcapng.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c b/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c new file mode 100644 index 00000000..059d438d --- /dev/null +++ b/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c @@ -0,0 +1,97 @@ +#include <stdint.h> +#include <string.h> + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + +} + +#elif defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + void **esp = (void **)regs->esp; + void * arg1 = esp[1]; + void **arg2 = &esp[2]; + memcpy(arg1, input_buf, input_buf_len); + *arg2 = (void *)input_buf_len; + +} + +#else + #pragma error "Unsupported architecture" +#endif + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/frida_mode/test/libpcap/get_symbol_addr.py b/frida_mode/test/libpcap/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/libpcap/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/frida_mode/test/output/GNUmakefile b/frida_mode/test/output/GNUmakefile new file mode 100644 index 00000000..eaa1c4dc --- /dev/null +++ b/frida_mode/test/output/GNUmakefile @@ -0,0 +1,47 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all 32 clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_FRIDA_OUTPUT_STDOUT=frida_stdout.txt \ + AFL_FRIDA_OUTPUT_STDERR=frida_stderr.txt \ + AFL_FRIDA_STATS_FILE=frida_stats.txt \ + AFL_FRIDA_STATS_INTERVAL=1 \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ diff --git a/frida_mode/test/output/Makefile b/frida_mode/test/output/Makefile new file mode 100644 index 00000000..07b139e9 --- /dev/null +++ b/frida_mode/test/output/Makefile @@ -0,0 +1,13 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida diff --git a/frida_mode/test/output/frida_stderr.txt b/frida_mode/test/output/frida_stderr.txt new file mode 100644 index 00000000..103216cf --- /dev/null +++ b/frida_mode/test/output/frida_stderr.txt @@ -0,0 +1,2824 @@ + + +total_transitions: 9 + call_imms: 1 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 1 + jmp_mems: 2 + jmp_regs: 0 + + jmp_cond_imms: 2 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 19 + call_imms: 4 + call_regs: 0 + call_mems: 0 + post_call_invokes: 2 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 1 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 6 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 29 + call_imms: 6 + call_regs: 1 + call_mems: 0 + post_call_invokes: 3 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 2 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 11 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 39 + call_imms: 6 + call_regs: 2 + call_mems: 0 + post_call_invokes: 5 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 2 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 18 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 49 + call_imms: 7 + call_regs: 2 + call_mems: 1 + post_call_invokes: 6 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 2 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 25 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 59 + call_imms: 8 + call_regs: 2 + call_mems: 3 + post_call_invokes: 6 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 3 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 31 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 69 + call_imms: 9 + call_regs: 2 + call_mems: 3 + post_call_invokes: 7 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 3 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 38 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 79 + call_imms: 10 + call_regs: 2 + call_mems: 3 + post_call_invokes: 7 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 4 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 46 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 89 + call_imms: 10 + call_regs: 2 + call_mems: 3 + post_call_invokes: 7 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 4 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 56 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 99 + call_imms: 11 + call_regs: 2 + call_mems: 3 + post_call_invokes: 9 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 4 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 63 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 109 + call_imms: 12 + call_regs: 2 + call_mems: 3 + post_call_invokes: 12 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 5 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 68 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 119 + call_imms: 12 + call_regs: 2 + call_mems: 4 + post_call_invokes: 14 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 6 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 74 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 129 + call_imms: 14 + call_regs: 2 + call_mems: 4 + post_call_invokes: 16 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 6 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 80 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 139 + call_imms: 14 + call_regs: 2 + call_mems: 5 + post_call_invokes: 17 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 6 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 87 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 149 + call_imms: 14 + call_regs: 2 + call_mems: 6 + post_call_invokes: 17 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 6 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 96 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 159 + call_imms: 15 + call_regs: 2 + call_mems: 6 + post_call_invokes: 18 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 8 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 102 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 170 + call_imms: 15 + call_regs: 2 + call_mems: 6 + post_call_invokes: 18 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 10 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 111 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 180 + call_imms: 15 + call_regs: 2 + call_mems: 6 + post_call_invokes: 20 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 11 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 118 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 190 + call_imms: 16 + call_regs: 2 + call_mems: 6 + post_call_invokes: 20 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 11 + jmp_mems: 6 + jmp_regs: 1 + + jmp_cond_imms: 125 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 201 + call_imms: 16 + call_regs: 2 + call_mems: 7 + post_call_invokes: 21 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 13 + jmp_mems: 6 + jmp_regs: 1 + + jmp_cond_imms: 132 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 211 + call_imms: 17 + call_regs: 2 + call_mems: 7 + post_call_invokes: 22 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 14 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 138 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 223 + call_imms: 18 + call_regs: 2 + call_mems: 8 + post_call_invokes: 24 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 15 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 145 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 233 + call_imms: 18 + call_regs: 2 + call_mems: 8 + post_call_invokes: 25 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 16 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 153 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 244 + call_imms: 19 + call_regs: 2 + call_mems: 9 + post_call_invokes: 26 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 16 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 161 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input + + +total_transitions: 254 + call_imms: 20 + call_regs: 2 + call_mems: 9 + post_call_invokes: 27 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 18 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 167 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 264 + call_imms: 20 + call_regs: 2 + call_mems: 9 + post_call_invokes: 29 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 20 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 173 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 275 + call_imms: 21 + call_regs: 2 + call_mems: 10 + post_call_invokes: 30 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 22 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 179 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 285 + call_imms: 22 + call_regs: 2 + call_mems: 10 + post_call_invokes: 30 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 23 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 186 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 295 + call_imms: 22 + call_regs: 2 + call_mems: 10 + post_call_invokes: 30 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 23 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 196 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 305 + call_imms: 22 + call_regs: 2 + call_mems: 10 + post_call_invokes: 30 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 24 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 205 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 315 + call_imms: 22 + call_regs: 2 + call_mems: 10 + post_call_invokes: 31 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 26 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 212 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 326 + call_imms: 22 + call_regs: 3 + call_mems: 10 + post_call_invokes: 32 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 27 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 220 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 337 + call_imms: 23 + call_regs: 4 + call_mems: 10 + post_call_invokes: 36 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 27 + jmp_mems: 9 + jmp_regs: 1 + + jmp_cond_imms: 224 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 348 + call_imms: 24 + call_regs: 4 + call_mems: 10 + post_call_invokes: 38 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 27 + jmp_mems: 10 + jmp_regs: 1 + + jmp_cond_imms: 231 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 362 + call_imms: 26 + call_regs: 4 + call_mems: 10 + post_call_invokes: 39 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 28 + jmp_mems: 11 + jmp_regs: 1 + + jmp_cond_imms: 240 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 375 + call_imms: 27 + call_regs: 4 + call_mems: 10 + post_call_invokes: 40 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 28 + jmp_mems: 12 + jmp_regs: 1 + + jmp_cond_imms: 250 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 387 + call_imms: 28 + call_regs: 4 + call_mems: 10 + post_call_invokes: 41 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 28 + jmp_mems: 12 + jmp_regs: 3 + + jmp_cond_imms: 258 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 397 + call_imms: 29 + call_regs: 4 + call_mems: 10 + post_call_invokes: 42 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 30 + jmp_mems: 12 + jmp_regs: 3 + + jmp_cond_imms: 264 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 407 + call_imms: 29 + call_regs: 4 + call_mems: 10 + post_call_invokes: 42 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 31 + jmp_mems: 12 + jmp_regs: 3 + + jmp_cond_imms: 273 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 418 + call_imms: 29 + call_regs: 4 + call_mems: 11 + post_call_invokes: 43 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 32 + jmp_mems: 12 + jmp_regs: 3 + + jmp_cond_imms: 281 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) + + +total_transitions: 430 + call_imms: 32 + call_regs: 4 + call_mems: 11 + post_call_invokes: 45 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 33 + jmp_mems: 13 + jmp_regs: 3 + + jmp_cond_imms: 286 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 441 + call_imms: 32 + call_regs: 4 + call_mems: 12 + post_call_invokes: 46 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 33 + jmp_mems: 13 + jmp_regs: 3 + + jmp_cond_imms: 295 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) + + +total_transitions: 453 + call_imms: 33 + call_regs: 4 + call_mems: 12 + post_call_invokes: 49 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 34 + jmp_mems: 13 + jmp_regs: 3 + + jmp_cond_imms: 302 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 465 + call_imms: 35 + call_regs: 4 + call_mems: 12 + post_call_invokes: 50 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 35 + jmp_mems: 15 + jmp_regs: 3 + + jmp_cond_imms: 308 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 475 + call_imms: 38 + call_regs: 4 + call_mems: 12 + post_call_invokes: 51 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 35 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 310 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 485 + call_imms: 38 + call_regs: 5 + call_mems: 12 + post_call_invokes: 52 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 36 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 317 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 495 + call_imms: 38 + call_regs: 5 + call_mems: 13 + post_call_invokes: 52 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 38 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 324 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 506 + call_imms: 38 + call_regs: 5 + call_mems: 13 + post_call_invokes: 53 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 39 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 333 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 516 + call_imms: 40 + call_regs: 5 + call_mems: 13 + post_call_invokes: 53 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 40 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 340 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 526 + call_imms: 40 + call_regs: 5 + call_mems: 13 + post_call_invokes: 54 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 40 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 349 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 540 + call_imms: 42 + call_regs: 5 + call_mems: 13 + post_call_invokes: 55 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 42 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 358 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 552 + call_imms: 43 + call_regs: 5 + call_mems: 13 + post_call_invokes: 57 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 43 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 366 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 563 + call_imms: 43 + call_regs: 5 + call_mems: 14 + post_call_invokes: 58 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 43 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 375 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 573 + call_imms: 43 + call_regs: 5 + call_mems: 15 + post_call_invokes: 59 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 44 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 382 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 583 + call_imms: 44 + call_regs: 5 + call_mems: 15 + post_call_invokes: 59 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 45 + jmp_mems: 17 + jmp_regs: 3 + + jmp_cond_imms: 389 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 593 + call_imms: 45 + call_regs: 5 + call_mems: 15 + post_call_invokes: 60 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 46 + jmp_mems: 17 + jmp_regs: 3 + + jmp_cond_imms: 396 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 603 + call_imms: 46 + call_regs: 6 + call_mems: 15 + post_call_invokes: 64 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 46 + jmp_mems: 17 + jmp_regs: 3 + + jmp_cond_imms: 400 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 615 + call_imms: 46 + call_regs: 7 + call_mems: 17 + post_call_invokes: 64 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 46 + jmp_mems: 17 + jmp_regs: 3 + + jmp_cond_imms: 407 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 626 + call_imms: 48 + call_regs: 8 + call_mems: 18 + post_call_invokes: 66 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 46 + jmp_mems: 18 + jmp_regs: 3 + + jmp_cond_imms: 411 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 637 + call_imms: 50 + call_regs: 9 + call_mems: 19 + post_call_invokes: 68 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 47 + jmp_mems: 19 + jmp_regs: 3 + + jmp_cond_imms: 414 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 648 + call_imms: 52 + call_regs: 9 + call_mems: 20 + post_call_invokes: 70 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 47 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 419 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 660 + call_imms: 52 + call_regs: 10 + call_mems: 20 + post_call_invokes: 72 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 49 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 426 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 672 + call_imms: 52 + call_regs: 10 + call_mems: 20 + post_call_invokes: 72 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 51 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 436 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 683 + call_imms: 53 + call_regs: 11 + call_mems: 21 + post_call_invokes: 73 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 52 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 442 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 697 + call_imms: 53 + call_regs: 11 + call_mems: 22 + post_call_invokes: 74 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 53 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 453 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 709 + call_imms: 53 + call_regs: 13 + call_mems: 22 + post_call_invokes: 77 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 53 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 460 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 720 + call_imms: 53 + call_regs: 13 + call_mems: 22 + post_call_invokes: 77 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 55 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 469 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 730 + call_imms: 54 + call_regs: 13 + call_mems: 24 + post_call_invokes: 77 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 56 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 475 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 740 + call_imms: 54 + call_regs: 13 + call_mems: 24 + post_call_invokes: 80 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 57 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 481 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 753 + call_imms: 54 + call_regs: 14 + call_mems: 24 + post_call_invokes: 81 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 58 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 491 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) diff --git a/frida_mode/test/output/frida_stdout.txt b/frida_mode/test/output/frida_stdout.txt new file mode 100644 index 00000000..8832681d --- /dev/null +++ b/frida_mode/test/output/frida_stdout.txt @@ -0,0 +1,349 @@ +OG Range - 0x00007FFFF7FFE000 - 0x00007FFFF7FFF000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7FFD000 - 0x00007FFFF7FFE000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7FFC000 - 0x00007FFFF7FFD000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7FF3000 - 0x00007FFFF7FFB000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7FD0000 - 0x00007FFFF7FF3000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7FCF000 - 0x00007FFFF7FD0000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7FCE000 - 0x00007FFFF7FCF000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7FCB000 - 0x00007FFFF7FCE000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7DC4000 - 0x00007FFFF7FCB000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7DBC000 - 0x00007FFFF7DC4000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7DB0000 - 0x00007FFFF7DBC000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7A94000 - 0x00007FFFF7DB0000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7942000 - 0x00007FFFF7A94000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF78BF000 - 0x00007FFFF7942000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF78AF000 - 0x00007FFFF78BF000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF78AA000 - 0x00007FFFF78AB000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF78A9000 - 0x00007FFFF78AA000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF78A2000 - 0x00007FFFF78A6000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF789F000 - 0x00007FFFF78A2000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF789C000 - 0x00007FFFF789F000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7851000 - 0x00007FFFF789B000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF76DB000 - 0x00007FFFF7851000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF76DA000 - 0x00007FFFF76DB000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF76D9000 - 0x00007FFFF76DA000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF76B4000 - 0x00007FFFF76D9000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF76B0000 - 0x00007FFFF76B4000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF76AF000 - 0x00007FFFF76B0000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF76AE000 - 0x00007FFFF76AF000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF76A9000 - 0x00007FFFF76AE000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7698000 - 0x00007FFFF76A9000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7691000 - 0x00007FFFF7698000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF768F000 - 0x00007FFFF7691000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF768E000 - 0x00007FFFF768F000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF768D000 - 0x00007FFFF768E000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7689000 - 0x00007FFFF768C000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7679000 - 0x00007FFFF7689000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7675000 - 0x00007FFFF7679000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7674000 - 0x00007FFFF7675000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7673000 - 0x00007FFFF7674000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7672000 - 0x00007FFFF7673000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF7670000 - 0x00007FFFF7672000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF766F000 - 0x00007FFFF7670000[0m +[1;92m[+] [0mCMPLOG Range - 0x00007FFFF766D000 - 0x00007FFFF766F000[0m +[1;92m[+] [0mRedirect 1 -> '/home/jon/git/AFLplusplus/frida_mode/test/output/frida_stdout.txt'[0m +[1;92m[+] [0mRedirect 2 -> '/home/jon/git/AFLplusplus/frida_mode/test/output/frida_stderr.txt'[0m +[1;92m[+] [0mInstrumentation - persistent mode [ ] (0x0000000000000000)[0m +[1;92m[+] [0mInstrumentation - persistent count [ ] (0)[0m +[1;92m[+] [0mInstrumentation - hook [(null)][0m +[1;92m[+] [0mInstrumentation - persistent ret [ ] (0x0000000000000000)[0m +[1;92m[+] [0mInstrumentation - persistent ret offset [ ] (0)[0m +[1;92m[+] [0mInstrumentation - prefetch [X][0m +[1;92m[+] [0mRange: Modules Length: 54[0m +[1;92m[+] [0mRange: Modules Idx: 0 - 0x0000555555554000-0x0000555555555000[0m +[1;92m[+] [0mRange: Modules Idx: 1 - 0x0000555555555000-0x0000555555556000[0m +[1;92m[+] [0mRange: Modules Idx: 2 - 0x0000555555556000-0x0000555555557000[0m +[1;92m[+] [0mRange: Modules Idx: 3 - 0x0000555555557000-0x0000555555558000[0m +[1;92m[+] [0mRange: Modules Idx: 4 - 0x0000555555558000-0x0000555555559000[0m +[1;92m[+] [0mRange: Modules Idx: 5 - 0x0000555555559000-0x000055555557a000[0m +[1;92m[+] [0mRange: Modules Idx: 6 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: Modules Idx: 7 - 0x00007ffff766d000-0x00007ffff766f000[0m +[1;92m[+] [0mRange: Modules Idx: 8 - 0x00007ffff766f000-0x00007ffff7670000[0m +[1;92m[+] [0mRange: Modules Idx: 9 - 0x00007ffff7670000-0x00007ffff7672000[0m +[1;92m[+] [0mRange: Modules Idx: 10 - 0x00007ffff7672000-0x00007ffff7673000[0m +[1;92m[+] [0mRange: Modules Idx: 11 - 0x00007ffff7673000-0x00007ffff7674000[0m +[1;92m[+] [0mRange: Modules Idx: 12 - 0x00007ffff7674000-0x00007ffff7675000[0m +[1;92m[+] [0mRange: Modules Idx: 13 - 0x00007ffff7675000-0x00007ffff7679000[0m +[1;92m[+] [0mRange: Modules Idx: 14 - 0x00007ffff7679000-0x00007ffff7689000[0m +[1;92m[+] [0mRange: Modules Idx: 15 - 0x00007ffff7689000-0x00007ffff768c000[0m +[1;92m[+] [0mRange: Modules Idx: 16 - 0x00007ffff768c000-0x00007ffff768d000[0m +[1;92m[+] [0mRange: Modules Idx: 17 - 0x00007ffff768d000-0x00007ffff768e000[0m +[1;92m[+] [0mRange: Modules Idx: 18 - 0x00007ffff768e000-0x00007ffff768f000[0m +[1;92m[+] [0mRange: Modules Idx: 19 - 0x00007ffff768f000-0x00007ffff7691000[0m +[1;92m[+] [0mRange: Modules Idx: 20 - 0x00007ffff7691000-0x00007ffff7698000[0m +[1;92m[+] [0mRange: Modules Idx: 21 - 0x00007ffff7698000-0x00007ffff76a9000[0m +[1;92m[+] [0mRange: Modules Idx: 22 - 0x00007ffff76a9000-0x00007ffff76ae000[0m +[1;92m[+] [0mRange: Modules Idx: 23 - 0x00007ffff76ae000-0x00007ffff76af000[0m +[1;92m[+] [0mRange: Modules Idx: 24 - 0x00007ffff76af000-0x00007ffff76b0000[0m +[1;92m[+] [0mRange: Modules Idx: 25 - 0x00007ffff76b0000-0x00007ffff76b4000[0m +[1;92m[+] [0mRange: Modules Idx: 26 - 0x00007ffff76b4000-0x00007ffff76d9000[0m +[1;92m[+] [0mRange: Modules Idx: 27 - 0x00007ffff76d9000-0x00007ffff76da000[0m +[1;92m[+] [0mRange: Modules Idx: 28 - 0x00007ffff76da000-0x00007ffff76db000[0m +[1;92m[+] [0mRange: Modules Idx: 29 - 0x00007ffff76db000-0x00007ffff7851000[0m +[1;92m[+] [0mRange: Modules Idx: 30 - 0x00007ffff7851000-0x00007ffff789b000[0m +[1;92m[+] [0mRange: Modules Idx: 31 - 0x00007ffff789b000-0x00007ffff789c000[0m +[1;92m[+] [0mRange: Modules Idx: 32 - 0x00007ffff789c000-0x00007ffff789f000[0m +[1;92m[+] [0mRange: Modules Idx: 33 - 0x00007ffff789f000-0x00007ffff78a2000[0m +[1;92m[+] [0mRange: Modules Idx: 34 - 0x00007ffff78a2000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: Modules Idx: 35 - 0x00007ffff78a9000-0x00007ffff78aa000[0m +[1;92m[+] [0mRange: Modules Idx: 36 - 0x00007ffff78aa000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: Modules Idx: 37 - 0x00007ffff78af000-0x00007ffff78bf000[0m +[1;92m[+] [0mRange: Modules Idx: 38 - 0x00007ffff78bf000-0x00007ffff7942000[0m +[1;92m[+] [0mRange: Modules Idx: 39 - 0x00007ffff7942000-0x00007ffff7a94000[0m +[1;92m[+] [0mRange: Modules Idx: 40 - 0x00007ffff7a94000-0x00007ffff7db0000[0m +[1;92m[+] [0mRange: Modules Idx: 41 - 0x00007ffff7db0000-0x00007ffff7dbc000[0m +[1;92m[+] [0mRange: Modules Idx: 42 - 0x00007ffff7dbc000-0x00007ffff7dc4000[0m +[1;92m[+] [0mRange: Modules Idx: 43 - 0x00007ffff7dc4000-0x00007ffff7fcb000[0m +[1;92m[+] [0mRange: Modules Idx: 44 - 0x00007ffff7fcb000-0x00007ffff7fce000[0m +[1;92m[+] [0mRange: Modules Idx: 45 - 0x00007ffff7fce000-0x00007ffff7fcf000[0m +[1;92m[+] [0mRange: Modules Idx: 46 - 0x00007ffff7fcf000-0x00007ffff7fd0000[0m +[1;92m[+] [0mRange: Modules Idx: 47 - 0x00007ffff7fd0000-0x00007ffff7ff3000[0m +[1;92m[+] [0mRange: Modules Idx: 48 - 0x00007ffff7ff3000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: Modules Idx: 49 - 0x00007ffff7ffc000-0x00007ffff7ffd000[0m +[1;92m[+] [0mRange: Modules Idx: 50 - 0x00007ffff7ffd000-0x00007ffff7ffe000[0m +[1;92m[+] [0mRange: Modules Idx: 51 - 0x00007ffff7ffe000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: Modules Idx: 52 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: Modules Idx: 53 - 0xffffffffff600000-0xffffffffff601000[0m +[1;92m[+] [0mRange: AFL_INST_LIBS Length: 1[0m +[1;92m[+] [0mRange: AFL_INST_LIBS Idx: 0 - 0x0000555555555160-0x0000555555555335[0m +[1;92m[+] [0mRange: step1 Length: 1[0m +[1;92m[+] [0mRange: step1 Idx: 0 - 0x0000555555555160-0x0000555555555335[0m +[1;92m[+] [0mRange: step2 Length: 1[0m +[1;92m[+] [0mRange: step2 Idx: 0 - 0x0000555555555160-0x0000555555555335[0m +[1;92m[+] [0mRange: step3 Length: 1[0m +[1;92m[+] [0mRange: step3 Idx: 0 - 0x0000555555555160-0x0000555555555335[0m +[1;92m[+] [0mRange: step4 Length: 55[0m +[1;92m[+] [0mRange: step4 Idx: 0 - 0x0000555555554000-0x0000555555555000[0m +[1;92m[+] [0mRange: step4 Idx: 1 - 0x0000555555555000-0x0000555555555160[0m +[1;92m[+] [0mRange: step4 Idx: 2 - 0x0000555555555335-0x0000555555556000[0m +[1;92m[+] [0mRange: step4 Idx: 3 - 0x0000555555556000-0x0000555555557000[0m +[1;92m[+] [0mRange: step4 Idx: 4 - 0x0000555555557000-0x0000555555558000[0m +[1;92m[+] [0mRange: step4 Idx: 5 - 0x0000555555558000-0x0000555555559000[0m +[1;92m[+] [0mRange: step4 Idx: 6 - 0x0000555555559000-0x000055555557a000[0m +[1;92m[+] [0mRange: step4 Idx: 7 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: step4 Idx: 8 - 0x00007ffff766d000-0x00007ffff766f000[0m +[1;92m[+] [0mRange: step4 Idx: 9 - 0x00007ffff766f000-0x00007ffff7670000[0m +[1;92m[+] [0mRange: step4 Idx: 10 - 0x00007ffff7670000-0x00007ffff7672000[0m +[1;92m[+] [0mRange: step4 Idx: 11 - 0x00007ffff7672000-0x00007ffff7673000[0m +[1;92m[+] [0mRange: step4 Idx: 12 - 0x00007ffff7673000-0x00007ffff7674000[0m +[1;92m[+] [0mRange: step4 Idx: 13 - 0x00007ffff7674000-0x00007ffff7675000[0m +[1;92m[+] [0mRange: step4 Idx: 14 - 0x00007ffff7675000-0x00007ffff7679000[0m +[1;92m[+] [0mRange: step4 Idx: 15 - 0x00007ffff7679000-0x00007ffff7689000[0m +[1;92m[+] [0mRange: step4 Idx: 16 - 0x00007ffff7689000-0x00007ffff768c000[0m +[1;92m[+] [0mRange: step4 Idx: 17 - 0x00007ffff768c000-0x00007ffff768d000[0m +[1;92m[+] [0mRange: step4 Idx: 18 - 0x00007ffff768d000-0x00007ffff768e000[0m +[1;92m[+] [0mRange: step4 Idx: 19 - 0x00007ffff768e000-0x00007ffff768f000[0m +[1;92m[+] [0mRange: step4 Idx: 20 - 0x00007ffff768f000-0x00007ffff7691000[0m +[1;92m[+] [0mRange: step4 Idx: 21 - 0x00007ffff7691000-0x00007ffff7698000[0m +[1;92m[+] [0mRange: step4 Idx: 22 - 0x00007ffff7698000-0x00007ffff76a9000[0m +[1;92m[+] [0mRange: step4 Idx: 23 - 0x00007ffff76a9000-0x00007ffff76ae000[0m +[1;92m[+] [0mRange: step4 Idx: 24 - 0x00007ffff76ae000-0x00007ffff76af000[0m +[1;92m[+] [0mRange: step4 Idx: 25 - 0x00007ffff76af000-0x00007ffff76b0000[0m +[1;92m[+] [0mRange: step4 Idx: 26 - 0x00007ffff76b0000-0x00007ffff76b4000[0m +[1;92m[+] [0mRange: step4 Idx: 27 - 0x00007ffff76b4000-0x00007ffff76d9000[0m +[1;92m[+] [0mRange: step4 Idx: 28 - 0x00007ffff76d9000-0x00007ffff76da000[0m +[1;92m[+] [0mRange: step4 Idx: 29 - 0x00007ffff76da000-0x00007ffff76db000[0m +[1;92m[+] [0mRange: step4 Idx: 30 - 0x00007ffff76db000-0x00007ffff7851000[0m +[1;92m[+] [0mRange: step4 Idx: 31 - 0x00007ffff7851000-0x00007ffff789b000[0m +[1;92m[+] [0mRange: step4 Idx: 32 - 0x00007ffff789b000-0x00007ffff789c000[0m +[1;92m[+] [0mRange: step4 Idx: 33 - 0x00007ffff789c000-0x00007ffff789f000[0m +[1;92m[+] [0mRange: step4 Idx: 34 - 0x00007ffff789f000-0x00007ffff78a2000[0m +[1;92m[+] [0mRange: step4 Idx: 35 - 0x00007ffff78a2000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: step4 Idx: 36 - 0x00007ffff78a9000-0x00007ffff78aa000[0m +[1;92m[+] [0mRange: step4 Idx: 37 - 0x00007ffff78aa000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: step4 Idx: 38 - 0x00007ffff78af000-0x00007ffff78bf000[0m +[1;92m[+] [0mRange: step4 Idx: 39 - 0x00007ffff78bf000-0x00007ffff7942000[0m +[1;92m[+] [0mRange: step4 Idx: 40 - 0x00007ffff7942000-0x00007ffff7a94000[0m +[1;92m[+] [0mRange: step4 Idx: 41 - 0x00007ffff7a94000-0x00007ffff7db0000[0m +[1;92m[+] [0mRange: step4 Idx: 42 - 0x00007ffff7db0000-0x00007ffff7dbc000[0m +[1;92m[+] [0mRange: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000[0m +[1;92m[+] [0mRange: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000[0m +[1;92m[+] [0mRange: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000[0m +[1;92m[+] [0mRange: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000[0m +[1;92m[+] [0mRange: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000[0m +[1;92m[+] [0mRange: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000[0m +[1;92m[+] [0mRange: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000[0m +[1;92m[+] [0mRange: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000[0m +[1;92m[+] [0mRange: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000[0m +[1;92m[+] [0mRange: final Length: 9[0m +[1;92m[+] [0mRange: final Idx: 0 - 0x0000555555554000-0x0000555555555160[0m +[1;92m[+] [0mRange: final Idx: 1 - 0x0000555555555335-0x000055555557a000[0m +[1;92m[+] [0mRange: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000[0m +Looks like a zero to me! +0x00007ffff7dbc000[0m +[1;92m[+] [0mRange: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000[0m +[1;92m[+] [0mRange: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000[0m +[1;92m[+] [0mRange: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000[0m +[1;92m[+] [0mRange: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000[0m +[1;92m[+] [0mRange: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000[0m +[1;92m[+] [0mRange: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000[0m +[1;92m[+] [0mRange: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000[0m +[1;92m[+] [0mRange: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000[0m +[1;92m[+] [0mRange: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000[0m +[1;92m[+] [0mRange: final Length: 9[0m +[1;92m[+] [0mRange: final Idx: 0 - 0x0000555555554000-0x0000555555555160[0m +[1;92m[+] [0mRange: final Idx: 1 - 0x0000555555555335-0x000055555557a000[0m +[1;92m[+] [0mRange: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000[0m +Looks like a zero to me! +0x00007ffff7dbc000[0m +[1;92m[+] [0mRange: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000[0m +[1;92m[+] [0mRange: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000[0m +[1;92m[+] [0mRange: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000[0m +[1;92m[+] [0mRange: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000[0m +[1;92m[+] [0mRange: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000[0m +[1;92m[+] [0mRange: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000[0m +[1;92m[+] [0mRange: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000[0m +[1;92m[+] [0mRange: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000[0m +[1;92m[+] [0mRange: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000[0m +[1;92m[+] [0mRange: final Length: 9[0m +[1;92m[+] [0mRange: final Idx: 0 - 0x0000555555554000-0x0000555555555160[0m +[1;92m[+] [0mRange: final Idx: 1 - 0x0000555555555335-0x000055555557a000[0m +[1;92m[+] [0mRange: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000[0m +Looks like a zero to me! +0x00007ffff7dbc000[0m +[1;92m[+] [0mRange: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000[0m +[1;92m[+] [0mRange: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000[0m +[1;92m[+] [0mRange: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000[0m +[1;92m[+] [0mRange: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000[0m +[1;92m[+] [0mRange: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000[0m +[1;92m[+] [0mRange: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000[0m +[1;92m[+] [0mRange: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000[0m +[1;92m[+] [0mRange: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000[0m +[1;92m[+] [0mRange: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000[0m +[1;92m[+] [0mRange: final Length: 9[0m +[1;92m[+] [0mRange: final Idx: 0 - 0x0000555555554000-0x0000555555555160[0m +[1;92m[+] [0mRange: final Idx: 1 - 0x0000555555555335-0x000055555557a000[0m +[1;92m[+] [0mRange: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000[0m +Looks like a zero to me! +0x00007ffff7dbc000[0m +[1;92m[+] [0mRange: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000[0m +[1;92m[+] [0mRange: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000[0m +[1;92m[+] [0mRange: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000[0m +[1;92m[+] [0mRange: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000[0m +[1;92m[+] [0mRange: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000[0m +[1;92m[+] [0mRange: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000[0m +[1;92m[+] [0mRange: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000[0m +[1;92m[+] [0mRange: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000[0m +[1;92m[+] [0mRange: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000[0m +[1;92m[+] [0mRange: final Length: 9[0m +[1;92m[+] [0mRange: final Idx: 0 - 0x0000555555554000-0x0000555555555160[0m +[1;92m[+] [0mRange: final Idx: 1 - 0x0000555555555335-0x000055555557a000[0m +[1;92m[+] [0mRange: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000[0m +Looks like a zero to me! +0x00007ffff7dbc000[0m +[1;92m[+] [0mRange: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000[0m +[1;92m[+] [0mRange: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000[0m +[1;92m[+] [0mRange: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000[0m +[1;92m[+] [0mRange: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000[0m +[1;92m[+] [0mRange: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000[0m +[1;92m[+] [0mRange: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000[0m +[1;92m[+] [0mRange: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000[0m +[1;92m[+] [0mRange: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000[0m +[1;92m[+] [0mRange: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000[0m +[1;92m[+] [0mRange: final Length: 9[0m +[1;92m[+] [0mRange: final Idx: 0 - 0x0000555555554000-0x0000555555555160[0m +[1;92m[+] [0mRange: final Idx: 1 - 0x0000555555555335-0x000055555557a000[0m +[1;92m[+] [0mRange: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000[0m +Looks like a zero to me! +0x00007ffff7dbc000[0m +[1;92m[+] [0mRange: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000[0m +[1;92m[+] [0mRange: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000[0m +[1;92m[+] [0mRange: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000[0m +[1;92m[+] [0mRange: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000[0m +[1;92m[+] [0mRange: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000[0m +[1;92m[+] [0mRange: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000[0m +[1;92m[+] [0mRange: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000[0m +[1;92m[+] [0mRange: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000[0m +[1;92m[+] [0mRange: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000[0m +[1;92m[+] [0mRange: final Length: 9[0m +[1;92m[+] [0mRange: final Idx: 0 - 0x0000555555554000-0x0000555555555160[0m +[1;92m[+] [0mRange: final Idx: 1 - 0x0000555555555335-0x000055555557a000[0m +[1;92m[+] [0mRange: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000[0m +Looks like a zero to me! +0x00007ffff7dbc000[0m +[1;92m[+] [0mRange: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000[0m +[1;92m[+] [0mRange: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000[0m +[1;92m[+] [0mRange: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000[0m +[1;92m[+] [0mRange: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000[0m +[1;92m[+] [0mRange: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000[0m +[1;92m[+] [0mRange: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000[0m +[1;92m[+] [0mRange: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000[0m +[1;92m[+] [0mRange: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000[0m +[1;92m[+] [0mRange: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000[0m +[1;92m[+] [0mRange: final Length: 9[0m +[1;92m[+] [0mRange: final Idx: 0 - 0x0000555555554000-0x0000555555555160[0m +[1;92m[+] [0mRange: final Idx: 1 - 0x0000555555555335-0x000055555557a000[0m +[1;92m[+] [0mRange: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000[0m +[1;92m[+] [0mRange: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000[0m +[1;92m[+] [0mRange: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000[0m +[1;92m[+] [0mRange: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000[0m +[1;92m[+] [0mRange: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000[0m +[1;92m[+] [0mRange: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000[0m +[1;92m[+] [0mRange: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000[0m +Looks like a zero to me! diff --git a/frida_mode/test/output/testinstr.c b/frida_mode/test/output/testinstr.c new file mode 100644 index 00000000..5e26fc46 --- /dev/null +++ b/frida_mode/test/output/testinstr.c @@ -0,0 +1,112 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +TESTINSTR_SECTION int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/test/persistent_ret/GNUmakefile b/frida_mode/test/persistent_ret/GNUmakefile new file mode 100644 index 00000000..df48d065 --- /dev/null +++ b/frida_mode/test/persistent_ret/GNUmakefile @@ -0,0 +1,105 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x56555000) + AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x56555000) +endif + +AFL_FRIDA_PERSISTENT_RETADDR_OFFSET:=0x50 + +.PHONY: all 32 clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida_ret: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \ + AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +debug: $(TESTINSTR_DATA_FILE) + gdb \ + --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET)' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET)' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \ + --ex 'set environment AFL_DEBUG_CHILD=1' \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + +run: $(TESTINSTR_DATA_FILE) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \ + AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \ + AFL_DEBUG_CHILD=1 \ + LD_PRELOAD=$(ROOT)afl-frida-trace.so \ + $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) diff --git a/frida_mode/test/persistent_ret/Makefile b/frida_mode/test/persistent_ret/Makefile new file mode 100644 index 00000000..e3deddbd --- /dev/null +++ b/frida_mode/test/persistent_ret/Makefile @@ -0,0 +1,22 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida + +frida_ret: + @gmake frida_ret + +debug: + @gmake debug + +run: + @gmake run diff --git a/frida_mode/test/persistent_ret/get_symbol_addr.py b/frida_mode/test/persistent_ret/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/persistent_ret/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/frida_mode/test/persistent_ret/testinstr.c b/frida_mode/test/persistent_ret/testinstr.c new file mode 100644 index 00000000..6cb88a50 --- /dev/null +++ b/frida_mode/test/persistent_ret/testinstr.c @@ -0,0 +1,120 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +void slow() { + + usleep(100000); + +} + +TESTINSTR_SECTION int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + slow(); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/test/png/GNUmakefile b/frida_mode/test/png/GNUmakefile new file mode 100644 index 00000000..e05bade2 --- /dev/null +++ b/frida_mode/test/png/GNUmakefile @@ -0,0 +1,114 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +LIBPNG_BUILD_DIR:=$(BUILD_DIR)libpng/ +HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ +PNGTEST_BUILD_DIR:=$(BUILD_DIR)pngtest/ + +LIBPNG_FILE:=$(LIBPNG_BUILD_DIR)libpng-1.2.56.tar.gz +LIBPNG_URL:=https://downloads.sourceforge.net/project/libpng/libpng12/older-releases/1.2.56/libpng-1.2.56.tar.gz +LIBPNG_DIR:=$(LIBPNG_BUILD_DIR)libpng-1.2.56/ +LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile +LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a + +HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" + +PNGTEST_FILE:=$(PNGTEST_BUILD_DIR)target.cc +PNGTEST_OBJ:=$(PNGTEST_BUILD_DIR)target.o +PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc" + +TEST_BIN:=$(BUILD_DIR)test +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +endif + +TEST_DATA_DIR:=$(LIBPNG_DIR)contrib/pngsuite/ + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all clean qemu frida + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +######### HARNESS ######## +$(HARNESS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(HARNESS_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ -c $< + +######### PNGTEST ######## + +$(PNGTEST_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(PNGTEST_FILE): | $(PNGTEST_BUILD_DIR) + wget -O $@ $(PNGTEST_URL) + +$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR) + $(CXX) $(CFLAGS) $(LDFLAGS) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $< + +######### LIBPNG ######## + +$(LIBPNG_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(LIBPNG_FILE): | $(LIBPNG_BUILD_DIR) + wget -O $@ $(LIBPNG_URL) + +$(LIBPNG_DIR): $(LIBPNG_FILE) + tar zxvf $(LIBPNG_FILE) -C $(LIBPNG_BUILD_DIR) + +$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR) + cd $(LIBPNG_DIR) && ./configure + +$(LIBPNG_LIB): $(LIBPNG_MAKEFILE) + make -C $(LIBPNG_DIR) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) + $(CXX) \ + $(CFLAGS) \ + $(LDFLAGS) \ + -o $@ \ + $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \ + -lz \ + $(TEST_BIN_LDFLAGS) \ + +clean: + rm -rf $(BUILD_DIR) + +qemu: $(TEST_BIN) + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +frida: $(TEST_BIN) + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ diff --git a/frida_mode/test/png/Makefile b/frida_mode/test/png/Makefile new file mode 100644 index 00000000..4bef1ccb --- /dev/null +++ b/frida_mode/test/png/Makefile @@ -0,0 +1,16 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida diff --git a/frida_mode/test/png/persistent/GNUmakefile b/frida_mode/test/png/persistent/GNUmakefile new file mode 100644 index 00000000..ca6f0ff2 --- /dev/null +++ b/frida_mode/test/png/persistent/GNUmakefile @@ -0,0 +1,98 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../../..)/ +BUILD_DIR:=$(PWD)build/ + +TEST_BIN:=$(PWD)../build/test +TEST_DATA_DIR:=../build/libpng/libpng-1.2.56/contrib/pngsuite/ + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x4000000000) + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x56555000) +endif + +.PHONY: all 32 clean qemu qemu_entry frida frida_entry + +all: + make -C $(ROOT)frida_mode/test/png/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +qemu: | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +qemu_entry: | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +frida: | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +frida_entry: | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +clean: + rm -rf $(BUILD_DIR) diff --git a/frida_mode/test/png/persistent/Makefile b/frida_mode/test/png/persistent/Makefile new file mode 100644 index 00000000..cde0cf30 --- /dev/null +++ b/frida_mode/test/png/persistent/Makefile @@ -0,0 +1,22 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +qemu_entry: + @gmake qemu_entry + +frida: + @gmake frida + +frida_entry: + @gmake frida_entry diff --git a/frida_mode/test/png/persistent/get_symbol_addr.py b/frida_mode/test/png/persistent/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/png/persistent/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/frida_mode/test/png/persistent/hook/GNUmakefile b/frida_mode/test/png/persistent/hook/GNUmakefile new file mode 100644 index 00000000..82f08fa4 --- /dev/null +++ b/frida_mode/test/png/persistent/hook/GNUmakefile @@ -0,0 +1,141 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../../../..)/ +BUILD_DIR:=$(PWD)build/ + +AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c +AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so + +CFLAGS+=-O3 \ + -funroll-loops \ + -g \ + -fPIC \ + -funroll-loops \ + +LDFLAGS+=-shared \ + +TEST_BIN:=$(PWD)../../build/test +TEST_DATA_DIR:=../../build/libpng/libpng-1.2.56/contrib/pngsuite/ + +AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)in +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) + +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) +endif + +.PHONY: all 32 clean format qemu qemu_entry frida frida_entry debug + +all: $(AFLPP_DRIVER_HOOK_OBJ) + make -C $(ROOT)frida_mode/test/png/persistent/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +.PHONY: all clean qemu qemu_entry frida frida_entry + +all: + make -C $(ROOT)frida_mode/test/png/persistent/ + +$(BUILD_DIR): + mkdir -p $@ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) + truncate -s 1M $@ + +$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)/afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +qemu_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)/afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +frida: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + + +frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +debug: + echo $(AFL_FRIDA_PERSISTENT_ADDR) + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ)' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \ + --ex 'set disassembly-flavor intel' \ + --args $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +clean: + rm -rf $(BUILD_DIR) + +format: + cd $(ROOT) && echo $(AFLPP_DRIVER_HOOK_SRC) | xargs -L1 ./.custom-format.py -i + diff --git a/frida_mode/test/png/persistent/hook/Makefile b/frida_mode/test/png/persistent/hook/Makefile new file mode 100644 index 00000000..983d009e --- /dev/null +++ b/frida_mode/test/png/persistent/hook/Makefile @@ -0,0 +1,28 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +format: + @gmake format + +qemu: + @gmake qemu + +qemu_entry: + @gmake qemu_entry + +frida: + @gmake frida + +frida_entry: + @gmake frida_entry + +debug: + @gmake debug diff --git a/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c b/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c new file mode 100644 index 00000000..059d438d --- /dev/null +++ b/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c @@ -0,0 +1,97 @@ +#include <stdint.h> +#include <string.h> + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + +} + +#elif defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + void **esp = (void **)regs->esp; + void * arg1 = esp[1]; + void **arg2 = &esp[2]; + memcpy(arg1, input_buf, input_buf_len); + *arg2 = (void *)input_buf_len; + +} + +#else + #pragma error "Unsupported architecture" +#endif + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/frida_mode/test/re2/GNUmakefile b/frida_mode/test/re2/GNUmakefile new file mode 100644 index 00000000..9f0b31d3 --- /dev/null +++ b/frida_mode/test/re2/GNUmakefile @@ -0,0 +1,170 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c +AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so + +LIBRE2_BUILD_DIR:=$(BUILD_DIR)libre2/ +HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ +RE2TEST_BUILD_DIR:=$(BUILD_DIR)re2test/ + +LIBRE2_URL:=https://github.com/google/re2.git +LIBRE2_DIR:=$(LIBRE2_BUILD_DIR)libre2/ +LIBRE2_MAKEFILE:=$(LIBRE2_DIR)Makefile +LIBRE2_LIB:=$(LIBRE2_DIR)obj/libre2.a + +HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" + +RE2TEST_FILE:=$(RE2TEST_BUILD_DIR)target.cc +RE2TEST_OBJ:=$(RE2TEST_BUILD_DIR)target.o +RE2TEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/re2-2014-12-09/target.cc" + +LDFLAGS += -lpthread + +TEST_BIN:=$(BUILD_DIR)test +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +endif + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +AFLPP_DRIVER_DUMMY_INPUT:=$(TEST_DATA_DIR)in + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) + +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) +endif + +.PHONY: all clean qemu frida hook + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +32: + CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +######### HARNESS ######## +$(HARNESS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(HARNESS_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $< + +######### RE2TEST ######## + +$(RE2TEST_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(RE2TEST_FILE): | $(RE2TEST_BUILD_DIR) + wget -O $@ $(RE2TEST_URL) + +$(RE2TEST_OBJ): $(RE2TEST_FILE) | $(LIBRE2_MAKEFILE) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -std=c++11 -I $(LIBRE2_DIR) -o $@ -c $< + +######### LIBRE2 ######## + +$(LIBRE2_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(LIBRE2_MAKEFILE): $(LIBRE2_BUILD_DIR) + git clone https://github.com/google/re2.git $(LIBRE2_DIR) + cd $(LIBRE2_DIR) && git checkout 499ef7eff7455ce9c9fae86111d4a77b6ac335de + +$(LIBRE2_LIB): $(LIBRE2_MAKEFILE) + make -C $(LIBRE2_DIR) -j $(shell nproc) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(RE2TEST_OBJ) $(LIBRE2_LIB) + $(CXX) \ + $(CFLAGS) \ + -o $@ \ + $(HARNESS_OBJ) $(RE2TEST_OBJ) $(LIBRE2_LIB) \ + -lz \ + $(LDFLAGS) \ + $(TEST_BIN_LDFLAGS) \ + +########## HOOK ######## + +$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) + $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ + +########## DUMMY ####### + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(AFLPP_DRIVER_DUMMY_INPUT): | $(TEST_DATA_DIR) + truncate -s 1M $@ + +###### TEST DATA ####### + +hook: $(AFLPP_DRIVER_HOOK_OBJ) + +clean: + rm -rf $(BUILD_DIR) + +qemu: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +frida: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +debug: + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TEST_BIN) $(TEST_DATA_DIR)basn0g01.re2 diff --git a/frida_mode/test/re2/Makefile b/frida_mode/test/re2/Makefile new file mode 100644 index 00000000..00b2b287 --- /dev/null +++ b/frida_mode/test/re2/Makefile @@ -0,0 +1,22 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida + +debug: + @gmake debug + +hook: + @gmake hook diff --git a/frida_mode/test/re2/aflpp_qemu_driver_hook.c b/frida_mode/test/re2/aflpp_qemu_driver_hook.c new file mode 100644 index 00000000..059d438d --- /dev/null +++ b/frida_mode/test/re2/aflpp_qemu_driver_hook.c @@ -0,0 +1,97 @@ +#include <stdint.h> +#include <string.h> + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + +} + +#elif defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + void **esp = (void **)regs->esp; + void * arg1 = esp[1]; + void **arg2 = &esp[2]; + memcpy(arg1, input_buf, input_buf_len); + *arg2 = (void *)input_buf_len; + +} + +#else + #pragma error "Unsupported architecture" +#endif + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/frida_mode/test/re2/get_symbol_addr.py b/frida_mode/test/re2/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/re2/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/frida_mode/test/testinstr/GNUmakefile b/frida_mode/test/testinstr/GNUmakefile new file mode 100644 index 00000000..a35073ab --- /dev/null +++ b/frida_mode/test/testinstr/GNUmakefile @@ -0,0 +1,59 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all 32 clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + + +qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -Q \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +debug: + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) diff --git a/frida_mode/test/testinstr/Makefile b/frida_mode/test/testinstr/Makefile new file mode 100644 index 00000000..f843af19 --- /dev/null +++ b/frida_mode/test/testinstr/Makefile @@ -0,0 +1,19 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida + +debug: + @gmake debug diff --git a/frida_mode/test/testinstr/testinstr.c b/frida_mode/test/testinstr/testinstr.c new file mode 100644 index 00000000..5e26fc46 --- /dev/null +++ b/frida_mode/test/testinstr/testinstr.c @@ -0,0 +1,112 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +TESTINSTR_SECTION int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/update_frida_version.sh b/frida_mode/update_frida_version.sh new file mode 100755 index 00000000..7d938712 --- /dev/null +++ b/frida_mode/update_frida_version.sh @@ -0,0 +1,13 @@ +#!/bin/sh +test -n "$1" && { echo This script has no options. It updates the referenced Frida version in GNUmakefile to the most current one. ; exit 1 ; } + +OLD=$(egrep '^GUM_DEVKIT_VERSION=' GNUmakefile 2>/dev/null|awk -F= '{print$2}') +NEW=$(curl https://github.com/frida/frida/releases/ 2>/dev/null|egrep 'frida-gum-devkit-[0-9.]*-linux-x86_64'|head -n 1|sed 's/.*frida-gum-devkit-//'|sed 's/-linux.*//') + +echo Current set version: $OLD +echo Newest available version: $NEW + +test -z "$OLD" -o -z "$NEW" -o "$OLD" = "$NEW" && { echo Nothing to be done. ; exit 0 ; } + +sed -i "s/=$OLD/=$NEW/" GNUmakefile || exit 1 +echo Successfully updated GNUmakefile diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f201782a..4aba3bdf 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -385,14 +385,14 @@ typedef struct afl_env_vars { afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, - afl_exit_on_seed_issues; + afl_exit_on_seed_issues, afl_try_affinity; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, - *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, + *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries, *afl_kill_signal, *afl_target_env, - *afl_persistent_record; + *afl_persistent_record, *afl_exit_on_time; } afl_env_vars_t; @@ -575,7 +575,8 @@ typedef struct afl_state { last_sync_cycle, /* Cycle no. of the last sync */ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ - last_hang_time; /* Time for most recent hang (ms) */ + last_hang_time, /* Time for most recent hang (ms) */ + exit_on_time; /* Delay to exit if no new paths */ u32 slowest_exec_ms, /* Slowest testcase non hang in ms */ subseq_tmouts; /* Number of timeouts in a row */ @@ -1134,6 +1135,7 @@ void check_if_tty(afl_state_t *); void setup_signal_handlers(void); void save_cmdline(afl_state_t *, u32, char **); void read_foreign_testcases(afl_state_t *, int); +void write_crash_readme(afl_state_t *afl); /* CmpLog */ diff --git a/include/config.h b/include/config.h index aa24ea6c..80cdb684 100644 --- a/include/config.h +++ b/include/config.h @@ -154,7 +154,7 @@ cases that show variable behavior): */ #define CAL_CYCLES 8U -#define CAL_CYCLES_LONG 40U +#define CAL_CYCLES_LONG 20U /* Number of subsequent timeouts before abandoning an input file: */ @@ -163,7 +163,7 @@ /* Maximum number of unique hangs or crashes to record: */ #define KEEP_UNIQUE_HANG 500U -#define KEEP_UNIQUE_CRASH 5000U +#define KEEP_UNIQUE_CRASH 10000U /* Baseline number of random tweaks during a single 'havoc' stage: */ diff --git a/include/envs.h b/include/envs.h index e6f6d7c9..15116fc1 100644 --- a/include/envs.h +++ b/include/envs.h @@ -49,16 +49,28 @@ static char *afl_environment_variables[] = { "AFL_DUMB_FORKSRV", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE", + "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS", "AFL_FRIDA_EXCLUDE_RANGES", + "AFL_FRIDA_INST_DEBUG_FILE", "AFL_FRIDA_INST_NO_OPTIMIZE", "AFL_FRIDA_INST_NO_PREFETCH", "AFL_FRIDA_INST_RANGES", - "AFL_FRIDA_INST_STRICT", "AFL_FRIDA_INST_TRACE", + "AFL_FRIDA_OUTPUT_STDOUT", + "AFL_FRIDA_OUTPUT_STDERR", + "AFL_FRIDA_PERSISTENT_ADDR", + "AFL_FRIDA_PERSISTENT_CNT", + "AFL_FRIDA_PERSISTENT_DEBUG", + "AFL_FRIDA_PERSISTENT_HOOK", + "AFL_FRIDA_PERSISTENT_RET", + "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET", + "AFL_FRIDA_STATS_FILE", + "AFL_FRIDA_STATS_INTERVAL", + "AFL_FRIDA_STATS_TRANSITIONS", "AFL_FUZZER_ARGS", // oss-fuzz "AFL_GDB", "AFL_GCC_ALLOWLIST", @@ -117,6 +129,7 @@ static char *afl_environment_variables[] = { "AFL_LLVM_THREADSAFE_INST", "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", + "AFL_TRY_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", @@ -188,7 +201,9 @@ static char *afl_environment_variables[] = { "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", + "AFL_USE_FASAN", "AFL_USE_QASAN", + "AFL_PRINT_FILENAMES", NULL }; diff --git a/include/forkserver.h b/include/forkserver.h index 48db94c7..2baa6f0a 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -79,6 +79,8 @@ typedef struct afl_forkserver { bool frida_mode; /* if running in frida mode or not */ + bool frida_asan; /* if running with asan in frida mode */ + bool use_stdin; /* use stdin for sending data */ bool no_unlink; /* do not unlink cur_input */ diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index a9d51829..02722588 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -2,11 +2,11 @@ (See [../README.md](../README.md) for the general instruction manual.) - (See [README.gcc_plugon.md](../README.gcc_plugin.md) for the GCC-based instrumentation.) + (See [README.gcc_plugin.md](../README.gcc_plugin.md) for the GCC-based instrumentation.) ## 1) Introduction -! llvm_mode works with llvm versions 3.4 up to 12 ! +! llvm_mode works with llvm versions 6.0 up to 12 ! The code in this directory allows you to instrument programs for AFL using true compiler-level instrumentation, instead of the more crude diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index f5af32d2..58969e18 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -60,15 +60,14 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -static const char *const SanCovTracePCIndirName = - "__sanitizer_cov_trace_pc_indir"; -static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; -// static const char *const SanCovTracePCGuardName = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +// const char SanCovTracePCGuardName = // "__sanitizer_cov_trace_pc_guard"; -static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_cntrs"; -static const char *const SanCovBoolFlagSectionName = "sancov_bools"; -static const char *const SanCovPCsSectionName = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; static cl::opt<int> ClCoverageLevel( "lto-coverage-level", diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index e1e922be..dbddad0a 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -52,49 +52,39 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -static const char *const SanCovTracePCIndirName = - "__sanitizer_cov_trace_pc_indir"; -static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; -static const char *const SanCovTraceCmp1 = "__sanitizer_cov_trace_cmp1"; -static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2"; -static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4"; -static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8"; -static const char *const SanCovTraceConstCmp1 = - "__sanitizer_cov_trace_const_cmp1"; -static const char *const SanCovTraceConstCmp2 = - "__sanitizer_cov_trace_const_cmp2"; -static const char *const SanCovTraceConstCmp4 = - "__sanitizer_cov_trace_const_cmp4"; -static const char *const SanCovTraceConstCmp8 = - "__sanitizer_cov_trace_const_cmp8"; -static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4"; -static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8"; -static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep"; -static const char *const SanCovTraceSwitchName = "__sanitizer_cov_trace_switch"; -static const char *const SanCovModuleCtorTracePcGuardName = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1"; +const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2"; +const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4"; +const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8"; +const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1"; +const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2"; +const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4"; +const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8"; +const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4"; +const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8"; +const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep"; +const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch"; +const char SanCovModuleCtorTracePcGuardName[] = "sancov.module_ctor_trace_pc_guard"; -static const char *const SanCovModuleCtor8bitCountersName = +const char SanCovModuleCtor8bitCountersName[] = "sancov.module_ctor_8bit_counters"; -static const char *const SanCovModuleCtorBoolFlagName = - "sancov.module_ctor_bool_flag"; +const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag"; static const uint64_t SanCtorAndDtorPriority = 2; -static const char *const SanCovTracePCGuardName = - "__sanitizer_cov_trace_pc_guard"; -static const char *const SanCovTracePCGuardInitName = - "__sanitizer_cov_trace_pc_guard_init"; -static const char *const SanCov8bitCountersInitName = - "__sanitizer_cov_8bit_counters_init"; -static const char *const SanCovBoolFlagInitName = - "__sanitizer_cov_bool_flag_init"; -static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init"; +const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard"; +const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init"; +const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init"; +const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init"; +const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init"; -static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_cntrs"; -static const char *const SanCovBoolFlagSectionName = "sancov_bools"; -static const char *const SanCovPCsSectionName = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; -static const char *const SanCovLowestStackName = "__sancov_lowest_stack"; +const char SanCovLowestStackName[] = "__sancov_lowest_stack"; static const char *skip_nozero; static const char *use_threadsafe_counters; @@ -321,12 +311,12 @@ std::pair<Value *, Value *> ModuleSanitizerCoverage::CreateSecStartEnd( Module &M, const char *Section, Type *Ty) { GlobalVariable *SecStart = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionStart(Section)); + M, Ty->getPointerElementType(), false, + GlobalVariable::ExternalWeakLinkage, nullptr, getSectionStart(Section)); SecStart->setVisibility(GlobalValue::HiddenVisibility); GlobalVariable *SecEnd = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionEnd(Section)); + M, Ty->getPointerElementType(), false, + GlobalVariable::ExternalWeakLinkage, nullptr, getSectionEnd(Section)); SecEnd->setVisibility(GlobalValue::HiddenVisibility); IRBuilder<> IRB(M.getContext()); if (!TargetTriple.isOSBinFormatCOFF()) @@ -575,7 +565,7 @@ bool ModuleSanitizerCoverage::instrumentModule( } // True if block has successors and it dominates all of them. -static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { +bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { if (succ_begin(BB) == succ_end(BB)) return false; @@ -590,8 +580,7 @@ static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { } // True if block has predecessors and it postdominates all of them. -static bool isFullPostDominator(const BasicBlock * BB, - const PostDominatorTree *PDT) { +bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) { if (pred_begin(BB) == pred_end(BB)) return false; @@ -605,10 +594,10 @@ static bool isFullPostDominator(const BasicBlock * BB, } -static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, - const DominatorTree * DT, - const PostDominatorTree * PDT, - const SanitizerCoverageOptions &Options) { +bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, + const DominatorTree * DT, + const PostDominatorTree * PDT, + const SanitizerCoverageOptions &Options) { // Don't insert coverage for blocks containing nothing but unreachable: we // will never call __sanitizer_cov() for them, so counting them in @@ -638,8 +627,7 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, // A twist here is that we treat From->To as a backedge if // * To dominates From or // * To->UniqueSuccessor dominates From -static bool IsBackEdge(BasicBlock *From, BasicBlock *To, - const DominatorTree *DT) { +bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) { if (DT->dominates(To, From)) return true; if (auto Next = To->getUniqueSuccessor()) @@ -653,8 +641,8 @@ static bool IsBackEdge(BasicBlock *From, BasicBlock *To, // // Note that Cmp pruning is controlled by the same flag as the // BB pruning. -static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, - const SanitizerCoverageOptions &Options) { +bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, + const SanitizerCoverageOptions &Options) { if (!Options.NoPrune) if (CMP->hasOneUse()) @@ -1048,7 +1036,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, if (IsEntryBB) { - // Keep static allocas and llvm.localescape calls in the entry block. Even + // Keep allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. IP = PrepareToSplitEntryBlock(BB, IP); @@ -1234,17 +1222,17 @@ ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass( } -static void registerPCGUARDPass(const PassManagerBuilder &, - legacy::PassManagerBase &PM) { +void registerPCGUARDPass(const PassManagerBuilder &, + legacy::PassManagerBase &PM) { auto p = new ModuleSanitizerCoverageLegacyPass(); PM.add(p); } -static RegisterStandardPasses RegisterCompTransPass( +RegisterStandardPasses RegisterCompTransPass( PassManagerBuilder::EP_OptimizerLast, registerPCGUARDPass); -static RegisterStandardPasses RegisterCompTransPass0( +RegisterStandardPasses RegisterCompTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerPCGUARDPass); diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 552bbea8..2089ce78 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -79,8 +79,9 @@ #endif #if defined(__HAIKU__) - extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize); -#endif // HAIKU +extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, + size_t bufferSize); +#endif // HAIKU u8 __afl_area_initial[MAP_INITIAL_SIZE]; u8 * __afl_area_ptr_dummy = __afl_area_initial; @@ -1754,11 +1755,11 @@ static int area_is_valid(void *ptr, size_t len) { if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; } - #ifndef __HAIKU__ - long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); - #else - long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); - #endif // HAIKU +#ifndef __HAIKU__ + long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); +#else + long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); +#endif // HAIKU if (r <= 0 || r > len) return 0; diff --git a/instrumentation/afl-gcc-pass.so.cc b/instrumentation/afl-gcc-pass.so.cc index 41bb5152..3b7eb878 100644 --- a/instrumentation/afl-gcc-pass.so.cc +++ b/instrumentation/afl-gcc-pass.so.cc @@ -177,7 +177,7 @@ int plugin_is_GPL_compatible = 1; namespace { -static const struct pass_data afl_pass_data = { +static constexpr struct pass_data afl_pass_data = { .type = GIMPLE_PASS, .name = "afl", @@ -503,7 +503,7 @@ struct afl_pass : gimple_opt_pass { // Starting from "LLVMFuzzer" these are functions used in libfuzzer based // fuzzing campaign installations, e.g. oss-fuzz - static const char *ignoreList[] = { + static constexpr const char *ignoreList[] = { "asan.", "llvm.", diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index 24498f3e..af32e2f9 100644 --- a/instrumentation/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc @@ -55,7 +55,7 @@ bool isIgnoreFunction(const llvm::Function *F) { // Starting from "LLVMFuzzer" these are functions used in libfuzzer based // fuzzing campaign installations, e.g. oss-fuzz - static const char *ignoreList[] = { + static constexpr const char *ignoreList[] = { "asan.", "llvm.", @@ -94,7 +94,7 @@ bool isIgnoreFunction(const llvm::Function *F) { } - static const char *ignoreSubstringList[] = { + static constexpr const char *ignoreSubstringList[] = { "__asan", "__msan", "__ubsan", "__lsan", "__san", "__sanitize", "__cxx", "_GLOBAL__", diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index c954054b..e2b44b21 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -426,7 +426,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { ConstantInt *ilen = dyn_cast<ConstantInt>(op2); if (ilen) { - uint64_t literalLength = Str2.size(); + uint64_t literalLength = Str2.length(); uint64_t optLength = ilen->getZExtValue(); if (literalLength + 1 == optLength) { @@ -434,6 +434,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { } + if (optLength > Str2.length()) { optLength = Str2.length(); } + } valueMap[Str1P] = new std::string(Str2); @@ -532,6 +534,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen > thestring.length()) { optLen = thestring.length(); } if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 10cfa579..b5fdb3d6 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -89,9 +89,9 @@ class AFLLTOPass : public ModulePass { bool runOnModule(Module &M) override; protected: - uint32_t afl_global_id = 1, autodictionary = 1; - uint32_t function_minimum_size = 1; - uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; + uint32_t afl_global_id = 1, autodictionary = 1; + uint32_t function_minimum_size = 1; + uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; unsigned long long int map_addr = 0x10000; const char *skip_nozero = NULL; const char *use_threadsafe_counters = nullptr; diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc index 97ab04a4..82f198aa 100644 --- a/instrumentation/split-switches-pass.so.cc +++ b/instrumentation/split-switches-pass.so.cc @@ -89,7 +89,7 @@ class SplitSwitchesTransform : public ModulePass { }; - typedef std::vector<CaseExpr> CaseVector; + using CaseVector = std::vector<CaseExpr>; private: bool splitSwitches(Module &M); diff --git a/qemu_mode/README.md b/qemu_mode/README.md index a14cbe64..d28479d9 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -110,22 +110,23 @@ takes priority over any included ranges or AFL_INST_LIBS. CompareCoverage is a sub-instrumentation with effects similar to laf-intel. -The environment variable that enables QEMU CompareCoverage is AFL_COMPCOV_LEVEL. -There is also ./libcompcov/ which implements CompareCoverage for *cmp functions -(splitting memcmp, strncmp, etc. to make these conditions easier solvable by -afl-fuzz). +You have to set `AFL_PRELOAD=/path/to/libcompcov.so` together with +setting the AFL_COMPCOV_LEVEL you want to enable it. AFL_COMPCOV_LEVEL=1 is to instrument comparisons with only immediate -values / read-only memory. AFL_COMPCOV_LEVEL=2 instruments all -comparison instructions and memory comparison functions when libcompcov -is preloaded. -AFL_COMPCOV_LEVEL=3 has the same effects of AFL_COMPCOV_LEVEL=2 but enables also -the instrumentation of the floating-point comparisons on x86 and x86_64 (experimental). +values / read-only memory. + +AFL_COMPCOV_LEVEL=2 instruments all comparison instructions and memory +comparison functions when libcompcov is preloaded. + +AFL_COMPCOV_LEVEL=3 has the same effects of AFL_COMPCOV_LEVEL=2 but enables +also the instrumentation of the floating-point comparisons on x86 and x86_64 +(experimental). Integer comparison instructions are currently instrumented only on the x86, x86_64, arm and aarch64 targets. -Highly recommended. +Recommended, but not as good as CMPLOG mode (see below). ## 8) CMPLOG mode @@ -141,7 +142,7 @@ To enable it you must pass on the command line of afl-fuzz: ## 9) Wine mode -AFL++ QEMU can use Wine to fuzz WIn32 PE binaries. Use the -W flag of afl-fuzz. +AFL++ QEMU can use Wine to fuzz Win32 PE binaries. Use the -W flag of afl-fuzz. Note that some binaries require user interaction with the GUI and must be patched. @@ -190,8 +191,8 @@ handlers of the target. ## 13) Gotchas, feedback, bugs -If you need to fix up checksums or do other cleanup on mutated test cases, see -utils/custom_mutators/ for a viable solution. +If you need to fix up checksums or do other cleanups on mutated test cases, see +`afl_custom_post_process` in custom_mutators/examples/example.c for a viable solution. Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate the "shadow VM" trick employed by the sanitizers and will probably just diff --git a/qemu_mode/README.wine.md b/qemu_mode/README.wine.md new file mode 100644 index 00000000..567901cd --- /dev/null +++ b/qemu_mode/README.wine.md @@ -0,0 +1,21 @@ +# How to troubleshoot AFL++'s wine mode + +## 1) Debugging +To turn on wine debugging use the `WINEDEBUG` environment variable, +e.g. `WINEDEBUG=+timestamp,+tid,+loaddll`. + +## 2) LoadLibraryA workaround +The forked process fails to load libraries loaded via `LoadLibrary` +if the load happens after the entry point (error code: 87). To resolve +this issue, one needs to load any external libraries before the fork happens. + +An early DLL load can be achieved by adding the DLL name into the `Import Directory` +in the PE file. Such an entry can be added manually in any PE editor. + +Alternativly, one can generate a `.lib` file from the DLL exports and link +them together with the harness to create an entry in the `Import Directory`. +Use `dumpbin /exports <filename>.dll` to extract the exports and paste the +exported function names into a `.def` file. Use `lib /def:<deffile> /OUT:<libfile>` +to generate a `.lib` and add the library to the linker options. Once the usage of +an export is detected (`__declspec(dllimport)`), the +linker adds the early DLL load. \ No newline at end of file diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 6436d43a..84f144be 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -9,7 +9,7 @@ # TCG instrumentation and block chaining support by Andrea Biondo # <andrea.biondo965@gmail.com> # -# QEMU 3.1.1 port, TCG thread-safety, CompareCoverage and NeverZero +# QEMU 5+ port, TCG thread-safety, CompareCoverage and NeverZero # counters by Andrea Fioraldi <andreafioraldi@gmail.com> # # Copyright 2015, 2016, 2017 Google Inc. All rights reserved. @@ -211,8 +211,9 @@ if [ "$STATIC" = "1" ]; then echo Building STATIC binary + # static PIE causes https://github.com/AFLplusplus/AFLplusplus/issues/892 QEMU_CONF_FLAGS="$QEMU_CONF_FLAGS \ - --static \ + --static --disable-pie \ --extra-cflags=-DAFL_QEMU_STATIC_BUILD=1 \ " diff --git a/qemu_mode/libqasan/hooks.c b/qemu_mode/libqasan/hooks.c index 0e6c3e08..c542521c 100644 --- a/qemu_mode/libqasan/hooks.c +++ b/qemu_mode/libqasan/hooks.c @@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "libqasan.h" #include "map_macro.h" +#include <unistd.h> +#include <sys/syscall.h> -ssize_t (*__lq_libc_write)(int, const void *, size_t); -ssize_t (*__lq_libc_read)(int, void *, size_t); char *(*__lq_libc_fgets)(char *, int, FILE *); int (*__lq_libc_atoi)(const char *); long (*__lq_libc_atol)(const char *); @@ -37,8 +37,6 @@ void __libqasan_init_hooks(void) { __libqasan_init_malloc(); - __lq_libc_write = ASSERT_DLSYM(write); - __lq_libc_read = ASSERT_DLSYM(read); __lq_libc_fgets = ASSERT_DLSYM(fgets); __lq_libc_atoi = ASSERT_DLSYM(atoi); __lq_libc_atol = ASSERT_DLSYM(atol); @@ -52,7 +50,7 @@ ssize_t write(int fd, const void *buf, size_t count) { QASAN_DEBUG("%14p: write(%d, %p, %zu)\n", rtv, fd, buf, count); QASAN_LOAD(buf, count); - ssize_t r = __lq_libc_write(fd, buf, count); + ssize_t r = syscall(SYS_write, fd, buf, count); QASAN_DEBUG("\t\t = %zd\n", r); return r; @@ -65,7 +63,7 @@ ssize_t read(int fd, void *buf, size_t count) { QASAN_DEBUG("%14p: read(%d, %p, %zu)\n", rtv, fd, buf, count); QASAN_STORE(buf, count); - ssize_t r = __lq_libc_read(fd, buf, count); + ssize_t r = syscall(SYS_read, fd, buf, count); QASAN_DEBUG("\t\t = %zd\n", r); return r; diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c index 9fc4ef7a..d4742e3e 100644 --- a/qemu_mode/libqasan/libqasan.c +++ b/qemu_mode/libqasan/libqasan.c @@ -61,9 +61,19 @@ void __libqasan_print_maps(void) { } -/*__attribute__((constructor))*/ void __libqasan_init() { +int __libqasan_is_initialized = 0; + +__attribute__((constructor)) void __libqasan_init() { + + if (__libqasan_is_initialized) return; + __libqasan_is_initialized = 1; __libqasan_init_hooks(); + + if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) + __libqasan_hotpatch(); + + if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); #ifdef DEBUG __qasan_debug = getenv("QASAN_DEBUG") != NULL; @@ -86,7 +96,6 @@ int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv, typeof(&__libc_start_main) orig = dlsym(RTLD_NEXT, "__libc_start_main"); __libqasan_init(); - if (getenv("AFL_INST_LIBS")) __libqasan_hotpatch(); return orig(main, argc, argv, init, fini, rtld_fini, stack_end); diff --git a/src/afl-cc.c b/src/afl-cc.c index 132f5f83..6be6e165 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -560,12 +560,14 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (lto_mode && !have_c) { u8 *ld_path = strdup(AFL_REAL_LD); - if (!*ld_path) ld_path = "ld.lld"; + if (!ld_path || !*ld_path) { ld_path = strdup("ld.lld"); } + if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); } #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12 cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", ld_path); #else cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_path); #endif + free(ld_path); cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; @@ -1222,6 +1224,14 @@ int main(int argc, char **argv, char **envp) { if (strncmp(argv[i], "--afl", 5) == 0) { + if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) { + + passthrough = 1; + argv[i] = "-g"; // we have to overwrite it, -g is always good + continue; + + } + if (compiler_mode) WARNF( "--afl-... compiler mode supersedes the AFL_CC_COMPILER and " @@ -1572,7 +1582,12 @@ int main(int argc, char **argv, char **envp) { else if (have_gcc_plugin) compiler_mode = GCC_PLUGIN; else if (have_gcc) +#ifdef __APPLE__ + // on OSX clang masquerades as GCC + compiler_mode = CLANG; +#else compiler_mode = GCC; +#endif else if (have_lto) compiler_mode = LTO; else @@ -1594,7 +1609,12 @@ int main(int argc, char **argv, char **envp) { } - if (compiler_mode == CLANG) { instrument_mode = INSTRUMENT_CLANG; } + if (compiler_mode == CLANG) { + + instrument_mode = INSTRUMENT_CLANG; + setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + + } if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) { @@ -1628,7 +1648,7 @@ int main(int argc, char **argv, char **envp) { " yes\n" " [LLVM] llvm: %s%s\n" " PCGUARD %s yes yes module yes yes " - "extern\n" + "yes\n" " CLASSIC %s no yes module yes yes " "yes\n" " - NORMAL\n" @@ -1810,6 +1830,12 @@ int main(int argc, char **argv, char **envp) { "If anything fails - be sure to read README.lto.md!\n"); #endif + SAYF( + "\nYou can supply --afl-noopt to not instrument, like AFL_NOOPT. " + "(this is helpful\n" + "in some build systems if you do not want to instrument " + "everything.\n"); + } SAYF( diff --git a/src/afl-common.c b/src/afl-common.c index 0fb1462e..8826de70 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1110,6 +1110,10 @@ u32 get_map_size(void) { if (map_size % 64) { map_size = (((map_size >> 6) + 1) << 6); } + } else if (getenv("AFL_SKIP_BIN_CHECK")) { + + map_size = MAP_SIZE; + } return map_size; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 727e7f8d..3d472b36 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -416,7 +416,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, struct rlimit r; - if (!fsrv->cmplog_binary && fsrv->qemu_mode == false) { + if (!fsrv->cmplog_binary && fsrv->qemu_mode == false && + fsrv->frida_mode == false) { unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv @@ -450,8 +451,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered before the dump is complete. */ - // r.rlim_max = r.rlim_cur = 0; - // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + if (!fsrv->debug) { + + r.rlim_max = r.rlim_cur = 0; + setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + } /* Isolate the process and configure standard descriptors. If out_file is specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ @@ -1089,7 +1094,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { #endif - if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { + if (likely(fsrv->use_shmem_fuzz)) { if (unlikely(len > MAX_FILE)) len = MAX_FILE; diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 3d0228db..97f10e6f 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -397,7 +397,7 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) { /* Write a message accompanying the crash directory :-) */ -static void write_crash_readme(afl_state_t *afl) { +void write_crash_readme(afl_state_t *afl) { u8 fn[PATH_MAX]; s32 fd; diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 27c6c413..c2e9c80f 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -35,7 +35,7 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { if (fsrv->qemu_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); } - if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) { + if (!fsrv->qemu_mode && !fsrv->frida_mode && argv[0] != fsrv->cmplog_binary) { argv[0] = fsrv->cmplog_binary; diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 6091db15..584241d4 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -130,6 +130,20 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, } + /* Skip [number] */ + + if (*lptr == '[') { + + do { + + ++lptr; + + } while (*lptr >= '0' && *lptr <= '9'); + + if (*lptr == ']') { ++lptr; } + + } + /* Skip whitespace and = signs. */ while (isspace(*lptr) || *lptr == '=') { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index b6bfbc29..88b5bc02 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -113,7 +113,7 @@ void bind_to_free_cpu(afl_state_t *afl) { u8 lockfile[PATH_MAX] = ""; s32 i; - if (afl->afl_env.afl_no_affinity) { + if (afl->afl_env.afl_no_affinity && !afl->afl_env.afl_try_affinity) { if (afl->cpu_to_bind != -1) { @@ -130,10 +130,21 @@ void bind_to_free_cpu(afl_state_t *afl) { if (!bind_cpu(afl, afl->cpu_to_bind)) { - FATAL( - "Could not bind to requested CPU %d! Make sure you passed a valid " - "-b.", - afl->cpu_to_bind); + if (afl->afl_env.afl_try_affinity) { + + WARNF( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } else { + + FATAL( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } } @@ -420,11 +431,14 @@ void bind_to_free_cpu(afl_state_t *afl) { "Uh-oh, looks like all %d CPU cores on your system are allocated to\n" " other instances of afl-fuzz (or similar CPU-locked tasks). " "Starting\n" - " another fuzzer on this machine is probably a bad plan, but if " - "you are\n" - " absolutely sure, you can set AFL_NO_AFFINITY and try again.\n", - afl->cpu_core_count); - FATAL("No more free CPU cores"); + " another fuzzer on this machine is probably a bad plan.\n" + "%s", + afl->cpu_core_count, + afl->afl_env.afl_try_affinity ? "" + : " If you are sure, you can set " + "AFL_NO_AFFINITY and try again.\n"); + + if (!afl->afl_env.afl_try_affinity) { FATAL("No more free CPU cores"); } } @@ -823,7 +837,6 @@ void perform_dry_run(afl_state_t *afl) { struct queue_entry *q; u32 cal_failures = 0, idx; - u8 * skip_crashes = afl->afl_env.afl_skip_crashes; u8 * use_mem; for (idx = 0; idx < afl->queued_paths; idx++) { @@ -923,27 +936,6 @@ void perform_dry_run(afl_state_t *afl) { if (afl->crash_mode) { break; } - if (skip_crashes) { - - if (afl->fsrv.uses_crash_exitcode) { - - WARNF( - "Test case results in a crash or AFL_CRASH_EXITCODE %d " - "(skipping)", - (int)(s8)afl->fsrv.crash_exitcode); - - } else { - - WARNF("Test case results in a crash (skipping)"); - - } - - q->cal_failed = CAL_CHANCES; - ++cal_failures; - break; - - } - if (afl->fsrv.mem_limit) { u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; @@ -1044,18 +1036,16 @@ void perform_dry_run(afl_state_t *afl) { /* Remove from fuzzing queue but keep for splicing */ - struct queue_entry *p = afl->queue; - - if (!p->was_fuzzed) { + if (!q->was_fuzzed) { - p->was_fuzzed = 1; + q->was_fuzzed = 1; --afl->pending_not_fuzzed; --afl->active_paths; } - p->disabled = 1; - p->perf_score = 0; + q->disabled = 1; + q->perf_score = 0; u32 i = 0; while (unlikely(i < afl->queued_paths && afl->queue_buf[i] && @@ -1119,14 +1109,12 @@ void perform_dry_run(afl_state_t *afl) { if (cal_failures == afl->queued_paths) { - FATAL("All test cases time out%s, giving up!", - skip_crashes ? " or crash" : ""); + FATAL("All test cases time out or crash, giving up!"); } - WARNF("Skipped %u test cases (%0.02f%%) due to timeouts%s.", cal_failures, - ((double)cal_failures) * 100 / afl->queued_paths, - skip_crashes ? " or crashes" : ""); + WARNF("Skipped %u test cases (%0.02f%%) due to timeouts or crashes.", + cal_failures, ((double)cal_failures) * 100 / afl->queued_paths); if (cal_failures * 5 > afl->queued_paths) { @@ -1294,9 +1282,13 @@ void pivot_inputs(afl_state_t *afl) { if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) { - struct queue_entry *s = afl->queue_buf[src_id]; + if (src_id < afl->queued_paths) { + + struct queue_entry *s = afl->queue_buf[src_id]; + + if (s) { q->depth = s->depth + 1; } - if (s) { q->depth = s->depth + 1; } + } if (afl->max_depth < q->depth) { afl->max_depth = q->depth; } @@ -2031,7 +2023,7 @@ void setup_dirs_fds(afl_state_t *afl) { fprintf( afl->fsrv.plot_file, - "# unix_time, cycles_done, cur_path, paths_total, " + "# relative_time, cycles_done, cur_path, paths_total, " "pending_total, pending_favs, map_size, unique_crashes, " "unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n"); @@ -2726,11 +2718,15 @@ void check_binary(afl_state_t *afl, u8 *fname) { " When source code is not available, you may be able to leverage " "QEMU\n" " mode support. Consult the README.md for tips on how to enable " - "this.\n" + "this.\n\n" + + " If your target is an instrumented binary (e.g. with zafl, " + "retrowrite,\n" + " etc.) then set 'AFL_SKIP_BIN_CHECK=1'\n\n" " (It is also possible to use afl-fuzz as a traditional, " - "non-instrumented fuzzer.\n" - " For that, you can use the -n option - but expect much worse " + "non-instrumented\n" + " fuzzer. For that use the -n option - but expect much worse " "results.)\n", doc_path); @@ -2774,6 +2770,14 @@ void check_binary(afl_state_t *afl, u8 *fname) { WARNF("AFL_PERSISTENT is no longer supported and may misbehave!"); + } else if (getenv("AFL_FRIDA_PERSISTENT_ADDR")) { + + OKF("FRIDA Persistent mode configuration options detected."); + setenv(PERSIST_ENV_VAR, "1", 1); + afl->persistent_mode = 1; + + afl->shmem_testcase_mode = 1; + } if (afl->fsrv.frida_mode || diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index a47b4f5f..e27d6fae 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -308,9 +308,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, struct custom_mutator *mutator) { - u8 needs_write = 0, fault = 0; + u8 fault = 0; u32 trim_exec = 0; u32 orig_len = q->len; + u32 out_len = 0; + u8 *out_buf = NULL; u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; @@ -397,27 +399,33 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (likely(retlen && cksum == q->exec_cksum)) { - q->len = retlen; - memcpy(in_buf, retbuf, retlen); - /* Let's save a clean trace, which will be needed by - update_bitmap_score once we're done with the trimming stuff. */ + update_bitmap_score once we're done with the trimming stuff. + Use out_buf NULL check to make this only happen once per trim. */ - if (!needs_write) { + if (!out_buf) { - needs_write = 1; memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, afl->fsrv.map_size); } + if (afl_realloc((void **)&out_buf, retlen) == NULL) { + + FATAL("can not allocate memory for trim"); + + } + + out_len = retlen; + memcpy(out_buf, retbuf, retlen); + /* Tell the custom mutator that the trimming was successful */ afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1); if (afl->not_on_tty && afl->debug) { SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)", - afl->stage_cur, afl->stage_max, q->len); + afl->stage_cur, afl->stage_max, out_len); } @@ -450,16 +458,10 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, } - if (afl->not_on_tty && afl->debug) { - - SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len); - - } - - /* If we have made changes to in_buf, we also need to update the on-disk + /* If we have made changes, we also need to update the on-disk version of the test case. */ - if (needs_write) { + if (out_buf) { s32 fd; @@ -469,16 +471,28 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } - ck_write(fd, in_buf, q->len, q->fname); + ck_write(fd, out_buf, out_len, q->fname); close(fd); + /* Update the queue's knowledge of length as soon as we write the file. + We do this here so that exit/error cases that *don't* update the file + also don't update q->len. */ + q->len = out_len; + memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size); update_bitmap_score(afl, q); } + if (afl->not_on_tty && afl->debug) { + + SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len); + + } + abort_trimming: + if (out_buf) afl_free(out_buf); afl->bytes_trim_out += q->len; return fault; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index d72d4145..4a3e7f33 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -562,7 +562,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { @@ -2013,7 +2013,7 @@ havoc_stage: } - if (unlikely(get_cur_time() - afl->last_path_time > 5000 && + if (unlikely(get_cur_time() - afl->last_path_time > 5000 /* 5 seconds */ && afl->ready_for_splicing_count > 1)) { /* add expensive havoc cases here if there is no findings in the last 5s */ @@ -3010,13 +3010,13 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { u8 res = trim_case(afl, afl->queue_cur, in_buf); orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); - if (res == FSRV_RUN_ERROR) { + if (unlikely(res == FSRV_RUN_ERROR)) { FATAL("Unable to execute target application"); } - if (afl->stop_soon) { + if (unlikely(afl->stop_soon)) { ++afl->cur_skipped_paths; goto abandon_entry; @@ -3060,7 +3060,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 8760194c..3aa97635 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -212,7 +212,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { PyObject_GetAttrString(py_module, "introspection"); py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit"); if (!py_functions[PY_FUNC_DEINIT]) - FATAL("deinit function not found in python module"); + WARNF("deinit function not found in python module"); for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) { diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 832f17bb..5a481639 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -203,7 +203,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (afl->fsrv.shmem_fuzz) { + if (likely(afl->fsrv.use_shmem_fuzz)) { if (!post_process_skipped) { @@ -211,9 +211,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, memcpy(afl->fsrv.shmem_fuzz, new_mem, new_size); - } - - else { + } else { memcpy(afl->fsrv.shmem_fuzz, mem, skip_at); @@ -244,7 +242,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, return; - } else if (afl->fsrv.out_file) { + } else if (unlikely(!afl->fsrv.use_stdin)) { if (unlikely(afl->no_unlink)) { @@ -279,7 +277,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (!afl->fsrv.out_file) { + if (afl->fsrv.use_stdin) { if (ftruncate(fd, new_size)) { PFATAL("ftruncate() failed"); } lseek(fd, 0, SEEK_SET); @@ -412,7 +410,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = CAL_CYCLES_LONG; + afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG; } else { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 28d3339a..0658070e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -99,6 +99,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; afl->hang_tmout = EXEC_TIMEOUT; + afl->exit_on_time = 0; afl->stats_update_freq = 1; afl->stats_avg_exec = 0; afl->skip_deterministic = 1; @@ -187,6 +188,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_exit_when_done = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXIT_ON_TIME", + + afl_environment_variable_len)) { + + afl->afl_env.afl_exit_on_time = + (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_NO_AFFINITY", afl_environment_variable_len)) { @@ -194,12 +202,18 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_no_affinity = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TRY_AFFINITY", + + afl_environment_variable_len)) { + + afl->afl_env.afl_try_affinity = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_SKIP_CRASHES", afl_environment_variable_len)) { - afl->afl_env.afl_skip_crashes = - (u8 *)get_afl_env(afl_environment_variables[i]); + // we should mark this obsolete in a few versions } else if (!strncmp(env, "AFL_HANG_TMOUT", diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 22c0cbd2..4884b942 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -179,6 +179,8 @@ void load_stats_file(afl_state_t *afl) { } + if (afl->unique_crashes) { write_crash_readme(afl); } + return; } @@ -366,7 +368,8 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, afl->plot_prev_uh == afl->unique_hangs && afl->plot_prev_md == afl->max_depth && afl->plot_prev_ed == afl->fsrv.total_execs) || - !afl->queue_cycle || get_cur_time() - afl->start_time <= 60))) { + !afl->queue_cycle || + get_cur_time() - afl->start_time <= 60000))) { return; @@ -384,14 +387,14 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, /* Fields in the file: - unix_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed, + relative_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed, favored_not_fuzzed, unique_crashes, unique_hangs, max_depth, execs_per_sec, edges_found */ fprintf(afl->fsrv.plot_file, "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, " "%u\n", - (afl->prev_run_time + get_cur_time() - afl->start_time), + ((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000), afl->queue_cycle - 1, afl->current_entry, afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps, @@ -544,7 +547,7 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->afl_env.afl_statsd)) { - if (unlikely(afl->force_ui_update && cur_ms - afl->statsd_last_send_ms > + if (unlikely(afl->force_ui_update || cur_ms - afl->statsd_last_send_ms > STATSD_UPDATE_SEC * 1000)) { /* reset counter, even if send failed. */ @@ -574,6 +577,16 @@ void show_stats(afl_state_t *afl) { } + /* AFL_EXIT_ON_TIME. */ + + if (unlikely(afl->last_path_time && !afl->non_instrumented_mode && + afl->afl_env.afl_exit_on_time && + (cur_ms - afl->last_path_time) > afl->exit_on_time)) { + + afl->stop_soon = 2; + + } + if (unlikely(afl->total_crashes && afl->afl_env.afl_bench_until_crash)) { afl->stop_soon = 2; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 3606533d..a3a623d9 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -35,6 +35,10 @@ #include <sys/shm.h> #endif +#ifdef __APPLE__ + #include <sys/qos.h> +#endif + #ifdef PROFILING extern u64 time_spent_working; #endif @@ -204,6 +208,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_DISABLE_TRIM: disable the trimming of test cases\n" "AFL_DUMB_FORKSRV: use fork server without feedback from target\n" "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n" + "AFL_EXIT_ON_TIME: exit when no new paths are found within the specified time period\n" "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60 minutes and a cycle without finds)\n" "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n" "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n" @@ -219,6 +224,7 @@ static void usage(u8 *argv0, int more_help) { " then they are randomly selected instead all of them being\n" " used. Defaults to 200.\n" "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n" + "AFL_TRY_AFFINITY: try to bind to an unused core, but don't fail if unsuccessful\n" "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n" "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" @@ -237,9 +243,9 @@ static void usage(u8 *argv0, int more_help) { "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TARGET_ENV: pass extra environment variables to target\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" - "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n" + "AFL_SKIP_BIN_CHECK: skip afl compatibility checks, also disables auto map size\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" - "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" + //"AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" "AFL_STATSD: enables StatsD metrics collection\n" "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n" "AFL_STATSD_PORT: change default statsd port (default: 8125)\n" @@ -327,11 +333,55 @@ static int stricmp(char const *a, char const *b) { } +static void fasan_check_afl_preload(char *afl_preload) { + + char first_preload[PATH_MAX + 1] = {0}; + char * separator = strchr(afl_preload, ':'); + size_t first_preload_len = PATH_MAX; + char * basename; + char clang_runtime_prefix[] = "libclang_rt.asan-"; + + if (separator != NULL && (separator - afl_preload) < PATH_MAX) { + + first_preload_len = separator - afl_preload; + + } + + strncpy(first_preload, afl_preload, first_preload_len); + + basename = strrchr(first_preload, '/'); + if (basename == NULL) { + + basename = first_preload; + + } else { + + basename = basename + 1; + + } + + if (strncmp(basename, clang_runtime_prefix, + sizeof(clang_runtime_prefix) - 1) != 0) { + + FATAL("Address Sanitizer DSO must be the first DSO in AFL_PRELOAD"); + + } + + if (access(first_preload, R_OK) != 0) { + + FATAL("Address Sanitizer DSO not found"); + + } + + OKF("Found ASAN DSO: %s", first_preload); + +} + /* Main entry point */ int main(int argc, char **argv_orig, char **envp) { - s32 opt, i, auto_sync = 0 /*, user_set_cache = 0*/; + s32 opt, auto_sync = 0 /*, user_set_cache = 0*/; u64 prev_queued = 0; u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, map_size = get_map_size(); @@ -784,6 +834,7 @@ int main(int argc, char **argv_orig, char **envp) { } afl->fsrv.frida_mode = 1; + if (get_afl_env("AFL_USE_FASAN")) { afl->fsrv.frida_asan = 1; } break; @@ -1246,6 +1297,13 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_exit_on_time) { + + u64 exit_on_time = atoi(afl->afl_env.afl_exit_on_time); + afl->exit_on_time = (u64)exit_on_time * 1000; + + } + if (afl->afl_env.afl_max_det_extras) { s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras); @@ -1358,20 +1416,29 @@ int main(int argc, char **argv_orig, char **envp) { afl_preload = getenv("AFL_PRELOAD"); u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); if (afl_preload) { - frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + if (afl->fsrv.frida_asan) { - } else { + OKF("Using Frida Address Sanitizer Mode"); - frida_afl_preload = alloc_printf("%s", frida_binary); + fasan_check_afl_preload(afl_preload); - } + setenv("ASAN_OPTIONS", "detect_leaks=false", 1); - ck_free(frida_binary); + } + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); - setenv("LD_PRELOAD", frida_afl_preload, 1); - setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + ck_free(frida_binary); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + + } } else { @@ -1382,10 +1449,22 @@ int main(int argc, char **argv_orig, char **envp) { } else if (afl->fsrv.frida_mode) { - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - setenv("LD_PRELOAD", frida_binary, 1); - setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); - ck_free(frida_binary); + if (afl->fsrv.frida_asan) { + + OKF("Using Frida Address Sanitizer Mode"); + FATAL( + "Address Sanitizer DSO must be loaded using AFL_PRELOAD in Frida " + "Address Sanitizer Mode"); + + } else { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + ck_free(frida_binary); + + } } @@ -1643,10 +1722,10 @@ int main(int argc, char **argv_orig, char **envp) { afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode); if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode && - !afl->unicorn_mode) { + !afl->unicorn_mode && !afl->fsrv.frida_mode && + !afl->afl_env.afl_skip_bin_check) { - if (map_size <= DEFAULT_SHMEM_SIZE && !afl->non_instrumented_mode && - !afl->fsrv.qemu_mode && !afl->unicorn_mode) { + if (map_size <= DEFAULT_SHMEM_SIZE) { afl->fsrv.map_size = DEFAULT_SHMEM_SIZE; // dummy temporary value char vbuf[16]; @@ -1697,13 +1776,15 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: this is semi-nice afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits; afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode; + afl->cmplog_fsrv.frida_mode = afl->fsrv.frida_mode; afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; afl->cmplog_fsrv.init_child_func = cmplog_exec_child; if ((map_size <= DEFAULT_SHMEM_SIZE || afl->cmplog_fsrv.map_size < map_size) && !afl->non_instrumented_mode && !afl->fsrv.qemu_mode && - !afl->unicorn_mode) { + !afl->fsrv.frida_mode && !afl->unicorn_mode && + !afl->afl_env.afl_skip_bin_check) { afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE); char vbuf[16]; @@ -1759,7 +1840,7 @@ int main(int argc, char **argv_orig, char **envp) { if (extras_dir_cnt) { - for (i = 0; i < extras_dir_cnt; i++) { + for (u8 i = 0; i < extras_dir_cnt; i++) { load_extras(afl, extras_dir[i]); @@ -1911,6 +1992,13 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(seek_to)) { + if (unlikely(seek_to >= afl->queued_paths)) { + + // This should never happen. + FATAL("BUG: seek_to location out of bounds!\n"); + + } + afl->current_entry = seek_to; afl->queue_cur = afl->queue_buf[seek_to]; seek_to = 0; @@ -1929,8 +2017,10 @@ int main(int argc, char **argv_orig, char **envp) { /* If we had a full queue cycle with no new finds, try recombination strategies next. */ - if (unlikely(afl->queued_paths == prev_queued && - (get_cur_time() - afl->start_time) >= 3600)) { + if (unlikely(afl->queued_paths == prev_queued + /* FIXME TODO BUG: && (get_cur_time() - afl->start_time) >= + 3600 */ + )) { if (afl->use_splicing) { @@ -2048,7 +2138,7 @@ int main(int argc, char **argv_orig, char **envp) { } // we must recalculate the scores of all queue entries - for (i = 0; i < (s32)afl->queued_paths; i++) { + for (u32 i = 0; i < afl->queued_paths; i++) { if (likely(!afl->queue_buf[i]->disabled)) { @@ -2209,6 +2299,14 @@ stop_fuzzing: } afl_fsrv_deinit(&afl->fsrv); + + /* remove tmpfile */ + if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) { + + (void)unlink(afl->fsrv.out_file); + + } + if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); } ck_free(afl->fsrv.target_path); ck_free(afl->fsrv.out_file); diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index d0113af9..1ce97649 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -298,13 +298,12 @@ int main(int argc, char **argv) { SAYF( "\n" - "This is a helper application for afl-clang-lto. It is a wrapper " - "around GNU " - "llvm's 'lld',\n" - "executed by the toolchain whenever using " - "afl-clang-lto/afl-clang-lto++.\n" + "This is a helper application for afl-clang-lto.\n" + "It is a wrapper around llvm's 'lld' in case afl-clang-lto cannot be " + "used.\n" + "Note that the target still has to be compiled with -flto=full!\n" "You probably don't want to run this program directly but rather pass " - "it as LD parameter to configure scripts\n\n" + "it as LD\nparameter to e.g. configure scripts.\n\n" "Environment variables:\n" " AFL_LD_PASSTHROUGH do not link+optimize == no instrumentation\n" diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 946b19cd..96b72dd9 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -52,6 +52,7 @@ #include <fcntl.h> #include <limits.h> +#include <dirent.h> #include <sys/wait.h> #include <sys/time.h> #ifndef USEMMAP @@ -76,17 +77,18 @@ static u32 in_len; /* Input data length */ static u32 map_size = MAP_SIZE; -static u8 quiet_mode, /* Hide non-essential messages? */ +static bool quiet_mode, /* Hide non-essential messages? */ edges_only, /* Ignore hit counts? */ raw_instr_output, /* Do not apply AFL filters */ cmin_mode, /* Generate output in afl-cmin mode? */ binary_mode, /* Write output as a binary map */ keep_cores, /* Allow coredumps? */ - remove_shm = 1, /* remove shmem? */ + remove_shm = true, /* remove shmem? */ collect_coverage, /* collect coverage */ have_coverage, /* have coverage? */ no_classify, /* do not classify counts */ - debug; /* debug mode */ + debug, /* debug mode */ + print_filenames; /* print the current filename */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -233,6 +235,9 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { if (cmin_mode && (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) { + // create empty file to prevent error messages in afl-cmin + fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + close(fd); return ret; } @@ -320,11 +325,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -335,11 +340,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(fsrv->child_status)) { - child_crashed = 1; + child_crashed = true; } else { - child_crashed = 0; + child_crashed = false; } @@ -375,6 +380,13 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, static u32 read_file(u8 *in_file) { + if (print_filenames) { + + SAYF("Processing %s\n", in_file); + fflush(stdout); + + } + struct stat st; s32 fd = open(in_file, O_RDONLY); @@ -386,7 +398,18 @@ static u32 read_file(u8 *in_file) { } - in_len = st.st_size; + if (st.st_size > MAX_FILE) { + + WARNF("Input file '%s' is too large, only reading %u bytes.", in_file, + MAX_FILE); + in_len = MAX_FILE; + + } else { + + in_len = st.st_size; + + } + in_data = ck_alloc_nozero(in_len); ck_read(fd, in_data, in_len, in_file); @@ -504,11 +527,11 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -518,7 +541,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) { - child_crashed = 1; + child_crashed = true; } @@ -548,7 +571,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { static void handle_stop_sig(int sig) { (void)sig; - stop_soon = 1; + stop_soon = true; afl_fsrv_killall(); } @@ -731,6 +754,8 @@ static void usage(u8 *argv0) { "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " "size the target was compiled for\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " + "printed to stdout\n" "AFL_QUIET: do not print extra informational output\n", argv0, MEM_LIMIT, doc_path); @@ -744,14 +769,17 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ - s32 opt, i; - u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; + s32 opt, i; + bool mem_limit_given = false, timeout_given = false, unicorn_mode = false, + use_wine = false; char **use_argv; char **argv = argv_cpy_dup(argc, argv_orig); afl_forkserver_t fsrv_var = {0}; - if (getenv("AFL_DEBUG")) { debug = 1; } + if (getenv("AFL_DEBUG")) { debug = true; } + if (get_afl_env("AFL_PRINT_FILENAMES")) { print_filenames = true; } + fsrv = &fsrv_var; afl_fsrv_init(fsrv); map_size = get_map_size(); @@ -759,19 +787,19 @@ int main(int argc, char **argv_orig, char **envp) { doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; - if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; } + if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) { switch (opt) { case 's': - no_classify = 1; + no_classify = true; break; case 'C': - collect_coverage = 1; - quiet_mode = 1; + collect_coverage = true; + quiet_mode = true; break; case 'i': @@ -790,7 +818,7 @@ int main(int argc, char **argv_orig, char **envp) { u8 suffix = 'M'; if (mem_limit_given) { FATAL("Multiple -m options not supported"); } - mem_limit_given = 1; + mem_limit_given = true; if (!optarg) { FATAL("Wrong usage of -m"); } @@ -851,7 +879,7 @@ int main(int argc, char **argv_orig, char **envp) { case 't': if (timeout_given) { FATAL("Multiple -t options not supported"); } - timeout_given = 1; + timeout_given = true; if (!optarg) { FATAL("Wrong usage of -t"); } @@ -873,12 +901,12 @@ int main(int argc, char **argv_orig, char **envp) { if (edges_only) { FATAL("Multiple -e options not supported"); } if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); } - edges_only = 1; + edges_only = true; break; case 'q': - quiet_mode = 1; + quiet_mode = true; break; case 'Z': @@ -886,8 +914,8 @@ int main(int argc, char **argv_orig, char **envp) { /* This is an undocumented option to write data in the syntax expected by afl-cmin. Nobody else should have any use for this. */ - cmin_mode = 1; - quiet_mode = 1; + cmin_mode = true; + quiet_mode = true; break; case 'A': @@ -899,7 +927,7 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } - fsrv->frida_mode = 1; + fsrv->frida_mode = true; break; @@ -907,21 +935,21 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } - fsrv->qemu_mode = 1; + fsrv->qemu_mode = true; break; case 'U': if (unicorn_mode) { FATAL("Multiple -U options not supported"); } - unicorn_mode = 1; + unicorn_mode = true; break; case 'W': /* Wine+QEMU mode */ if (use_wine) { FATAL("Multiple -W options not supported"); } - fsrv->qemu_mode = 1; - use_wine = 1; + fsrv->qemu_mode = true; + use_wine = true; break; @@ -930,20 +958,20 @@ int main(int argc, char **argv_orig, char **envp) { /* Secret undocumented mode. Writes output in raw binary format similar to that dumped by afl-fuzz in <out_dir/queue/fuzz_bitmap. */ - binary_mode = 1; + binary_mode = true; break; case 'c': if (keep_cores) { FATAL("Multiple -c options not supported"); } - keep_cores = 1; + keep_cores = true; break; case 'r': if (raw_instr_output) { FATAL("Multiple -r options not supported"); } if (edges_only) { FATAL("-e and -r are mutually exclusive"); } - raw_instr_output = 1; + raw_instr_output = true; break; case 'h': @@ -1053,7 +1081,7 @@ int main(int argc, char **argv_orig, char **envp) { /* initialize cmplog_mode */ shm_fuzz->cmplog_mode = 0; u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1); - shm_fuzz->shmemfuzz_mode = 1; + shm_fuzz->shmemfuzz_mode = true; if (!map) { FATAL("BUG: Zero return from afl_shm_init."); } #ifdef USEMMAP setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1); @@ -1062,7 +1090,7 @@ int main(int argc, char **argv_orig, char **envp) { setenv(SHM_FUZZ_ENV_VAR, shm_str, 1); ck_free(shm_str); #endif - fsrv->support_shmem_fuzz = 1; + fsrv->support_shmem_fuzz = true; fsrv->shmem_fuzz_len = (u32 *)map; fsrv->shmem_fuzz = map + sizeof(u32); @@ -1079,6 +1107,9 @@ int main(int argc, char **argv_orig, char **envp) { : 0); be_quiet = save_be_quiet; + fsrv->kill_signal = + parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); + if (new_map_size) { // only reinitialize when it makes sense @@ -1105,8 +1136,9 @@ int main(int argc, char **argv_orig, char **envp) { if (in_dir) { - DIR * dir_in, *dir_out = NULL; - struct dirent *dir_ent; + DIR * dir_in, *dir_out = NULL; + struct dirent **file_list; + // int done = 0; u8 infile[PATH_MAX], outfile[PATH_MAX]; u8 wait_for_gdb = 0; @@ -1114,7 +1146,7 @@ int main(int argc, char **argv_orig, char **envp) { struct stat statbuf; #endif - if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = 1; + if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -1131,12 +1163,6 @@ int main(int argc, char **argv_orig, char **envp) { ck_free(dn); if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); - if (!(dir_in = opendir(in_dir))) { - - PFATAL("cannot open directory %s", in_dir); - - } - if (!collect_coverage) { if (!(dir_out = opendir(out_file))) { @@ -1153,8 +1179,8 @@ int main(int argc, char **argv_orig, char **envp) { if ((coverage_map = (u8 *)malloc(map_size)) == NULL) FATAL("coult not grab memory"); - edges_only = 0; - raw_instr_output = 1; + edges_only = false; + raw_instr_output = true; } @@ -1191,9 +1217,6 @@ int main(int argc, char **argv_orig, char **envp) { } - fsrv->kill_signal = - parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); - if (getenv("AFL_CRASH_EXITCODE")) { long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); @@ -1222,7 +1245,16 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - while ((dir_ent = readdir(dir_in))) { + int file_count = scandir(in_dir, &file_list, NULL, alphasort); + if (file_count < 0) { + + PFATAL("Failed to read from input dir at %s\n", in_dir); + + } + + for (int i = 0; i < file_count; i++) { + + struct dirent *dir_ent = file_list[i]; if (dir_ent->d_name[0] == '.') { @@ -1269,9 +1301,11 @@ int main(int argc, char **argv_orig, char **envp) { } + free(file_list); + file_list = NULL; + if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); } - closedir(dir_in); if (dir_out) { closedir(dir_out); } if (collect_coverage) { diff --git a/test/test-all.sh b/test/test-all.sh index 8df4bef9..0c189727 100755 --- a/test/test-all.sh +++ b/test/test-all.sh @@ -14,6 +14,8 @@ . ./test-qemu-mode.sh +. ./test-frida-mode.sh + . ./test-unicorn-mode.sh . ./test-custom-mutators.sh diff --git a/test/test-custom-mutators.sh b/test/test-custom-mutators.sh index bae4220f..5d679a82 100755 --- a/test/test-custom-mutators.sh +++ b/test/test-custom-mutators.sh @@ -5,7 +5,7 @@ $ECHO "$BLUE[*] Testing: custom mutator" test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { # normalize path - CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../utils/custom_mutators;pwd) + CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../custom_mutators/examples;pwd) test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && { unset AFL_CC # Compile the vulnerable program for single mutator @@ -29,8 +29,8 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { } } # Compile the custom mutator - cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 - cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1 + cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 + cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1 test -e test-custom-mutator -a -e ./libexamplemutator.so && { # Create input directory mkdir -p in diff --git a/test/test-frida-mode.sh b/test/test-frida-mode.sh new file mode 100755 index 00000000..b47d016a --- /dev/null +++ b/test/test-frida-mode.sh @@ -0,0 +1,108 @@ +#!/bin/sh + +. ./test-pre.sh + +$ECHO "$BLUE[*] Testing: frida_mode" +test -z "$AFL_CC" && { + if type gcc >/dev/null; then + export AFL_CC=gcc + else + if type clang >/dev/null; then + export AFL_CC=clang + fi + fi +} + +test -e ../afl-frida-trace.so && { + cc -no-pie -o test-instr ../test-instr.c + cc -o test-compcov test-compcov.c + test -e test-instr -a -e test-compcov && { + { + mkdir -p in + echo 00000 > in/in + $ECHO "$GREY[*] running afl-fuzz for frida_mode, this will take approx 10 seconds" + { + ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr >>errors 2>&1 + } >>errors 2>&1 + test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && { + $ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode" + RUNTIME=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'` + } || { + echo CUT------------------------------------------------------------------CUT + cat errors + echo CUT------------------------------------------------------------------CUT + $ECHO "$RED[!] afl-fuzz is not working correctly with frida_mode" + CODE=1 + } + rm -f errors + + test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && { + $ECHO "$GREY[*] running afl-fuzz for frida_mode cmplog, this will take approx 10 seconds" + { + ../afl-fuzz -m none -V10 -O -c 0 -i in -o out -- ./test-compcov >>errors 2>&1 + } >>errors 2>&1 + test -n "$( ls out/default/queue/id:000003* 2>/dev/null )" && { + $ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode cmplog" + } || { + echo CUT------------------------------------------------------------------CUT + cat errors + echo CUT------------------------------------------------------------------CUT + $ECHO "$RED[!] afl-fuzz is not working correctly with frida_mode cmplog" + CODE=1 + } + rm -f errors + } || { + $ECHO "$YELLOW[-] not an intel or arm platform, cannot test frida_mode cmplog" + } + + test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && { + $ECHO "$GREY[*] running afl-fuzz for persistent frida_mode, this will take approx 10 seconds" + { + #if file test-instr | grep -q "32-bit"; then + #else + #fi + export AFL_FRIDA_PERSISTENT_ADDR=0x`nm test-instr | grep "T main" | awk '{print $1}'` + $ECHO "Info: AFL_FRIDA_PERSISTENT_ADDR=$AFL_FRIDA_PERSISTENT_ADDR <= $(nm test-instr | grep "T main" | awk '{print $1}')" + env|grep AFL_|sort + file test-instr + ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr + unset AFL_FRIDA_PERSISTENT_ADDR + } >>errors 2>&1 + test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && { + $ECHO "$GREEN[+] afl-fuzz is working correctly with persistent frida_mode" + RUNTIMEP=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'` + test -n "$RUNTIME" -a -n "$RUNTIMEP" && { + DIFF=`expr $RUNTIMEP / $RUNTIME` + test "$DIFF" -gt 1 && { # must be at least twice as fast + $ECHO "$GREEN[+] persistent frida_mode was noticeable faster than standard frida_mode" + } || { + $ECHO "$YELLOW[-] persistent frida_mode was not noticeable faster than standard frida_mode" + } + } || { + $ECHO "$YELLOW[-] we got no data on executions performed? weird!" + } + } || { + echo CUT------------------------------------------------------------------CUT + cat errors + echo CUT------------------------------------------------------------------CUT + $ECHO "$RED[!] afl-fuzz is not working correctly with persistent frida_mode" + CODE=1 + } + rm -rf in out errors + } || { + $ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent frida_mode" + } + + } + } || { + $ECHO "$RED[!] gcc compilation of test targets failed - what is going on??" + CODE=1 + } + + rm -f test-instr test-compcov +} || { + $ECHO "$YELLOW[-] frida_mode is not compiled, cannot test" + INCOMPLETE=1 +} + +. ./test-post.sh diff --git a/test/test-performance.sh b/test/test-performance.sh index cd9f6caf..d61e2f2a 100755 --- a/test/test-performance.sh +++ b/test/test-performance.sh @@ -18,6 +18,7 @@ export AFL_QUIET=1 export AFL_PATH=`pwd`/.. unset AFL_EXIT_WHEN_DONE +unset AFL_EXIT_ON_TIME unset AFL_SKIP_CPUFREQ unset AFL_DEBUG unset AFL_HARDEN diff --git a/test/test-pre.sh b/test/test-pre.sh index 174f2f7f..7819da47 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -62,6 +62,7 @@ $ECHO \\101 2>&1 | grep -qE '^A' || { test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; } export AFL_EXIT_WHEN_DONE=1 +export AFL_EXIT_ON_TIME=60 export AFL_SKIP_CPUFREQ=1 export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 unset AFL_NO_X86 diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index d9ae5590..ffcf3b4c 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -fb2fc9f2 +019b871539fe9ed3f41d882385a8b02c243d49ad diff --git a/unicorn_mode/samples/speedtest/c/Makefile b/unicorn_mode/samples/speedtest/c/Makefile index ce784d4f..46789954 100644 --- a/unicorn_mode/samples/speedtest/c/Makefile +++ b/unicorn_mode/samples/speedtest/c/Makefile @@ -29,7 +29,11 @@ MYCC = $(__CC:$(_UNIQ)$(CROSS)=$(CROSS)gcc) .PHONY: all clean -all: fuzz +all: ../target harness + +afl-fuzz: ../../../../afl-fuzz +../../../../afl-fuzz: + $(MAKE) -C ../../../../ afl-fuzz clean: rm -rf *.o harness harness-debug @@ -49,6 +53,6 @@ harness-debug: harness-debug.o ../target: $(MAKE) -C .. -fuzz: ../target harness +fuzz: all afl-fuzz rm -rf ./output - SKIP_BINCHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./harness @@ + SKIP_BIN_CHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./harness @@ diff --git a/unicorn_mode/samples/speedtest/python/Makefile b/unicorn_mode/samples/speedtest/python/Makefile index 4282c6cb..c0c64269 100644 --- a/unicorn_mode/samples/speedtest/python/Makefile +++ b/unicorn_mode/samples/speedtest/python/Makefile @@ -1,8 +1,15 @@ -all: fuzz +.PHONY: all fuzz + +all: ../target + +afl-fuzz: ../../../../afl-fuzz +../../../../afl-fuzz: + $(MAKE) -C ../../../../ afl-fuzz + ../target: $(MAKE) -C .. -fuzz: ../target +fuzz: all afl-fuzz rm -rf ./ouptput ../../../../afl-fuzz -s 1 -U -i ../sample_inputs -o ./output -- python3 harness.py @@ diff --git a/unicorn_mode/samples/speedtest/rust/Makefile b/unicorn_mode/samples/speedtest/rust/Makefile index fe18d6ee..46934c93 100644 --- a/unicorn_mode/samples/speedtest/rust/Makefile +++ b/unicorn_mode/samples/speedtest/rust/Makefile @@ -1,4 +1,10 @@ -all: fuzz +.PHONY: all fuzz + +all: ../target ./target/release/unicornafl_harness + +afl-fuzz: ../../../../afl-fuzz +../../../../afl-fuzz: + $(MAKE) -C ../../../../ afl-fuzz clean: cargo clean @@ -12,6 +18,6 @@ clean: ../target: $(MAKE) -c .. -fuzz: ../target ./target/release/unicornafl_harness +fuzz: all afl-fuzz rm -rf ./output - SKIP_BINCHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./target/release/unicornafl_harness @@ + SKIP_BIN_CHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./target/release/unicornafl_harness @@ diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl -Subproject fb2fc9f25df32f17f6b6b859e4dbd70f9a857e0 +Subproject 019b871539fe9ed3f41d882385a8b02c243d49a diff --git a/utils/README.md b/utils/README.md index 336b6b6c..b157424f 100644 --- a/utils/README.md +++ b/utils/README.md @@ -32,7 +32,8 @@ Here's a quick overview of the stuff you can find in this directory: with additional gdb metadata. - custom_mutators - examples for the afl++ custom mutator interface in - C and Python + C and Python. Note: They were moved to + ../custom_mutators/examples/ - distributed_fuzzing - a sample script for synchronizing fuzzer instances across multiple machines (see parallel_fuzzing.md). diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c index aa7a361a..6006e238 100644 --- a/utils/afl_proxy/afl-proxy.c +++ b/utils/afl_proxy/afl-proxy.c @@ -70,6 +70,10 @@ static void __afl_map_shm(void) { char *id_str = getenv(SHM_ENV_VAR); char *ptr; + /* NOTE TODO BUG FIXME: if you want to supply a variable sized map then + uncomment the following: */ + + /* if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { u32 val = atoi(ptr); @@ -77,6 +81,8 @@ static void __afl_map_shm(void) { } + */ + if (__afl_map_size > MAP_SIZE) { if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { @@ -189,10 +195,7 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) { /* report that we are starting the target */ if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; - if (status < 1) - return 0; - else - return status; + return status; } @@ -210,7 +213,7 @@ int main(int argc, char *argv[]) { /* This is were the testcase data is written into */ u8 buf[1024]; // this is the maximum size for a test case! set it! - u32 len; + s32 len; /* here you specify the map size you need that you are reporting to afl-fuzz. Any value is fine as long as it can be divided by 32. */ @@ -222,10 +225,20 @@ int main(int argc, char *argv[]) { while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { - /* here you have to create the magic that feeds the buf/len to the - target and write the coverage to __afl_area_ptr */ + if (len > 4) { // the minimum data size you need for the target + + /* here you have to create the magic that feeds the buf/len to the + target and write the coverage to __afl_area_ptr */ - // ... the magic ... + // ... the magic ... + + // remove this, this is just to make afl-fuzz not complain when run + if (buf[0] == 0xff) + __afl_area_ptr[1] = 1; + else + __afl_area_ptr[2] = 2; + + } /* report the test case is done and wait for the next */ __afl_end_testcase(); diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile index 8ac054a6..ad99b893 100644 --- a/utils/aflpp_driver/GNUmakefile +++ b/utils/aflpp_driver/GNUmakefile @@ -7,7 +7,7 @@ ifneq "" "$(LLVM_BINDIR)" LLVM_BINDIR := $(LLVM_BINDIR)/ endif -CFLAGS := -O3 -funroll-loops -g +CFLAGS := -O3 -funroll-loops -g -fPIC all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so @@ -33,10 +33,10 @@ libAFLQemuDriver.a: aflpp_qemu_driver.o -cp -vf libAFLQemuDriver.a ../../ aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o - -$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so + -test -e aflpp_qemu_driver_hook.o && $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built." aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c - -$(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c + -test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built." test: debug #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c diff --git a/utils/aflpp_driver/README.md b/utils/aflpp_driver/README.md index 01bd10c0..f03c2fe3 100644 --- a/utils/aflpp_driver/README.md +++ b/utils/aflpp_driver/README.md @@ -13,6 +13,12 @@ If this is the clang compile command to build for libfuzzer: then just switch `clang++` with `afl-clang-fast++` and our compiler will magically insert libAFLDriver.a :) +To use shared-memory testcases, you need nothing to do. +To use stdin testcases give `-` as the only command line parameter. +To use file input testcases give `@@` as the only command line parameter. + +IMPORTANT: if you use `afl-cmin` or `afl-cmin.bash` then either pass `-` +or `@@` as command line parameters. ## aflpp_qemu_driver diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c index ad781e64..c094c425 100644 --- a/utils/aflpp_driver/aflpp_driver.c +++ b/utils/aflpp_driver/aflpp_driver.c @@ -174,11 +174,17 @@ size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { static int ExecuteFilesOnyByOne(int argc, char **argv) { unsigned char *buf = (unsigned char *)malloc(MAX_FILE); + for (int i = 1; i < argc; i++) { - int fd = open(argv[i], O_RDONLY); - if (fd == -1) continue; + int fd = 0; + + if (strcmp(argv[i], "-") != 0) { fd = open(argv[i], O_RDONLY); } + + if (fd == -1) { continue; } + ssize_t length = read(fd, buf, MAX_FILE); + if (length > 0) { printf("Reading %zu bytes from %s\n", length, argv[i]); @@ -187,7 +193,7 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) { } - close(fd); + if (fd > 0) { close(fd); } } @@ -199,15 +205,19 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) { int main(int argc, char **argv) { printf( - "======================= INFO =========================\n" + "============================== INFO ================================\n" "This binary is built for afl++.\n" + "To use with afl-cmin or afl-cmin.bash pass '-' as single command line " + "option\n" "To run the target function on individual input(s) execute this:\n" " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" "To fuzz with afl-fuzz execute this:\n" " afl-fuzz [afl-flags] -- %s [-N]\n" "afl-fuzz will run N iterations before re-spawning the process (default: " "INT_MAX)\n" - "======================================================\n", + "For stdin input processing, pass '-' as single command line option.\n" + "For file input processing, pass '@@' as single command line option.\n" + "===================================================================\n", argv[0], argv[0]); if (getenv("AFL_GDB")) { @@ -237,22 +247,35 @@ int main(int argc, char **argv) { memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT)); memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR, sizeof(AFL_DEFER_FORKSVR)); + int N = INT_MAX; - if (argc == 2 && argv[1][0] == '-') + + if (argc == 2 && !strcmp(argv[1], "-")) { + + __afl_sharedmem_fuzzing = 0; + __afl_manual_init(); + return ExecuteFilesOnyByOne(argc, argv); + + } else if (argc == 2 && argv[1][0] == '-') { + N = atoi(argv[1] + 1); - else if (argc == 2 && (N = atoi(argv[1])) > 0) + + } else if (argc == 2 && (N = atoi(argv[1])) > 0) { + printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N); - else if (argc > 1) { + + } else if (argc > 1) { __afl_sharedmem_fuzzing = 0; - __afl_manual_init(); + + if (argc == 2) { __afl_manual_init(); } + return ExecuteFilesOnyByOne(argc, argv); } assert(N > 0); - // if (!getenv("AFL_DRIVER_DONT_DEFER")) __afl_manual_init(); // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization @@ -271,6 +294,7 @@ int main(int argc, char **argv) { fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); fprintf(stderr, "\n"); #endif + if (*__afl_fuzz_len) { num_runs++; diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c index d3dd98b0..2979fadc 100644 --- a/utils/aflpp_driver/aflpp_qemu_driver_hook.c +++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c @@ -3,12 +3,12 @@ #include <stdint.h> #include <string.h> -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) #define h2g(x) ((uint64_t)(x)-guest_base) +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + // In this example the register RDI is pointing to the memory location // of the target buffer, and the length of the input is in RSI. // This can be seen with a debugger, e.g. gdb (and "disass main") @@ -16,11 +16,11 @@ void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, memcpy(g2h(regs->rdi), input_buf, input_buf_len); regs->rsi = input_buf_len; +} + #undef g2h #undef h2g -} - int afl_persistent_hook_init(void) { // 1 for shared memory input (faster), 0 for normal input (you have to use diff --git a/utils/libdislocator/libdislocator.so.c b/utils/libdislocator/libdislocator.so.c index 1b247c86..dde78f7b 100644 --- a/utils/libdislocator/libdislocator.so.c +++ b/utils/libdislocator/libdislocator.so.c @@ -144,8 +144,8 @@ typedef struct { /* Configurable stuff (use AFL_LD_* to set): */ -static u32 max_mem = MAX_ALLOC; /* Max heap usage to permit */ -static u8 alloc_verbose, /* Additional debug messages */ +static size_t max_mem = MAX_ALLOC; /* Max heap usage to permit */ +static u8 alloc_verbose, /* Additional debug messages */ hard_fail, /* abort() when max_mem exceeded? */ no_calloc_over, /* abort() on calloc() overflows? */ align_allocations; /* Force alignment to sizeof(void*) */ @@ -154,7 +154,7 @@ static u8 alloc_verbose, /* Additional debug messages */ #define __thread #warning no thread support available #endif -static __thread size_t total_mem; /* Currently allocated mem */ +static _Atomic size_t total_mem; /* Currently allocated mem */ static __thread u32 call_depth; /* To avoid recursion via fprintf() */ static u32 alloc_canary; @@ -172,9 +172,9 @@ static void *__dislocator_alloc(size_t len) { if (total_mem + len > max_mem || total_mem + len < total_mem) { - if (hard_fail) FATAL("total allocs exceed %u MB", max_mem / 1024 / 1024); + if (hard_fail) FATAL("total allocs exceed %zu MB", max_mem / 1024 / 1024); - DEBUGF("total allocs exceed %u MB, returning NULL", max_mem / 1024 / 1024); + DEBUGF("total allocs exceed %zu MB, returning NULL", max_mem / 1024 / 1024); return NULL; @@ -500,19 +500,20 @@ size_t malloc_usable_size(const void *ptr) { __attribute__((constructor)) void __dislocator_init(void) { - u8 *tmp = (u8 *)getenv("AFL_LD_LIMIT_MB"); + char *tmp = getenv("AFL_LD_LIMIT_MB"); if (tmp) { - u8 *tok; - s32 mmem = (s32)strtol((char *)tmp, (char **)&tok, 10); - if (*tok != '\0' || errno == ERANGE) FATAL("Bad value for AFL_LD_LIMIT_MB"); + char * tok; + unsigned long long mmem = strtoull(tmp, &tok, 10); + if (*tok != '\0' || errno == ERANGE || mmem > SIZE_MAX / 1024 / 1024) + FATAL("Bad value for AFL_LD_LIMIT_MB"); max_mem = mmem * 1024 * 1024; } alloc_canary = ALLOC_CANARY; - tmp = (u8 *)getenv("AFL_RANDOM_ALLOC_CANARY"); + tmp = getenv("AFL_RANDOM_ALLOC_CANARY"); if (tmp) arc4random_buf(&alloc_canary, sizeof(alloc_canary)); diff --git a/utils/qbdi_mode/template.cpp b/utils/qbdi_mode/template.cpp index b2066cc8..182a014b 100755 --- a/utils/qbdi_mode/template.cpp +++ b/utils/qbdi_mode/template.cpp @@ -25,7 +25,7 @@ #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) #define INC_AFL_AREA(loc) \ asm volatile( \ - "incb (%0, %1, 1)\n" \ + "addb $1, (%0, %1, 1)\n" \ "adcb $0, (%0, %1, 1)\n" \ : /* no out */ \ : "r"(afl_area_ptr), "r"(loc) \ diff --git a/utils/qemu_persistent_hook/read_into_rdi.c b/utils/qemu_persistent_hook/read_into_rdi.c index c1c6642f..14b2ed85 100644 --- a/utils/qemu_persistent_hook/read_into_rdi.c +++ b/utils/qemu_persistent_hook/read_into_rdi.c @@ -3,12 +3,12 @@ #include <stdio.h> #include <string.h> -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) #define h2g(x) ((uint64_t)(x)-guest_base) +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + // In this example the register RDI is pointing to the memory location // of the target buffer, and the length of the input is in RSI. // This can be seen with a debugger, e.g. gdb (and "disass main") @@ -19,11 +19,11 @@ void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, memcpy(g2h(regs->rdi), input_buf, input_buf_len); regs->rsi = input_buf_len; +} + #undef g2h #undef h2g -} - int afl_persistent_hook_init(void) { // 1 for shared memory input (faster), 0 for normal input (you have to use |